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