xref: /haiku/src/kits/interface/PicturePlayer.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 		RETURN_STRING(B_PIC_STROKE_RECT_GRADIENT);
646 		RETURN_STRING(B_PIC_FILL_RECT_GRADIENT);
647 		RETURN_STRING(B_PIC_STROKE_ROUND_RECT_GRADIENT);
648 		RETURN_STRING(B_PIC_FILL_ROUND_RECT_GRADIENT);
649 		RETURN_STRING(B_PIC_STROKE_BEZIER_GRADIENT);
650 		RETURN_STRING(B_PIC_FILL_BEZIER_GRADIENT);
651 		RETURN_STRING(B_PIC_STROKE_POLYGON_GRADIENT);
652 		RETURN_STRING(B_PIC_FILL_POLYGON_GRADIENT);
653 		RETURN_STRING(B_PIC_STROKE_SHAPE_GRADIENT);
654 		RETURN_STRING(B_PIC_FILL_SHAPE_GRADIENT);
655 		RETURN_STRING(B_PIC_STROKE_ARC_GRADIENT);
656 		RETURN_STRING(B_PIC_FILL_ARC_GRADIENT);
657 		RETURN_STRING(B_PIC_STROKE_ELLIPSE_GRADIENT);
658 		RETURN_STRING(B_PIC_FILL_ELLIPSE_GRADIENT);
659 
660 		RETURN_STRING(B_PIC_ENTER_STATE_CHANGE);
661 		RETURN_STRING(B_PIC_SET_CLIPPING_RECTS);
662 		RETURN_STRING(B_PIC_CLIP_TO_PICTURE);
663 		RETURN_STRING(B_PIC_PUSH_STATE);
664 		RETURN_STRING(B_PIC_POP_STATE);
665 		RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS);
666 		RETURN_STRING(B_PIC_CLIP_TO_RECT);
667 		RETURN_STRING(B_PIC_CLIP_TO_SHAPE);
668 
669 		RETURN_STRING(B_PIC_SET_ORIGIN);
670 		RETURN_STRING(B_PIC_SET_PEN_LOCATION);
671 		RETURN_STRING(B_PIC_SET_DRAWING_MODE);
672 		RETURN_STRING(B_PIC_SET_LINE_MODE);
673 		RETURN_STRING(B_PIC_SET_PEN_SIZE);
674 		RETURN_STRING(B_PIC_SET_SCALE);
675 		RETURN_STRING(B_PIC_SET_TRANSFORM);
676 		RETURN_STRING(B_PIC_SET_FORE_COLOR);
677 		RETURN_STRING(B_PIC_SET_BACK_COLOR);
678 		RETURN_STRING(B_PIC_SET_STIPLE_PATTERN);
679 		RETURN_STRING(B_PIC_ENTER_FONT_STATE);
680 		RETURN_STRING(B_PIC_SET_BLENDING_MODE);
681 		RETURN_STRING(B_PIC_SET_FILL_RULE);
682 		RETURN_STRING(B_PIC_SET_FONT_FAMILY);
683 		RETURN_STRING(B_PIC_SET_FONT_STYLE);
684 		RETURN_STRING(B_PIC_SET_FONT_SPACING);
685 		RETURN_STRING(B_PIC_SET_FONT_ENCODING);
686 		RETURN_STRING(B_PIC_SET_FONT_FLAGS);
687 		RETURN_STRING(B_PIC_SET_FONT_SIZE);
688 		RETURN_STRING(B_PIC_SET_FONT_ROTATE);
689 		RETURN_STRING(B_PIC_SET_FONT_SHEAR);
690 		RETURN_STRING(B_PIC_SET_FONT_BPP);
691 		RETURN_STRING(B_PIC_SET_FONT_FACE);
692 
693 		RETURN_STRING(B_PIC_AFFINE_TRANSLATE);
694 		RETURN_STRING(B_PIC_AFFINE_SCALE);
695 		RETURN_STRING(B_PIC_AFFINE_ROTATE);
696 
697 		RETURN_STRING(B_PIC_BLEND_LAYER);
698 
699 		default: return "Unknown op";
700 	}
701 	#undef RETURN_STRING
702 }
703 #endif
704 
705 
706 PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures)
707 	:	fData(data),
708 		fSize(size),
709 		fPictures(pictures)
710 {
711 }
712 
713 
714 PicturePlayer::~PicturePlayer()
715 {
716 }
717 
718 
719 status_t
720 PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData)
721 {
722 	const BPrivate::picture_player_callbacks kAdapterCallbacks = {
723 		move_pen_by,
724 		stroke_line,
725 		draw_rect,
726 		draw_round_rect,
727 		draw_bezier,
728 		draw_arc,
729 		draw_ellipse,
730 		draw_polygon,
731 		draw_shape,
732 		draw_string,
733 		draw_pixels,
734 		draw_picture,
735 		set_clipping_rects,
736 		clip_to_picture,
737 		push_state,
738 		pop_state,
739 		enter_state_change,
740 		exit_state_change,
741 		enter_font_state,
742 		exit_font_state,
743 		set_origin,
744 		set_pen_location,
745 		set_drawing_mode,
746 		set_line_mode,
747 		set_pen_size,
748 		set_fore_color,
749 		set_back_color,
750 		set_stipple_pattern,
751 		set_scale,
752 		set_font_family,
753 		set_font_style,
754 		set_font_spacing,
755 		set_font_size,
756 		set_font_rotation,
757 		set_font_encoding,
758 		set_font_flags,
759 		set_font_shear,
760 		set_font_face,
761 		set_blending_mode,
762 		set_transform,
763 		translate_by,
764 		scale_by,
765 		rotate_by,
766 		blend_layer,
767 		clip_to_rect,
768 		clip_to_shape,
769 		draw_string_locations,
770 		draw_rect_gradient,
771 		draw_round_rect_gradient,
772 		draw_bezier_gradient,
773 		draw_arc_gradient,
774 		draw_ellipse_gradient,
775 		draw_polygon_gradient,
776 		draw_shape_gradient,
777 		set_fill_rule
778 	};
779 
780 	// We don't check if the functions in the table are NULL, but we
781 	// check the tableEntries to see if the table is big enough.
782 	// If an application supplies the wrong size or an invalid pointer,
783 	// it's its own fault.
784 
785 	// If the caller supplied a function table smaller than needed,
786 	// we use our dummy table, and copy the supported ops from the supplied one.
787 	void *dummyTable[kOpsTableSize];
788 
789 	adapter_context adapterContext;
790 	adapterContext.user_data = userData;
791 	adapterContext.function_table = callBackTable;
792 
793 	if ((size_t)tableEntries < kOpsTableSize) {
794 		memcpy(dummyTable, callBackTable, tableEntries * sizeof(void*));
795 		for (size_t i = (size_t)tableEntries; i < kOpsTableSize; i++)
796 			dummyTable[i] = (void*)nop;
797 
798 		adapterContext.function_table = dummyTable;
799 	}
800 
801 	return _Play(kAdapterCallbacks, &adapterContext, fData, fSize, 0);
802 }
803 
804 
805 status_t
806 PicturePlayer::Play(const picture_player_callbacks& callbacks,
807 	size_t callbacksSize, void* userData)
808 {
809 	return _Play(callbacks, userData, fData, fSize, 0);
810 }
811 
812 
813 class DataReader {
814 public:
815 		DataReader(const void* buffer, size_t length)
816 			:
817 			fBuffer((const uint8*)buffer),
818 			fRemaining(length)
819 		{
820 		}
821 
822 		size_t
823 		Remaining() const
824 		{
825 			return fRemaining;
826 		}
827 
828 		template<typename T>
829 		bool
830 		Get(const T*& typed, size_t count = 1)
831 		{
832 			if (fRemaining < sizeof(T) * count)
833 				return false;
834 
835 			typed = reinterpret_cast<const T *>(fBuffer);
836 			fRemaining -= sizeof(T) * count;
837 			fBuffer += sizeof(T) * count;
838 			return true;
839 		}
840 
841 		bool GetGradient(BGradient*& gradient)
842 		{
843 			BMemoryIO stream(fBuffer, fRemaining);
844 			printf("fRemaining: %ld\n", fRemaining);
845 			if (BGradient::Unflatten(gradient, &stream) != B_OK) {
846 				printf("BGradient::Unflatten(_gradient, &stream) != B_OK\n");
847 				return false;
848 			}
849 
850 			fRemaining -= stream.Position();
851 			fBuffer += stream.Position();
852 			return true;
853 		}
854 
855 		template<typename T>
856 		bool
857 		GetRemaining(const T*& buffer, size_t& size)
858 		{
859 			if (fRemaining == 0)
860 				return false;
861 
862 			buffer = reinterpret_cast<const T*>(fBuffer);
863 			size = fRemaining;
864 			fRemaining = 0;
865 			return true;
866 		}
867 
868 private:
869 		const uint8*	fBuffer;
870 		size_t			fRemaining;
871 };
872 
873 
874 struct picture_data_entry_header {
875 	uint16 op;
876 	uint32 size;
877 } _PACKED;
878 
879 
880 status_t
881 PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData,
882 	const void* buffer, size_t length, uint16 parentOp)
883 {
884 #if DEBUG
885 	printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : "");
886 	bigtime_t startTime = system_time();
887 	int32 numOps = 0;
888 #endif
889 
890 	DataReader pictureReader(buffer, length);
891 
892 	while (pictureReader.Remaining() > 0) {
893 		const picture_data_entry_header* header;
894 		const uint8* opData = NULL;
895 		if (!pictureReader.Get(header)
896 			|| !pictureReader.Get(opData, header->size)) {
897 			return B_BAD_DATA;
898 		}
899 
900 		DataReader reader(opData, header->size);
901 
902 		// Disallow ops that don't fit the parent.
903 		switch (parentOp) {
904 			case 0:
905 				// No parent op, no restrictions.
906 				break;
907 
908 			case B_PIC_ENTER_STATE_CHANGE:
909 				if (header->op <= B_PIC_ENTER_STATE_CHANGE
910 					|| header->op > B_PIC_SET_TRANSFORM) {
911 					return B_BAD_DATA;
912 				}
913 				break;
914 
915 			case B_PIC_ENTER_FONT_STATE:
916 				if (header->op < B_PIC_SET_FONT_FAMILY
917 					|| header->op > B_PIC_SET_FONT_FACE) {
918 					return B_BAD_DATA;
919 					}
920 				break;
921 
922 			default:
923 				return B_BAD_DATA;
924 		}
925 
926 #if DEBUG > 1
927 		bigtime_t startOpTime = system_time();
928 		printf("Op %s ", PictureOpToString(header->op));
929 #endif
930 		switch (header->op) {
931 			case B_PIC_MOVE_PEN_BY:
932 			{
933 				const BPoint* where;
934 				if (callbacks.move_pen_by == NULL || !reader.Get(where))
935 					break;
936 
937 				callbacks.move_pen_by(userData, *where);
938 				break;
939 			}
940 
941 			case B_PIC_STROKE_LINE:
942 			{
943 				const BPoint* start;
944 				const BPoint* end;
945 				if (callbacks.stroke_line == NULL || !reader.Get(start)
946 					|| !reader.Get(end)) {
947 					break;
948 				}
949 
950 				callbacks.stroke_line(userData, *start, *end);
951 				break;
952 			}
953 
954 			case B_PIC_STROKE_RECT:
955 			case B_PIC_FILL_RECT:
956 			{
957 				const BRect* rect;
958 				if (callbacks.draw_rect == NULL || !reader.Get(rect))
959 					break;
960 
961 				callbacks.draw_rect(userData, *rect,
962 					header->op == B_PIC_FILL_RECT);
963 				break;
964 			}
965 
966 			case B_PIC_STROKE_ROUND_RECT:
967 			case B_PIC_FILL_ROUND_RECT:
968 			{
969 				const BRect* rect;
970 				const BPoint* radii;
971 				if (callbacks.draw_round_rect == NULL || !reader.Get(rect)
972 					|| !reader.Get(radii)) {
973 					break;
974 				}
975 
976 				callbacks.draw_round_rect(userData, *rect, *radii,
977 					header->op == B_PIC_FILL_ROUND_RECT);
978 				break;
979 			}
980 
981 			case B_PIC_STROKE_BEZIER:
982 			case B_PIC_FILL_BEZIER:
983 			{
984 				const size_t kNumControlPoints = 4;
985 				const BPoint* controlPoints;
986 				if (callbacks.draw_bezier == NULL
987 					|| !reader.Get(controlPoints, kNumControlPoints)) {
988 					break;
989 				}
990 
991 				callbacks.draw_bezier(userData, kNumControlPoints,
992 					controlPoints, header->op == B_PIC_FILL_BEZIER);
993 				break;
994 			}
995 
996 			case B_PIC_STROKE_ARC:
997 			case B_PIC_FILL_ARC:
998 			{
999 				const BPoint* center;
1000 				const BPoint* radii;
1001 				const float* startTheta;
1002 				const float* arcTheta;
1003 				if (callbacks.draw_arc == NULL || !reader.Get(center)
1004 					|| !reader.Get(radii) || !reader.Get(startTheta)
1005 					|| !reader.Get(arcTheta)) {
1006 					break;
1007 				}
1008 
1009 				callbacks.draw_arc(userData, *center, *radii, *startTheta,
1010 					*arcTheta, header->op == B_PIC_FILL_ARC);
1011 				break;
1012 			}
1013 
1014 			case B_PIC_STROKE_ELLIPSE:
1015 			case B_PIC_FILL_ELLIPSE:
1016 			{
1017 				const BRect* rect;
1018 				if (callbacks.draw_ellipse == NULL || !reader.Get(rect))
1019 					break;
1020 
1021 				callbacks.draw_ellipse(userData, *rect,
1022 					header->op == B_PIC_FILL_ELLIPSE);
1023 				break;
1024 			}
1025 
1026 			case B_PIC_STROKE_POLYGON:
1027 			case B_PIC_FILL_POLYGON:
1028 			{
1029 				const uint32* numPoints;
1030 				const BPoint* points;
1031 				if (callbacks.draw_polygon == NULL || !reader.Get(numPoints)
1032 					|| !reader.Get(points, *numPoints)) {
1033 					break;
1034 				}
1035 
1036 				bool isClosed = true;
1037 				const bool* closedPointer;
1038 				if (header->op != B_PIC_FILL_POLYGON) {
1039 					if (!reader.Get(closedPointer))
1040 						break;
1041 
1042 					isClosed = *closedPointer;
1043 				}
1044 
1045 				callbacks.draw_polygon(userData, *numPoints, points, isClosed,
1046 					header->op == B_PIC_FILL_POLYGON);
1047 				break;
1048 			}
1049 
1050 			case B_PIC_STROKE_SHAPE:
1051 			case B_PIC_FILL_SHAPE:
1052 			{
1053 				const uint32* opCount;
1054 				const uint32* pointCount;
1055 				const uint32* opList;
1056 				const BPoint* pointList;
1057 				if (callbacks.draw_shape == NULL || !reader.Get(opCount)
1058 					|| !reader.Get(pointCount) || !reader.Get(opList, *opCount)
1059 					|| !reader.Get(pointList, *pointCount)) {
1060 					break;
1061 				}
1062 
1063 				// TODO: remove BShape data copying
1064 				BShape shape;
1065 				shape.SetData(*opCount, *pointCount, opList, pointList);
1066 
1067 				callbacks.draw_shape(userData, shape,
1068 					header->op == B_PIC_FILL_SHAPE);
1069 				break;
1070 			}
1071 
1072 			case B_PIC_STROKE_RECT_GRADIENT:
1073 			case B_PIC_FILL_RECT_GRADIENT:
1074 			{
1075 				const BRect* rect;
1076 				BGradient* gradient;
1077 				if (callbacks.draw_rect_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient))
1078 					break;
1079 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1080 
1081 				callbacks.draw_rect_gradient(userData, *rect, *gradient,
1082 					header->op == B_PIC_FILL_RECT_GRADIENT);
1083 				break;
1084 			}
1085 
1086 			case B_PIC_STROKE_ROUND_RECT_GRADIENT:
1087 			case B_PIC_FILL_ROUND_RECT_GRADIENT:
1088 			{
1089 				const BRect* rect;
1090 				const BPoint* radii;
1091 				BGradient* gradient;
1092 				if (callbacks.draw_round_rect_gradient == NULL || !reader.Get(rect)
1093 					|| !reader.Get(radii) || !reader.GetGradient(gradient)) {
1094 					break;
1095 				}
1096 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1097 
1098 				callbacks.draw_round_rect_gradient(userData, *rect, *radii, *gradient,
1099 					header->op == B_PIC_FILL_ROUND_RECT_GRADIENT);
1100 				break;
1101 			}
1102 
1103 			case B_PIC_STROKE_BEZIER_GRADIENT:
1104 			case B_PIC_FILL_BEZIER_GRADIENT:
1105 			{
1106 				const size_t kNumControlPoints = 4;
1107 				const BPoint* controlPoints;
1108 				BGradient* gradient;
1109 				if (callbacks.draw_bezier_gradient == NULL
1110 					|| !reader.Get(controlPoints, kNumControlPoints) || !reader.GetGradient(gradient)) {
1111 					break;
1112 				}
1113 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1114 
1115 				callbacks.draw_bezier_gradient(userData, kNumControlPoints,
1116 					controlPoints, *gradient, header->op == B_PIC_FILL_BEZIER_GRADIENT);
1117 				break;
1118 			}
1119 
1120 			case B_PIC_STROKE_POLYGON_GRADIENT:
1121 			case B_PIC_FILL_POLYGON_GRADIENT:
1122 			{
1123 				const uint32* numPoints;
1124 				const BPoint* points;
1125 				BGradient* gradient;
1126 				if (callbacks.draw_polygon_gradient == NULL || !reader.Get(numPoints)
1127 					|| !reader.Get(points, *numPoints)) {
1128 					break;
1129 				}
1130 
1131 				bool isClosed = true;
1132 				const bool* closedPointer;
1133 				if (header->op != B_PIC_FILL_POLYGON_GRADIENT) {
1134 					if (!reader.Get(closedPointer))
1135 						break;
1136 
1137 					isClosed = *closedPointer;
1138 				}
1139 
1140 				if (!reader.GetGradient(gradient))
1141 					break;
1142 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1143 
1144 				callbacks.draw_polygon_gradient(userData, *numPoints, points, isClosed, *gradient,
1145 					header->op == B_PIC_FILL_POLYGON_GRADIENT);
1146 				break;
1147 			}
1148 
1149 			case B_PIC_STROKE_SHAPE_GRADIENT:
1150 			case B_PIC_FILL_SHAPE_GRADIENT:
1151 			{
1152 				const uint32* opCount;
1153 				const uint32* pointCount;
1154 				const uint32* opList;
1155 				const BPoint* pointList;
1156 				BGradient* gradient;
1157 				if (callbacks.draw_shape_gradient == NULL || !reader.Get(opCount)
1158 					|| !reader.Get(pointCount) || !reader.Get(opList, *opCount)
1159 					|| !reader.Get(pointList, *pointCount) || !reader.GetGradient(gradient)) {
1160 					break;
1161 				}
1162 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1163 
1164 				// TODO: remove BShape data copying
1165 				BShape shape;
1166 				shape.SetData(*opCount, *pointCount, opList, pointList);
1167 
1168 				callbacks.draw_shape_gradient(userData, shape, *gradient,
1169 					header->op == B_PIC_FILL_SHAPE_GRADIENT);
1170 				break;
1171 			}
1172 
1173 			case B_PIC_STROKE_ARC_GRADIENT:
1174 			case B_PIC_FILL_ARC_GRADIENT:
1175 			{
1176 				const BPoint* center;
1177 				const BPoint* radii;
1178 				const float* startTheta;
1179 				const float* arcTheta;
1180 				BGradient* gradient;
1181 				if (callbacks.draw_arc_gradient == NULL || !reader.Get(center)
1182 					|| !reader.Get(radii) || !reader.Get(startTheta)
1183 					|| !reader.Get(arcTheta) || !reader.GetGradient(gradient)) {
1184 					break;
1185 				}
1186 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1187 
1188 				callbacks.draw_arc_gradient(userData, *center, *radii, *startTheta,
1189 					*arcTheta, *gradient, header->op == B_PIC_FILL_ARC_GRADIENT);
1190 				break;
1191 			}
1192 
1193 			case B_PIC_STROKE_ELLIPSE_GRADIENT:
1194 			case B_PIC_FILL_ELLIPSE_GRADIENT:
1195 			{
1196 				const BRect* rect;
1197 				BGradient* gradient;
1198 				if (callbacks.draw_ellipse_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient))
1199 					break;
1200 				ObjectDeleter<BGradient> gradientDeleter(gradient);
1201 
1202 				callbacks.draw_ellipse_gradient(userData, *rect, *gradient,
1203 					header->op == B_PIC_FILL_ELLIPSE_GRADIENT);
1204 				break;
1205 			}
1206 
1207 			case B_PIC_DRAW_STRING:
1208 			{
1209 				const float* escapementSpace;
1210 				const float* escapementNonSpace;
1211 				const char* string;
1212 				size_t length;
1213 				if (callbacks.draw_string == NULL
1214 					|| !reader.Get(escapementSpace)
1215 					|| !reader.Get(escapementNonSpace)
1216 					|| !reader.GetRemaining(string, length)) {
1217 					break;
1218 				}
1219 
1220 				callbacks.draw_string(userData, string, length,
1221 					*escapementSpace, *escapementNonSpace);
1222 				break;
1223 			}
1224 
1225 			case B_PIC_DRAW_STRING_LOCATIONS:
1226 			{
1227 				const uint32* pointCount;
1228 				const BPoint* pointList;
1229 				const char* string;
1230 				size_t length;
1231 				if (callbacks.draw_string_locations == NULL
1232 					|| !reader.Get(pointCount)
1233 					|| !reader.Get(pointList, *pointCount)
1234 					|| !reader.GetRemaining(string, length)) {
1235 					break;
1236 				}
1237 
1238 				callbacks.draw_string_locations(userData, string, length,
1239 					pointList, *pointCount);
1240 				break;
1241 			}
1242 
1243 			case B_PIC_DRAW_PIXELS:
1244 			{
1245 				const BRect* sourceRect;
1246 				const BRect* destinationRect;
1247 				const uint32* width;
1248 				const uint32* height;
1249 				const uint32* bytesPerRow;
1250 				const uint32* colorSpace;
1251 				const uint32* flags;
1252 				const void* data;
1253 				size_t length;
1254 				if (callbacks.draw_pixels == NULL || !reader.Get(sourceRect)
1255 					|| !reader.Get(destinationRect) || !reader.Get(width)
1256 					|| !reader.Get(height) || !reader.Get(bytesPerRow)
1257 					|| !reader.Get(colorSpace) || !reader.Get(flags)
1258 					|| !reader.GetRemaining(data, length)) {
1259 					break;
1260 				}
1261 
1262 				callbacks.draw_pixels(userData, *sourceRect, *destinationRect,
1263 					*width, *height, *bytesPerRow, (color_space)*colorSpace,
1264 					*flags, data, length);
1265 				break;
1266 			}
1267 
1268 			case B_PIC_DRAW_PICTURE:
1269 			{
1270 				const BPoint* where;
1271 				const int32* token;
1272 				if (callbacks.draw_picture == NULL || !reader.Get(where)
1273 					|| !reader.Get(token)) {
1274 					break;
1275 				}
1276 
1277 				callbacks.draw_picture(userData, *where, *token);
1278 				break;
1279 			}
1280 
1281 			case B_PIC_SET_CLIPPING_RECTS:
1282 			{
1283 				const uint32* numRects;
1284 				const BRect* rects;
1285 				if (callbacks.set_clipping_rects == NULL
1286 					|| !reader.Get(numRects) || !reader.Get(rects, *numRects)) {
1287 					break;
1288 				}
1289 
1290 				callbacks.set_clipping_rects(userData, *numRects, rects);
1291 				break;
1292 			}
1293 
1294 			case B_PIC_CLEAR_CLIPPING_RECTS:
1295 			{
1296 				if (callbacks.set_clipping_rects == NULL)
1297 					break;
1298 
1299 				callbacks.set_clipping_rects(userData, 0, NULL);
1300 				break;
1301 			}
1302 
1303 			case B_PIC_CLIP_TO_PICTURE:
1304 			{
1305 				const int32* token;
1306 				const BPoint* where;
1307 				const bool* inverse;
1308 				if (callbacks.clip_to_picture == NULL || !reader.Get(token)
1309 					|| !reader.Get(where) || !reader.Get(inverse))
1310 					break;
1311 
1312 				callbacks.clip_to_picture(userData, *token, *where, *inverse);
1313 				break;
1314 			}
1315 
1316 			case B_PIC_PUSH_STATE:
1317 			{
1318 				if (callbacks.push_state == NULL)
1319 					break;
1320 
1321 				callbacks.push_state(userData);
1322 				break;
1323 			}
1324 
1325 			case B_PIC_POP_STATE:
1326 			{
1327 				if (callbacks.pop_state == NULL)
1328 					break;
1329 
1330 				callbacks.pop_state(userData);
1331 				break;
1332 			}
1333 
1334 			case B_PIC_ENTER_STATE_CHANGE:
1335 			case B_PIC_ENTER_FONT_STATE:
1336 			{
1337 				const void* data;
1338 				size_t length;
1339 				if (!reader.GetRemaining(data, length))
1340 					break;
1341 
1342 				if (header->op == B_PIC_ENTER_STATE_CHANGE) {
1343 					if (callbacks.enter_state_change != NULL)
1344 						callbacks.enter_state_change(userData);
1345 				} else if (callbacks.enter_font_state != NULL)
1346 					callbacks.enter_font_state(userData);
1347 
1348 				status_t result = _Play(callbacks, userData, data, length,
1349 					header->op);
1350 				if (result != B_OK)
1351 					return result;
1352 
1353 				if (header->op == B_PIC_ENTER_STATE_CHANGE) {
1354 					if (callbacks.exit_state_change != NULL)
1355 						callbacks.exit_state_change(userData);
1356 				} else if (callbacks.exit_font_state != NULL)
1357 					callbacks.exit_font_state(userData);
1358 
1359 				break;
1360 			}
1361 
1362 			case B_PIC_SET_ORIGIN:
1363 			{
1364 				const BPoint* origin;
1365 				if (callbacks.set_origin == NULL || !reader.Get(origin))
1366 					break;
1367 
1368 				callbacks.set_origin(userData, *origin);
1369 				break;
1370 			}
1371 
1372 			case B_PIC_SET_PEN_LOCATION:
1373 			{
1374 				const BPoint* location;
1375 				if (callbacks.set_pen_location == NULL || !reader.Get(location))
1376 					break;
1377 
1378 				callbacks.set_pen_location(userData, *location);
1379 				break;
1380 			}
1381 
1382 			case B_PIC_SET_DRAWING_MODE:
1383 			{
1384 				const uint16* mode;
1385 				if (callbacks.set_drawing_mode == NULL || !reader.Get(mode))
1386 					break;
1387 
1388 				callbacks.set_drawing_mode(userData, (drawing_mode)*mode);
1389 				break;
1390 			}
1391 
1392 			case B_PIC_SET_LINE_MODE:
1393 			{
1394 				const uint16* capMode;
1395 				const uint16* joinMode;
1396 				const float* miterLimit;
1397 				if (callbacks.set_line_mode == NULL || !reader.Get(capMode)
1398 					|| !reader.Get(joinMode) || !reader.Get(miterLimit)) {
1399 					break;
1400 				}
1401 
1402 				callbacks.set_line_mode(userData, (cap_mode)*capMode,
1403 					(join_mode)*joinMode, *miterLimit);
1404 				break;
1405 			}
1406 
1407 			case B_PIC_SET_PEN_SIZE:
1408 			{
1409 				const float* penSize;
1410 				if (callbacks.set_pen_size == NULL || !reader.Get(penSize))
1411 					break;
1412 
1413 				callbacks.set_pen_size(userData, *penSize);
1414 				break;
1415 			}
1416 
1417 			case B_PIC_SET_FORE_COLOR:
1418 			{
1419 				const rgb_color* color;
1420 				if (callbacks.set_fore_color == NULL || !reader.Get(color))
1421 					break;
1422 
1423 				callbacks.set_fore_color(userData, *color);
1424 				break;
1425 			}
1426 
1427 			case B_PIC_SET_BACK_COLOR:
1428 			{
1429 				const rgb_color* color;
1430 				if (callbacks.set_back_color == NULL || !reader.Get(color))
1431 					break;
1432 
1433 				callbacks.set_back_color(userData, *color);
1434 				break;
1435 			}
1436 
1437 			case B_PIC_SET_STIPLE_PATTERN:
1438 			{
1439 				const pattern* stipplePattern;
1440 				if (callbacks.set_stipple_pattern == NULL
1441 					|| !reader.Get(stipplePattern)) {
1442 					break;
1443 				}
1444 
1445 				callbacks.set_stipple_pattern(userData, *stipplePattern);
1446 				break;
1447 			}
1448 
1449 			case B_PIC_SET_SCALE:
1450 			{
1451 				const float* scale;
1452 				if (callbacks.set_scale == NULL || !reader.Get(scale))
1453 					break;
1454 
1455 				callbacks.set_scale(userData, *scale);
1456 				break;
1457 			}
1458 
1459 			case B_PIC_SET_FONT_FAMILY:
1460 			{
1461 				const char* family;
1462 				size_t length;
1463 				if (callbacks.set_font_family == NULL
1464 					|| !reader.GetRemaining(family, length)) {
1465 					break;
1466 				}
1467 
1468 				callbacks.set_font_family(userData, family, length);
1469 				break;
1470 			}
1471 
1472 			case B_PIC_SET_FONT_STYLE:
1473 			{
1474 				const char* style;
1475 				size_t length;
1476 				if (callbacks.set_font_style == NULL
1477 					|| !reader.GetRemaining(style, length)) {
1478 					break;
1479 				}
1480 
1481 				callbacks.set_font_style(userData, style, length);
1482 				break;
1483 			}
1484 
1485 			case B_PIC_SET_FONT_SPACING:
1486 			{
1487 				const uint32* spacing;
1488 				if (callbacks.set_font_spacing == NULL || !reader.Get(spacing))
1489 					break;
1490 
1491 				callbacks.set_font_spacing(userData, *spacing);
1492 				break;
1493 			}
1494 
1495 			case B_PIC_SET_FONT_SIZE:
1496 			{
1497 				const float* size;
1498 				if (callbacks.set_font_size == NULL || !reader.Get(size))
1499 					break;
1500 
1501 				callbacks.set_font_size(userData, *size);
1502 				break;
1503 			}
1504 
1505 			case B_PIC_SET_FONT_ROTATE:
1506 			{
1507 				const float* rotation;
1508 				if (callbacks.set_font_rotation == NULL
1509 					|| !reader.Get(rotation)) {
1510 					break;
1511 				}
1512 
1513 				callbacks.set_font_rotation(userData, *rotation);
1514 				break;
1515 			}
1516 
1517 			case B_PIC_SET_FONT_ENCODING:
1518 			{
1519 				const uint32* encoding;
1520 				if (callbacks.set_font_encoding == NULL
1521 					|| !reader.Get(encoding)) {
1522 					break;
1523 				}
1524 
1525 				callbacks.set_font_encoding(userData, *encoding);
1526 				break;
1527 			}
1528 
1529 			case B_PIC_SET_FONT_FLAGS:
1530 			{
1531 				const uint32* flags;
1532 				if (callbacks.set_font_flags == NULL || !reader.Get(flags))
1533 					break;
1534 
1535 				callbacks.set_font_flags(userData, *flags);
1536 				break;
1537 			}
1538 
1539 			case B_PIC_SET_FONT_SHEAR:
1540 			{
1541 				const float* shear;
1542 				if (callbacks.set_font_shear == NULL || !reader.Get(shear))
1543 					break;
1544 
1545 				callbacks.set_font_shear(userData, *shear);
1546 				break;
1547 			}
1548 
1549 			case B_PIC_SET_FONT_FACE:
1550 			{
1551 				const uint32* face;
1552 				if (callbacks.set_font_face == NULL || !reader.Get(face))
1553 					break;
1554 
1555 				callbacks.set_font_face(userData, *face);
1556 				break;
1557 			}
1558 
1559 			case B_PIC_SET_BLENDING_MODE:
1560 			{
1561 				const uint16* alphaSourceMode;
1562 				const uint16* alphaFunctionMode;
1563 				if (callbacks.set_blending_mode == NULL
1564 					|| !reader.Get(alphaSourceMode)
1565 					|| !reader.Get(alphaFunctionMode)) {
1566 					break;
1567 				}
1568 
1569 				callbacks.set_blending_mode(userData,
1570 					(source_alpha)*alphaSourceMode,
1571 					(alpha_function)*alphaFunctionMode);
1572 				break;
1573 			}
1574 
1575 			case B_PIC_SET_FILL_RULE:
1576 			{
1577 				const uint32* fillRule;
1578 				if (callbacks.set_fill_rule == NULL
1579 					|| !reader.Get(fillRule)) {
1580 					break;
1581 				}
1582 
1583 				callbacks.set_fill_rule(userData, *fillRule);
1584 				break;
1585 			}
1586 
1587 			case B_PIC_SET_TRANSFORM:
1588 			{
1589 				const BAffineTransform* transform;
1590 				if (callbacks.set_transform == NULL || !reader.Get(transform))
1591 					break;
1592 
1593 				callbacks.set_transform(userData, *transform);
1594 				break;
1595 			}
1596 
1597 			case B_PIC_AFFINE_TRANSLATE:
1598 			{
1599 				const double* x;
1600 				const double* y;
1601 				if (callbacks.translate_by == NULL || !reader.Get(x)
1602 					|| !reader.Get(y)) {
1603 					break;
1604 				}
1605 
1606 				callbacks.translate_by(userData, *x, *y);
1607 				break;
1608 			}
1609 
1610 			case B_PIC_AFFINE_SCALE:
1611 			{
1612 				const double* x;
1613 				const double* y;
1614 				if (callbacks.scale_by == NULL || !reader.Get(x)
1615 					|| !reader.Get(y)) {
1616 					break;
1617 				}
1618 
1619 				callbacks.scale_by(userData, *x, *y);
1620 				break;
1621 			}
1622 
1623 			case B_PIC_AFFINE_ROTATE:
1624 			{
1625 				const double* angleRadians;
1626 				if (callbacks.rotate_by == NULL || !reader.Get(angleRadians))
1627 					break;
1628 
1629 				callbacks.rotate_by(userData, *angleRadians);
1630 				break;
1631 			}
1632 
1633 			case B_PIC_BLEND_LAYER:
1634 			{
1635 				Layer* const* layer;
1636 				if (callbacks.blend_layer == NULL || !reader.Get<Layer*>(layer))
1637 					break;
1638 
1639 				callbacks.blend_layer(userData, *layer);
1640 				break;
1641 			}
1642 
1643 			case B_PIC_CLIP_TO_RECT:
1644 			{
1645 				const bool* inverse;
1646 				const BRect* rect;
1647 
1648 				if (callbacks.clip_to_rect == NULL || !reader.Get(inverse)
1649 					|| !reader.Get(rect)) {
1650 					break;
1651 				}
1652 
1653 				callbacks.clip_to_rect(userData, *rect, *inverse);
1654 				break;
1655 			}
1656 
1657 			case B_PIC_CLIP_TO_SHAPE:
1658 			{
1659 				const bool* inverse;
1660 				const uint32* opCount;
1661 				const uint32* pointCount;
1662 				const uint32* opList;
1663 				const BPoint* pointList;
1664 				if (callbacks.clip_to_shape == NULL || !reader.Get(inverse)
1665 					|| !reader.Get(opCount) || !reader.Get(pointCount)
1666 					|| !reader.Get(opList, *opCount)
1667 					|| !reader.Get(pointList, *pointCount)) {
1668 					break;
1669 				}
1670 
1671 				callbacks.clip_to_shape(userData, *opCount, opList,
1672 					*pointCount, pointList, *inverse);
1673 				break;
1674 			}
1675 
1676 			default:
1677 				break;
1678 		}
1679 
1680 #if DEBUG
1681 		numOps++;
1682 #if DEBUG > 1
1683 		printf("executed in %" B_PRId64 " usecs\n", system_time()
1684 			- startOpTime);
1685 #endif
1686 #endif
1687 	}
1688 
1689 #if DEBUG
1690 	printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64
1691 		" usecs.\n", numOps, system_time() - startTime);
1692 #endif
1693 	return B_OK;
1694 }
1695