xref: /haiku/src/servers/app/PictureBoundingBoxPlayer.cpp (revision 54624bda43f13312a491fe1c91d22834be3374f5)
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 	font.GetBoundingBoxesForStrings((char**)&string, &length, 1, &rect,
409 		B_SCREEN_METRIC, &delta);
410 
411 	BPoint location = state->GetDrawState()->PenLocation();
412 
413 	state->PenToLocalTransform().Apply(&location);
414 	rect.OffsetBy(location);
415 	state->IncludeRect(rect);
416 
417 	state->PenToLocalTransform().Apply(&location);
418 	state->GetDrawState()->SetPenLocation(location);
419 }
420 
421 
422 static void
423 determine_bounds_draw_pixels(void* _state, const BRect&, const BRect& _dest,
424 	uint32, uint32, size_t, color_space, uint32, const void*, size_t)
425 {
426 	TRACE_BB("%p pixels (dest %.2f %.2f %.2f %.2f)\n", _state,
427 		_dest.left, _dest.top, _dest.right, _dest.bottom);
428 	BoundingBoxState* const state =
429 		reinterpret_cast<BoundingBoxState*>(_state);
430 
431 	BRect dest = _dest;
432 	state->PenToLocalTransform().Apply(&dest);
433 	state->IncludeRect(dest);
434 }
435 
436 
437 static void
438 draw_picture(void* _state, const BPoint& where, int32 token)
439 {
440 	TRACE_BB("%p picture (unimplemented)\n", _state);
441 
442 	// TODO
443 	(void)_state;
444 	(void)where;
445 	(void)token;
446 }
447 
448 
449 static void
450 set_clipping_rects(void* _state, size_t numRects, const BRect rects[])
451 {
452 	TRACE_BB("%p cliping rects (%ld rects)\n", _state, numRects);
453 
454 	// TODO
455 	(void)_state;
456 	(void)rects;
457 	(void)numRects;
458 }
459 
460 
461 static void
462 clip_to_picture(void* _state, int32 pictureToken, const BPoint& where,
463 	bool clipToInverse)
464 {
465 	TRACE_BB("%p clip to picture (unimplemented)\n", _state);
466 
467 	// TODO
468 }
469 
470 
471 static void
472 push_state(void* _state)
473 {
474 	TRACE_BB("%p push state\n", _state);
475 	BoundingBoxState* const state =
476 		reinterpret_cast<BoundingBoxState*>(_state);
477 
478 	state->PushDrawState();
479 }
480 
481 
482 static void
483 pop_state(void* _state)
484 {
485 	TRACE_BB("%p pop state\n", _state);
486 	BoundingBoxState* const state =
487 		reinterpret_cast<BoundingBoxState*>(_state);
488 
489 	state->PopDrawState();
490 }
491 
492 
493 static void
494 enter_state_change(void*)
495 {
496 }
497 
498 
499 static void
500 exit_state_change(void*)
501 {
502 }
503 
504 
505 static void
506 enter_font_state(void*)
507 {
508 }
509 
510 
511 static void
512 exit_font_state(void*)
513 {
514 }
515 
516 
517 static void
518 set_origin(void* _state, const BPoint& pt)
519 {
520 	TRACE_BB("%p set origin %.2f %.2f\n", _state, pt.x, pt.y);
521 	BoundingBoxState* const state =
522 		reinterpret_cast<BoundingBoxState*>(_state);
523 	state->GetDrawState()->SetOrigin(pt);
524 }
525 
526 
527 static void
528 set_pen_location(void* _state, const BPoint& pt)
529 {
530 	TRACE_BB("%p set pen location %.2f %.2f\n", _state, pt.x, pt.y);
531 	BoundingBoxState* const state =
532 		reinterpret_cast<BoundingBoxState*>(_state);
533 	state->GetDrawState()->SetPenLocation(pt);
534 }
535 
536 
537 static void
538 set_drawing_mode(void*, drawing_mode)
539 {
540 }
541 
542 
543 static void
544 set_line_mode(void* _state, cap_mode capMode, join_mode joinMode,
545 	float miterLimit)
546 {
547 	BoundingBoxState* const state =
548 		reinterpret_cast<BoundingBoxState*>(_state);
549 
550 	DrawState* drawState = state->GetDrawState();
551 	drawState->SetLineCapMode(capMode);
552 	drawState->SetLineJoinMode(joinMode);
553 	drawState->SetMiterLimit(miterLimit);
554 }
555 
556 
557 static void
558 set_pen_size(void* _state, float size)
559 {
560 	TRACE_BB("%p set pen size %.2f\n", _state, size);
561 	BoundingBoxState* const state =
562 		reinterpret_cast<BoundingBoxState*>(_state);
563 
564 	state->GetDrawState()->SetPenSize(size);
565 }
566 
567 
568 static void
569 set_fore_color(void* _state, const rgb_color& color)
570 {
571 	BoundingBoxState* const state =
572 		reinterpret_cast<BoundingBoxState*>(_state);
573 
574 	state->GetDrawState()->SetHighColor(color);
575 }
576 
577 
578 static void
579 set_back_color(void* _state, const rgb_color& color)
580 {
581 	BoundingBoxState* const state =
582 		reinterpret_cast<BoundingBoxState*>(_state);
583 
584 	state->GetDrawState()->SetLowColor(color);
585 }
586 
587 
588 static void
589 set_stipple_pattern(void* _state, const pattern& _pattern)
590 {
591 	BoundingBoxState* const state =
592 		reinterpret_cast<BoundingBoxState*>(_state);
593 
594 	state->GetDrawState()->SetPattern(Pattern(_pattern));
595 }
596 
597 
598 static void
599 set_scale(void* _state, float scale)
600 {
601 	BoundingBoxState* const state =
602 		reinterpret_cast<BoundingBoxState*>(_state);
603 
604 	state->GetDrawState()->SetScale(scale);
605 }
606 
607 
608 static void
609 set_font_family(void* _state, const char* _family, size_t length)
610 {
611 	BoundingBoxState* const state =
612 		reinterpret_cast<BoundingBoxState*>(_state);
613 
614 	BString family(_family, length);
615 	FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
616 	ServerFont font;
617 	font.SetStyle(fontStyle);
618 	state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
619 }
620 
621 
622 static void
623 set_font_style(void* _state, const char* _style, size_t length)
624 {
625 	BoundingBoxState* const state =
626 		reinterpret_cast<BoundingBoxState*>(_state);
627 
628 	BString style(_style, length);
629 	ServerFont font(state->GetDrawState()->Font());
630 	FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
631 	font.SetStyle(fontStyle);
632 	state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
633 }
634 
635 
636 static void
637 set_font_spacing(void* _state, uint8 spacing)
638 {
639 	BoundingBoxState* const state =
640 		reinterpret_cast<BoundingBoxState*>(_state);
641 
642 	ServerFont font;
643 	font.SetSpacing(spacing);
644 	state->GetDrawState()->SetFont(font, B_FONT_SPACING);
645 }
646 
647 
648 static void
649 set_font_size(void* _state, float size)
650 {
651 	BoundingBoxState* const state =
652 		reinterpret_cast<BoundingBoxState*>(_state);
653 
654 	ServerFont font;
655 	font.SetSize(size);
656 	state->GetDrawState()->SetFont(font, B_FONT_SIZE);
657 }
658 
659 
660 static void
661 set_font_rotate(void* _state, float rotation)
662 {
663 	BoundingBoxState* const state =
664 		reinterpret_cast<BoundingBoxState*>(_state);
665 
666 	ServerFont font;
667 	font.SetRotation(rotation);
668 	state->GetDrawState()->SetFont(font, B_FONT_ROTATION);
669 }
670 
671 
672 static void
673 set_font_encoding(void* _state, uint8 encoding)
674 {
675 	BoundingBoxState* const state =
676 		reinterpret_cast<BoundingBoxState*>(_state);
677 
678 	ServerFont font;
679 	font.SetEncoding(encoding);
680 	state->GetDrawState()->SetFont(font, B_FONT_ENCODING);
681 }
682 
683 
684 static void
685 set_font_flags(void* _state, uint32 flags)
686 {
687 	BoundingBoxState* const state =
688 		reinterpret_cast<BoundingBoxState*>(_state);
689 
690 	ServerFont font;
691 	font.SetFlags(flags);
692 	state->GetDrawState()->SetFont(font, B_FONT_FLAGS);
693 }
694 
695 
696 static void
697 set_font_shear(void* _state, float shear)
698 {
699 	BoundingBoxState* const state =
700 		reinterpret_cast<BoundingBoxState*>(_state);
701 
702 	ServerFont font;
703 	font.SetShear(shear);
704 	state->GetDrawState()->SetFont(font, B_FONT_SHEAR);
705 }
706 
707 
708 static void
709 set_font_face(void* _state, uint16 face)
710 {
711 	BoundingBoxState* const state =
712 		reinterpret_cast<BoundingBoxState*>(_state);
713 
714 	ServerFont font;
715 	font.SetFace(face);
716 	state->GetDrawState()->SetFont(font, B_FONT_FACE);
717 }
718 
719 
720 static void
721 set_blending_mode(void*, source_alpha, alpha_function)
722 {
723 }
724 
725 
726 static void
727 set_transform(void* _state, const BAffineTransform& transform)
728 {
729 	TRACE_BB("%p transform\n", _state);
730 	BoundingBoxState* const state =
731 		reinterpret_cast<BoundingBoxState*>(_state);
732 	state->GetDrawState()->SetTransform(transform);
733 }
734 
735 
736 static void
737 translate_by(void* _state, double x, double y)
738 {
739 	TRACE_BB("%p translate\n", _state);
740 	BoundingBoxState* const state =
741 		reinterpret_cast<BoundingBoxState*>(_state);
742 	BAffineTransform transform = state->GetDrawState()->Transform();
743 	transform.PreTranslateBy(x, y);
744 	state->GetDrawState()->SetTransform(transform);
745 }
746 
747 
748 static void
749 scale_by(void* _state, double x, double y)
750 {
751 	TRACE_BB("%p scale\n", _state);
752 	BoundingBoxState* const state =
753 		reinterpret_cast<BoundingBoxState*>(_state);
754 	BAffineTransform transform = state->GetDrawState()->Transform();
755 	transform.PreScaleBy(x, y);
756 	state->GetDrawState()->SetTransform(transform);
757 }
758 
759 
760 static void
761 rotate_by(void* _state, double angleRadians)
762 {
763 	TRACE_BB("%p rotate\n", _state);
764 	BoundingBoxState* const state =
765 		reinterpret_cast<BoundingBoxState*>(_state);
766 	BAffineTransform transform = state->GetDrawState()->Transform();
767 	transform.PreRotateBy(angleRadians);
768 	state->GetDrawState()->SetTransform(transform);
769 }
770 
771 
772 static void
773 determine_bounds_nested_layer(void* _state, Layer* layer)
774 {
775 	TRACE_BB("%p nested layer\n", _state);
776 	BoundingBoxState* const state =
777 		reinterpret_cast<BoundingBoxState*>(_state);
778 
779 	BRect boundingBox;
780 	PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox);
781 	if (boundingBox.IsValid())
782 		state->IncludeRect(boundingBox);
783 }
784 
785 
786 static const BPrivate::picture_player_callbacks
787 	kPictureBoundingBoxPlayerCallbacks = {
788 	move_pen_by,
789 	determine_bounds_stroke_line,
790 	determine_bounds_draw_rect,
791 	determine_bounds_draw_round_rect,
792 	determine_bounds_draw_bezier,
793 	determine_bounds_draw_arc,
794 	determine_bounds_draw_ellipse,
795 	determine_bounds_draw_polygon,
796 	determine_bounds_draw_shape,
797 	determine_bounds_draw_string,
798 	determine_bounds_draw_pixels,
799 	draw_picture,
800 	set_clipping_rects,
801 	clip_to_picture,
802 	push_state,
803 	pop_state,
804 	enter_state_change,
805 	exit_state_change,
806 	enter_font_state,
807 	exit_font_state,
808 	set_origin,
809 	set_pen_location,
810 	set_drawing_mode,
811 	set_line_mode,
812 	set_pen_size,
813 	set_fore_color,
814 	set_back_color,
815 	set_stipple_pattern,
816 	set_scale,
817 	set_font_family,
818 	set_font_style,
819 	set_font_spacing,
820 	set_font_size,
821 	set_font_rotate,
822 	set_font_encoding,
823 	set_font_flags,
824 	set_font_shear,
825 	set_font_face,
826 	set_blending_mode,
827 	set_transform,
828 	translate_by,
829 	scale_by,
830 	rotate_by,
831 	determine_bounds_nested_layer
832 };
833 
834 
835 // #pragma mark - PictureBoundingBoxPlayer
836 
837 
838 /* static */ void
839 PictureBoundingBoxPlayer::Play(ServerPicture* picture,
840 	const DrawState* drawState, BRect* outBoundingBox)
841 {
842 	State state(drawState, outBoundingBox);
843 
844 	BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(picture->fData);
845 	if (mallocIO == NULL)
846 		return;
847 
848 	BPrivate::PicturePlayer player(mallocIO->Buffer(),
849 		mallocIO->BufferLength(), ServerPicture::PictureList::Private(
850 			picture->fPictures).AsBList());
851 	player.Play(kPictureBoundingBoxPlayerCallbacks,
852 		sizeof(kPictureBoundingBoxPlayerCallbacks), &state);
853 }
854