11b4dba92SJulian Harnath/*
21b4dba92SJulian Harnath * Copyright 2001-2015, Haiku.
31b4dba92SJulian Harnath * Distributed under the terms of the MIT License.
41b4dba92SJulian Harnath *
51b4dba92SJulian Harnath * Authors:
61b4dba92SJulian Harnath *		Marc Flerackers (mflerackers@androme.be)
71b4dba92SJulian Harnath *		Stefano Ceccherini (stefano.ceccherini@gmail.com)
81b4dba92SJulian Harnath *		Marcus Overhagen <marcus@overhagen.de>
91b4dba92SJulian Harnath *      Julian Harnath <julian.harnath@rwth-aachen.de>
101b4dba92SJulian Harnath */
111b4dba92SJulian Harnath
121b4dba92SJulian Harnath#include "PictureBoundingBoxPlayer.h"
131b4dba92SJulian Harnath
141b4dba92SJulian Harnath#include <new>
151b4dba92SJulian Harnath#include <stdio.h>
161b4dba92SJulian Harnath
171b4dba92SJulian Harnath#include "DrawState.h"
181b4dba92SJulian Harnath#include "FontManager.h"
19551438b9SJulian Harnath#include "Layer.h"
201b4dba92SJulian Harnath#include "ServerApp.h"
211b4dba92SJulian Harnath#include "ServerBitmap.h"
221b4dba92SJulian Harnath#include "ServerFont.h"
231b4dba92SJulian Harnath#include "ServerPicture.h"
241b4dba92SJulian Harnath#include "ServerTokenSpace.h"
251b4dba92SJulian Harnath#include "View.h"
261b4dba92SJulian Harnath#include "Window.h"
271b4dba92SJulian Harnath
281b4dba92SJulian Harnath#include <Bitmap.h>
291b4dba92SJulian Harnath#include <Debug.h>
301b4dba92SJulian Harnath#include <List.h>
311b4dba92SJulian Harnath#include <ObjectListPrivate.h>
321b4dba92SJulian Harnath#include <PicturePlayer.h>
331b4dba92SJulian Harnath#include <PictureProtocol.h>
341b4dba92SJulian Harnath#include <Shape.h>
351b4dba92SJulian Harnath
361b4dba92SJulian Harnath
371b4dba92SJulian Harnath//#define DEBUG_TRACE_BB
381b4dba92SJulian Harnath#ifdef DEBUG_TRACE_BB
391b4dba92SJulian Harnath#	define TRACE_BB(text, ...) debug_printf("PBBP: " text, ##__VA_ARGS__)
401b4dba92SJulian Harnath#else
411b4dba92SJulian Harnath#	define TRACE_BB(text, ...)
421b4dba92SJulian Harnath#endif
431b4dba92SJulian Harnath
441b4dba92SJulian Harnath
451b4dba92SJulian Harnathtypedef PictureBoundingBoxPlayer::State BoundingBoxState;
461b4dba92SJulian Harnath
471b4dba92SJulian Harnath
481b4dba92SJulian Harnath// #pragma mark - PictureBoundingBoxPlayer::State
491b4dba92SJulian Harnath
501b4dba92SJulian Harnath
511b4dba92SJulian Harnathclass PictureBoundingBoxPlayer::State {
521b4dba92SJulian Harnathpublic:
53bafd2b46SJulian Harnath	State(const DrawState* drawState, BRect* boundingBox)
541b4dba92SJulian Harnath		:
551b4dba92SJulian Harnath		fDrawState(drawState->Squash()),
561b4dba92SJulian Harnath		fBoundingBox(boundingBox)
571b4dba92SJulian Harnath	{
58bafd2b46SJulian Harnath		fBoundingBox->Set(INT_MAX, INT_MAX, INT_MIN, INT_MIN);
591b4dba92SJulian Harnath	}
601b4dba92SJulian Harnath
611b4dba92SJulian Harnath	~State()
621b4dba92SJulian Harnath	{
631b4dba92SJulian Harnath		delete fDrawState;
641b4dba92SJulian Harnath	}
651b4dba92SJulian Harnath
661b4dba92SJulian Harnath	DrawState* GetDrawState()
671b4dba92SJulian Harnath	{
681b4dba92SJulian Harnath		return fDrawState;
691b4dba92SJulian Harnath	}
701b4dba92SJulian Harnath
711b4dba92SJulian Harnath	void PushDrawState()
721b4dba92SJulian Harnath	{
731b4dba92SJulian Harnath		DrawState* nextState = fDrawState->PushState();
741b4dba92SJulian Harnath		if (nextState != NULL)
751b4dba92SJulian Harnath			fDrawState = nextState;
761b4dba92SJulian Harnath	}
771b4dba92SJulian Harnath
781b4dba92SJulian Harnath	void PopDrawState()
791b4dba92SJulian Harnath	{
801b4dba92SJulian Harnath		if (fDrawState->PreviousState() != NULL)
811b4dba92SJulian Harnath			fDrawState = fDrawState->PopState();
821b4dba92SJulian Harnath	}
831b4dba92SJulian Harnath
841b4dba92SJulian Harnath	SimpleTransform PenToLocalTransform() const
851b4dba92SJulian Harnath	{
861b4dba92SJulian Harnath		SimpleTransform transform;
871b4dba92SJulian Harnath		fDrawState->Transform(transform);
881b4dba92SJulian Harnath		return transform;
891b4dba92SJulian Harnath	}
901b4dba92SJulian Harnath
911b4dba92SJulian Harnath	void IncludeRect(BRect& rect)
921b4dba92SJulian Harnath	{
931b4dba92SJulian Harnath		_AffineTransformRect(rect);
941b4dba92SJulian Harnath		*fBoundingBox = (*fBoundingBox) | rect;
951b4dba92SJulian Harnath	}
961b4dba92SJulian Harnath
971b4dba92SJulian Harnathprivate:
981b4dba92SJulian Harnath	void _AffineTransformRect(BRect& rect)
991b4dba92SJulian Harnath	{
100bafd2b46SJulian Harnath		BAffineTransform transform = fDrawState->CombinedTransform();
1011b4dba92SJulian Harnath		if (transform.IsIdentity())
1021b4dba92SJulian Harnath			return;
1031b4dba92SJulian Harnath
1041b4dba92SJulian Harnath		BPoint transformedShape[4];
1051b4dba92SJulian Harnath		transformedShape[0] = rect.LeftTop();
1061b4dba92SJulian Harnath		transformedShape[1] = rect.LeftBottom();
1071b4dba92SJulian Harnath		transformedShape[2] = rect.RightTop();
1081b4dba92SJulian Harnath		transformedShape[3] = rect.RightBottom();
1091b4dba92SJulian Harnath
1101b4dba92SJulian Harnath		transform.Apply(&transformedShape[0], 4);
1111b4dba92SJulian Harnath
1121b4dba92SJulian Harnath		float minX = INT_MAX;
1131b4dba92SJulian Harnath		float minY = INT_MAX;
114bafd2b46SJulian Harnath		float maxX = INT_MIN;
115bafd2b46SJulian Harnath		float maxY = INT_MIN;
1161b4dba92SJulian Harnath
1171b4dba92SJulian Harnath		for (uint32 i = 0; i < 4; i++) {
1181b4dba92SJulian Harnath			if (transformedShape[i].x < minX)
1191b4dba92SJulian Harnath				minX = transformedShape[i].x;
1201b4dba92SJulian Harnath			else if (transformedShape[i].x > maxX)
1211b4dba92SJulian Harnath				maxX = transformedShape[i].x;
1221b4dba92SJulian Harnath			if (transformedShape[i].y < minY)
1231b4dba92SJulian Harnath				minY = transformedShape[i].y;
1241b4dba92SJulian Harnath			else if (transformedShape[i].y > maxY)
1251b4dba92SJulian Harnath				maxY = transformedShape[i].y;
1261b4dba92SJulian Harnath		}
1271b4dba92SJulian Harnath
1281b4dba92SJulian Harnath		rect.Set(minX, minY, maxX, maxY);
1291b4dba92SJulian Harnath	}
1301b4dba92SJulian Harnath
1311b4dba92SJulian Harnath
1321b4dba92SJulian Harnathprivate:
1331b4dba92SJulian Harnath	DrawState*	fDrawState;
1341b4dba92SJulian Harnath	BRect*		fBoundingBox;
1351b4dba92SJulian Harnath};
1361b4dba92SJulian Harnath
1371b4dba92SJulian Harnath
1381b4dba92SJulian Harnath// #pragma mark - Picture playback hooks
1391b4dba92SJulian Harnath
1401b4dba92SJulian Harnath
1411b4dba92SJulian Harnathstatic void
1421b4dba92SJulian Harnathget_polygon_frame(const BPoint* points, int32 numPoints, BRect* frame)
1431b4dba92SJulian Harnath{
1441b4dba92SJulian Harnath	ASSERT(numPoints > 0);
1451b4dba92SJulian Harnath
1461b4dba92SJulian Harnath	float left = points->x;
1471b4dba92SJulian Harnath	float top = points->y;
1481b4dba92SJulian Harnath	float right = left;
1491b4dba92SJulian Harnath	float bottom = top;
1501b4dba92SJulian Harnath
1511b4dba92SJulian Harnath	points++;
1521b4dba92SJulian Harnath	numPoints--;
1531b4dba92SJulian Harnath
1541b4dba92SJulian Harnath	while (numPoints--) {
1551b4dba92SJulian Harnath		if (points->x < left)
1561b4dba92SJulian Harnath			left = points->x;
1571b4dba92SJulian Harnath		if (points->x > right)
1581b4dba92SJulian Harnath			right = points->x;
1591b4dba92SJulian Harnath		if (points->y < top)
1601b4dba92SJulian Harnath			top = points->y;
1611b4dba92SJulian Harnath		if (points->y > bottom)
1621b4dba92SJulian Harnath			bottom = points->y;
1631b4dba92SJulian Harnath		points++;
1641b4dba92SJulian Harnath	}
1651b4dba92SJulian Harnath
1661b4dba92SJulian Harnath	frame->Set(left, top, right, bottom);
1671b4dba92SJulian Harnath}
1681b4dba92SJulian Harnath
1691b4dba92SJulian Harnath
1701b4dba92SJulian Harnathtemplate<class RectType>
1711b4dba92SJulian Harnathstatic void
1721b4dba92SJulian Harnathexpand_rect_for_pen_size(BoundingBoxState* state, RectType& rect)
1731b4dba92SJulian Harnath{
1741b4dba92SJulian Harnath	float penInset = -((state->GetDrawState()->PenSize() / 2.0f) + 1.0f);
1751b4dba92SJulian Harnath	rect.InsetBy(penInset, penInset);
1761b4dba92SJulian Harnath}
1771b4dba92SJulian Harnath
1781b4dba92SJulian Harnath
1791b4dba92SJulian Harnathstatic void
1806109a208SJulian Harnathmove_pen_by(void* _state, const BPoint& delta)
1811b4dba92SJulian Harnath{
1826109a208SJulian Harnath	TRACE_BB("%p move pen by %.2f %.2f\n", _state, delta.x, delta.y);
1836109a208SJulian Harnath	BoundingBoxState* const state =
1846109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
1851b4dba92SJulian Harnath
1861b4dba92SJulian Harnath	state->GetDrawState()->SetPenLocation(
1871b4dba92SJulian Harnath		state->GetDrawState()->PenLocation() + delta);
1881b4dba92SJulian Harnath}
1891b4dba92SJulian Harnath
1901b4dba92SJulian Harnath
1911b4dba92SJulian Harnathstatic void
1926109a208SJulian Harnathdetermine_bounds_stroke_line(void* _state, const BPoint& _start,
1936109a208SJulian Harnath	const BPoint& _end)
1941b4dba92SJulian Harnath{
1956109a208SJulian Harnath	TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", _state,
1966109a208SJulian Harnath		_start.x, _start.y, _end.x, _end.y);
1976109a208SJulian Harnath	BoundingBoxState* const state =
1986109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
1991b4dba92SJulian Harnath
2006109a208SJulian Harnath	BPoint start = _start;
2016109a208SJulian Harnath	BPoint end = _end;
2021b4dba92SJulian Harnath
2031b4dba92SJulian Harnath	const SimpleTransform transform = state->PenToLocalTransform();
2041b4dba92SJulian Harnath	transform.Apply(&start);
2051b4dba92SJulian Harnath	transform.Apply(&end);
2061b4dba92SJulian Harnath
2071b4dba92SJulian Harnath	BRect rect;
2081b4dba92SJulian Harnath	if (start.x <= end.x) {
2091b4dba92SJulian Harnath		rect.left = start.x;
2101b4dba92SJulian Harnath		rect.right = end.x;
2111b4dba92SJulian Harnath	} else {
2121b4dba92SJulian Harnath		rect.left = end.x;
2131b4dba92SJulian Harnath		rect.right = start.x;
2141b4dba92SJulian Harnath	}
2151b4dba92SJulian Harnath	if (start.y <= end.y) {
2161b4dba92SJulian Harnath		rect.top = start.y;
2171b4dba92SJulian Harnath		rect.bottom = end.y;
2181b4dba92SJulian Harnath	} else {
2191b4dba92SJulian Harnath		rect.top = end.y;
2201b4dba92SJulian Harnath		rect.bottom = start.y;
2211b4dba92SJulian Harnath	}
2221b4dba92SJulian Harnath
2231b4dba92SJulian Harnath	expand_rect_for_pen_size(state, rect);
2241b4dba92SJulian Harnath	state->IncludeRect(rect);
2251b4dba92SJulian Harnath
2266109a208SJulian Harnath	state->GetDrawState()->SetPenLocation(_end);
2271b4dba92SJulian Harnath}
2281b4dba92SJulian Harnath
2291b4dba92SJulian Harnath
2301b4dba92SJulian Harnathstatic void
2316109a208SJulian Harnathdetermine_bounds_draw_rect(void* _state, const BRect& _rect, bool fill)
2321b4dba92SJulian Harnath{
2336109a208SJulian Harnath	TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", _state, fill,
2346109a208SJulian Harnath		_rect.left, _rect.top, _rect.right, _rect.bottom);
2356109a208SJulian Harnath	BoundingBoxState* const state =
2366109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
2371b4dba92SJulian Harnath
2386109a208SJulian Harnath	BRect rect = _rect;
2391b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&rect);
2406109a208SJulian Harnath	if (!fill)
2416109a208SJulian Harnath		expand_rect_for_pen_size(state, rect);
2421b4dba92SJulian Harnath	state->IncludeRect(rect);
2431b4dba92SJulian Harnath}
2441b4dba92SJulian Harnath
2451b4dba92SJulian Harnath
2461b4dba92SJulian Harnathstatic void
2476109a208SJulian Harnathdetermine_bounds_draw_round_rect(void* _state, const BRect& _rect,
2486109a208SJulian Harnath	const BPoint&, bool fill)
2491b4dba92SJulian Harnath{
2506109a208SJulian Harnath	determine_bounds_draw_rect(_state, _rect, fill);
2511b4dba92SJulian Harnath}
2521b4dba92SJulian Harnath
2531b4dba92SJulian Harnath
2541b4dba92SJulian Harnathstatic void
2551b4dba92SJulian Harnathdetermine_bounds_bezier(BoundingBoxState* state, const BPoint* viewPoints,
2561b4dba92SJulian Harnath	BRect& outRect)
2571b4dba92SJulian Harnath{
2581b4dba92SJulian Harnath	// Note: this is an approximation which results in a rectangle which
2591b4dba92SJulian Harnath	// encloses all four control points. That will always enclose the curve,
2601b4dba92SJulian Harnath	// although not necessarily tightly, but it's good enough for the purpose.
2611b4dba92SJulian Harnath	// The exact bounding box of a bezier curve is not trivial to determine,
2621b4dba92SJulian Harnath	// (need to calculate derivative of the curve) and we're going for
2631b4dba92SJulian Harnath	// performance here.
2641b4dba92SJulian Harnath	BPoint points[4];
2651b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(points, viewPoints, 4);
2661b4dba92SJulian Harnath	BPoint topLeft = points[0];
2671b4dba92SJulian Harnath	BPoint bottomRight = points[0];
2681b4dba92SJulian Harnath	for (uint32 index = 1; index < 4; index++) {
2691b4dba92SJulian Harnath		if (points[index].x < topLeft.x || points[index].y < topLeft.y)
2701b4dba92SJulian Harnath			topLeft = points[index];
2711b4dba92SJulian Harnath		if (points[index].x > topLeft.x || points[index].y > topLeft.y)
2721b4dba92SJulian Harnath			bottomRight = points[index];
2731b4dba92SJulian Harnath	}
2741b4dba92SJulian Harnath	outRect.SetLeftTop(topLeft);
2751b4dba92SJulian Harnath	outRect.SetRightBottom(bottomRight);
2761b4dba92SJulian Harnath}
2771b4dba92SJulian Harnath
2781b4dba92SJulian Harnath
2791b4dba92SJulian Harnathstatic void
2806109a208SJulian Harnathdetermine_bounds_draw_bezier(void* _state, size_t numPoints,
2816109a208SJulian Harnath	const BPoint viewPoints[], bool fill)
2821b4dba92SJulian Harnath{
2836109a208SJulian Harnath	TRACE_BB("%p draw bezier fill=%d (%.2f %.2f) (%.2f %.2f) "
2846109a208SJulian Harnath		"(%.2f %.2f) (%.2f %.2f)\n",
2856109a208SJulian Harnath		_state,
2866109a208SJulian Harnath		fill,
2871b4dba92SJulian Harnath		viewPoints[0].x, viewPoints[0].y,
2881b4dba92SJulian Harnath		viewPoints[1].x, viewPoints[1].y,
2891b4dba92SJulian Harnath		viewPoints[2].x, viewPoints[2].y,
2901b4dba92SJulian Harnath		viewPoints[3].x, viewPoints[3].y);
2916109a208SJulian Harnath	BoundingBoxState* const state =
2926109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
2931b4dba92SJulian Harnath
2946109a208SJulian Harnath	const size_t kSupportedPoints = 4;
2956109a208SJulian Harnath	if (numPoints != kSupportedPoints)
2966109a208SJulian Harnath		return;
2971b4dba92SJulian Harnath
2981b4dba92SJulian Harnath	BRect rect;
2991b4dba92SJulian Harnath	determine_bounds_bezier(state, viewPoints, rect);
3006109a208SJulian Harnath	if (!fill)
3016109a208SJulian Harnath		expand_rect_for_pen_size(state, rect);
3021b4dba92SJulian Harnath	state->IncludeRect(rect);
3031b4dba92SJulian Harnath}
3041b4dba92SJulian Harnath
3051b4dba92SJulian Harnath
3061b4dba92SJulian Harnathstatic void
3076109a208SJulian Harnathdetermine_bounds_draw_ellipse(void* _state, const BRect& _rect, bool fill)
3081b4dba92SJulian Harnath{
3096109a208SJulian Harnath	TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", _state, fill,
3106109a208SJulian Harnath		_rect.left, _rect.top, _rect.right, _rect.bottom);
3116109a208SJulian Harnath	BoundingBoxState* const state =
3126109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
3131b4dba92SJulian Harnath
3146109a208SJulian Harnath	BRect rect = _rect;
3151b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&rect);
3166109a208SJulian Harnath	if (!fill)
3176109a208SJulian Harnath		expand_rect_for_pen_size(state, rect);
3181b4dba92SJulian Harnath	state->IncludeRect(rect);
3191b4dba92SJulian Harnath}
3201b4dba92SJulian Harnath
3211b4dba92SJulian Harnath
3221b4dba92SJulian Harnathstatic void
3236109a208SJulian Harnathdetermine_bounds_draw_arc(void* _state, const BPoint& center,
3246109a208SJulian Harnath	const BPoint& radii, float, float, bool fill)
3251b4dba92SJulian Harnath{
3261b4dba92SJulian Harnath	BRect rect(center.x - radii.x, center.y - radii.y,
3271b4dba92SJulian Harnath		center.x + radii.x - 1, center.y + radii.y - 1);
3286109a208SJulian Harnath	determine_bounds_draw_ellipse(_state, rect, fill);
3291b4dba92SJulian Harnath}
3301b4dba92SJulian Harnath
3311b4dba92SJulian Harnath
3321b4dba92SJulian Harnathstatic void
3331b4dba92SJulian Harnathdetermine_bounds_polygon(BoundingBoxState* state, int32 numPoints,
3341b4dba92SJulian Harnath	const BPoint* viewPoints, BRect& outRect)
3351b4dba92SJulian Harnath{
3361b4dba92SJulian Harnath	if (numPoints <= 0)
3371b4dba92SJulian Harnath		return;
3381b4dba92SJulian Harnath
3391b4dba92SJulian Harnath	if (numPoints <= 200) {
3401b4dba92SJulian Harnath		// fast path: no malloc/free, also avoid
3411b4dba92SJulian Harnath		// constructor/destructor calls
3421b4dba92SJulian Harnath		char data[200 * sizeof(BPoint)];
3431b4dba92SJulian Harnath		BPoint* points = (BPoint*)data;
3441b4dba92SJulian Harnath
3451b4dba92SJulian Harnath		state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
3461b4dba92SJulian Harnath		get_polygon_frame(points, numPoints, &outRect);
3471b4dba92SJulian Harnath
3481b4dba92SJulian Harnath	} else {
3491b4dba92SJulian Harnath		 // avoid constructor/destructor calls by
3501b4dba92SJulian Harnath		 // using malloc instead of new []
3511b4dba92SJulian Harnath		BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint));
3521b4dba92SJulian Harnath		if (points == NULL)
3531b4dba92SJulian Harnath			return;
3541b4dba92SJulian Harnath
3551b4dba92SJulian Harnath		state->PenToLocalTransform().Apply(points, viewPoints, numPoints);
3561b4dba92SJulian Harnath		get_polygon_frame(points, numPoints, &outRect);
3571b4dba92SJulian Harnath
3581b4dba92SJulian Harnath		free(points);
3591b4dba92SJulian Harnath	}
3601b4dba92SJulian Harnath}
3611b4dba92SJulian Harnath
3621b4dba92SJulian Harnath
3631b4dba92SJulian Harnathvoid
3646109a208SJulian Harnathdetermine_bounds_draw_polygon(void* _state, size_t numPoints,
3656109a208SJulian Harnath	const BPoint viewPoints[], bool, bool fill)
3661b4dba92SJulian Harnath{
3676109a208SJulian Harnath	TRACE_BB("%p draw polygon fill=%d (%ld points)\n", _state, fill, numPoints);
3686109a208SJulian Harnath	BoundingBoxState* const state =
3696109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
3701b4dba92SJulian Harnath
3711b4dba92SJulian Harnath	BRect rect;
3721b4dba92SJulian Harnath	determine_bounds_polygon(state, numPoints, viewPoints, rect);
3736109a208SJulian Harnath	if (!fill)
3746109a208SJulian Harnath		expand_rect_for_pen_size(state, rect);
3751b4dba92SJulian Harnath	state->IncludeRect(rect);
3761b4dba92SJulian Harnath}
3771b4dba92SJulian Harnath
3781b4dba92SJulian Harnath
3791b4dba92SJulian Harnathstatic void
3806109a208SJulian Harnathdetermine_bounds_draw_shape(void* _state, const BShape& shape, bool fill)
3811b4dba92SJulian Harnath{
3826109a208SJulian Harnath	BRect rect = shape.Bounds();
3831b4dba92SJulian Harnath
3846109a208SJulian Harnath	TRACE_BB("%p stroke shape (bounds %.2f %.2f %.2f %.2f)\n", _state,
3851b4dba92SJulian Harnath		rect.left, rect.top, rect.right, rect.bottom);
3866109a208SJulian Harnath	BoundingBoxState* const state =
3876109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
3881b4dba92SJulian Harnath
3891b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&rect);
3906109a208SJulian Harnath	if (!fill)
3916109a208SJulian Harnath		expand_rect_for_pen_size(state, rect);
3921b4dba92SJulian Harnath	state->IncludeRect(rect);
3931b4dba92SJulian Harnath}
3941b4dba92SJulian Harnath
3951b4dba92SJulian Harnath
3961b4dba92SJulian Harnathstatic void
39722ce5525SMichael Lotzdetermine_bounds_draw_string(void* _state, const char* string, size_t length,
3986109a208SJulian Harnath	float deltaSpace, float deltaNonSpace)
3991b4dba92SJulian Harnath{
4006109a208SJulian Harnath	TRACE_BB("%p string '%s'\n", _state, string);
4016109a208SJulian Harnath	BoundingBoxState* const state =
4026109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
4031b4dba92SJulian Harnath
4041b4dba92SJulian Harnath	ServerFont font = state->GetDrawState()->Font();
4051b4dba92SJulian Harnath
4061b4dba92SJulian Harnath	escapement_delta delta = { deltaSpace, deltaNonSpace };
4071b4dba92SJulian Harnath	BRect rect;
4081b4dba92SJulian Harnath	font.GetBoundingBoxesForStrings((char**)&string, &length, 1, &rect,
4091b4dba92SJulian Harnath		B_SCREEN_METRIC, &delta);
4101b4dba92SJulian Harnath
4111b4dba92SJulian Harnath	BPoint location = state->GetDrawState()->PenLocation();
4121b4dba92SJulian Harnath
4131b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&location);
4141b4dba92SJulian Harnath	rect.OffsetBy(location);
4151b4dba92SJulian Harnath	state->IncludeRect(rect);
4161b4dba92SJulian Harnath
4171b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&location);
4181b4dba92SJulian Harnath	state->GetDrawState()->SetPenLocation(location);
4191b4dba92SJulian Harnath}
4201b4dba92SJulian Harnath
4211b4dba92SJulian Harnath
4221b4dba92SJulian Harnathstatic void
4236109a208SJulian Harnathdetermine_bounds_draw_pixels(void* _state, const BRect&, const BRect& _dest,
4246109a208SJulian Harnath	uint32, uint32, size_t, color_space, uint32, const void*, size_t)
4251b4dba92SJulian Harnath{
4266109a208SJulian Harnath	TRACE_BB("%p pixels (dest %.2f %.2f %.2f %.2f)\n", _state,
4276109a208SJulian Harnath		_dest.left, _dest.top, _dest.right, _dest.bottom);
4286109a208SJulian Harnath	BoundingBoxState* const state =
4296109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
4301b4dba92SJulian Harnath
4316109a208SJulian Harnath	BRect dest = _dest;
4321b4dba92SJulian Harnath	state->PenToLocalTransform().Apply(&dest);
4331b4dba92SJulian Harnath	state->IncludeRect(dest);
4341b4dba92SJulian Harnath}
4351b4dba92SJulian Harnath
4361b4dba92SJulian Harnath
4371b4dba92SJulian Harnathstatic void
4386109a208SJulian Harnathdraw_picture(void* _state, const BPoint& where, int32 token)
4391b4dba92SJulian Harnath{
4406109a208SJulian Harnath	TRACE_BB("%p picture (unimplemented)\n", _state);
4411b4dba92SJulian Harnath
4421b4dba92SJulian Harnath	// TODO
4436109a208SJulian Harnath	(void)_state;
4441b4dba92SJulian Harnath	(void)where;
4451b4dba92SJulian Harnath	(void)token;
4461b4dba92SJulian Harnath}
4471b4dba92SJulian Harnath
4481b4dba92SJulian Harnath
4491b4dba92SJulian Harnathstatic void
4506109a208SJulian Harnathset_clipping_rects(void* _state, size_t numRects, const BRect rects[])
4511b4dba92SJulian Harnath{
4526109a208SJulian Harnath	TRACE_BB("%p cliping rects (%ld rects)\n", _state, numRects);
4531b4dba92SJulian Harnath
4541b4dba92SJulian Harnath	// TODO
4556109a208SJulian Harnath	(void)_state;
4561b4dba92SJulian Harnath	(void)rects;
4571b4dba92SJulian Harnath	(void)numRects;
4581b4dba92SJulian Harnath}
4591b4dba92SJulian Harnath
4601b4dba92SJulian Harnath
4611b4dba92SJulian Harnathstatic void
4626109a208SJulian Harnathclip_to_picture(void* _state, int32 pictureToken, const BPoint& where,
4631b4dba92SJulian Harnath	bool clipToInverse)
4641b4dba92SJulian Harnath{
4656109a208SJulian Harnath	TRACE_BB("%p clip to picture (unimplemented)\n", _state);
4661b4dba92SJulian Harnath
4671b4dba92SJulian Harnath	// TODO
4681b4dba92SJulian Harnath}
4691b4dba92SJulian Harnath
4701b4dba92SJulian Harnath
4711b4dba92SJulian Harnathstatic void
4726109a208SJulian Harnathpush_state(void* _state)
4731b4dba92SJulian Harnath{
4746109a208SJulian Harnath	TRACE_BB("%p push state\n", _state);
4756109a208SJulian Harnath	BoundingBoxState* const state =
4766109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
4776109a208SJulian Harnath
4781b4dba92SJulian Harnath	state->PushDrawState();
4791b4dba92SJulian Harnath}
4801b4dba92SJulian Harnath
4811b4dba92SJulian Harnath
4821b4dba92SJulian Harnathstatic void
4836109a208SJulian Harnathpop_state(void* _state)
4841b4dba92SJulian Harnath{
4856109a208SJulian Harnath	TRACE_BB("%p pop state\n", _state);
4866109a208SJulian Harnath	BoundingBoxState* const state =
4876109a208SJulian Harnath		reinterpret_cast<BoundingBoxState*>(_state);
4886109a208SJulian Harnath
4891b4dba92SJulian Harnath	state->PopDrawState();
4901b4dba92SJulian Harnath}
4911b4dba92SJulian Harnath
4921b4dba92SJulian Harnath
4931b4dba92SJulian Harnathstatic void
494