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