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