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