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 46typedef PictureBoundingBoxPlayer::State BoundingBoxState; 47 48 49// #pragma mark - PictureBoundingBoxPlayer::State 50 51 52class PictureBoundingBoxPlayer::State { 53public: 54 State(const DrawState* drawState, BRect* boundingBox) 55 : 56 fDrawState(drawState->Squash()), 57 fBoundingBox(boundingBox) 58 { 59 fBoundingBox->Set(INT_MAX, INT_MAX, INT_MIN, INT_MIN); 60 } 61 62 ~State() 63 { 64 } 65 66 DrawState* GetDrawState() 67 { 68 return fDrawState.Get(); 69 } 70 71 void PushDrawState() 72 { 73 DrawState* previousState = fDrawState.Detach(); 74 DrawState* newState = previousState->PushState(); 75 if (newState == NULL) 76 newState = previousState; 77 78 fDrawState.SetTo(newState); 79 } 80 81 void PopDrawState() 82 { 83 if (fDrawState->PreviousState() != NULL) 84 fDrawState.SetTo(fDrawState->PopState()); 85 } 86 87 SimpleTransform PenToLocalTransform() const 88 { 89 SimpleTransform transform; 90 fDrawState->Transform(transform); 91 return transform; 92 } 93 94 void IncludeRect(BRect& rect) 95 { 96 _AffineTransformRect(rect); 97 *fBoundingBox = (*fBoundingBox) | rect; 98 } 99 100private: 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 135private: 136 ObjectDeleter<DrawState> 137 fDrawState; 138 BRect* fBoundingBox; 139}; 140 141 142// #pragma mark - Picture playback hooks 143 144 145static void 146get_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 174template<class RectType> 175static void 176expand_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 183static void 184move_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 195static void 196determine_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 234static void 235determine_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 250static void 251determine_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 258static void 259determine_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 283static void 284determine_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 310static void 311determine_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 326static void 327determine_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 336static void 337determine_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 367void 368determine_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 383static void 384determine_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 400static void 401determine_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 426static void 427determine_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 441static void 442draw_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 453static void 454set_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 465static void 466clip_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 475static void 476push_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 486static void 487pop_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 497static void 498enter_state_change(void*) 499{ 500} 501 502 503static void 504exit_state_change(void*) 505{ 506} 507 508 509static void 510enter_font_state(void*) 511{ 512} 513 514 515static void 516exit_font_state(void*) 517{ 518} 519 520 521static void 522set_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 531static void 532set_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 541static void 542set_drawing_mode(void*, drawing_mode) 543{ 544} 545 546 547static void 548set_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 561static void 562set_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 572static void 573set_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 582static void 583set_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 592static void 593set_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 602static void 603set_scale(void* _state, float scale) 604{ 605 BoundingBoxState* const state = 606 reinterpret_cast<BoundingBoxState*>(_state); 607 608 state->GetDrawState()->SetScale(scale); 609} 610 611 612static void 613set_font_family(void* _state, const char* _family, size_t length) 614{ 615 BoundingBoxState* const state = 616 reinterpret_cast<BoundingBoxState*>(_state); 617 618 BString family(_family, length); 619 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); 620 ServerFont font; 621 font.SetStyle(fontStyle); 622 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 623} 624 625 626static void 627set_font_style(void* _state, const char* _style, size_t length) 628{ 629 BoundingBoxState* const state = 630 reinterpret_cast<BoundingBoxState*>(_state); 631 632 BString style(_style, length); 633 ServerFont font(state->GetDrawState()->Font()); 634 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); 635 font.SetStyle(fontStyle); 636 state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 637} 638 639 640static void 641set_font_spacing(void* _state, uint8 spacing) 642{ 643 BoundingBoxState* const state = 644 reinterpret_cast<BoundingBoxState*>(_state); 645 646 ServerFont font; 647 font.SetSpacing(spacing); 648 state->GetDrawState()->SetFont(font, B_FONT_SPACING); 649} 650 651 652static void 653set_font_size(void* _state, float size) 654{ 655 BoundingBoxState* const state = 656 reinterpret_cast<BoundingBoxState*>(_state); 657 658 ServerFont font; 659 font.SetSize(size); 660 state->GetDrawState()->SetFont(font, B_FONT_SIZE); 661} 662 663 664static void 665set_font_rotate(void* _state, float rotation) 666{ 667 BoundingBoxState* const state = 668 reinterpret_cast<BoundingBoxState*>(_state); 669 670 ServerFont font; 671 font.SetRotation(rotation); 672 state->GetDrawState()->SetFont(font, B_FONT_ROTATION); 673} 674 675 676static void 677set_font_encoding(void* _state, uint8 encoding) 678{ 679 BoundingBoxState* const state = 680 reinterpret_cast<BoundingBoxState*>(_state); 681 682 ServerFont font; 683 font.SetEncoding(encoding); 684 state->GetDrawState()->SetFont(font, B_FONT_ENCODING); 685} 686 687 688static void 689set_font_flags(void* _state, uint32 flags) 690{ 691 BoundingBoxState* const state = 692 reinterpret_cast<BoundingBoxState*>(_state); 693 694 ServerFont font; 695 font.SetFlags(flags); 696 state->GetDrawState()->SetFont(font, B_FONT_FLAGS); 697} 698 699 700static void 701set_font_shear(void* _state, float shear) 702{ 703 BoundingBoxState* const state = 704 reinterpret_cast<BoundingBoxState*>(_state); 705 706 ServerFont font; 707 font.SetShear(shear); 708 state->GetDrawState()->SetFont(font, B_FONT_SHEAR); 709} 710 711 712static void 713set_font_face(void* _state, uint16 face) 714{ 715 BoundingBoxState* const state = 716 reinterpret_cast<BoundingBoxState*>(_state); 717 718 ServerFont font; 719 font.SetFace(face); 720 state->GetDrawState()->SetFont(font, B_FONT_FACE); 721} 722 723 724static void 725set_blending_mode(void*, source_alpha, alpha_function) 726{ 727} 728 729 730static void 731set_transform(void* _state, const BAffineTransform& transform) 732{ 733 TRACE_BB("%p transform\n", _state); 734 BoundingBoxState* const state = 735 reinterpret_cast<BoundingBoxState*>(_state); 736 state->GetDrawState()->SetTransform(transform); 737} 738 739 740static void 741translate_by(void* _state, double x, double y) 742{ 743 TRACE_BB("%p translate\n", _state); 744 BoundingBoxState* const state = 745 reinterpret_cast<BoundingBoxState*>(_state); 746 BAffineTransform transform = state->GetDrawState()->Transform(); 747 transform.PreTranslateBy(x, y); 748 state->GetDrawState()->SetTransform(transform); 749} 750 751 752static void 753scale_by(void* _state, double x, double y) 754{ 755 TRACE_BB("%p scale\n", _state); 756 BoundingBoxState* const state = 757 reinterpret_cast<BoundingBoxState*>(_state); 758 BAffineTransform transform = state->GetDrawState()->Transform(); 759 transform.PreScaleBy(x, y); 760 state->GetDrawState()->SetTransform(transform); 761} 762 763 764static void 765rotate_by(void* _state, double angleRadians) 766{ 767 TRACE_BB("%p rotate\n", _state); 768 BoundingBoxState* const state = 769 reinterpret_cast<BoundingBoxState*>(_state); 770 BAffineTransform transform = state->GetDrawState()->Transform(); 771 transform.PreRotateBy(angleRadians); 772 state->GetDrawState()->SetTransform(transform); 773} 774 775 776static void 777determine_bounds_nested_layer(void* _state, Layer* layer) 778{ 779 TRACE_BB("%p nested layer\n", _state); 780 BoundingBoxState* const state = 781 reinterpret_cast<BoundingBoxState*>(_state); 782 783 BRect boundingBox; 784 PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox); 785 if (boundingBox.IsValid()) 786 state->IncludeRect(boundingBox); 787} 788 789 790static const BPrivate::picture_player_callbacks 791 kPictureBoundingBoxPlayerCallbacks = { 792 move_pen_by, 793 determine_bounds_stroke_line, 794 determine_bounds_draw_rect, 795 determine_bounds_draw_round_rect, 796 determine_bounds_draw_bezier, 797 determine_bounds_draw_arc, 798 determine_bounds_draw_ellipse, 799 determine_bounds_draw_polygon, 800 determine_bounds_draw_shape, 801 determine_bounds_draw_string, 802 determine_bounds_draw_pixels, 803 draw_picture, 804 set_clipping_rects, 805 clip_to_picture, 806 push_state, 807 pop_state, 808 enter_state_change, 809 exit_state_change, 810 enter_font_state, 811 exit_font_state, 812 set_origin, 813 set_pen_location, 814 set_drawing_mode, 815 set_line_mode, 816 set_pen_size, 817 set_fore_color, 818 set_back_color, 819 set_stipple_pattern, 820 set_scale, 821 set_font_family, 822 set_font_style, 823 set_font_spacing, 824 set_font_size, 825 set_font_rotate, 826 set_font_encoding, 827 set_font_flags, 828 set_font_shear, 829 set_font_face, 830 set_blending_mode, 831 set_transform, 832 translate_by, 833 scale_by, 834 rotate_by, 835 determine_bounds_nested_layer 836}; 837 838 839// #pragma mark - PictureBoundingBoxPlayer 840 841 842/* static */ void 843PictureBoundingBoxPlayer::Play(ServerPicture* picture, 844 const DrawState* drawState, BRect* outBoundingBox) 845{ 846 State state(drawState, outBoundingBox); 847 848 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(picture->fData.Get()); 849 if (mallocIO == NULL) 850 return; 851 852 BPrivate::PicturePlayer player(mallocIO->Buffer(), 853 mallocIO->BufferLength(), ServerPicture::PictureList::Private( 854 picture->fPictures.Get()).AsBList()); 855 player.Play(kPictureBoundingBoxPlayerCallbacks, 856 sizeof(kPictureBoundingBoxPlayerCallbacks), &state); 857} 858