xref: /haiku/src/servers/app/PictureBoundingBoxPlayer.cpp (revision 97dfeb96704e5dbc5bec32ad7b21379d0125e031)
1 /*
2  * Copyright 2001-2015, Haiku.
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  *      Julian Harnath <julian.harnath@rwth-aachen.de>
10  */
11 
12 #include "PictureBoundingBoxPlayer.h"
13 
14 #include <new>
15 #include <stdio.h>
16 
17 #include "DrawState.h"
18 #include "FontManager.h"
19 #include "Layer.h"
20 #include "ServerApp.h"
21 #include "ServerBitmap.h"
22 #include "ServerFont.h"
23 #include "ServerPicture.h"
24 #include "ServerTokenSpace.h"
25 #include "View.h"
26 #include "Window.h"
27 
28 #include <Bitmap.h>
29 #include <Debug.h>
30 #include <List.h>
31 #include <ObjectListPrivate.h>
32 #include <PicturePlayer.h>
33 #include <PictureProtocol.h>
34 #include <Shape.h>
35 
36 
37 //#define DEBUG_TRACE_BB
38 #ifdef DEBUG_TRACE_BB
39 #	define TRACE_BB(text, ...) debug_printf("PBBP: " text, ##__VA_ARGS__)
40 #else
41 #	define TRACE_BB(text, ...)
42 #endif
43 
44 
45 typedef PictureBoundingBoxPlayer::State BoundingBoxState;
46 
47 
48 // #pragma mark - PictureBoundingBoxPlayer::State
49 
50 
51 class PictureBoundingBoxPlayer::State {
52 public:
53 	State(const DrawState* drawState, BRect* boundingBox)
54 		:
55 		fDrawState(drawState->Squash()),
56 		fBoundingBox(boundingBox)
57 	{
58 		fBoundingBox->Set(INT_MAX, INT_MAX, INT_MIN, INT_MIN);
59 	}
60 
61 	~State()
62 	{
63 		delete fDrawState;
64 	}
65 
66 	DrawState* GetDrawState()
67 	{
68 		return fDrawState;
69 	}
70 
71 	void PushDrawState()
72 	{
73 		DrawState* nextState = fDrawState->PushState();
74 		if (nextState != NULL)
75 			fDrawState = nextState;
76 	}
77 
78 	void PopDrawState()
79 	{
80 		if (fDrawState->PreviousState() != NULL)
81 			fDrawState = fDrawState->PopState();
82 	}
83 
84 	SimpleTransform PenToLocalTransform() const
85 	{
86 		SimpleTransform transform;
87 		fDrawState->Transform(transform);
88 		return transform;
89 	}
90 
91 	void IncludeRect(BRect& rect)
92 	{
93 		_AffineTransformRect(rect);
94 		*fBoundingBox = (*fBoundingBox) | rect;
95 	}
96 
97 private:
98 	void _AffineTransformRect(BRect& rect)
99 	{
100 		BAffineTransform transform = fDrawState->CombinedTransform();
101 		if (transform.IsIdentity())
102 			return;
103 
104 		BPoint transformedShape[4];
105 		transformedShape[0] = rect.LeftTop();
106 		transformedShape[1] = rect.LeftBottom();
107 		transformedShape[2] = rect.RightTop();
108 		transformedShape[3] = rect.RightBottom();
109 
110 		transform.Apply(&transformedShape[0], 4);
111 
112 		float minX = INT_MAX;
113 		float minY = INT_MAX;
114 		float maxX = INT_MIN;
115 		float maxY = INT_MIN;
116 
117 		for (uint32 i = 0; i < 4; i++) {
118 			if (transformedShape[i].x < minX)
119 				minX = transformedShape[i].x;
120 			else if (transformedShape[i].x > maxX)
121 				maxX = transformedShape[i].x;
122 			if (transformedShape[i].y < minY)
123 				minY = transformedShape[i].y;
124 			else if (transformedShape[i].y > maxY)
125 				maxY = transformedShape[i].y;
126 		}
127 
128 		rect.Set(minX, minY, maxX, maxY);
129 	}
130 
131 
132 private:
133 	DrawState*	fDrawState;
134 	BRect*		fBoundingBox;
135 };
136 
137 
138 // #pragma mark - Picture playback hooks
139 
140 
141 static void
142 get_polygon_frame(const BPoint* points, int32 numPoints, BRect* frame)
143 {
144 	ASSERT(numPoints > 0);
145 
146 	float left = points->x;
147 	float top = points->y;
148 	float right = left;
149 	float bottom = top;
150 
151 	points++;
152 	numPoints--;
153 
154 	while (numPoints--) {
155 		if (points->x < left)
156 			left = points->x;
157 		if (points->x > right)
158 			right = points->x;
159 		if (points->y < top)
160 			top = points->y;
161 		if (points->y > bottom)
162 			bottom = points->y;
163 		points++;
164 	}
165 
166 	frame->Set(left, top, right, bottom);
167 }
168 
169 
170 template<class RectType>
171 static void
172 expand_rect_for_pen_size(BoundingBoxState* state, RectType& rect)
173 {
174 	float penInset = -((state->GetDrawState()->PenSize() / 2.0f) + 1.0f);
175 	rect.InsetBy(penInset, penInset);
176 }
177 
178 
179 static void
180 move_pen_by(void* _state, const BPoint& delta)
181 {
182 	TRACE_BB("%p move pen by %.2f %.2f\n", _state, delta.x, delta.y);
183 	BoundingBoxState* const state =
184 		reinterpret_cast<BoundingBoxState*>(_state);
185 
186 	state->GetDrawState()->SetPenLocation(
187 		state->GetDrawState()->PenLocation() + delta);
188 }
189 
190 
191 static void
192 determine_bounds_stroke_line(void* _state, const BPoint& _start,
193 	const BPoint& _end)
194 {
195 	TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", _state,
196 		_start.x, _start.y, _end.x, _end.y);
197 	BoundingBoxState* const state =
198 		reinterpret_cast<BoundingBoxState*>(_state);
199 
200 	BPoint start = _start;
201 	BPoint end = _end;
202 
203 	const SimpleTransform transform = state->PenToLocalTransform();
204 	transform.Apply(&start);
205 	transform.Apply(&end);
206 
207 	BRect rect;
208 	if (start.x <= end.x) {
209 		rect.left = start.x;
210 		rect.right = end.x;
211 	} else {
212 		rect.left = end.x;
213 		rect.right = start.x;
214 	}
215 	if (start.y <= end.y) {
216 		rect.top = start.y;
217 		rect.bottom = end.y;
218 	} else {
219 		rect.top = end.y;
220 		rect.bottom = start.y;
221 	}
222 
223 	expand_rect_for_pen_size(state, rect);
224 	state->IncludeRect(rect);
225 
226 	state->GetDrawState()->SetPenLocation(_end);
227 }
228 
229 
230 static void
231 determine_bounds_draw_rect(void* _state, const BRect& _rect, bool fill)
232 {
233 	TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", _state, fill,
234 		_rect.left, _rect.top, _rect.right, _rect.bottom);
235 	BoundingBoxState* const state =
236 		reinterpret_cast<BoundingBoxState*>(_state);
237 
238 	BRect rect = _rect;
239 	state->PenToLocalTransform().Apply(&rect);
240 	if (!fill)
241 		expand_rect_for_pen_size(state, rect);
242 	state->IncludeRect(rect);
243 }
244 
245 
246 static void
247 determine_bounds_draw_round_rect(void* _state, const BRect& _rect,
248 	const BPoint&, bool fill)
249 {
250 	determine_bounds_draw_rect(_state, _rect, fill);
251 }
252 
253 
254 static void
255 determine_bounds_bezier(BoundingBoxState* state, const BPoint* viewPoints,
256 	BRect& outRect)
257 {
258 	// Note: this is an approximation which results in a rectangle which
259 	// encloses all four control points. That will always enclose the curve,
260 	// although not necessarily tightly, but it's good enough for the purpose.
261 	// The exact bounding box of a bezier curve is not trivial to determine,
262 	// (need to calculate derivative of the curve) and we're going for
263 	// performance here.
264 	BPoint points[4];
265 	state->PenToLocalTransform().Apply(points, viewPoints, 4);
266 	BPoint topLeft = points[0];
267 	BPoint bottomRight = points[0];
268 	for (uint32 index = 1; index < 4; index++) {
269 		if (points[index].x < topLeft.x || points[index].y < topLeft.y)
270 			topLeft = points[index];
271 		if (points[index].x > topLeft.x || points[index].y > topLeft.y)
272 			bottomRight = points[index];
273 	}
274 	outRect.SetLeftTop(topLeft);
275 	outRect.SetRightBottom(bottomRight);
276 }
277 
278 
279 static void
280 determine_bounds_draw_bezier(void* _state, size_t numPoints,
281 	const BPoint viewPoints[], bool fill)
282 {
283 	TRACE_BB("%p draw bezier fill=%d (%.2f %.2f) (%.2f %.2f) "
284 		"(%.2f %.2f) (%.2f %.2f)\n",
285 		_state,
286 		fill,
287 		viewPoints[0].x, viewPoints[0].y,
288 		viewPoints[1].x, viewPoints[1].y,
289 		viewPoints[2].x, viewPoints[2].y,
290 		viewPoints[3].x, viewPoints[3].y);
291 	BoundingBoxState* const state =
292 		reinterpret_cast<BoundingBoxState*>(_state);
293 
294 	const size_t kSupportedPoints = 4;
295 	if (numPoints != kSupportedPoints)
296 		return;
297 
298 	BRect rect;
299 	determine_bounds_bezier(state, viewPoints, rect);
300 	if (!fill)
301 		expand_rect_for_pen_size(state, rect);
302 	state->IncludeRect(rect);
303 }
304 
305 
306 static void
307 determine_bounds_draw_ellipse(void* _state, const BRect& _rect, bool fill)
308 {
309 	TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", _state, fill,
310 		_rect.left, _rect.top, _rect.right, _rect.bottom);
311 	BoundingBoxState* const state =
312 		reinterpret_cast<BoundingBoxState*>(_state);
313 
314 	BRect rect = _rect;
315 	state->PenToLocalTransform().Apply(&rect);
316 	if (!fill)
317 		expand_rect_for_pen_size(state, rect);
318 	state->IncludeRect(rect);
319 }
320 
321 
322 static void
323 determine_bounds_draw_arc(void* _state, const BPoint& center,
324 	const BPoint& radii, float, float, bool fill)
325 {
326 	BRect rect(center.x - radii.x, center.y - radii.y,
327 		center.x + radii.x - 1, center.y + radii.y - 1);
328 	determine_bounds_draw_ellipse(_state, rect, fill);
329 }
330 
331 
332 static void
333 determine_bounds_polygon(BoundingBoxState* state, int32 numPoints,
334 	const BPoint* viewPoints, BRect& outRect)
335 {
336 	if (numPoints <= 0)
337 		return;
338 
339 	if (numPoints <= 200) {
340 		// fast path: no malloc/free, also avoid
341 		// constructor/destructor calls
342 		char data[200 * sizeof(BPoint)];
343 		BPoint* points = (BPoint*)data;
344 
345 		state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
346 		get_polygon_frame(points, numPoints, &outRect);
347 
348 	} else {
349 		 // avoid constructor/destructor calls by
350 		 // using malloc instead of new []
351 		BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint));
352 		if (points == NULL)
353 			return;
354 
355 		state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
356 		get_polygon_frame(points, numPoints, &outRect);
357 
358 		free(points);
359 	}
360 }
361 
362 
363 void
364 determine_bounds_draw_polygon(void* _state, size_t numPoints,
365 	const BPoint viewPoints[], bool, bool fill)
366 {
367 	TRACE_BB("%p draw polygon fill=%d (%ld points)\n", _state, fill, numPoints);
368 	BoundingBoxState* const state =
369 		reinterpret_cast<BoundingBoxState*>(_state);
370 
371 	BRect rect;
372 	determine_bounds_polygon(state, numPoints, viewPoints, rect);
373 	if (!fill)
374 		expand_rect_for_pen_size(state, rect);
375 	state->IncludeRect(rect);
376 }
377 
378 
379 static void
380 determine_bounds_draw_shape(void* _state, const BShape& shape, bool fill)
381 {
382 	BRect rect = shape.Bounds();
383 
384 	TRACE_BB("%p stroke shape (bounds %.2f %.2f %.2f %.2f)\n", _state,
385 		rect.left, rect.top, rect.right, rect.bottom);
386 	BoundingBoxState* const state =
387 		reinterpret_cast<BoundingBoxState*>(_state);
388 
389 	state->PenToLocalTransform().Apply(&rect);
390 	if (!fill)
391 		expand_rect_for_pen_size(state, rect);
392 	state->IncludeRect(rect);
393 }
394 
395 
396 static void
397 determine_bounds_draw_string(void* _state, const char* string, size_t _length,
398 	float deltaSpace, float deltaNonSpace)
399 {
400 	TRACE_BB("%p string '%s'\n", _state, string);
401 	BoundingBoxState* const state =
402 		reinterpret_cast<BoundingBoxState*>(_state);
403 
404 	ServerFont font = state->GetDrawState()->Font();
405 
406 	escapement_delta delta = { deltaSpace, deltaNonSpace };
407 	BRect rect;
408 	int32 length = _length;
409 	font.GetBoundingBoxesForStrings((char**)&string, &length, 1, &rect,
410 		B_SCREEN_METRIC, &delta);
411 
412 	BPoint location = state->GetDrawState()->PenLocation();
413 
414 	state->PenToLocalTransform().Apply(&location);
415 	rect.OffsetBy(location);
416 	state->IncludeRect(rect);
417 
418 	state->PenToLocalTransform().Apply(&location);
419 	state->GetDrawState()->SetPenLocation(location);
420 }
421 
422 
423 static void
424 determine_bounds_draw_pixels(void* _state, const BRect&, const BRect& _dest,
425 	uint32, uint32, size_t, color_space, uint32, const void*, size_t)
426 {
427 	TRACE_BB("%p pixels (dest %.2f %.2f %.2f %.2f)\n", _state,
428 		_dest.left, _dest.top, _dest.right, _dest.bottom);
429 	BoundingBoxState* const state =
430 		reinterpret_cast<BoundingBoxState*>(_state);
431 
432 	BRect dest = _dest;
433 	state->PenToLocalTransform().Apply(&dest);
434 	state->IncludeRect(dest);
435 }
436 
437 
438 static void
439 draw_picture(void* _state, const BPoint& where, int32 token)
440 {
441 	TRACE_BB("%p picture (unimplemented)\n", _state);
442 
443 	// TODO
444 	(void)_state;
445 	(void)where;
446 	(void)token;
447 }
448 
449 
450 static void
451 set_clipping_rects(void* _state, size_t numRects, const BRect rects[])
452 {
453 	TRACE_BB("%p cliping rects (%ld rects)\n", _state, numRects);
454 
455 	// TODO
456 	(void)_state;
457 	(void)rects;
458 	(void)numRects;
459 }
460 
461 
462 static void
463 clip_to_picture(void* _state, int32 pictureToken, const BPoint& where,
464 	bool clipToInverse)
465 {
466 	TRACE_BB("%p clip to picture (unimplemented)\n", _state);
467 
468 	// TODO
469 }
470 
471 
472 static void
473 push_state(void* _state)
474 {
475 	TRACE_BB("%p push state\n", _state);
476 	BoundingBoxState* const state =
477 		reinterpret_cast<BoundingBoxState*>(_state);
478 
479 	state->PushDrawState();
480 }
481 
482 
483 static void
484 pop_state(void* _state)
485 {
486 	TRACE_BB("%p pop state\n", _state);
487 	BoundingBoxState* const state =
488 		reinterpret_cast<BoundingBoxState*>(_state);
489 
490 	state->PopDrawState();
491 }
492 
493 
494 static void
495 enter_state_change(void*)
496 {
497 }
498 
499 
500 static void
501 exit_state_change(void*)
502 {
503 }
504 
505 
506 static void
507 enter_font_state(void*)
508 {
509 }
510 
511 
512 static void
513 exit_font_state(void*)
514 {
515 }
516 
517 
518 static void
519 set_origin(void* _state, const BPoint& pt)
520 {
521 	TRACE_BB("%p set origin %.2f %.2f\n", _state, pt.x, pt.y);
522 	BoundingBoxState* const state =
523 		reinterpret_cast<BoundingBoxState*>(_state);
524 	state->GetDrawState()->SetOrigin(pt);
525 }
526 
527 
528 static void
529 set_pen_location(void* _state, const BPoint& pt)
530 {
531 	TRACE_BB("%p set pen location %.2f %.2f\n", _state, pt.x, pt.y);
532 	BoundingBoxState* const state =
533 		reinterpret_cast<BoundingBoxState*>(_state);
534 	state->GetDrawState()->SetPenLocation(pt);
535 }
536 
537 
538 static void
539 set_drawing_mode(void*, drawing_mode)
540 {
541 }
542 
543 
544 static void
545 set_line_mode(void* _state, cap_mode capMode, join_mode joinMode,
546 	float miterLimit)
547 {
548 	BoundingBoxState* const state =
549 		reinterpret_cast<BoundingBoxState*>(_state);
550 
551 	DrawState* drawState = state->GetDrawState();
552 	drawState->SetLineCapMode(capMode);
553 	drawState->SetLineJoinMode(joinMode);
554 	drawState->SetMiterLimit(miterLimit);
555 }
556 
557 
558 static void
559 set_pen_size(void* _state, float size)
560 {
561 	TRACE_BB("%p set pen size %.2f\n", _state, size);
562 	BoundingBoxState* const state =
563 		reinterpret_cast<BoundingBoxState*>(_state);
564 
565 	state->GetDrawState()->SetPenSize(size);
566 }
567 
568 
569 static void
570 set_fore_color(void* _state, const rgb_color& color)
571 {
572 	BoundingBoxState* const state =
573 		reinterpret_cast<BoundingBoxState*>(_state);
574 
575 	state->GetDrawState()->SetHighColor(color);
576 }
577 
578 
579 static void
580 set_back_color(void* _state, const rgb_color& color)
581 {
582 	BoundingBoxState* const state =
583 		reinterpret_cast<BoundingBoxState*>(_state);
584 
585 	state->GetDrawState()->SetLowColor(color);
586 }
587 
588 
589 static void
590 set_stipple_pattern(void* _state, const pattern& _pattern)
591 {
592 	BoundingBoxState* const state =
593 		reinterpret_cast<BoundingBoxState*>(_state);
594 
595 	state->GetDrawState()->SetPattern(Pattern(_pattern));
596 }
597 
598 
599 static void
600 set_scale(void* _state, float scale)
601 {
602 	BoundingBoxState* const state =
603 		reinterpret_cast<BoundingBoxState*>(_state);
604 
605 	state->GetDrawState()->SetScale(scale);
606 }
607 
608 
609 static void
610 set_font_family(void* _state, const char* _family, size_t length)
611 {
612 	BoundingBoxState* const state =
613 		reinterpret_cast<BoundingBoxState*>(_state);
614 
615 	BString family(_family, length);
616 	FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
617 	ServerFont font;
618 	font.SetStyle(fontStyle);
619 	state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
620 }
621 
622 
623 static void
624 set_font_style(void* _state, const char* _style, size_t length)
625 {
626 	BoundingBoxState* const state =
627 		reinterpret_cast<BoundingBoxState*>(_state);
628 
629 	BString style(_style, length);
630 	ServerFont font(state->GetDrawState()->Font());
631 	FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
632 	font.SetStyle(fontStyle);
633 	state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
634 }
635 
636 
637 static void
638 set_font_spacing(void* _state, uint8 spacing)
639 {
640 	BoundingBoxState* const state =
641 		reinterpret_cast<BoundingBoxState*>(_state);
642 
643 	ServerFont font;
644 	font.SetSpacing(spacing);
645 	state->GetDrawState()->SetFont(font, B_FONT_SPACING);
646 }
647 
648 
649 static void
650 set_font_size(void* _state, float size)
651 {
652 	BoundingBoxState* const state =
653 		reinterpret_cast<BoundingBoxState*>(_state);
654 
655 	ServerFont font;
656 	font.SetSize(size);
657 	state->GetDrawState()->SetFont(font, B_FONT_SIZE);
658 }
659 
660 
661 static void
662 set_font_rotate(void* _state, float rotation)
663 {
664 	BoundingBoxState* const state =
665 		reinterpret_cast<BoundingBoxState*>(_state);
666 
667 	ServerFont font;
668 	font.SetRotation(rotation);
669 	state->GetDrawState()->SetFont(font, B_FONT_ROTATION);
670 }
671 
672 
673 static void
674 set_font_encoding(void* _state, uint8 encoding)
675 {
676 	BoundingBoxState* const state =
677 		reinterpret_cast<BoundingBoxState*>(_state);
678 
679 	ServerFont font;
680 	font.SetEncoding(encoding);
681 	state->GetDrawState()->SetFont(font, B_FONT_ENCODING);
682 }
683 
684 
685 static void
686 set_font_flags(void* _state, uint32 flags)
687 {
688 	BoundingBoxState* const state =
689 		reinterpret_cast<BoundingBoxState*>(_state);
690 
691 	ServerFont font;
692 	font.SetFlags(flags);
693 	state->GetDrawState()->SetFont(font, B_FONT_FLAGS);
694 }
695 
696 
697 static void
698 set_font_shear(void* _state, float shear)
699 {
700 	BoundingBoxState* const state =
701 		reinterpret_cast<BoundingBoxState*>(_state);
702 
703 	ServerFont font;
704 	font.SetShear(shear);
705 	state->GetDrawState()->SetFont(font, B_FONT_SHEAR);
706 }
707 
708 
709 static void
710 set_font_face(void* _state, uint16 face)
711 {
712 	BoundingBoxState* const state =
713 		reinterpret_cast<BoundingBoxState*>(_state);
714 
715 	ServerFont font;
716 	font.SetFace(face);
717 	state->GetDrawState()->SetFont(font, B_FONT_FACE);
718 }
719 
720 
721 static void
722 set_blending_mode(void*, source_alpha, alpha_function)
723 {
724 }
725 
726 
727 static void
728 set_transform(void* _state, const BAffineTransform& transform)
729 {
730 	TRACE_BB("%p transform\n", _state);
731 	BoundingBoxState* const state =
732 		reinterpret_cast<BoundingBoxState*>(_state);
733 	state->GetDrawState()->SetTransform(transform);
734 }
735 
736 
737 static void
738 translate_by(void* _state, double x, double y)
739 {
740 	TRACE_BB("%p translate\n", _state);
741 	BoundingBoxState* const state =
742 		reinterpret_cast<BoundingBoxState*>(_state);
743 	BAffineTransform transform = state->GetDrawState()->Transform();
744 	transform.PreTranslateBy(x, y);
745 	state->GetDrawState()->SetTransform(transform);
746 }
747 
748 
749 static void
750 scale_by(void* _state, double x, double y)
751 {
752 	TRACE_BB("%p scale\n", _state);
753 	BoundingBoxState* const state =
754 		reinterpret_cast<BoundingBoxState*>(_state);
755 	BAffineTransform transform = state->GetDrawState()->Transform();
756 	transform.PreScaleBy(x, y);
757 	state->GetDrawState()->SetTransform(transform);
758 }
759 
760 
761 static void
762 rotate_by(void* _state, double angleRadians)
763 {
764 	TRACE_BB("%p rotate\n", _state);
765 	BoundingBoxState* const state =
766 		reinterpret_cast<BoundingBoxState*>(_state);
767 	BAffineTransform transform = state->GetDrawState()->Transform();
768 	transform.PreRotateBy(angleRadians);
769 	state->GetDrawState()->SetTransform(transform);
770 }
771 
772 
773 static void
774 determine_bounds_nested_layer(void* _state, Layer* layer)
775 {
776 	TRACE_BB("%p nested layer\n", _state);
777 	BoundingBoxState* const state =
778 		reinterpret_cast<BoundingBoxState*>(_state);
779 
780 	BRect boundingBox;
781 	PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox);
782 	if (boundingBox.IsValid())
783 		state->IncludeRect(boundingBox);
784 }
785 
786 
787 static const BPrivate::picture_player_callbacks
788 	kPictureBoundingBoxPlayerCallbacks = {
789 	move_pen_by,
790 	determine_bounds_stroke_line,
791 	determine_bounds_draw_rect,
792 	determine_bounds_draw_round_rect,
793 	determine_bounds_draw_bezier,
794 	determine_bounds_draw_arc,
795 	determine_bounds_draw_ellipse,
796 	determine_bounds_draw_polygon,
797 	determine_bounds_draw_shape,
798 	determine_bounds_draw_string,
799 	determine_bounds_draw_pixels,
800 	draw_picture,
801 	set_clipping_rects,
802 	clip_to_picture,
803 	push_state,
804 	pop_state,
805 	enter_state_change,
806 	exit_state_change,
807 	enter_font_state,
808 	exit_font_state,
809 	set_origin,
810 	set_pen_location,
811 	set_drawing_mode,
812 	set_line_mode,
813 	set_pen_size,
814 	set_fore_color,
815 	set_back_color,
816 	set_stipple_pattern,
817 	set_scale,
818 	set_font_family,
819 	set_font_style,
820 	set_font_spacing,
821 	set_font_size,
822 	set_font_rotate,
823 	set_font_encoding,
824 	set_font_flags,
825 	set_font_shear,
826 	set_font_face,
827 	set_blending_mode,
828 	set_transform,
829 	translate_by,
830 	scale_by,
831 	rotate_by,
832 	determine_bounds_nested_layer
833 };
834 
835 
836 // #pragma mark - PictureBoundingBoxPlayer
837 
838 
839 /* static */ void
840 PictureBoundingBoxPlayer::Play(ServerPicture* picture,
841 	const DrawState* drawState, BRect* outBoundingBox)
842 {
843 	State state(drawState, outBoundingBox);
844 
845 	BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(picture->fData);
846 	if (mallocIO == NULL)
847 		return;
848 
849 	BPrivate::PicturePlayer player(mallocIO->Buffer(),
850 		mallocIO->BufferLength(), ServerPicture::PictureList::Private(
851 			picture->fPictures).AsBList());
852 	player.Play(kPictureBoundingBoxPlayerCallbacks,
853 		sizeof(kPictureBoundingBoxPlayerCallbacks), &state);
854 }
855