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