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