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