xref: /haiku/src/kits/interface/PicturePlayer.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
1 /*
2  * Copyright 2001-2018, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stefano Ceccherini (stefano.ceccherini@gmail.com)
8  *		Marcus Overhagen (marcus@overhagen.de)
9  *		Stephan Aßmus <superstippi@gmx.de>
10  */
11 
12 /**	PicturePlayer is used to play picture data. */
13 
14 #include <PicturePlayer.h>
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include <AffineTransform.h>
21 #include <DataIO.h>
22 #include <Gradient.h>
23 #include <PictureProtocol.h>
24 #include <Shape.h>
25 #include <ShapePrivate.h>
26 
27 #include <AutoDeleter.h>
28 #include <StackOrHeapArray.h>
29 
30 
31 using BPrivate::PicturePlayer;
32 
33 
34 struct adapter_context {
35 	void* user_data;
36 	void** function_table;
37 };
38 
39 
40 static void
41 nop()
42 {
43 }
44 
45 
46 static void
47 move_pen_by(void* _context, const BPoint& delta)
48 {
49 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
50 	((void (*)(void*, BPoint))context->function_table[1])(context->user_data,
51 		delta);
52 }
53 
54 
55 static void
56 stroke_line(void* _context, const BPoint& start, const BPoint& end)
57 {
58 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
59 	((void (*)(void*, BPoint, BPoint))context->function_table[2])(
60 		context->user_data, start, end);
61 }
62 
63 
64 static void
65 draw_rect(void* _context, const BRect& rect, bool fill)
66 {
67 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
68 	((void (*)(void*, BRect))context->function_table[fill ? 4 : 3])(
69 		context->user_data, rect);
70 }
71 
72 
73 static void
74 draw_round_rect(void* _context, const BRect& rect, const BPoint& radii,
75 	bool fill)
76 {
77 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
78 	((void (*)(void*, BRect, BPoint))context->function_table[fill ? 6 : 5])(
79 		context->user_data, rect, radii);
80 }
81 
82 
83 static void
84 draw_bezier(void* _context, size_t numPoints, const BPoint _points[], bool fill)
85 {
86 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
87 	if (numPoints != 4)
88 		return;
89 
90 	BPoint points[4] = { _points[0], _points[1], _points[2], _points[3] };
91 	((void (*)(void*, BPoint*))context->function_table[fill ? 8 : 7])(
92 		context->user_data, points);
93 }
94 
95 
96 static void
97 draw_arc(void* _context, const BPoint& center, const BPoint& radii,
98 	float startTheta, float arcTheta, bool fill)
99 {
100 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
101 	((void (*)(void*, BPoint, BPoint, float, float))
102 		context->function_table[fill ? 10 : 9])(context->user_data, center,
103 			radii, startTheta, arcTheta);
104 }
105 
106 
107 static void
108 draw_ellipse(void* _context, const BRect& rect, bool fill)
109 {
110 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
111 	BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f);
112 	BPoint center = rect.LeftTop() + radii;
113 	((void (*)(void*, BPoint, BPoint))
114 		context->function_table[fill ? 12 : 11])(context->user_data, center,
115 			radii);
116 }
117 
118 
119 static void
120 draw_polygon(void* _context, size_t numPoints, const BPoint _points[],
121 	bool isClosed, bool fill)
122 {
123 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
124 
125 	BStackOrHeapArray<BPoint, 200> points(numPoints);
126 	if (!points.IsValid())
127 		return;
128 
129 	memcpy((void*)points, _points, numPoints * sizeof(BPoint));
130 
131 	((void (*)(void*, int32, BPoint*, bool))
132 		context->function_table[fill ? 14 : 13])(context->user_data, numPoints,
133 			points, isClosed);
134 }
135 
136 
137 static void
138 draw_shape(void* _context, const BShape& shape, bool fill)
139 {
140 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
141 	((void (*)(void*, BShape))context->function_table[fill ? 16 : 15])(
142 		context->user_data, shape);
143 }
144 
145 
146 static void
147 draw_string(void* _context, const char* _string, size_t length,
148 	float deltaSpace, float deltaNonSpace)
149 {
150 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
151 	char* string = strndup(_string, length);
152 
153 	((void (*)(void*, char*, float, float))
154 		context->function_table[17])(context->user_data, string, deltaSpace,
155 			deltaNonSpace);
156 
157 	free(string);
158 }
159 
160 
161 static void
162 draw_pixels(void* _context, const BRect& src, const BRect& dest, uint32 width,
163 	uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
164 	const void* _data, size_t length)
165 {
166 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
167 	void* data = malloc(length);
168 	if (data == NULL)
169 		return;
170 
171 	memcpy(data, _data, length);
172 
173 	((void (*)(void*, BRect, BRect, int32, int32, int32, int32, int32, void*))
174 		context->function_table[18])(context->user_data, src, dest, width,
175 			height, bytesPerRow, pixelFormat, options, data);
176 
177 	free(data);
178 }
179 
180 
181 static void
182 draw_picture(void* _context, const BPoint& where, int32 token)
183 {
184 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
185 	((void (*)(void*, BPoint, int32))context->function_table[19])(
186 		context->user_data, where, token);
187 }
188 
189 
190 static void
191 set_clipping_rects(void* _context, size_t numRects, const BRect _rects[])
192 {
193 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
194 
195 	// This is rather ugly but works for such a trivial class.
196 	BStackOrHeapArray<BRect, 100> rects(numRects);
197 	if (!rects.IsValid())
198 		return;
199 
200 	memcpy((void*)rects, _rects, numRects * sizeof(BRect));
201 
202 	((void (*)(void*, BRect*, uint32))context->function_table[20])(
203 		context->user_data, rects, numRects);
204 }
205 
206 
207 static void
208 clip_to_picture(void* _context, int32 token, const BPoint& origin,
209 	bool clipToInverse)
210 {
211 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
212 	((void (*)(void*, int32, BPoint, bool))context->function_table[21])(
213 			context->user_data, token, origin, clipToInverse);
214 }
215 
216 
217 static void
218 push_state(void* _context)
219 {
220 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
221 	((void (*)(void*))context->function_table[22])(context->user_data);
222 }
223 
224 
225 static void
226 pop_state(void* _context)
227 {
228 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
229 	((void (*)(void*))context->function_table[23])(context->user_data);
230 }
231 
232 
233 static void
234 enter_state_change(void* _context)
235 {
236 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
237 	((void (*)(void*))context->function_table[24])(context->user_data);
238 }
239 
240 
241 static void
242 exit_state_change(void* _context)
243 {
244 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
245 	((void (*)(void*))context->function_table[25])(context->user_data);
246 }
247 
248 
249 static void
250 enter_font_state(void* _context)
251 {
252 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
253 	((void (*)(void*))context->function_table[26])(context->user_data);
254 }
255 
256 
257 static void
258 exit_font_state(void* _context)
259 {
260 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
261 	((void (*)(void*))context->function_table[27])(context->user_data);
262 }
263 
264 
265 static void
266 set_origin(void* _context, const BPoint& origin)
267 {
268 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
269 	((void (*)(void*, BPoint))context->function_table[28])(context->user_data,
270 		origin);
271 }
272 
273 
274 static void
275 set_pen_location(void* _context, const BPoint& penLocation)
276 {
277 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
278 	((void (*)(void*, BPoint))context->function_table[29])(context->user_data,
279 		penLocation);
280 }
281 
282 
283 static void
284 set_drawing_mode(void* _context, drawing_mode mode)
285 {
286 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
287 	((void (*)(void*, drawing_mode))context->function_table[30])(
288 		context->user_data, mode);
289 }
290 
291 
292 static void
293 set_line_mode(void* _context, cap_mode capMode, join_mode joinMode,
294 	float miterLimit)
295 {
296 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
297 	((void (*)(void*, cap_mode, join_mode, float))context->function_table[31])(
298 		context->user_data, capMode, joinMode, miterLimit);
299 }
300 
301 
302 static void
303 set_pen_size(void* _context, float size)
304 {
305 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
306 	((void (*)(void*, float))context->function_table[32])(context->user_data,
307 		size);
308 }
309 
310 
311 static void
312 set_fore_color(void* _context, const rgb_color& color)
313 {
314 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
315 	((void (*)(void*, rgb_color))context->function_table[33])(
316 		context->user_data, color);
317 }
318 
319 
320 static void
321 set_back_color(void* _context, const rgb_color& color)
322 {
323 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
324 	((void (*)(void*, rgb_color))context->function_table[34])(
325 		context->user_data, color);
326 }
327 
328 
329 static void
330 set_stipple_pattern(void* _context, const pattern& stipplePattern)
331 {
332 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
333 	((void (*)(void*, pattern))context->function_table[35])(context->user_data,
334 		stipplePattern);
335 }
336 
337 
338 static void
339 set_scale(void* _context, float scale)
340 {
341 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
342 	((void (*)(void*, float))context->function_table[36])(context->user_data,
343 		scale);
344 }
345 
346 
347 static void
348 set_font_family(void* _context, const char* _family, size_t length)
349 {
350 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
351 	char* family = strndup(_family, length);
352 
353 	((void (*)(void*, char*))context->function_table[37])(context->user_data,
354 		family);
355 
356 	free(family);
357 }
358 
359 
360 static void
361 set_font_style(void* _context, const char* _style, size_t length)
362 {
363 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
364 	char* style = strndup(_style, length);
365 
366 	((void (*)(void*, char*))context->function_table[38])(context->user_data,
367 		style);
368 
369 	free(style);
370 }
371 
372 
373 static void
374 set_font_spacing(void* _context, uint8 spacing)
375 {
376 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
377 	((void (*)(void*, int32))context->function_table[39])(context->user_data,
378 		spacing);
379 }
380 
381 
382 static void
383 set_font_size(void* _context, float size)
384 {
385 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
386 	((void (*)(void*, float))context->function_table[40])(context->user_data,
387 		size);
388 }
389 
390 
391 static void
392 set_font_rotation(void* _context, float rotation)
393 {
394 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
395 	((void (*)(void*, float))context->function_table[41])(context->user_data,
396 		rotation);
397 }
398 
399 
400 static void
401 set_font_encoding(void* _context, uint8 encoding)
402 {
403 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
404 	((void (*)(void*, int32))context->function_table[42])(context->user_data,
405 		encoding);
406 }
407 
408 
409 static void
410 set_font_flags(void* _context, uint32 flags)
411 {
412 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
413 	((void (*)(void*, int32))context->function_table[43])(context->user_data,
414 		flags);
415 }
416 
417 
418 static void
419 set_font_shear(void* _context, float shear)
420 {
421 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
422 	((void (*)(void*, float))context->function_table[44])(context->user_data,
423 		shear);
424 }
425 
426 
427 static void
428 set_font_face(void* _context, uint16 face)
429 {
430 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
431 	((void (*)(void*, int32))context->function_table[46])(context->user_data,
432 		face);
433 }
434 
435 
436 static void
437 set_blending_mode(void* _context, source_alpha alphaSrcMode,
438 	alpha_function alphaFncMode)
439 {
440 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
441 	((void (*)(void*, source_alpha, alpha_function))
442 		context->function_table[47])(context->user_data, alphaSrcMode,
443 			alphaFncMode);
444 }
445 
446 
447 static void
448 set_transform(void* _context, const BAffineTransform& transform)
449 {
450 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
451 	((void (*)(void*, const BAffineTransform&))
452 		context->function_table[48])(context->user_data, transform);
453 }
454 
455 
456 static void
457 translate_by(void* _context, double x, double y)
458 {
459 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
460 	((void (*)(void*, double, double))
461 		context->function_table[49])(context->user_data, x, y);
462 }
463 
464 
465 static void
466 scale_by(void* _context, double x, double y)
467 {
468 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
469 	((void (*)(void*, double, double))
470 		context->function_table[50])(context->user_data, x, y);
471 }
472 
473 
474 static void
475 rotate_by(void* _context, double angleRadians)
476 {
477 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
478 	((void (*)(void*, double))
479 		context->function_table[51])(context->user_data, angleRadians);
480 }
481 
482 
483 static void
484 blend_layer(void* _context, Layer* layer)
485 {
486 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
487 	((void (*)(void*, Layer*))
488 		context->function_table[52])(context->user_data, layer);
489 }
490 
491 
492 static void
493 clip_to_rect(void* _context, const BRect& rect, bool inverse)
494 {
495 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
496 	((void (*)(void*, const BRect&, bool))
497 		context->function_table[53])(context->user_data, rect, inverse);
498 }
499 
500 
501 static void
502 clip_to_shape(void* _context, int32 opCount, const uint32 opList[],
503 	int32 ptCount, const BPoint ptList[], bool inverse)
504 {
505 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
506 	((void (*)(void*, int32, const uint32*, int32, const BPoint*, bool))
507 		context->function_table[54])(context->user_data, opCount, opList,
508 			ptCount, ptList, inverse);
509 }
510 
511 
512 static void
513 draw_string_locations(void* _context, const char* _string, size_t length,
514 	const BPoint* locations, size_t locationCount)
515 {
516 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
517 	char* string = strndup(_string, length);
518 
519 	((void (*)(void*, char*, const BPoint*, size_t))
520 		context->function_table[55])(context->user_data, string, locations,
521 			locationCount);
522 
523 	free(string);
524 }
525 
526 
527 static void
528 draw_rect_gradient(void* _context, const BRect& rect, BGradient& gradient, bool fill)
529 {
530 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
531 	((void (*)(void*, BRect, BGradient&))context->function_table[fill ? 56 : 57])(
532 		context->user_data, rect, gradient);
533 }
534 
535 
536 static void
537 draw_round_rect_gradient(void* _context, const BRect& rect, const BPoint& radii, BGradient& gradient,
538 	bool fill)
539 {
540 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
541 	((void (*)(void*, BRect, BPoint, BGradient&))context->function_table[fill ? 58 : 59])(
542 		context->user_data, rect, radii, gradient);
543 }
544 
545 
546 static void
547 draw_bezier_gradient(void* _context, size_t numPoints, const BPoint _points[], BGradient& gradient, bool fill)
548 {
549 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
550 	if (numPoints != 4)
551 		return;
552 
553 	BPoint points[4] = { _points[0], _points[1], _points[2], _points[3] };
554 	((void (*)(void*, BPoint*, BGradient&))context->function_table[fill ? 60 : 61])(
555 		context->user_data, points, gradient);
556 }
557 
558 
559 static void
560 draw_arc_gradient(void* _context, const BPoint& center, const BPoint& radii,
561 	float startTheta, float arcTheta, BGradient& gradient, bool fill)
562 {
563 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
564 	((void (*)(void*, BPoint, BPoint, float, float, BGradient&))
565 		context->function_table[fill ? 62 : 63])(context->user_data, center,
566 			radii, startTheta, arcTheta, gradient);
567 }
568 
569 
570 static void
571 draw_ellipse_gradient(void* _context, const BRect& rect, BGradient& gradient, bool fill)
572 {
573 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
574 	BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f);
575 	BPoint center = rect.LeftTop() + radii;
576 	((void (*)(void*, BPoint, BPoint, BGradient&))
577 		context->function_table[fill ? 64 : 65])(context->user_data, center,
578 			radii, gradient);
579 }
580 
581 
582 static void
583 draw_polygon_gradient(void* _context, size_t numPoints, const BPoint _points[],
584 	bool isClosed, BGradient& gradient, bool fill)
585 {
586 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
587 
588 	BStackOrHeapArray<BPoint, 200> points(numPoints);
589 	if (!points.IsValid())
590 		return;
591 
592 	memcpy((void*)points, _points, numPoints * sizeof(BPoint));
593 
594 	((void (*)(void*, int32, BPoint*, bool, BGradient&))
595 		context->function_table[fill ? 66 : 67])(context->user_data, numPoints,
596 			points, isClosed, gradient);
597 }
598 
599 
600 static void
601 draw_shape_gradient(void* _context, const BShape& shape, BGradient& gradient, bool fill)
602 {
603 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
604 	((void (*)(void*, BShape, BGradient&))context->function_table[fill ? 68 : 69])(
605 		context->user_data, shape, gradient);
606 }
607 
608 
609 static void
610 set_fill_rule(void* _context, int32 fillRule)
611 {
612 	adapter_context* context = reinterpret_cast<adapter_context*>(_context);
613 	((void (*)(void*, int32))context->function_table[70])(
614 		context->user_data, fillRule);
615 }
616 
617 
618 
619 #if DEBUG > 1
620 static const char *
621 PictureOpToString(int op)
622 {
623 	#define RETURN_STRING(x) case x: return #x
624 
625 	switch(op) {
626 		RETURN_STRING(B_PIC_MOVE_PEN_BY);
627 		RETURN_STRING(B_PIC_STROKE_LINE);
628 		RETURN_STRING(B_PIC_STROKE_RECT);
629 		RETURN_STRING(B_PIC_FILL_RECT);
630 		RETURN_STRING(B_PIC_STROKE_ROUND_RECT);
631 		RETURN_STRING(B_PIC_FILL_ROUND_RECT);
632 		RETURN_STRING(B_PIC_STROKE_BEZIER);
633 		RETURN_STRING(B_PIC_FILL_BEZIER);
634 		RETURN_STRING(B_PIC_STROKE_POLYGON);
635 		RETURN_STRING(B_PIC_FILL_POLYGON);
636 		RETURN_STRING(B_PIC_STROKE_SHAPE);
637 		RETURN_STRING(B_PIC_FILL_SHAPE);
638 		RETURN_STRING(B_PIC_DRAW_STRING);
639 		RETURN_STRING(B_PIC_DRAW_STRING_LOCATIONS);
640 		RETURN_STRING(B_PIC_DRAW_PIXELS);
641 		RETURN_STRING(B_PIC_DRAW_PICTURE);
642 		RETURN_STRING(B_PIC_STROKE_ARC);
643 		RETURN_STRING(B_PIC_FILL_ARC);
644 		RETURN_STRING(B_PIC_STROKE_ELLIPSE);
645 		RETURN_STRING(B_PIC_FILL_ELLIPSE);
646 		RETURN_STRING(B_PIC_STROKE_RECT_GRADIENT);
647 		RETURN_STRING(B_PIC_FILL_RECT_GRADIENT);
648 		RETURN_STRING(B_PIC_STROKE_ROUND_RECT_GRADIENT);
649 		RETURN_STRING(B_PIC_FILL_ROUND_RECT_GRADIENT);
650 		RETURN_STRING(B_PIC_STROKE_BEZIER_GRADIENT);
651 		RETURN_STRING(B_PIC_FILL_BEZIER_GRADIENT);
652 		RETURN_STRING(B_PIC_STROKE_POLYGON_GRADIENT);
653 		RETURN_STRING(B_PIC_FILL_POLYGON_GRADIENT);
654 		RETURN_STRING(B_PIC_STROKE_SHAPE_GRADIENT);
655 		RETURN_STRING(B_PIC_FILL_SHAPE_GRADIENT);
656 		RETURN_STRING(B_PIC_STROKE_ARC_GRADIENT);
657 		RETURN_STRING(B_PIC_FILL_ARC_GRADIENT);
658 		RETURN_STRING(B_PIC_STROKE_ELLIPSE_GRADIENT);
659 		RETURN_STRING(B_PIC_FILL_ELLIPSE_GRADIENT);
660 
661 		RETURN_STRING(B_PIC_ENTER_STATE_CHANGE);
662 		RETURN_STRING(B_PIC_SET_CLIPPING_RECTS);
663 		RETURN_STRING(B_PIC_CLIP_TO_PICTURE);
664 		RETURN_STRING(B_PIC_PUSH_STATE);
665 		RETURN_STRING(B_PIC_POP_STATE);
666 		RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS);
667 		RETURN_STRING(B_PIC_CLIP_TO_RECT);
668 		RETURN_STRING(B_PIC_CLIP_TO_SHAPE);
669 
670 		RETURN_STRING(B_PIC_SET_ORIGIN);
671 		RETURN_STRING(B_PIC_SET_PEN_LOCATION);
672 		RETURN_STRING(B_PIC_SET_DRAWING_MODE);
673 		RETURN_STRING(B_PIC_SET_LINE_MODE);
674 		RETURN_STRING(B_PIC_SET_PEN_SIZE);
675 		RETURN_STRING(B_PIC_SET_SCALE);
676 		RETURN_STRING(B_PIC_SET_TRANSFORM);
677 		RETURN_STRING(B_PIC_SET_FORE_COLOR);
678 		RETURN_STRING(B_PIC_SET_BACK_COLOR);
679 		RETURN_STRING(B_PIC_SET_STIPLE_PATTERN);
680 		RETURN_STRING(B_PIC_ENTER_FONT_STATE);
681 		RETURN_STRING(B_PIC_SET_BLENDING_MODE);
682 		RETURN_STRING(B_PIC_SET_FILL_RULE);
683 		RETURN_STRING(B_PIC_SET_FONT_FAMILY);
684 		RETURN_STRING(B_PIC_SET_FONT_STYLE);
685 		RETURN_STRING(B_PIC_SET_FONT_SPACING);
686 		RETURN_STRING(B_PIC_SET_FONT_ENCODING);
687 		RETURN_STRING(B_PIC_SET_FONT_FLAGS);
688 		RETURN_STRING(B_PIC_SET_FONT_SIZE);
689 		RETURN_STRING(B_PIC_SET_FONT_ROTATE);
690 		RETURN_STRING(B_PIC_SET_FONT_SHEAR);
691 		RETURN_STRING(B_PIC_SET_FONT_BPP);
692 		RETURN_STRING(B_PIC_SET_FONT_FACE);
693 
694 		RETURN_STRING(B_PIC_AFFINE_TRANSLATE);
695 		RETURN_STRING(B_PIC_AFFINE_SCALE);
696 		RETURN_STRING(B_PIC_AFFINE_ROTATE);
697 
698 		RETURN_STRING(B_PIC_BLEND_LAYER);
699 
700 		default: return "Unknown op";
701 	}
702 	#undef RETURN_STRING
703 }
704 #endif
705 
706 
707 PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures)
708 	:	fData(data),
709 		fSize(size),
710 		fPictures(pictures)
711 {
712 }
713 
714 
715 PicturePlayer::~PicturePlayer()
716 {
717 }
718 
719 
720 status_t
721 PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData)
722 {
723 	const BPrivate::picture_player_callbacks kAdapterCallbacks = {
724 		move_pen_by,
725 		stroke_line,
726 		draw_rect,
727 		draw_round_rect,
728 		draw_bezier,
729 		draw_arc,
730 		draw_ellipse,
731 		draw_polygon,
732 		draw_shape,
733 		draw_string,
734 		draw_pixels,
735 		draw_picture,
736 		set_clipping_rects,
737 		clip_to_picture,
738 		push_state,
739 		pop_state,
740 		enter_state_change,
741 		exit_state_change,
742 		enter_font_state,
743 		exit_font_state,
744 		set_origin,
745 		set_pen_location,
746 		set_drawing_mode,
747 		set_line_mode,
748 		set_pen_size,
749 		set_fore_color,
750 		set_back_color,
751 		set_stipple_pattern,
752 		set_scale,
753 		set_font_family,
754 		set_font_style,
755 		set_font_spacing,
756 		set_font_size,
757 		set_font_rotation,
758 		set_font_encoding,
759 		set_font_flags,
760 		set_font_shear,
761 		set_font_face,
762 		set_blending_mode,
763 		set_transform,
764 		translate_by,
765 		scale_by,
766 		rotate_by,
767 		blend_layer,
768 		clip_to_rect,
769 		clip_to_shape,
770 		draw_string_locations,
771 		draw_rect_gradient,
772 		draw_round_rect_gradient,
773 		draw_bezier_gradient,
774 		draw_arc_gradient,
775 		draw_ellipse_gradient,
776 		draw_polygon_gradient,
777 		draw_shape_gradient,
778 		set_fill_rule
779 	};
780 
781 	// We don't check if the functions in the table are NULL, but we
782 	// check the tableEntries to see if the table is big enough.
783 	// If an application supplies the wrong size or an invalid pointer,
784 	// it's its own fault.
785 
786 	// If the caller supplied a function table smaller than needed,
787 	// we use our dummy table, and copy the supported ops from the supplied one.
788 	void *dummyTable[kOpsTableSize];
789 
790 	adapter_context adapterContext;
791 	adapterContext.user_data = userData;
792 	adapterContext.function_table = callBackTable;
793 
794 	if ((size_t)tableEntries < kOpsTableSize) {
795 		memcpy(dummyTable, callBackTable, tableEntries * sizeof(void*));
796 		for (size_t i = (size_t)tableEntries; i < kOpsTableSize; i++)
797 			dummyTable[i] = (void*)nop;
798 
799 		adapterContext.function_table = dummyTable;
800 	}
801 
802 	return _Play(kAdapterCallbacks, &adapterContext, fData, fSize, 0);
803 }
804 
805 
806 status_t
807 PicturePlayer::Play(const picture_player_callbacks& callbacks,
808 	size_t callbacksSize, void* userData)
809 {
810 	return _Play(callbacks, userData, fData, fSize, 0);
811 }
812 
813 
814 class DataReader {
815 public:
816 		DataReader(const void* buffer, size_t length)
817 			:
818 			fBuffer((const uint8*)buffer),
819 			fRemaining(length)
820 		{
821 		}
822 
823 		size_t
824 		Remaining() const
825 		{
826 			return fRemaining;
827 		}
828 
829 		template<typename T>
830 		bool
831 		Get(const T*& typed, size_t count = 1)
832 		{
833 			if (fRemaining < sizeof(T) * count)
834 				return false;
835 
836 			typed = reinterpret_cast<const T *>(fBuffer);
837 			fRemaining -= sizeof(T) * count;
838 			fBuffer += sizeof(T) * count;
839 			return true;
840 		}
841 
842 		bool GetGradient(BGradient*& gradient)
843 		{
844 			BMemoryIO stream(fBuffer, fRemaining);
845 			printf("fRemaining: %ld\n", fRemaining);
846 			if (BGradient::Unflatten(gradient, &stream) != B_OK) {
847 				printf("BGradient::Unflatten(_gradient, &stream) != B_OK\n");
848 				return false;
849 			}
850 
851 			fRemaining -= stream.Position();
852 			fBuffer += stream.Position();
853 			return true;
854 		}
855 
856 		template<typename T>
857 		bool
858 		GetRemaining(const T*& buffer, size_t& size)
859 		{
860 			if (fRemaining == 0)
861 				return false;
862 
863 			buffer = reinterpret_cast<const T*>(fBuffer);
864 			size = fRemaining;
865 			fRemaining = 0;
866 			return true;
867 		}
868 
869 private:
870 		const uint8*	fBuffer;
871 		size_t			fRemaining;
872 };
873 
874 
875 struct picture_data_entry_header {
876 	uint16 op;
877 	uint32 size;
878 } _PACKED;
879 
880 
881 status_t
882 PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData,
883 	const void* buffer, size_t length, uint16 parentOp)
884 {
885 #if DEBUG
886 	printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : "");
887 	bigtime_t startTime = system_time();
888 	int32 numOps = 0;
889 #endif
890 
891 	DataReader pictureReader(buffer, length);
892 
893 	while (pictureReader.Remaining() > 0) {
894 		const picture_data_entry_header* header;
895 		const uint8* opData = NULL;
896 		if (!pictureReader.Get(header)
897 			|| !pictureReader.Get(opData, header->size)) {
898 			return B_BAD_DATA;
899 		}
900 
901 		DataReader reader(opData, header->size);
902 
903 		// Disallow ops that don't fit the parent.
904 		switch (parentOp) {
905 			case 0:
906 				// No parent op, no restrictions.
907 				break;
908 
909 			case B_PIC_ENTER_STATE_CHANGE:
910 				if (header->op <= B_PIC_ENTER_STATE_CHANGE
911 					|| header->op > B_PIC_SET_TRANSFORM) {
912 					return B_BAD_DATA;
913 				}
914 				break;
915 
916 			case B_PIC_ENTER_FONT_STATE:
917 				if (header->op < B_PIC_SET_FONT_FAMILY
918 					|| header->op > B_PIC_SET_FONT_FACE) {
919 					return B_BAD_DATA;
920 					}
921 				break;
922 
923 			default:
924 				return B_BAD_DATA;
925 		}
926 
927 #if DEBUG > 1
928 		bigtime_t startOpTime = system_time();
929 		printf("Op %s ", PictureOpToString(header->op));
930 #endif
931 		switch (header->op) {
932 			case B_PIC_MOVE_PEN_BY:
933 			{
934 				const BPoint* where;
935 				if (callbacks.move_pen_by == NULL || !reader.Get(where))
936 					break;
937 
938 				callbacks.move_pen_by(userData, *where);
939 				break;
940 			}
941 
942 			case B_PIC_STROKE_LINE:
943 			{
944 				const BPoint* start;
945 				const BPoint* end;
946 				if (callbacks.stroke_line == NULL || !reader.Get(start)
947 					|| !reader.Get(end)) {
948 					break;
949 				}
950 
951 				callbacks.stroke_line(userData, *start, *end);
952 				break;
953 			}
954 
955 			case B_PIC_STROKE_RECT:
956 			case B_PIC_FILL_RECT:
957 			{
958 				const BRect* rect;
959 				if (callbacks.draw_rect == NULL || !reader.Get(rect))
960 					break;
961 
962 				callbacks.draw_rect(userData, *rect,
963 					header->op == B_PIC_FILL_RECT);
964 				break;
965 			}
966 
967 			case B_PIC_STROKE_ROUND_RECT:
968 			case B_PIC_FILL_ROUND_RECT:
969 			{
970 				const BRect* rect;
971 				const BPoint* radii;
972 				if (callbacks.draw_round_rect == NULL || !reader.Get(rect)
973 					|| !reader.Get(radii)) {
974 					break;
975 				}
976 
977 				callbacks.draw_round_rect(userData, *rect, *radii,
978 					header->op == B_PIC_FILL_ROUND_RECT);
979 				break;
980 			}
981 
982 			case B_PIC_STROKE_BEZIER:
983 			case B_PIC_FILL_BEZIER:
984 			{
985 				const size_t kNumControlPoints = 4;
986 				const BPoint* controlPoints;
987 				if (callbacks.draw_bezier == NULL
988 					|| !reader.Get(controlPoints, kNumControlPoints)) {
989 					break;
990 				}
991 
992 				callbacks.draw_bezier(userData, kNumControlPoints,
993 					controlPoints, header->op == B_PIC_FILL_BEZIER);
994 				break;
995 			}
996 
997 			case B_PIC_STROKE_ARC:
998 			case B_PIC_FILL_ARC:
999 			{
1000 				const BPoint* center;
1001 				const BPoint* radii;
1002 				const float* startTheta;
1003 				const float* arcTheta;
1004 				if (callbacks.draw_arc == NULL || !reader.Get(center)
1005 					|| !reader.Get(radii) || !reader.Get(startTheta)
1006 					|| !reader.Get(arcTheta)) {
1007 					break;
1008 				}
1009 
1010 				callbacks.draw_arc(userData, *center, *radii, *startTheta,
1011 					*arcTheta, header->op == B_PIC_FILL_ARC);
1012 				break;
1013 			}
1014 
1015 			case B_PIC_STROKE_ELLIPSE:
1016 			case B_PIC_FILL_ELLIPSE:
1017 			{
1018 				const BRect* rect;
1019 				if (callbacks.draw_ellipse == NULL || !reader.Get(rect))
1020 					break;
1021 
1022 				callbacks.draw_ellipse(userData, *rect,
1023 					header->op == B_PIC_FILL_ELLIPSE);
1024 				break;
1025 			}
1026 
1027 			case B_PIC_STROKE_POLYGON:
1028 			case B_PIC_FILL_POLYGON:
1029 			{
1030 				const uint32* numPoints;
1031 				const BPoint* points;
1032 				if (callbacks.draw_polygon == NULL || !reader.Get(numPoints)
1033 					|| !reader.Get(points, *numPoints)) {
1034 					break;
1035 				}
1036 
1037 				bool isClosed = true;
1038 				const bool* closedPointer;
1039 				if (header->op != B_PIC_FILL_POLYGON) {
1040 					if (!reader.Get(closedPointer))
1041 						break;
1042 
1043 					isClosed = *closedPointer;
1044 				}
1045 
1046 				callbacks.draw_polygon(userData, *numPoints, points, isClosed,
1047 					header->op == B_PIC_FILL_POLYGON);
1048 				break;
1049 			}
1050 
1051 			case B_PIC_STROKE_SHAPE:
1052 			case B_PIC_FILL_SHAPE:
1053 			{
1054 				const uint32* opCount;
1055 				const uint32* pointCount;
1056 				const uint32* opList;
1057 				const BPoint* pointList;
1058 				if (callbacks.draw_shape == NULL || !reader.Get(opCount)
1059 					|| !reader.Get(pointCount) || !reader.Get(opList, *opCount)
1060 					|| !reader.Get(pointList, *pointCount)) {
1061 					break;
1062 				}
1063 
1064 				// TODO: remove BShape data copying
1065 				BShape shape;
1066 				BShape::Private(shape).SetData(*opCount, *pointCount, opList, pointList);
1067 
1068 				callbacks.draw_shape(userData, shape,
1069 					header->op == B_PIC_FILL_SHAPE);
1070 				break;
1071 			}
1072 
1073 			case B_PIC_STROKE_RECT_GRADIENT:
1074 			case B_PIC_FILL_RECT_GRADIENT:
1075 			{
1076 				const BRect* rect;
1077 				BGradient* gradient;
1078 				if (callbacks.draw_rect_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient))
1079 					break;
1080 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1081 
1082 				callbacks.draw_rect_gradient(userData, *rect, *gradient,
1083 					header->op == B_PIC_FILL_RECT_GRADIENT);
1084 				break;
1085 			}
1086 
1087 			case B_PIC_STROKE_ROUND_RECT_GRADIENT:
1088 			case B_PIC_FILL_ROUND_RECT_GRADIENT:
1089 			{
1090 				const BRect* rect;
1091 				const BPoint* radii;
1092 				BGradient* gradient;
1093 				if (callbacks.draw_round_rect_gradient == NULL || !reader.Get(rect)
1094 					|| !reader.Get(radii) || !reader.GetGradient(gradient)) {
1095 					break;
1096 				}
1097 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1098 
1099 				callbacks.draw_round_rect_gradient(userData, *rect, *radii, *gradient,
1100 					header->op == B_PIC_FILL_ROUND_RECT_GRADIENT);
1101 				break;
1102 			}
1103 
1104 			case B_PIC_STROKE_BEZIER_GRADIENT:
1105 			case B_PIC_FILL_BEZIER_GRADIENT:
1106 			{
1107 				const size_t kNumControlPoints = 4;
1108 				const BPoint* controlPoints;
1109 				BGradient* gradient;
1110 				if (callbacks.draw_bezier_gradient == NULL
1111 					|| !reader.Get(controlPoints, kNumControlPoints) || !reader.GetGradient(gradient)) {
1112 					break;
1113 				}
1114 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1115 
1116 				callbacks.draw_bezier_gradient(userData, kNumControlPoints,
1117 					controlPoints, *gradient, header->op == B_PIC_FILL_BEZIER_GRADIENT);
1118 				break;
1119 			}
1120 
1121 			case B_PIC_STROKE_POLYGON_GRADIENT:
1122 			case B_PIC_FILL_POLYGON_GRADIENT:
1123 			{
1124 				const uint32* numPoints;
1125 				const BPoint* points;
1126 				BGradient* gradient;
1127 				if (callbacks.draw_polygon_gradient == NULL || !reader.Get(numPoints)
1128 					|| !reader.Get(points, *numPoints)) {
1129 					break;
1130 				}
1131 
1132 				bool isClosed = true;
1133 				const bool* closedPointer;
1134 				if (header->op != B_PIC_FILL_POLYGON_GRADIENT) {
1135 					if (!reader.Get(closedPointer))
1136 						break;
1137 
1138 					isClosed = *closedPointer;
1139 				}
1140 
1141 				if (!reader.GetGradient(gradient))
1142 					break;
1143 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1144 
1145 				callbacks.draw_polygon_gradient(userData, *numPoints, points, isClosed, *gradient,
1146 					header->op == B_PIC_FILL_POLYGON_GRADIENT);
1147 				break;
1148 			}
1149 
1150 			case B_PIC_STROKE_SHAPE_GRADIENT:
1151 			case B_PIC_FILL_SHAPE_GRADIENT:
1152 			{
1153 				const uint32* opCount;
1154 				const uint32* pointCount;
1155 				const uint32* opList;
1156 				const BPoint* pointList;
1157 				BGradient* gradient;
1158 				if (callbacks.draw_shape_gradient == NULL || !reader.Get(opCount)
1159 					|| !reader.Get(pointCount) || !reader.Get(opList, *opCount)
1160 					|| !reader.Get(pointList, *pointCount) || !reader.GetGradient(gradient)) {
1161 					break;
1162 				}
1163 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1164 
1165 				// TODO: remove BShape data copying
1166 				BShape shape;
1167 				BShape::Private(shape).SetData(*opCount, *pointCount, opList, pointList);
1168 
1169 				callbacks.draw_shape_gradient(userData, shape, *gradient,
1170 					header->op == B_PIC_FILL_SHAPE_GRADIENT);
1171 				break;
1172 			}
1173 
1174 			case B_PIC_STROKE_ARC_GRADIENT:
1175 			case B_PIC_FILL_ARC_GRADIENT:
1176 			{
1177 				const BPoint* center;
1178 				const BPoint* radii;
1179 				const float* startTheta;
1180 				const float* arcTheta;
1181 				BGradient* gradient;
1182 				if (callbacks.draw_arc_gradient == NULL || !reader.Get(center)
1183 					|| !reader.Get(radii) || !reader.Get(startTheta)
1184 					|| !reader.Get(arcTheta) || !reader.GetGradient(gradient)) {
1185 					break;
1186 				}
1187 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1188 
1189 				callbacks.draw_arc_gradient(userData, *center, *radii, *startTheta,
1190 					*arcTheta, *gradient, header->op == B_PIC_FILL_ARC_GRADIENT);
1191 				break;
1192 			}
1193 
1194 			case B_PIC_STROKE_ELLIPSE_GRADIENT:
1195 			case B_PIC_FILL_ELLIPSE_GRADIENT:
1196 			{
1197 				const BRect* rect;
1198 				BGradient* gradient;
1199 				if (callbacks.draw_ellipse_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient))
1200 					break;
1201 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1202 
1203 				callbacks.draw_ellipse_gradient(userData, *rect, *gradient,
1204 					header->op == B_PIC_FILL_ELLIPSE_GRADIENT);
1205 				break;
1206 			}
1207 
1208 			case B_PIC_DRAW_STRING:
1209 			{
1210 				const float* escapementSpace;
1211 				const float* escapementNonSpace;
1212 				const char* string;
1213 				size_t length;
1214 				if (callbacks.draw_string == NULL
1215 					|| !reader.Get(escapementSpace)
1216 					|| !reader.Get(escapementNonSpace)
1217 					|| !reader.GetRemaining(string, length)) {
1218 					break;
1219 				}
1220 
1221 				callbacks.draw_string(userData, string, length,
1222 					*escapementSpace, *escapementNonSpace);
1223 				break;
1224 			}
1225 
1226 			case B_PIC_DRAW_STRING_LOCATIONS:
1227 			{
1228 				const uint32* pointCount;
1229 				const BPoint* pointList;
1230 				const char* string;
1231 				size_t length;
1232 				if (callbacks.draw_string_locations == NULL
1233 					|| !reader.Get(pointCount)
1234 					|| !reader.Get(pointList, *pointCount)
1235 					|| !reader.GetRemaining(string, length)) {
1236 					break;
1237 				}
1238 
1239 				callbacks.draw_string_locations(userData, string, length,
1240 					pointList, *pointCount);
1241 				break;
1242 			}
1243 
1244 			case B_PIC_DRAW_PIXELS:
1245 			{
1246 				const BRect* sourceRect;
1247 				const BRect* destinationRect;
1248 				const uint32* width;
1249 				const uint32* height;
1250 				const uint32* bytesPerRow;
1251 				const uint32* colorSpace;
1252 				const uint32* flags;
1253 				const void* data;
1254 				size_t length;
1255 				if (callbacks.draw_pixels == NULL || !reader.Get(sourceRect)
1256 					|| !reader.Get(destinationRect) || !reader.Get(width)
1257 					|| !reader.Get(height) || !reader.Get(bytesPerRow)
1258 					|| !reader.Get(colorSpace) || !reader.Get(flags)
1259 					|| !reader.GetRemaining(data, length)) {
1260 					break;
1261 				}
1262 
1263 				callbacks.draw_pixels(userData, *sourceRect, *destinationRect,
1264 					*width, *height, *bytesPerRow, (color_space)*colorSpace,
1265 					*flags, data, length);
1266 				break;
1267 			}
1268 
1269 			case B_PIC_DRAW_PICTURE:
1270 			{
1271 				const BPoint* where;
1272 				const int32* token;
1273 				if (callbacks.draw_picture == NULL || !reader.Get(where)
1274 					|| !reader.Get(token)) {
1275 					break;
1276 				}
1277 
1278 				callbacks.draw_picture(userData, *where, *token);
1279 				break;
1280 			}
1281 
1282 			case B_PIC_SET_CLIPPING_RECTS:
1283 			{
1284 				const uint32* numRects;
1285 				const BRect* rects;
1286 				if (callbacks.set_clipping_rects == NULL
1287 					|| !reader.Get(numRects) || !reader.Get(rects, *numRects)) {
1288 					break;
1289 				}
1290 
1291 				callbacks.set_clipping_rects(userData, *numRects, rects);
1292 				break;
1293 			}
1294 
1295 			case B_PIC_CLEAR_CLIPPING_RECTS:
1296 			{
1297 				if (callbacks.set_clipping_rects == NULL)
1298 					break;
1299 
1300 				callbacks.set_clipping_rects(userData, 0, NULL);
1301 				break;
1302 			}
1303 
1304 			case B_PIC_CLIP_TO_PICTURE:
1305 			{
1306 				const int32* token;
1307 				const BPoint* where;
1308 				const bool* inverse;
1309 				if (callbacks.clip_to_picture == NULL || !reader.Get(token)
1310 					|| !reader.Get(where) || !reader.Get(inverse))
1311 					break;
1312 
1313 				callbacks.clip_to_picture(userData, *token, *where, *inverse);
1314 				break;
1315 			}
1316 
1317 			case B_PIC_PUSH_STATE:
1318 			{
1319 				if (callbacks.push_state == NULL)
1320 					break;
1321 
1322 				callbacks.push_state(userData);
1323 				break;
1324 			}
1325 
1326 			case B_PIC_POP_STATE:
1327 			{
1328 				if (callbacks.pop_state == NULL)
1329 					break;
1330 
1331 				callbacks.pop_state(userData);
1332 				break;
1333 			}
1334 
1335 			case B_PIC_ENTER_STATE_CHANGE:
1336 			case B_PIC_ENTER_FONT_STATE:
1337 			{
1338 				const void* data;
1339 				size_t length;
1340 				if (!reader.GetRemaining(data, length))
1341 					break;
1342 
1343 				if (header->op == B_PIC_ENTER_STATE_CHANGE) {
1344 					if (callbacks.enter_state_change != NULL)
1345 						callbacks.enter_state_change(userData);
1346 				} else if (callbacks.enter_font_state != NULL)
1347 					callbacks.enter_font_state(userData);
1348 
1349 				status_t result = _Play(callbacks, userData, data, length,
1350 					header->op);
1351 				if (result != B_OK)
1352 					return result;
1353 
1354 				if (header->op == B_PIC_ENTER_STATE_CHANGE) {
1355 					if (callbacks.exit_state_change != NULL)
1356 						callbacks.exit_state_change(userData);
1357 				} else if (callbacks.exit_font_state != NULL)
1358 					callbacks.exit_font_state(userData);
1359 
1360 				break;
1361 			}
1362 
1363 			case B_PIC_SET_ORIGIN:
1364 			{
1365 				const BPoint* origin;
1366 				if (callbacks.set_origin == NULL || !reader.Get(origin))
1367 					break;
1368 
1369 				callbacks.set_origin(userData, *origin);
1370 				break;
1371 			}
1372 
1373 			case B_PIC_SET_PEN_LOCATION:
1374 			{
1375 				const BPoint* location;
1376 				if (callbacks.set_pen_location == NULL || !reader.Get(location))
1377 					break;
1378 
1379 				callbacks.set_pen_location(userData, *location);
1380 				break;
1381 			}
1382 
1383 			case B_PIC_SET_DRAWING_MODE:
1384 			{
1385 				const uint16* mode;
1386 				if (callbacks.set_drawing_mode == NULL || !reader.Get(mode))
1387 					break;
1388 
1389 				callbacks.set_drawing_mode(userData, (drawing_mode)*mode);
1390 				break;
1391 			}
1392 
1393 			case B_PIC_SET_LINE_MODE:
1394 			{
1395 				const uint16* capMode;
1396 				const uint16* joinMode;
1397 				const float* miterLimit;
1398 				if (callbacks.set_line_mode == NULL || !reader.Get(capMode)
1399 					|| !reader.Get(joinMode) || !reader.Get(miterLimit)) {
1400 					break;
1401 				}
1402 
1403 				callbacks.set_line_mode(userData, (cap_mode)*capMode,
1404 					(join_mode)*joinMode, *miterLimit);
1405 				break;
1406 			}
1407 
1408 			case B_PIC_SET_PEN_SIZE:
1409 			{
1410 				const float* penSize;
1411 				if (callbacks.set_pen_size == NULL || !reader.Get(penSize))
1412 					break;
1413 
1414 				callbacks.set_pen_size(userData, *penSize);
1415 				break;
1416 			}
1417 
1418 			case B_PIC_SET_FORE_COLOR:
1419 			{
1420 				const rgb_color* color;
1421 				if (callbacks.set_fore_color == NULL || !reader.Get(color))
1422 					break;
1423 
1424 				callbacks.set_fore_color(userData, *color);
1425 				break;
1426 			}
1427 
1428 			case B_PIC_SET_BACK_COLOR:
1429 			{
1430 				const rgb_color* color;
1431 				if (callbacks.set_back_color == NULL || !reader.Get(color))
1432 					break;
1433 
1434 				callbacks.set_back_color(userData, *color);
1435 				break;
1436 			}
1437 
1438 			case B_PIC_SET_STIPLE_PATTERN:
1439 			{
1440 				const pattern* stipplePattern;
1441 				if (callbacks.set_stipple_pattern == NULL
1442 					|| !reader.Get(stipplePattern)) {
1443 					break;
1444 				}
1445 
1446 				callbacks.set_stipple_pattern(userData, *stipplePattern);
1447 				break;
1448 			}
1449 
1450 			case B_PIC_SET_SCALE:
1451 			{
1452 				const float* scale;
1453 				if (callbacks.set_scale == NULL || !reader.Get(scale))
1454 					break;
1455 
1456 				callbacks.set_scale(userData, *scale);
1457 				break;
1458 			}
1459 
1460 			case B_PIC_SET_FONT_FAMILY:
1461 			{
1462 				const char* family;
1463 				size_t length;
1464 				if (callbacks.set_font_family == NULL
1465 					|| !reader.GetRemaining(family, length)) {
1466 					break;
1467 				}
1468 
1469 				callbacks.set_font_family(userData, family, length);
1470 				break;
1471 			}
1472 
1473 			case B_PIC_SET_FONT_STYLE:
1474 			{
1475 				const char* style;
1476 				size_t length;
1477 				if (callbacks.set_font_style == NULL
1478 					|| !reader.GetRemaining(style, length)) {
1479 					break;
1480 				}
1481 
1482 				callbacks.set_font_style(userData, style, length);
1483 				break;
1484 			}
1485 
1486 			case B_PIC_SET_FONT_SPACING:
1487 			{
1488 				const uint32* spacing;
1489 				if (callbacks.set_font_spacing == NULL || !reader.Get(spacing))
1490 					break;
1491 
1492 				callbacks.set_font_spacing(userData, *spacing);
1493 				break;
1494 			}
1495 
1496 			case B_PIC_SET_FONT_SIZE:
1497 			{
1498 				const float* size;
1499 				if (callbacks.set_font_size == NULL || !reader.Get(size))
1500 					break;
1501 
1502 				callbacks.set_font_size(userData, *size);
1503 				break;
1504 			}
1505 
1506 			case B_PIC_SET_FONT_ROTATE:
1507 			{
1508 				const float* rotation;
1509 				if (callbacks.set_font_rotation == NULL
1510 					|| !reader.Get(rotation)) {
1511 					break;
1512 				}
1513 
1514 				callbacks.set_font_rotation(userData, *rotation);
1515 				break;
1516 			}
1517 
1518 			case B_PIC_SET_FONT_ENCODING:
1519 			{
1520 				const uint32* encoding;
1521 				if (callbacks.set_font_encoding == NULL
1522 					|| !reader.Get(encoding)) {
1523 					break;
1524 				}
1525 
1526 				callbacks.set_font_encoding(userData, *encoding);
1527 				break;
1528 			}
1529 
1530 			case B_PIC_SET_FONT_FLAGS:
1531 			{
1532 				const uint32* flags;
1533 				if (callbacks.set_font_flags == NULL || !reader.Get(flags))
1534 					break;
1535 
1536 				callbacks.set_font_flags(userData, *flags);
1537 				break;
1538 			}
1539 
1540 			case B_PIC_SET_FONT_SHEAR:
1541 			{
1542 				const float* shear;
1543 				if (callbacks.set_font_shear == NULL || !reader.Get(shear))
1544 					break;
1545 
1546 				callbacks.set_font_shear(userData, *shear);
1547 				break;
1548 			}
1549 
1550 			case B_PIC_SET_FONT_FACE:
1551 			{
1552 				const uint32* face;
1553 				if (callbacks.set_font_face == NULL || !reader.Get(face))
1554 					break;
1555 
1556 				callbacks.set_font_face(userData, *face);
1557 				break;
1558 			}
1559 
1560 			case B_PIC_SET_BLENDING_MODE:
1561 			{
1562 				const uint16* alphaSourceMode;
1563 				const uint16* alphaFunctionMode;
1564 				if (callbacks.set_blending_mode == NULL
1565 					|| !reader.Get(alphaSourceMode)
1566 					|| !reader.Get(alphaFunctionMode)) {
1567 					break;
1568 				}
1569 
1570 				callbacks.set_blending_mode(userData,
1571 					(source_alpha)*alphaSourceMode,
1572 					(alpha_function)*alphaFunctionMode);
1573 				break;
1574 			}
1575 
1576 			case B_PIC_SET_FILL_RULE:
1577 			{
1578 				const uint32* fillRule;
1579 				if (callbacks.set_fill_rule == NULL
1580 					|| !reader.Get(fillRule)) {
1581 					break;
1582 				}
1583 
1584 				callbacks.set_fill_rule(userData, *fillRule);
1585 				break;
1586 			}
1587 
1588 			case B_PIC_SET_TRANSFORM:
1589 			{
1590 				const BAffineTransform* transform;
1591 				if (callbacks.set_transform == NULL || !reader.Get(transform))
1592 					break;
1593 
1594 				callbacks.set_transform(userData, *transform);
1595 				break;
1596 			}
1597 
1598 			case B_PIC_AFFINE_TRANSLATE:
1599 			{
1600 				const double* x;
1601 				const double* y;
1602 				if (callbacks.translate_by == NULL || !reader.Get(x)
1603 					|| !reader.Get(y)) {
1604 					break;
1605 				}
1606 
1607 				callbacks.translate_by(userData, *x, *y);
1608 				break;
1609 			}
1610 
1611 			case B_PIC_AFFINE_SCALE:
1612 			{
1613 				const double* x;
1614 				const double* y;
1615 				if (callbacks.scale_by == NULL || !reader.Get(x)
1616 					|| !reader.Get(y)) {
1617 					break;
1618 				}
1619 
1620 				callbacks.scale_by(userData, *x, *y);
1621 				break;
1622 			}
1623 
1624 			case B_PIC_AFFINE_ROTATE:
1625 			{
1626 				const double* angleRadians;
1627 				if (callbacks.rotate_by == NULL || !reader.Get(angleRadians))
1628 					break;
1629 
1630 				callbacks.rotate_by(userData, *angleRadians);
1631 				break;
1632 			}
1633 
1634 			case B_PIC_BLEND_LAYER:
1635 			{
1636 				Layer* const* layer;
1637 				if (callbacks.blend_layer == NULL || !reader.Get<Layer*>(layer))
1638 					break;
1639 
1640 				callbacks.blend_layer(userData, *layer);
1641 				break;
1642 			}
1643 
1644 			case B_PIC_CLIP_TO_RECT:
1645 			{
1646 				const bool* inverse;
1647 				const BRect* rect;
1648 
1649 				if (callbacks.clip_to_rect == NULL || !reader.Get(inverse)
1650 					|| !reader.Get(rect)) {
1651 					break;
1652 				}
1653 
1654 				callbacks.clip_to_rect(userData, *rect, *inverse);
1655 				break;
1656 			}
1657 
1658 			case B_PIC_CLIP_TO_SHAPE:
1659 			{
1660 				const bool* inverse;
1661 				const uint32* opCount;
1662 				const uint32* pointCount;
1663 				const uint32* opList;
1664 				const BPoint* pointList;
1665 				if (callbacks.clip_to_shape == NULL || !reader.Get(inverse)
1666 					|| !reader.Get(opCount) || !reader.Get(pointCount)
1667 					|| !reader.Get(opList, *opCount)
1668 					|| !reader.Get(pointList, *pointCount)) {
1669 					break;
1670 				}
1671 
1672 				callbacks.clip_to_shape(userData, *opCount, opList,
1673 					*pointCount, pointList, *inverse);
1674 				break;
1675 			}
1676 
1677 			default:
1678 				break;
1679 		}
1680 
1681 #if DEBUG
1682 		numOps++;
1683 #if DEBUG > 1
1684 		printf("executed in %" B_PRId64 " usecs\n", system_time()
1685 			- startOpTime);
1686 #endif
1687 #endif
1688 	}
1689 
1690 #if DEBUG
1691 	printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64
1692 		" usecs.\n", numOps, system_time() - startTime);
1693 #endif
1694 	return B_OK;
1695 }
1696