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