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