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