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:
State(const DrawState * drawState,BRect * boundingBox)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
~State()62 ~State()
63 {
64 }
65
GetDrawState()66 DrawState* GetDrawState()
67 {
68 return fDrawState.Get();
69 }
70
PushDrawState()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
PopDrawState()81 void PopDrawState()
82 {
83 if (fDrawState->PreviousState() != NULL)
84 fDrawState.SetTo(fDrawState->PopState());
85 }
86
PenToLocalTransform() const87 SimpleTransform PenToLocalTransform() const
88 {
89 SimpleTransform transform;
90 fDrawState->Transform(transform);
91 return transform;
92 }
93
IncludeRect(BRect & rect)94 void IncludeRect(BRect& rect)
95 {
96 _AffineTransformRect(rect);
97 *fBoundingBox = (*fBoundingBox) | rect;
98 }
99
100 private:
_AffineTransformRect(BRect & rect)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
get_polygon_frame(const BPoint * points,int32 numPoints,BRect * frame)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
expand_rect_for_pen_size(BoundingBoxState * state,RectType & rect)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
move_pen_by(void * _state,const BPoint & delta)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
determine_bounds_stroke_line(void * _state,const BPoint & _start,const BPoint & _end)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
determine_bounds_draw_rect(void * _state,const BRect & _rect,bool fill)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
determine_bounds_draw_round_rect(void * _state,const BRect & _rect,const BPoint &,bool fill)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
determine_bounds_bezier(BoundingBoxState * state,const BPoint * viewPoints,BRect & outRect)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
determine_bounds_draw_bezier(void * _state,size_t numPoints,const BPoint viewPoints[],bool fill)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
determine_bounds_draw_ellipse(void * _state,const BRect & _rect,bool fill)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
determine_bounds_draw_arc(void * _state,const BPoint & center,const BPoint & radii,float,float,bool fill)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
determine_bounds_polygon(BoundingBoxState * state,int32 numPoints,const BPoint * viewPoints,BRect & outRect)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
determine_bounds_draw_polygon(void * _state,size_t numPoints,const BPoint viewPoints[],bool,bool fill)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
determine_bounds_draw_shape(void * _state,const BShape & shape,bool fill)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
determine_bounds_draw_string(void * _state,const char * string,size_t length,float deltaSpace,float deltaNonSpace)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
determine_bounds_draw_pixels(void * _state,const BRect &,const BRect & _dest,uint32,uint32,size_t,color_space,uint32,const void *,size_t)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
draw_picture(void * _state,const BPoint & where,int32 token)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
set_clipping_rects(void * _state,size_t numRects,const BRect rects[])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
clip_to_picture(void * _state,int32 pictureToken,const BPoint & where,bool clipToInverse)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
push_state(void * _state)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
pop_state(void * _state)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
enter_state_change(void *)498 enter_state_change(void*)
499 {
500 }
501
502
503 static void
exit_state_change(void *)504 exit_state_change(void*)
505 {
506 }
507
508
509 static void
enter_font_state(void *)510 enter_font_state(void*)
511 {
512 }
513
514
515 static void
exit_font_state(void *)516 exit_font_state(void*)
517 {
518 }
519
520
521 static void
set_origin(void * _state,const BPoint & pt)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
set_pen_location(void * _state,const BPoint & pt)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
set_drawing_mode(void *,drawing_mode)542 set_drawing_mode(void*, drawing_mode)
543 {
544 }
545
546
547 static void
set_line_mode(void * _state,cap_mode capMode,join_mode joinMode,float miterLimit)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
set_pen_size(void * _state,float size)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
set_fore_color(void * _state,const rgb_color & color)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
set_back_color(void * _state,const rgb_color & color)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
set_stipple_pattern(void * _state,const pattern & _pattern)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
set_scale(void * _state,float scale)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
set_font_family(void * _state,const char * _family,size_t length)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 gFontManager->Lock();
620 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
621 ServerFont font;
622 font.SetStyle(fontStyle);
623 gFontManager->Unlock();
624 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
625 }
626
627
628 static void
set_font_style(void * _state,const char * _style,size_t length)629 set_font_style(void* _state, const char* _style, size_t length)
630 {
631 BoundingBoxState* const state =
632 reinterpret_cast<BoundingBoxState*>(_state);
633
634 BString style(_style, length);
635 ServerFont font(state->GetDrawState()->Font());
636 gFontManager->Lock();
637 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
638 font.SetStyle(fontStyle);
639 gFontManager->Unlock();
640 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
641 }
642
643
644 static void
set_font_spacing(void * _state,uint8 spacing)645 set_font_spacing(void* _state, uint8 spacing)
646 {
647 BoundingBoxState* const state =
648 reinterpret_cast<BoundingBoxState*>(_state);
649
650 ServerFont font;
651 font.SetSpacing(spacing);
652 state->GetDrawState()->SetFont(font, B_FONT_SPACING);
653 }
654
655
656 static void
set_font_size(void * _state,float size)657 set_font_size(void* _state, float size)
658 {
659 BoundingBoxState* const state =
660 reinterpret_cast<BoundingBoxState*>(_state);
661
662 ServerFont font;
663 font.SetSize(size);
664 state->GetDrawState()->SetFont(font, B_FONT_SIZE);
665 }
666
667
668 static void
set_font_rotate(void * _state,float rotation)669 set_font_rotate(void* _state, float rotation)
670 {
671 BoundingBoxState* const state =
672 reinterpret_cast<BoundingBoxState*>(_state);
673
674 ServerFont font;
675 font.SetRotation(rotation);
676 state->GetDrawState()->SetFont(font, B_FONT_ROTATION);
677 }
678
679
680 static void
set_font_encoding(void * _state,uint8 encoding)681 set_font_encoding(void* _state, uint8 encoding)
682 {
683 BoundingBoxState* const state =
684 reinterpret_cast<BoundingBoxState*>(_state);
685
686 ServerFont font;
687 font.SetEncoding(encoding);
688 state->GetDrawState()->SetFont(font, B_FONT_ENCODING);
689 }
690
691
692 static void
set_font_flags(void * _state,uint32 flags)693 set_font_flags(void* _state, uint32 flags)
694 {
695 BoundingBoxState* const state =
696 reinterpret_cast<BoundingBoxState*>(_state);
697
698 ServerFont font;
699 font.SetFlags(flags);
700 state->GetDrawState()->SetFont(font, B_FONT_FLAGS);
701 }
702
703
704 static void
set_font_shear(void * _state,float shear)705 set_font_shear(void* _state, float shear)
706 {
707 BoundingBoxState* const state =
708 reinterpret_cast<BoundingBoxState*>(_state);
709
710 ServerFont font;
711 font.SetShear(shear);
712 state->GetDrawState()->SetFont(font, B_FONT_SHEAR);
713 }
714
715
716 static void
set_font_face(void * _state,uint16 face)717 set_font_face(void* _state, uint16 face)
718 {
719 BoundingBoxState* const state =
720 reinterpret_cast<BoundingBoxState*>(_state);
721
722 ServerFont font;
723 font.SetFace(face);
724 state->GetDrawState()->SetFont(font, B_FONT_FACE);
725 }
726
727
728 static void
set_blending_mode(void *,source_alpha,alpha_function)729 set_blending_mode(void*, source_alpha, alpha_function)
730 {
731 }
732
733
734 static void
set_transform(void * _state,const BAffineTransform & transform)735 set_transform(void* _state, const BAffineTransform& transform)
736 {
737 TRACE_BB("%p transform\n", _state);
738 BoundingBoxState* const state =
739 reinterpret_cast<BoundingBoxState*>(_state);
740 state->GetDrawState()->SetTransform(transform);
741 }
742
743
744 static void
translate_by(void * _state,double x,double y)745 translate_by(void* _state, double x, double y)
746 {
747 TRACE_BB("%p translate\n", _state);
748 BoundingBoxState* const state =
749 reinterpret_cast<BoundingBoxState*>(_state);
750 BAffineTransform transform = state->GetDrawState()->Transform();
751 transform.PreTranslateBy(x, y);
752 state->GetDrawState()->SetTransform(transform);
753 }
754
755
756 static void
scale_by(void * _state,double x,double y)757 scale_by(void* _state, double x, double y)
758 {
759 TRACE_BB("%p scale\n", _state);
760 BoundingBoxState* const state =
761 reinterpret_cast<BoundingBoxState*>(_state);
762 BAffineTransform transform = state->GetDrawState()->Transform();
763 transform.PreScaleBy(x, y);
764 state->GetDrawState()->SetTransform(transform);
765 }
766
767
768 static void
rotate_by(void * _state,double angleRadians)769 rotate_by(void* _state, double angleRadians)
770 {
771 TRACE_BB("%p rotate\n", _state);
772 BoundingBoxState* const state =
773 reinterpret_cast<BoundingBoxState*>(_state);
774 BAffineTransform transform = state->GetDrawState()->Transform();
775 transform.PreRotateBy(angleRadians);
776 state->GetDrawState()->SetTransform(transform);
777 }
778
779
780 static void
determine_bounds_nested_layer(void * _state,Layer * layer)781 determine_bounds_nested_layer(void* _state, Layer* layer)
782 {
783 TRACE_BB("%p nested layer\n", _state);
784 BoundingBoxState* const state =
785 reinterpret_cast<BoundingBoxState*>(_state);
786
787 BRect boundingBox;
788 PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox);
789 if (boundingBox.IsValid())
790 state->IncludeRect(boundingBox);
791 }
792
793
794 static const BPrivate::picture_player_callbacks
795 kPictureBoundingBoxPlayerCallbacks = {
796 move_pen_by,
797 determine_bounds_stroke_line,
798 determine_bounds_draw_rect,
799 determine_bounds_draw_round_rect,
800 determine_bounds_draw_bezier,
801 determine_bounds_draw_arc,
802 determine_bounds_draw_ellipse,
803 determine_bounds_draw_polygon,
804 determine_bounds_draw_shape,
805 determine_bounds_draw_string,
806 determine_bounds_draw_pixels,
807 draw_picture,
808 set_clipping_rects,
809 clip_to_picture,
810 push_state,
811 pop_state,
812 enter_state_change,
813 exit_state_change,
814 enter_font_state,
815 exit_font_state,
816 set_origin,
817 set_pen_location,
818 set_drawing_mode,
819 set_line_mode,
820 set_pen_size,
821 set_fore_color,
822 set_back_color,
823 set_stipple_pattern,
824 set_scale,
825 set_font_family,
826 set_font_style,
827 set_font_spacing,
828 set_font_size,
829 set_font_rotate,
830 set_font_encoding,
831 set_font_flags,
832 set_font_shear,
833 set_font_face,
834 set_blending_mode,
835 set_transform,
836 translate_by,
837 scale_by,
838 rotate_by,
839 determine_bounds_nested_layer
840 };
841
842
843 // #pragma mark - PictureBoundingBoxPlayer
844
845
846 /* static */ void
Play(ServerPicture * picture,const DrawState * drawState,BRect * outBoundingBox)847 PictureBoundingBoxPlayer::Play(ServerPicture* picture,
848 const DrawState* drawState, BRect* outBoundingBox)
849 {
850 State state(drawState, outBoundingBox);
851
852 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(picture->fData.Get());
853 if (mallocIO == NULL)
854 return;
855
856 BPrivate::PicturePlayer player(mallocIO->Buffer(),
857 mallocIO->BufferLength(), ServerPicture::PictureList::Private(
858 picture->fPictures.Get()).AsBList());
859 player.Play(kPictureBoundingBoxPlayerCallbacks,
860 sizeof(kPictureBoundingBoxPlayerCallbacks), &state);
861 }
862