xref: /haiku/src/kits/interface/PictureDataWriter.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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::WriteSetTransform(BAffineTransform transform)
162 {
163 	try {
164 		BeginOp(B_PIC_SET_TRANSFORM);
165 		Write<BAffineTransform>(transform);
166 		EndOp();
167 	} catch (status_t &status) {
168 		return status;
169 	}
170 	return B_OK;
171 }
172 
173 
174 status_t
175 PictureDataWriter::WriteSetPattern(const pattern &pat)
176 {
177 	try {
178 		BeginOp(B_PIC_SET_STIPLE_PATTERN);
179 		Write<pattern>(pat);
180 		EndOp();
181 	} catch (status_t &status) {
182 		return status;
183 	}
184 	return B_OK;
185 }
186 
187 
188 status_t
189 PictureDataWriter::WriteSetClipping(const BRegion &region)
190 {
191 	// TODO: I don't know if it's compatible with R5's BPicture version
192 	try {
193 		const int32 numRects = region.CountRects();
194 		if (numRects > 0 && region.Frame().IsValid()) {
195 			BeginOp(B_PIC_SET_CLIPPING_RECTS);
196 			Write<uint32>(numRects);
197 			for (int32 i = 0; i < numRects; i++) {
198 				Write<BRect>(region.RectAt(i));
199 			}
200 			EndOp();
201 		} else
202 			WriteClearClipping();
203 	} catch (status_t &status) {
204 		return status;
205 	}
206 
207 	return B_OK;
208 }
209 
210 
211 status_t
212 PictureDataWriter::WriteClearClipping()
213 {
214 	try {
215 		BeginOp(B_PIC_CLEAR_CLIPPING_RECTS);
216 		EndOp();
217 	} catch (status_t &status) {
218 		return status;
219 	}
220 	return B_OK;
221 }
222 
223 
224 status_t
225 PictureDataWriter::WriteSetHighColor(const rgb_color &color)
226 {
227 	try {
228 		BeginOp(B_PIC_SET_FORE_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::WriteSetLowColor(const rgb_color &color)
240 {
241 	try {
242 		BeginOp(B_PIC_SET_BACK_COLOR);
243 		Write<rgb_color>(color);
244 		EndOp();
245 	} catch (status_t &status) {
246 		return status;
247 	}
248 	return B_OK;
249 }
250 
251 
252 status_t
253 PictureDataWriter::WriteDrawRect(const BRect &rect,
254 	const bool &fill)
255 {
256 	try {
257 		BeginOp(fill ? B_PIC_FILL_RECT : B_PIC_STROKE_RECT);
258 		Write<BRect>(rect);
259 		EndOp();
260 	} catch (status_t &status) {
261 		return status;
262 	}
263 	return B_OK;
264 }
265 
266 
267 status_t
268 PictureDataWriter::WriteDrawRoundRect(const BRect &rect,
269 	const BPoint &radius, const bool &fill)
270 {
271 	try {
272 		BeginOp(fill ? B_PIC_FILL_ROUND_RECT : B_PIC_STROKE_ROUND_RECT);
273 		Write<BRect>(rect);
274 		Write<BPoint>(radius);
275 		EndOp();
276 	} catch (status_t &status) {
277 		return status;
278 	}
279 	return B_OK;
280 }
281 
282 
283 status_t
284 PictureDataWriter::WriteDrawEllipse(const BRect &rect, const bool &fill)
285 {
286 	try {
287 		BeginOp(fill ? B_PIC_FILL_ELLIPSE : B_PIC_STROKE_ELLIPSE);
288 		Write<BRect>(rect);
289 		EndOp();
290 	} catch (status_t &status) {
291 		return status;
292 	}
293 	return B_OK;
294 }
295 
296 
297 status_t
298 PictureDataWriter::WriteDrawArc(const BPoint &center,
299 	const BPoint &radius, const float &startTheta,
300 	const float &arcTheta, const bool &fill)
301 {
302 	try {
303 		BeginOp(fill ? B_PIC_FILL_ARC : B_PIC_STROKE_ARC);
304 		Write<BPoint>(center);
305 		Write<BPoint>(radius);
306 		Write<float>(startTheta);
307 		Write<float>(arcTheta);
308 		EndOp();
309 	} catch (status_t &status) {
310 		return status;
311 	}
312 	return B_OK;
313 }
314 
315 
316 status_t
317 PictureDataWriter::WriteDrawPolygon(const int32 &numPoints,
318 	BPoint *points, const bool &isClosed, const bool &fill)
319 {
320 	try {
321 		BeginOp(fill ? B_PIC_FILL_POLYGON : B_PIC_STROKE_POLYGON);
322 		Write<int32>(numPoints);
323 		for (int32 i = 0; i < numPoints; i++)
324 			Write<BPoint>(points[i]);
325 		if (!fill)
326 			Write<uint8>((uint8)isClosed);
327 		EndOp();
328 	} catch (status_t &status) {
329 		return status;
330 	}
331 	return B_OK;
332 }
333 
334 
335 status_t
336 PictureDataWriter::WriteDrawBezier(const BPoint points[4],
337 	const bool &fill)
338 {
339 	try {
340 		BeginOp(fill ? B_PIC_FILL_BEZIER : B_PIC_STROKE_BEZIER);
341 		for (int32 i = 0; i < 4; i++)
342 			Write<BPoint>(points[i]);
343 		EndOp();
344 	} catch (status_t &status) {
345 		return status;
346 	}
347 	return B_OK;
348 }
349 
350 
351 status_t
352 PictureDataWriter::WriteStrokeLine(const BPoint &start,
353 	const BPoint &end)
354 {
355 	try {
356 		BeginOp(B_PIC_STROKE_LINE);
357 		Write<BPoint>(start);
358 		Write<BPoint>(end);
359 		EndOp();
360 	} catch (status_t &status) {
361 		return status;
362 	}
363 	return B_OK;
364 }
365 
366 
367 status_t
368 PictureDataWriter::WriteDrawString(const BPoint &where,
369 	const char *string, const int32 &length,
370 	const escapement_delta &escapement)
371 {
372 	try {
373 		BeginOp(B_PIC_SET_PEN_LOCATION);
374 		Write<BPoint>(where);
375 		EndOp();
376 
377 		BeginOp(B_PIC_DRAW_STRING);
378 		Write<float>(escapement.space);
379 		Write<float>(escapement.nonspace);
380 		//WriteData(string, length + 1);
381 			// TODO: is string 0 terminated? why is length given?
382 		WriteData(string, length);
383 		Write<uint8>(0);
384 		EndOp();
385 	} catch (status_t &status) {
386 		return status;
387 	}
388 
389 	return B_OK;
390 }
391 
392 
393 status_t
394 PictureDataWriter::WriteDrawShape(const int32 &opCount,
395 	const void *opList, const int32 &ptCount, const void *ptList,
396 	const bool &fill)
397 {
398 	try {
399 		BeginOp(fill ? B_PIC_FILL_SHAPE : B_PIC_STROKE_SHAPE);
400 		Write<int32>(opCount);
401 		Write<int32>(ptCount);
402 		WriteData(opList, opCount * sizeof(uint32));
403 		WriteData(ptList, ptCount * sizeof(BPoint));
404 		EndOp();
405 	} catch (status_t &status) {
406 		return status;
407 	}
408 
409 	return B_OK;
410 }
411 
412 
413 status_t
414 PictureDataWriter::WriteDrawBitmap(const BRect &srcRect,
415 	const BRect &dstRect, const int32 &width, const int32 &height,
416 	const int32 &bytesPerRow, const int32 &colorSpace,
417 	const int32 &flags, const void *data, const int32 &length)
418 {
419 	if (length != height * bytesPerRow)
420 		debugger("PictureDataWriter::WriteDrawBitmap: invalid length");
421 	try {
422 		BeginOp(B_PIC_DRAW_PIXELS);
423 		Write<BRect>(srcRect);
424 		Write<BRect>(dstRect);
425 		Write<int32>(width);
426 		Write<int32>(height);
427 		Write<int32>(bytesPerRow);
428 		Write<int32>(colorSpace);
429 		Write<int32>(flags);
430 		WriteData(data, length);
431 		EndOp();
432 	} catch (status_t &status) {
433 		return status;
434 	}
435 	return B_OK;
436 }
437 
438 
439 status_t
440 PictureDataWriter::WriteDrawPicture(const BPoint &where,
441 	const int32 &token)
442 {
443 	// TODO: I'm not sure about this function. I think we need
444 	// to attach the picture data too.
445 	// The token won't be sufficient in many cases (for example, when
446 	// we archive/flatten the picture.
447 	try {
448 		BeginOp(B_PIC_DRAW_PICTURE);
449 		Write<BPoint>(where);
450 		Write<int32>(token);
451 		EndOp();
452 	} catch (status_t &status) {
453 		return status;
454 	}
455 	return B_OK;
456 }
457 
458 
459 status_t
460 PictureDataWriter::WriteSetFontFamily(const font_family family)
461 {
462 	try {
463 		BeginOp(B_PIC_SET_FONT_FAMILY);
464 		WriteData(family, strlen(family));
465 		Write<uint8>(0);
466 		EndOp();
467 	} catch (status_t &status) {
468 		return status;
469 	}
470 	return B_OK;
471 }
472 
473 
474 status_t
475 PictureDataWriter::WriteSetFontStyle(const font_style style)
476 {
477 	try {
478 		BeginOp(B_PIC_SET_FONT_STYLE);
479 		WriteData(style, strlen(style));
480 		Write<uint8>(0);
481 		EndOp();
482 	} catch (status_t &status) {
483 		return status;
484 	}
485 	return B_OK;
486 }
487 
488 
489 status_t
490 PictureDataWriter::WriteSetFontSpacing(const int32 &spacing)
491 {
492 	try {
493 		BeginOp(B_PIC_SET_FONT_SPACING);
494 		Write<int32>(spacing);
495 		EndOp();
496 	} catch (status_t &status) {
497 		return status;
498 	}
499 	return B_OK;
500 }
501 
502 
503 status_t
504 PictureDataWriter::WriteSetFontSize(const float &size)
505 {
506 	try {
507 		BeginOp(B_PIC_SET_FONT_SIZE);
508 		Write<float>(size);
509 		EndOp();
510 	} catch (status_t &status) {
511 		return status;
512 	}
513 	return B_OK;
514 }
515 
516 
517 status_t
518 PictureDataWriter::WriteSetFontRotation(const float &rotation)
519 {
520 	try {
521 		BeginOp(B_PIC_SET_FONT_ROTATE);
522 		Write<float>(rotation);
523 		EndOp();
524 	} catch (status_t &status) {
525 		return status;
526 	}
527 	return B_OK;
528 }
529 
530 
531 status_t
532 PictureDataWriter::WriteSetFontEncoding(const int32 &encoding)
533 {
534 	try {
535 		BeginOp(B_PIC_SET_FONT_ENCODING);
536 		Write<int32>(encoding);
537 		EndOp();
538 	} catch (status_t &status) {
539 		return status;
540 	}
541 	return B_OK;
542 }
543 
544 
545 status_t
546 PictureDataWriter::WriteSetFontFlags(const int32 &flags)
547 {
548 	try {
549 		BeginOp(B_PIC_SET_FONT_FLAGS);
550 		Write<int32>(flags);
551 		EndOp();
552 	} catch (status_t &status) {
553 		return status;
554 	}
555 	return B_OK;
556 }
557 
558 
559 status_t
560 PictureDataWriter::WriteSetFontShear(const float &shear)
561 {
562 	try {
563 		BeginOp(B_PIC_SET_FONT_SHEAR);
564 		Write<float>(shear);
565 		EndOp();
566 	} catch (status_t &status) {
567 		return status;
568 	}
569 	return B_OK;
570 }
571 
572 
573 status_t
574 PictureDataWriter::WriteSetFontFace(const int32 &face)
575 {
576 	try {
577 		BeginOp(B_PIC_SET_FONT_FACE);
578 		Write<int32>(face);
579 		EndOp();
580 	} catch (status_t &status) {
581 		return status;
582 	}
583 	return B_OK;
584 }
585 
586 
587 status_t
588 PictureDataWriter::WritePushState()
589 {
590 	try {
591 		BeginOp(B_PIC_PUSH_STATE);
592 		EndOp();
593 	} catch (status_t &status) {
594 		return status;
595 	}
596 	return B_OK;
597 }
598 
599 
600 status_t
601 PictureDataWriter::WritePopState()
602 {
603 	try {
604 		BeginOp(B_PIC_POP_STATE);
605 		EndOp();
606 	} catch (status_t &status) {
607 		return status;
608 	}
609 	return B_OK;
610 }
611 
612 
613 // private
614 void
615 PictureDataWriter::BeginOp(const int16 &op)
616 {
617 	if (fData == NULL)
618 		THROW_ERROR(B_NO_INIT);
619 
620 	fStack.push(fData->Position());
621 	fData->Write(&op, sizeof(op));
622 
623 	// Init the size of the opcode block to 0
624 	int32 size = 0;
625 	fData->Write(&size, sizeof(size));
626 }
627 
628 
629 void
630 PictureDataWriter::EndOp()
631 {
632 	if (fData == NULL)
633 		THROW_ERROR(B_NO_INIT);
634 
635 	off_t curPos = fData->Position();
636 	off_t stackPos = fStack.top();
637 	fStack.pop();
638 
639 	// The size of the op is calculated like this:
640 	// current position on the stream minus the position on the stack,
641 	// minus the space occupied by the op code itself (int16)
642 	// and the space occupied by the size field (int32)
643 	int32 size = curPos - stackPos - sizeof(int32) - sizeof(int16);
644 
645 	// Size was set to 0 in BeginOp()
646 	// Now we overwrite it with the correct value
647 	fData->Seek(stackPos + sizeof(int16), SEEK_SET);
648 	fData->Write(&size, sizeof(size));
649 	fData->Seek(curPos, SEEK_SET);
650 }
651 
652 
653 void
654 PictureDataWriter::WriteData(const void *data, size_t size)
655 {
656 	ssize_t result = fData->Write(data, size);
657 	if (result < 0)
658 		THROW_ERROR(result);
659 	if ((size_t)result != size)
660 		THROW_ERROR(B_IO_ERROR);
661 }
662