xref: /haiku/src/kits/interface/PictureDataWriter.cpp (revision e688bf23d48bfd1216a0cacbdbda5e35a1bcd779)
1 /*
2  * Copyright 2006-2009, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stefano Ceccherini (stefano.ceccherini@gmail.com)
7  */
8 
9 #include <PictureDataWriter.h>
10 
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include <DataIO.h>
15 #include <Point.h>
16 #include <Rect.h>
17 #include <Region.h>
18 
19 #include <PictureProtocol.h>
20 
21 #define THROW_ERROR(error) throw (status_t)(error)
22 
23 // TODO: Review writing of strings. AFAIK in the picture data format
24 // They are not supposed to be NULL terminated
25 // (at least, it's not mandatory) so we should write their size too.
26 PictureDataWriter::PictureDataWriter()
27 	:
28 	fData(NULL)
29 {
30 }
31 
32 
33 PictureDataWriter::PictureDataWriter(BPositionIO *data)
34 	:
35 	fData(data)
36 {
37 }
38 
39 
40 PictureDataWriter::~PictureDataWriter()
41 {
42 }
43 
44 
45 status_t
46 PictureDataWriter::SetTo(BPositionIO *data)
47 {
48 	if (data == NULL)
49 		return B_BAD_VALUE;
50 	fData = data;
51 	return B_OK;
52 }
53 
54 
55 status_t
56 PictureDataWriter::WriteSetOrigin(const BPoint &point)
57 {
58 	try {
59 		BeginOp(B_PIC_SET_ORIGIN);
60 		Write<BPoint>(point);
61 		EndOp();
62 	} catch (status_t &status) {
63 		return status;
64 	}
65 	return B_OK;
66 }
67 
68 
69 status_t
70 PictureDataWriter::WriteInvertRect(const BRect &rect)
71 {
72 	try {
73 		WriteSetDrawingMode(B_OP_INVERT);
74 
75 		BeginOp(B_PIC_FILL_RECT);
76 		Write<BRect>(rect);
77 		EndOp();
78 
79 		WriteSetDrawingMode(B_OP_COPY);
80 	} catch (status_t &status) {
81 		return status;
82 	}
83 	return B_OK;
84 }
85 
86 
87 status_t
88 PictureDataWriter::WriteSetDrawingMode(const drawing_mode &mode)
89 {
90 	try {
91 		BeginOp(B_PIC_SET_DRAWING_MODE);
92 		Write<int16>((int16)mode);
93 		EndOp();
94 	} catch (status_t &status) {
95 		return status;
96 	}
97 	return B_OK;
98 }
99 
100 
101 status_t
102 PictureDataWriter::WriteSetPenLocation(const BPoint &point)
103 {
104 	try {
105 		BeginOp(B_PIC_SET_PEN_LOCATION);
106 		Write<BPoint>(point);
107 		EndOp();
108 	} catch (status_t &status) {
109 		return status;
110 	}
111 	return B_OK;
112 }
113 
114 
115 status_t
116 PictureDataWriter::WriteSetPenSize(const float &penSize)
117 {
118 	try {
119 		BeginOp(B_PIC_SET_PEN_SIZE);
120 		Write<float>(penSize);
121 		EndOp();
122 	} catch (status_t &status) {
123 		return status;
124 	}
125 	return B_OK;
126 }
127 
128 
129 status_t
130 PictureDataWriter::WriteSetLineMode(const cap_mode &cap,
131 	const join_mode &join, const float &miterLimit)
132 {
133 	try {
134 		BeginOp(B_PIC_SET_LINE_MODE);
135 		Write<int16>((int16)cap);
136 		Write<int16>((int16)join);
137 		Write<float>(miterLimit);
138 		EndOp();
139 	} catch (status_t &status) {
140 		return status;
141 	}
142 	return B_OK;
143 }
144 
145 
146 status_t
147 PictureDataWriter::WriteSetScale(const float &scale)
148 {
149 	try {
150 		BeginOp(B_PIC_SET_SCALE);
151 		Write<float>(scale);
152 		EndOp();
153 	} catch (status_t &status) {
154 		return status;
155 	}
156 	return B_OK;
157 }
158 
159 
160 status_t
161 PictureDataWriter::WriteSetPattern(const pattern &pat)
162 {
163 	try {
164 		BeginOp(B_PIC_SET_STIPLE_PATTERN);
165 		Write<pattern>(pat);
166 		EndOp();
167 	} catch (status_t &status) {
168 		return status;
169 	}
170 	return B_OK;
171 }
172 
173 
174 status_t
175 PictureDataWriter::WriteSetClipping(const BRegion &region)
176 {
177 	// TODO: I don't know if it's compatible with R5's BPicture version
178 	try {
179 		const int32 numRects = region.CountRects();
180 		if (numRects > 0 && region.Frame().IsValid()) {
181 			BeginOp(B_PIC_SET_CLIPPING_RECTS);
182 			Write<uint32>(numRects);
183 			for (int32 i = 0; i < numRects; i++) {
184 				Write<BRect>(region.RectAt(i));
185 			}
186 			EndOp();
187 		} else
188 			WriteClearClipping();
189 	} catch (status_t &status) {
190 		return status;
191 	}
192 
193 	return B_OK;
194 }
195 
196 
197 status_t
198 PictureDataWriter::WriteClearClipping()
199 {
200 	try {
201 		BeginOp(B_PIC_CLEAR_CLIPPING_RECTS);
202 		EndOp();
203 	} catch (status_t &status) {
204 		return status;
205 	}
206 	return B_OK;
207 }
208 
209 
210 status_t
211 PictureDataWriter::WriteSetHighColor(const rgb_color &color)
212 {
213 	try {
214 		BeginOp(B_PIC_SET_FORE_COLOR);
215 		Write<rgb_color>(color);
216 		EndOp();
217 	} catch (status_t &status) {
218 		return status;
219 	}
220 	return B_OK;
221 }
222 
223 
224 status_t
225 PictureDataWriter::WriteSetLowColor(const rgb_color &color)
226 {
227 	try {
228 		BeginOp(B_PIC_SET_BACK_COLOR);
229 		Write<rgb_color>(color);
230 		EndOp();
231 	} catch (status_t &status) {
232 		return status;
233 	}
234 	return B_OK;
235 }
236 
237 
238 status_t
239 PictureDataWriter::WriteDrawRect(const BRect &rect,
240 	const bool &fill)
241 {
242 	try {
243 		BeginOp(fill ? B_PIC_FILL_RECT : B_PIC_STROKE_RECT);
244 		Write<BRect>(rect);
245 		EndOp();
246 	} catch (status_t &status) {
247 		return status;
248 	}
249 	return B_OK;
250 }
251 
252 
253 status_t
254 PictureDataWriter::WriteDrawRoundRect(const BRect &rect,
255 	const BPoint &radius, const bool &fill)
256 {
257 	try {
258 		BeginOp(fill ? B_PIC_FILL_ROUND_RECT : B_PIC_STROKE_ROUND_RECT);
259 		Write<BRect>(rect);
260 		Write<BPoint>(radius);
261 		EndOp();
262 	} catch (status_t &status) {
263 		return status;
264 	}
265 	return B_OK;
266 }
267 
268 
269 status_t
270 PictureDataWriter::WriteDrawEllipse(const BRect &rect, const bool &fill)
271 {
272 	try {
273 		BeginOp(fill ? B_PIC_FILL_ELLIPSE : B_PIC_STROKE_ELLIPSE);
274 		Write<BRect>(rect);
275 		EndOp();
276 	} catch (status_t &status) {
277 		return status;
278 	}
279 	return B_OK;
280 }
281 
282 
283 status_t
284 PictureDataWriter::WriteDrawArc(const BPoint &center,
285 	const BPoint &radius, const float &startTheta,
286 	const float &arcTheta, const bool &fill)
287 {
288 	try {
289 		BeginOp(fill ? B_PIC_FILL_ARC : B_PIC_STROKE_ARC);
290 		Write<BPoint>(center);
291 		Write<BPoint>(radius);
292 		Write<float>(startTheta);
293 		Write<float>(arcTheta);
294 		EndOp();
295 	} catch (status_t &status) {
296 		return status;
297 	}
298 	return B_OK;
299 }
300 
301 
302 status_t
303 PictureDataWriter::WriteDrawPolygon(const int32 &numPoints,
304 	BPoint *points, const bool &isClosed, const bool &fill)
305 {
306 	try {
307 		BeginOp(fill ? B_PIC_FILL_POLYGON : B_PIC_STROKE_POLYGON);
308 		Write<int32>(numPoints);
309 		for (int32 i = 0; i < numPoints; i++)
310 			Write<BPoint>(points[i]);
311 		if (!fill)
312 			Write<uint8>((uint8)isClosed);
313 		EndOp();
314 	} catch (status_t &status) {
315 		return status;
316 	}
317 	return B_OK;
318 }
319 
320 
321 status_t
322 PictureDataWriter::WriteDrawBezier(const BPoint points[4],
323 	const bool &fill)
324 {
325 	try {
326 		BeginOp(fill ? B_PIC_FILL_BEZIER : B_PIC_STROKE_BEZIER);
327 		for (int32 i = 0; i < 4; i++)
328 			Write<BPoint>(points[i]);
329 		EndOp();
330 	} catch (status_t &status) {
331 		return status;
332 	}
333 	return B_OK;
334 }
335 
336 
337 status_t
338 PictureDataWriter::WriteStrokeLine(const BPoint &start,
339 	const BPoint &end)
340 {
341 	try {
342 		BeginOp(B_PIC_STROKE_LINE);
343 		Write<BPoint>(start);
344 		Write<BPoint>(end);
345 		EndOp();
346 	} catch (status_t &status) {
347 		return status;
348 	}
349 	return B_OK;
350 }
351 
352 
353 status_t
354 PictureDataWriter::WriteDrawString(const BPoint &where,
355 	const char *string, const int32 &length,
356 	const escapement_delta &escapement)
357 {
358 	try {
359 		BeginOp(B_PIC_SET_PEN_LOCATION);
360 		Write<BPoint>(where);
361 		EndOp();
362 
363 		BeginOp(B_PIC_DRAW_STRING);
364 		Write<float>(escapement.space);
365 		Write<float>(escapement.nonspace);
366 		//WriteData(string, length + 1);
367 			// TODO: is string 0 terminated? why is length given?
368 		WriteData(string, length);
369 		Write<uint8>(0);
370 		EndOp();
371 	} catch (status_t &status) {
372 		return status;
373 	}
374 
375 	return B_OK;
376 }
377 
378 
379 status_t
380 PictureDataWriter::WriteDrawShape(const int32 &opCount,
381 	const void *opList, const int32 &ptCount, const void *ptList,
382 	const bool &fill)
383 {
384 	try {
385 		BeginOp(fill ? B_PIC_FILL_SHAPE : B_PIC_STROKE_SHAPE);
386 		Write<int32>(opCount);
387 		Write<int32>(ptCount);
388 		WriteData(opList, opCount * sizeof(uint32));
389 		WriteData(ptList, ptCount * sizeof(BPoint));
390 		EndOp();
391 	} catch (status_t &status) {
392 		return status;
393 	}
394 
395 	return B_OK;
396 }
397 
398 
399 status_t
400 PictureDataWriter::WriteDrawBitmap(const BRect &srcRect,
401 	const BRect &dstRect, const int32 &width, const int32 &height,
402 	const int32 &bytesPerRow, const int32 &colorSpace,
403 	const int32 &flags, const void *data, const int32 &length)
404 {
405 	if (length != height * bytesPerRow)
406 		debugger("PictureDataWriter::WriteDrawBitmap: invalid length");
407 	try {
408 		BeginOp(B_PIC_DRAW_PIXELS);
409 		Write<BRect>(srcRect);
410 		Write<BRect>(dstRect);
411 		Write<int32>(width);
412 		Write<int32>(height);
413 		Write<int32>(bytesPerRow);
414 		Write<int32>(colorSpace);
415 		Write<int32>(flags);
416 		WriteData(data, length);
417 		EndOp();
418 	} catch (status_t &status) {
419 		return status;
420 	}
421 	return B_OK;
422 }
423 
424 
425 status_t
426 PictureDataWriter::WriteDrawPicture(const BPoint &where,
427 	const int32 &token)
428 {
429 	// TODO: I'm not sure about this function. I think we need
430 	// to attach the picture data too.
431 	// The token won't be sufficient in many cases (for example, when
432 	// we archive/flatten the picture.
433 	try {
434 		BeginOp(B_PIC_DRAW_PICTURE);
435 		Write<BPoint>(where);
436 		Write<int32>(token);
437 		EndOp();
438 	} catch (status_t &status) {
439 		return status;
440 	}
441 	return B_OK;
442 }
443 
444 
445 status_t
446 PictureDataWriter::WriteSetFontFamily(const font_family family)
447 {
448 	try {
449 		BeginOp(B_PIC_SET_FONT_FAMILY);
450 		WriteData(family, strlen(family));
451 		Write<uint8>(0);
452 		EndOp();
453 	} catch (status_t &status) {
454 		return status;
455 	}
456 	return B_OK;
457 }
458 
459 
460 status_t
461 PictureDataWriter::WriteSetFontStyle(const font_style style)
462 {
463 	try {
464 		BeginOp(B_PIC_SET_FONT_STYLE);
465 		WriteData(style, strlen(style));
466 		Write<uint8>(0);
467 		EndOp();
468 	} catch (status_t &status) {
469 		return status;
470 	}
471 	return B_OK;
472 }
473 
474 
475 status_t
476 PictureDataWriter::WriteSetFontSpacing(const int32 &spacing)
477 {
478 	try {
479 		BeginOp(B_PIC_SET_FONT_SPACING);
480 		Write<int32>(spacing);
481 		EndOp();
482 	} catch (status_t &status) {
483 		return status;
484 	}
485 	return B_OK;
486 }
487 
488 
489 status_t
490 PictureDataWriter::WriteSetFontSize(const float &size)
491 {
492 	try {
493 		BeginOp(B_PIC_SET_FONT_SIZE);
494 		Write<float>(size);
495 		EndOp();
496 	} catch (status_t &status) {
497 		return status;
498 	}
499 	return B_OK;
500 }
501 
502 
503 status_t
504 PictureDataWriter::WriteSetFontRotation(const float &rotation)
505 {
506 	try {
507 		BeginOp(B_PIC_SET_FONT_ROTATE);
508 		Write<float>(rotation);
509 		EndOp();
510 	} catch (status_t &status) {
511 		return status;
512 	}
513 	return B_OK;
514 }
515 
516 
517 status_t
518 PictureDataWriter::WriteSetFontEncoding(const int32 &encoding)
519 {
520 	try {
521 		BeginOp(B_PIC_SET_FONT_ENCODING);
522 		Write<int32>(encoding);
523 		EndOp();
524 	} catch (status_t &status) {
525 		return status;
526 	}
527 	return B_OK;
528 }
529 
530 
531 status_t
532 PictureDataWriter::WriteSetFontFlags(const int32 &flags)
533 {
534 	try {
535 		BeginOp(B_PIC_SET_FONT_FLAGS);
536 		Write<int32>(flags);
537 		EndOp();
538 	} catch (status_t &status) {
539 		return status;
540 	}
541 	return B_OK;
542 }
543 
544 
545 status_t
546 PictureDataWriter::WriteSetFontShear(const float &shear)
547 {
548 	try {
549 		BeginOp(B_PIC_SET_FONT_SHEAR);
550 		Write<float>(shear);
551 		EndOp();
552 	} catch (status_t &status) {
553 		return status;
554 	}
555 	return B_OK;
556 }
557 
558 
559 status_t
560 PictureDataWriter::WriteSetFontFace(const int32 &face)
561 {
562 	try {
563 		BeginOp(B_PIC_SET_FONT_FACE);
564 		Write<int32>(face);
565 		EndOp();
566 	} catch (status_t &status) {
567 		return status;
568 	}
569 	return B_OK;
570 }
571 
572 
573 status_t
574 PictureDataWriter::WritePushState()
575 {
576 	try {
577 		BeginOp(B_PIC_PUSH_STATE);
578 		EndOp();
579 	} catch (status_t &status) {
580 		return status;
581 	}
582 	return B_OK;
583 }
584 
585 
586 status_t
587 PictureDataWriter::WritePopState()
588 {
589 	try {
590 		BeginOp(B_PIC_POP_STATE);
591 		EndOp();
592 	} catch (status_t &status) {
593 		return status;
594 	}
595 	return B_OK;
596 }
597 
598 
599 // private
600 void
601 PictureDataWriter::BeginOp(const int16 &op)
602 {
603 	if (fData == NULL)
604 		THROW_ERROR(B_NO_INIT);
605 
606 	fStack.push(fData->Position());
607 	fData->Write(&op, sizeof(op));
608 
609 	// Init the size of the opcode block to 0
610 	int32 size = 0;
611 	fData->Write(&size, sizeof(size));
612 }
613 
614 
615 void
616 PictureDataWriter::EndOp()
617 {
618 	if (fData == NULL)
619 		THROW_ERROR(B_NO_INIT);
620 
621 	off_t curPos = fData->Position();
622 	off_t stackPos = fStack.top();
623 	fStack.pop();
624 
625 	// The size of the op is calculated like this:
626 	// current position on the stream minus the position on the stack,
627 	// minus the space occupied by the op code itself (int16)
628 	// and the space occupied by the size field (int32)
629 	int32 size = curPos - stackPos - sizeof(int32) - sizeof(int16);
630 
631 	// Size was set to 0 in BeginOp()
632 	// Now we overwrite it with the correct value
633 	fData->Seek(stackPos + sizeof(int16), SEEK_SET);
634 	fData->Write(&size, sizeof(size));
635 	fData->Seek(curPos, SEEK_SET);
636 }
637 
638 
639 void
640 PictureDataWriter::WriteData(const void *data, size_t size)
641 {
642 	ssize_t result = fData->Write(data, size);
643 	if (result < 0)
644 		THROW_ERROR(result);
645 	if ((size_t)result != size)
646 		THROW_ERROR(B_IO_ERROR);
647 }
648