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
30using BPrivate::PicturePlayer;
31
32
33struct adapter_context {
34	void* user_data;
35	void** function_table;
36};
37
38
39static void
40nop()
41{
42}
43
44
45static void
46move_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
54static void
55stroke_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
63static void
64draw_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
72static void
73draw_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
82static void
83draw_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
95static void
96draw_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
106static void
107draw_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
118static void
119draw_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
136static void
137draw_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
145static void
146draw_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
160static void
161draw_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
180static void
181draw_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
189static void
190set_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
206static void
207clip_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
216static void
217push_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
224static void
225pop_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
232static void
233enter_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
240static void
241exit_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
248static void
249enter_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
256static void
257exit_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
264static void
265set_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
273static void
274set_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
282static void
283set_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
291static void
292set_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
301static void
302set_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
310static void
311set_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
319static void
320set_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
328static void
329set_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
337static void
338set_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
346static void
347set_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
359static void
360set_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
372static void
373set_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
381static void
382set_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
390static void
391set_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
399static void
400set_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
408static void
409set_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
417static void
418set_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
426static void
427set_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
435static void
436set_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
446static void
447set_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
455static void
456translate_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
464static void
465scale_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
473static void
474rotate_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
482static void
483blend_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
491static void
492clip_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
500static void
501clip_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
511static void
512draw_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
526static void
527draw_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
535static void
536draw_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
545static void
546draw_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
558static void
559draw_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
569static void
570draw_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
581static void
582draw_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
599static void
600draw_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
608static void
609set_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
619static const char *
620PictureOpToString(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
706PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures)
707	:	fData(data),
708		fSize(size),
709		fPictures(pictures)
710{
711}
712
713
714PicturePlayer::~PicturePlayer()
715{
716}
717
718
719status_t
720PicturePlayer::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
805status_t
806PicturePlayer::Play(const picture_player_callbacks& callbacks,
807	size_t callbacksSize, void* userData)
808{
809	return _Play(callbacks, userData, fData, fSize, 0);
810}
811
812
813class DataReader {
814public:
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
868private:
869		const uint8*	fBuffer;
870		size_t			fRemaining;
871};
872
873
874struct picture_data_entry_header {
875	uint16 op;
876	uint32 size;
877} _PACKED;
878
879
880status_t
881PicturePlayer::_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