1 /* 2 * Copyright 2001-2019, 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 * Stephan Aßmus <superstippi@gmx.de> 11 */ 12 13 #include "ServerPicture.h" 14 15 #include <new> 16 #include <stdio.h> 17 #include <stack> 18 19 #include "AlphaMask.h" 20 #include "DrawingEngine.h" 21 #include "DrawState.h" 22 #include "FontManager.h" 23 #include "Layer.h" 24 #include "ServerApp.h" 25 #include "ServerBitmap.h" 26 #include "ServerFont.h" 27 #include "ServerTokenSpace.h" 28 #include "View.h" 29 #include "Window.h" 30 31 #include <LinkReceiver.h> 32 #include <OffsetFile.h> 33 #include <ObjectListPrivate.h> 34 #include <PicturePlayer.h> 35 #include <PictureProtocol.h> 36 #include <PortLink.h> 37 #include <ServerProtocol.h> 38 #include <ShapePrivate.h> 39 #include <StackOrHeapArray.h> 40 41 #include <Bitmap.h> 42 #include <Debug.h> 43 #include <List.h> 44 #include <Shape.h> 45 46 47 using std::stack; 48 49 50 class ShapePainter : public BShapeIterator { 51 public: 52 ShapePainter(Canvas* canvas); 53 virtual ~ShapePainter(); 54 55 status_t Iterate(const BShape* shape); 56 57 virtual status_t IterateMoveTo(BPoint* point); 58 virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); 59 virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); 60 virtual status_t IterateClose(); 61 virtual status_t IterateArcTo(float& rx, float& ry, 62 float& angle, bool largeArc, bool counterClockWise, BPoint& point); 63 64 void Draw(BRect frame, bool filled); 65 66 private: 67 Canvas* fCanvas; 68 stack<uint32> fOpStack; 69 stack<BPoint> fPtStack; 70 }; 71 72 73 ShapePainter::ShapePainter(Canvas* canvas) 74 : 75 fCanvas(canvas) 76 { 77 } 78 79 80 ShapePainter::~ShapePainter() 81 { 82 } 83 84 85 status_t 86 ShapePainter::Iterate(const BShape* shape) 87 { 88 // this class doesn't modify the shape data 89 return BShapeIterator::Iterate(const_cast<BShape*>(shape)); 90 } 91 92 93 status_t 94 ShapePainter::IterateMoveTo(BPoint* point) 95 { 96 try { 97 fOpStack.push(OP_MOVETO); 98 fPtStack.push(*point); 99 } catch (std::bad_alloc&) { 100 return B_NO_MEMORY; 101 } 102 103 return B_OK; 104 } 105 106 107 status_t 108 ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts) 109 { 110 try { 111 fOpStack.push(OP_LINETO | lineCount); 112 for (int32 i = 0; i < lineCount; i++) 113 fPtStack.push(linePts[i]); 114 } catch (std::bad_alloc&) { 115 return B_NO_MEMORY; 116 } 117 118 return B_OK; 119 } 120 121 122 status_t 123 ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts) 124 { 125 bezierCount *= 3; 126 try { 127 fOpStack.push(OP_BEZIERTO | bezierCount); 128 for (int32 i = 0; i < bezierCount; i++) 129 fPtStack.push(bezierPts[i]); 130 } catch (std::bad_alloc&) { 131 return B_NO_MEMORY; 132 } 133 134 return B_OK; 135 } 136 137 138 status_t 139 ShapePainter::IterateArcTo(float& rx, float& ry, 140 float& angle, bool largeArc, bool counterClockWise, BPoint& point) 141 { 142 uint32 op; 143 if (largeArc) { 144 if (counterClockWise) 145 op = OP_LARGE_ARC_TO_CCW; 146 else 147 op = OP_LARGE_ARC_TO_CW; 148 } else { 149 if (counterClockWise) 150 op = OP_SMALL_ARC_TO_CCW; 151 else 152 op = OP_SMALL_ARC_TO_CW; 153 } 154 155 try { 156 fOpStack.push(op | 3); 157 fPtStack.push(BPoint(rx, ry)); 158 fPtStack.push(BPoint(angle, 0)); 159 fPtStack.push(point); 160 } catch (std::bad_alloc&) { 161 return B_NO_MEMORY; 162 } 163 164 return B_OK; 165 } 166 167 168 status_t 169 ShapePainter::IterateClose() 170 { 171 try { 172 fOpStack.push(OP_CLOSE); 173 } catch (std::bad_alloc&) { 174 return B_NO_MEMORY; 175 } 176 177 return B_OK; 178 } 179 180 181 void 182 ShapePainter::Draw(BRect frame, bool filled) 183 { 184 // We're going to draw the currently iterated shape. 185 // TODO: This can be more efficient by skipping the conversion. 186 int32 opCount = fOpStack.size(); 187 int32 ptCount = fPtStack.size(); 188 189 if (opCount > 0 && ptCount > 0) { 190 int32 i; 191 uint32* opList = new(std::nothrow) uint32[opCount]; 192 if (opList == NULL) 193 return; 194 195 BPoint* ptList = new(std::nothrow) BPoint[ptCount]; 196 if (ptList == NULL) { 197 delete[] opList; 198 return; 199 } 200 201 for (i = opCount - 1; i >= 0; i--) { 202 opList[i] = fOpStack.top(); 203 fOpStack.pop(); 204 } 205 206 for (i = ptCount - 1; i >= 0; i--) { 207 ptList[i] = fPtStack.top(); 208 fPtStack.pop(); 209 } 210 211 BPoint offset(fCanvas->CurrentState()->PenLocation()); 212 fCanvas->PenToScreenTransform().Apply(&offset); 213 fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList, 214 ptCount, ptList, filled, offset, fCanvas->Scale()); 215 216 delete[] opList; 217 delete[] ptList; 218 } 219 } 220 221 222 // #pragma mark - drawing functions 223 224 225 static void 226 get_polygon_frame(const BPoint* points, uint32 numPoints, BRect* _frame) 227 { 228 ASSERT(numPoints > 0); 229 230 float left = points->x; 231 float top = points->y; 232 float right = left; 233 float bottom = top; 234 235 points++; 236 numPoints--; 237 238 while (numPoints--) { 239 if (points->x < left) 240 left = points->x; 241 if (points->x > right) 242 right = points->x; 243 if (points->y < top) 244 top = points->y; 245 if (points->y > bottom) 246 bottom = points->y; 247 points++; 248 } 249 250 _frame->Set(left, top, right, bottom); 251 } 252 253 254 static void 255 move_pen_by(void* _canvas, const BPoint& delta) 256 { 257 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 258 canvas->CurrentState()->SetPenLocation( 259 canvas->CurrentState()->PenLocation() + delta); 260 } 261 262 263 static void 264 stroke_line(void* _canvas, const BPoint& _start, const BPoint& _end) 265 { 266 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 267 BPoint start = _start; 268 BPoint end = _end; 269 270 const SimpleTransform transform = canvas->PenToScreenTransform(); 271 transform.Apply(&start); 272 transform.Apply(&end); 273 canvas->GetDrawingEngine()->StrokeLine(start, end); 274 275 canvas->CurrentState()->SetPenLocation(_end); 276 // the DrawingEngine/Painter does not need to be updated, since this 277 // effects only the view->screen coord conversion, which is handled 278 // by the view only 279 } 280 281 282 static void 283 draw_rect(void* _canvas, const BRect& _rect, bool fill) 284 { 285 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 286 BRect rect = _rect; 287 288 canvas->PenToScreenTransform().Apply(&rect); 289 if (fill) 290 canvas->GetDrawingEngine()->FillRect(rect); 291 else 292 canvas->GetDrawingEngine()->StrokeRect(rect); 293 } 294 295 296 static void 297 draw_round_rect(void* _canvas, const BRect& _rect, const BPoint& radii, 298 bool fill) 299 { 300 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 301 BRect rect = _rect; 302 303 canvas->PenToScreenTransform().Apply(&rect); 304 float scale = canvas->CurrentState()->CombinedScale(); 305 canvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale, 306 radii.y * scale, fill); 307 } 308 309 310 static void 311 draw_bezier(void* _canvas, size_t numPoints, const BPoint viewPoints[], 312 bool fill) 313 { 314 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 315 316 const size_t kSupportedPoints = 4; 317 if (numPoints != kSupportedPoints) 318 return; 319 320 BPoint points[kSupportedPoints]; 321 canvas->PenToScreenTransform().Apply(points, viewPoints, kSupportedPoints); 322 canvas->GetDrawingEngine()->DrawBezier(points, fill); 323 } 324 325 326 static void 327 draw_arc(void* _canvas, const BPoint& center, const BPoint& radii, 328 float startTheta, float arcTheta, bool fill) 329 { 330 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 331 332 BRect rect(center.x - radii.x, center.y - radii.y, 333 center.x + radii.x - 1, center.y + radii.y - 1); 334 canvas->PenToScreenTransform().Apply(&rect); 335 canvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill); 336 } 337 338 339 static void 340 draw_ellipse(void* _canvas, const BRect& _rect, bool fill) 341 { 342 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 343 344 BRect rect = _rect; 345 canvas->PenToScreenTransform().Apply(&rect); 346 canvas->GetDrawingEngine()->DrawEllipse(rect, fill); 347 } 348 349 350 static void 351 draw_polygon(void* _canvas, size_t numPoints, const BPoint viewPoints[], 352 bool isClosed, bool fill) 353 { 354 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 355 356 if (numPoints == 0) 357 return; 358 359 BStackOrHeapArray<BPoint, 200> points(numPoints); 360 if (!points.IsValid()) 361 return; 362 363 canvas->PenToScreenTransform().Apply(points, viewPoints, numPoints); 364 365 BRect polyFrame; 366 get_polygon_frame(points, numPoints, &polyFrame); 367 368 canvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, 369 fill, isClosed && numPoints > 2); 370 } 371 372 373 static void 374 draw_shape(void* _canvas, const BShape& shape, bool fill) 375 { 376 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 377 ShapePainter drawShape(canvas); 378 379 drawShape.Iterate(&shape); 380 drawShape.Draw(shape.Bounds(), fill); 381 } 382 383 384 static void 385 draw_string(void* _canvas, const char* string, size_t length, float deltaSpace, 386 float deltaNonSpace) 387 { 388 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 389 390 // NOTE: the picture data was recorded with a "set pen location" 391 // command inserted before the "draw string" command, so we can 392 // use PenLocation() 393 BPoint location = canvas->CurrentState()->PenLocation(); 394 395 escapement_delta delta = { deltaSpace, deltaNonSpace }; 396 canvas->PenToScreenTransform().Apply(&location); 397 location = canvas->GetDrawingEngine()->DrawString(string, length, 398 location, &delta); 399 400 canvas->PenToScreenTransform().Apply(&location); 401 canvas->CurrentState()->SetPenLocation(location); 402 // the DrawingEngine/Painter does not need to be updated, since this 403 // effects only the view->screen coord conversion, which is handled 404 // by the view only 405 } 406 407 408 static void 409 draw_string_locations(void* _canvas, const char* string, size_t length, 410 const BPoint* locations, size_t locationsCount) 411 { 412 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 413 414 BPoint location = canvas->GetDrawingEngine()->DrawString(string, length, 415 locations); 416 417 canvas->PenToScreenTransform().Apply(&location); 418 canvas->CurrentState()->SetPenLocation(location); 419 // the DrawingEngine/Painter does not need to be updated, since this 420 // effects only the view->screen coord conversion, which is handled 421 // by the view only 422 } 423 424 425 static void 426 draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width, 427 uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options, 428 const void* data, size_t length) 429 { 430 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 431 432 UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1), 433 (color_space)pixelFormat, 0, bytesPerRow); 434 435 if (!bitmap.IsValid()) 436 return; 437 438 memcpy(bitmap.Bits(), data, std::min(height * bytesPerRow, length)); 439 440 BRect dest = _dest; 441 canvas->PenToScreenTransform().Apply(&dest); 442 canvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options); 443 } 444 445 446 static void 447 draw_picture(void* _canvas, const BPoint& where, int32 token) 448 { 449 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 450 451 ServerPicture* picture = canvas->GetPicture(token); 452 if (picture != NULL) { 453 canvas->PushState(); 454 canvas->SetDrawingOrigin(where); 455 456 canvas->PushState(); 457 picture->Play(canvas); 458 canvas->PopState(); 459 460 canvas->PopState(); 461 picture->ReleaseReference(); 462 } 463 } 464 465 466 static void 467 set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[]) 468 { 469 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 470 471 if (numRects == 0) 472 canvas->SetUserClipping(NULL); 473 else { 474 // TODO: This might be too slow, we should copy the rects 475 // directly to BRegion's internal data 476 BRegion region; 477 for (uint32 c = 0; c < numRects; c++) 478 region.Include(rects[c]); 479 canvas->SetUserClipping(®ion); 480 } 481 canvas->UpdateCurrentDrawingRegion(); 482 } 483 484 485 static void 486 clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where, 487 bool clipToInverse) 488 { 489 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 490 491 ServerPicture* picture = canvas->GetPicture(pictureToken); 492 if (picture == NULL) 493 return; 494 AlphaMask* mask = new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(), 495 picture, *canvas->CurrentState(), where, clipToInverse); 496 canvas->SetAlphaMask(mask); 497 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 498 canvas->Bounds()); 499 canvas->ResyncDrawState(); 500 if (mask != NULL) 501 mask->ReleaseReference(); 502 503 picture->ReleaseReference(); 504 } 505 506 507 static void 508 push_state(void* _canvas) 509 { 510 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 511 canvas->PushState(); 512 } 513 514 515 static void 516 pop_state(void* _canvas) 517 { 518 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 519 canvas->PopState(); 520 521 BPoint p(0, 0); 522 canvas->PenToScreenTransform().Apply(&p); 523 canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(), 524 (int32)p.x, (int32)p.y); 525 } 526 527 528 // TODO: Be smart and actually take advantage of these methods: 529 // only apply state changes when they are called 530 static void 531 enter_state_change(void* _canvas) 532 { 533 } 534 535 536 static void 537 exit_state_change(void* _canvas) 538 { 539 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 540 canvas->ResyncDrawState(); 541 } 542 543 544 static void 545 enter_font_state(void* _canvas) 546 { 547 } 548 549 550 static void 551 exit_font_state(void* _canvas) 552 { 553 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 554 canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font()); 555 } 556 557 558 static void 559 set_origin(void* _canvas, const BPoint& pt) 560 { 561 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 562 canvas->CurrentState()->SetOrigin(pt); 563 } 564 565 566 static void 567 set_pen_location(void* _canvas, const BPoint& pt) 568 { 569 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 570 canvas->CurrentState()->SetPenLocation(pt); 571 // the DrawingEngine/Painter does not need to be updated, since this 572 // effects only the view->screen coord conversion, which is handled 573 // by the view only 574 } 575 576 577 static void 578 set_drawing_mode(void* _canvas, drawing_mode mode) 579 { 580 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 581 if (canvas->CurrentState()->SetDrawingMode(mode)) 582 canvas->GetDrawingEngine()->SetDrawingMode(mode); 583 } 584 585 586 static void 587 set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode, 588 float miterLimit) 589 { 590 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 591 DrawState* state = canvas->CurrentState(); 592 state->SetLineCapMode(capMode); 593 state->SetLineJoinMode(joinMode); 594 state->SetMiterLimit(miterLimit); 595 canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit); 596 } 597 598 599 static void 600 set_pen_size(void* _canvas, float size) 601 { 602 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 603 canvas->CurrentState()->SetPenSize(size); 604 canvas->GetDrawingEngine()->SetPenSize( 605 canvas->CurrentState()->PenSize()); 606 // DrawState::PenSize() returns the scaled pen size, so we 607 // need to use that value to set the drawing engine pen size. 608 } 609 610 611 static void 612 set_fore_color(void* _canvas, const rgb_color& color) 613 { 614 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 615 canvas->CurrentState()->SetHighColor(color); 616 canvas->GetDrawingEngine()->SetHighColor(color); 617 } 618 619 620 static void 621 set_back_color(void* _canvas, const rgb_color& color) 622 { 623 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 624 canvas->CurrentState()->SetLowColor(color); 625 canvas->GetDrawingEngine()->SetLowColor(color); 626 } 627 628 629 static void 630 set_stipple_pattern(void* _canvas, const pattern& pattern) 631 { 632 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 633 canvas->CurrentState()->SetPattern(Pattern(pattern)); 634 canvas->GetDrawingEngine()->SetPattern(pattern); 635 } 636 637 638 static void 639 set_scale(void* _canvas, float scale) 640 { 641 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 642 canvas->CurrentState()->SetScale(scale); 643 canvas->ResyncDrawState(); 644 645 // Update the drawing engine draw state, since some stuff 646 // (for example the pen size) needs to be recalculated. 647 } 648 649 650 static void 651 set_font_family(void* _canvas, const char* _family, size_t length) 652 { 653 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 654 BString family(_family, length); 655 656 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); 657 ServerFont font; 658 font.SetStyle(fontStyle); 659 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 660 } 661 662 663 static void 664 set_font_style(void* _canvas, const char* _style, size_t length) 665 { 666 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 667 BString style(_style, length); 668 669 ServerFont font(canvas->CurrentState()->Font()); 670 671 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); 672 673 font.SetStyle(fontStyle); 674 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 675 } 676 677 678 static void 679 set_font_spacing(void* _canvas, uint8 spacing) 680 { 681 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 682 ServerFont font; 683 font.SetSpacing(spacing); 684 canvas->CurrentState()->SetFont(font, B_FONT_SPACING); 685 } 686 687 688 static void 689 set_font_size(void* _canvas, float size) 690 { 691 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 692 ServerFont font; 693 font.SetSize(size); 694 canvas->CurrentState()->SetFont(font, B_FONT_SIZE); 695 } 696 697 698 static void 699 set_font_rotation(void* _canvas, float rotation) 700 { 701 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 702 ServerFont font; 703 font.SetRotation(rotation); 704 canvas->CurrentState()->SetFont(font, B_FONT_ROTATION); 705 } 706 707 708 static void 709 set_font_encoding(void* _canvas, uint8 encoding) 710 { 711 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 712 ServerFont font; 713 font.SetEncoding(encoding); 714 canvas->CurrentState()->SetFont(font, B_FONT_ENCODING); 715 } 716 717 718 static void 719 set_font_flags(void* _canvas, uint32 flags) 720 { 721 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 722 ServerFont font; 723 font.SetFlags(flags); 724 canvas->CurrentState()->SetFont(font, B_FONT_FLAGS); 725 } 726 727 728 static void 729 set_font_shear(void* _canvas, float shear) 730 { 731 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 732 ServerFont font; 733 font.SetShear(shear); 734 canvas->CurrentState()->SetFont(font, B_FONT_SHEAR); 735 } 736 737 738 static void 739 set_font_face(void* _canvas, uint16 face) 740 { 741 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 742 ServerFont font; 743 font.SetFace(face); 744 canvas->CurrentState()->SetFont(font, B_FONT_FACE); 745 } 746 747 748 static void 749 set_blending_mode(void* _canvas, source_alpha alphaSrcMode, 750 alpha_function alphaFncMode) 751 { 752 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 753 canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode); 754 } 755 756 757 static void 758 set_transform(void* _canvas, const BAffineTransform& transform) 759 { 760 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 761 canvas->CurrentState()->SetTransform(transform); 762 canvas->GetDrawingEngine()->SetTransform(transform); 763 } 764 765 766 static void 767 translate_by(void* _canvas, double x, double y) 768 { 769 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 770 BAffineTransform transform = canvas->CurrentState()->Transform(); 771 transform.PreTranslateBy(x, y); 772 canvas->CurrentState()->SetTransform(transform); 773 canvas->GetDrawingEngine()->SetTransform(transform); 774 } 775 776 777 static void 778 scale_by(void* _canvas, double x, double y) 779 { 780 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 781 BAffineTransform transform = canvas->CurrentState()->Transform(); 782 transform.PreScaleBy(x, y); 783 canvas->CurrentState()->SetTransform(transform); 784 canvas->GetDrawingEngine()->SetTransform(transform); 785 } 786 787 788 static void 789 rotate_by(void* _canvas, double angleRadians) 790 { 791 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 792 BAffineTransform transform = canvas->CurrentState()->Transform(); 793 transform.PreRotateBy(angleRadians); 794 canvas->CurrentState()->SetTransform(transform); 795 canvas->GetDrawingEngine()->SetTransform(transform); 796 } 797 798 799 static void 800 blend_layer(void* _canvas, Layer* layer) 801 { 802 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 803 canvas->BlendLayer(layer); 804 } 805 806 807 static void 808 clip_to_rect(void* _canvas, const BRect& rect, bool inverse) 809 { 810 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 811 bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse); 812 if (needDrawStateUpdate) { 813 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 814 canvas->Bounds()); 815 canvas->ResyncDrawState(); 816 } 817 canvas->UpdateCurrentDrawingRegion(); 818 } 819 820 821 static void 822 clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[], 823 int32 ptCount, const BPoint ptList[], bool inverse) 824 { 825 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 826 shape_data shapeData; 827 828 // TODO: avoid copies 829 shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32)); 830 memcpy(shapeData.opList, opList, opCount * sizeof(uint32)); 831 shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint)); 832 memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint)); 833 834 shapeData.opCount = opCount; 835 shapeData.opSize = opCount * sizeof(uint32); 836 shapeData.ptCount = ptCount; 837 shapeData.ptSize = ptCount * sizeof(BPoint); 838 839 canvas->ClipToShape(&shapeData, inverse); 840 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 841 canvas->Bounds()); 842 canvas->ResyncDrawState(); 843 844 free(shapeData.opList); 845 free(shapeData.ptList); 846 } 847 848 849 static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = { 850 move_pen_by, 851 stroke_line, 852 draw_rect, 853 draw_round_rect, 854 draw_bezier, 855 draw_arc, 856 draw_ellipse, 857 draw_polygon, 858 draw_shape, 859 draw_string, 860 draw_pixels, 861 draw_picture, 862 set_clipping_rects, 863 clip_to_picture, 864 push_state, 865 pop_state, 866 enter_state_change, 867 exit_state_change, 868 enter_font_state, 869 exit_font_state, 870 set_origin, 871 set_pen_location, 872 set_drawing_mode, 873 set_line_mode, 874 set_pen_size, 875 set_fore_color, 876 set_back_color, 877 set_stipple_pattern, 878 set_scale, 879 set_font_family, 880 set_font_style, 881 set_font_spacing, 882 set_font_size, 883 set_font_rotation, 884 set_font_encoding, 885 set_font_flags, 886 set_font_shear, 887 set_font_face, 888 set_blending_mode, 889 set_transform, 890 translate_by, 891 scale_by, 892 rotate_by, 893 blend_layer, 894 clip_to_rect, 895 clip_to_shape, 896 draw_string_locations 897 }; 898 899 900 // #pragma mark - ServerPicture 901 902 903 ServerPicture::ServerPicture() 904 : 905 fFile(NULL), 906 fPictures(NULL), 907 fPushed(NULL), 908 fOwner(NULL) 909 { 910 fToken = gTokenSpace.NewToken(kPictureToken, this); 911 fData = new(std::nothrow) BMallocIO(); 912 913 PictureDataWriter::SetTo(fData); 914 } 915 916 917 ServerPicture::ServerPicture(const ServerPicture& picture) 918 : 919 fFile(NULL), 920 fData(NULL), 921 fPictures(NULL), 922 fPushed(NULL), 923 fOwner(NULL) 924 { 925 fToken = gTokenSpace.NewToken(kPictureToken, this); 926 927 BMallocIO* mallocIO = new(std::nothrow) BMallocIO(); 928 if (mallocIO == NULL) 929 return; 930 931 fData = mallocIO; 932 933 const off_t size = picture.DataLength(); 934 if (mallocIO->SetSize(size) < B_OK) 935 return; 936 937 picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()), 938 size); 939 940 PictureDataWriter::SetTo(fData); 941 } 942 943 944 ServerPicture::ServerPicture(const char* fileName, int32 offset) 945 : 946 fFile(NULL), 947 fData(NULL), 948 fPictures(NULL), 949 fPushed(NULL), 950 fOwner(NULL) 951 { 952 fToken = gTokenSpace.NewToken(kPictureToken, this); 953 954 fFile = new(std::nothrow) BFile(fileName, B_READ_WRITE); 955 if (fFile == NULL) 956 return; 957 958 BPrivate::Storage::OffsetFile* offsetFile 959 = new(std::nothrow) BPrivate::Storage::OffsetFile(fFile, offset); 960 if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) { 961 delete offsetFile; 962 return; 963 } 964 965 fData = offsetFile; 966 967 PictureDataWriter::SetTo(fData); 968 } 969 970 971 ServerPicture::~ServerPicture() 972 { 973 ASSERT(fOwner == NULL); 974 975 delete fData; 976 delete fFile; 977 gTokenSpace.RemoveToken(fToken); 978 979 if (fPictures != NULL) { 980 for (int32 i = fPictures->CountItems(); i-- > 0;) { 981 ServerPicture* picture = fPictures->ItemAt(i); 982 picture->SetOwner(NULL); 983 picture->ReleaseReference(); 984 } 985 986 delete fPictures; 987 } 988 989 if (fPushed != NULL) { 990 fPushed->SetOwner(NULL); 991 fPushed->ReleaseReference(); 992 } 993 } 994 995 996 bool 997 ServerPicture::SetOwner(ServerApp* owner) 998 { 999 if (owner == fOwner) 1000 return true; 1001 1002 // Acquire an extra reference, since calling RemovePicture() 1003 // May remove the last reference and then we will self-destruct right then. 1004 // Setting fOwner to NULL would access free'd memory. If owner is another 1005 // ServerApp, it's expected to already have a reference of course. 1006 BReference<ServerPicture> _(this); 1007 1008 if (fOwner != NULL) 1009 fOwner->RemovePicture(this); 1010 1011 fOwner = NULL; 1012 if (owner == NULL) 1013 return true; 1014 1015 if (!owner->AddPicture(this)) 1016 return false; 1017 1018 fOwner = owner; 1019 return true; 1020 } 1021 1022 1023 void 1024 ServerPicture::EnterStateChange() 1025 { 1026 BeginOp(B_PIC_ENTER_STATE_CHANGE); 1027 } 1028 1029 1030 void 1031 ServerPicture::ExitStateChange() 1032 { 1033 EndOp(); 1034 } 1035 1036 1037 void 1038 ServerPicture::SyncState(Canvas* canvas) 1039 { 1040 // TODO: Finish this 1041 EnterStateChange(); 1042 1043 WriteSetOrigin(canvas->CurrentState()->Origin()); 1044 WriteSetPenLocation(canvas->CurrentState()->PenLocation()); 1045 WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize()); 1046 WriteSetScale(canvas->CurrentState()->Scale()); 1047 WriteSetLineMode(canvas->CurrentState()->LineCapMode(), 1048 canvas->CurrentState()->LineJoinMode(), 1049 canvas->CurrentState()->MiterLimit()); 1050 //WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8()); 1051 WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode()); 1052 1053 WriteSetHighColor(canvas->CurrentState()->HighColor()); 1054 WriteSetLowColor(canvas->CurrentState()->LowColor()); 1055 1056 ExitStateChange(); 1057 } 1058 1059 1060 void 1061 ServerPicture::WriteFontState(const ServerFont& font, uint16 mask) 1062 { 1063 BeginOp(B_PIC_ENTER_FONT_STATE); 1064 1065 if (mask & B_FONT_FAMILY_AND_STYLE) { 1066 WriteSetFontFamily(font.Family()); 1067 WriteSetFontStyle(font.Style()); 1068 } 1069 1070 if (mask & B_FONT_SIZE) { 1071 WriteSetFontSize(font.Size()); 1072 } 1073 1074 if (mask & B_FONT_SHEAR) { 1075 WriteSetFontShear(font.Shear()); 1076 } 1077 1078 if (mask & B_FONT_ROTATION) { 1079 WriteSetFontRotation(font.Rotation()); 1080 } 1081 1082 if (mask & B_FONT_FALSE_BOLD_WIDTH) { 1083 // TODO: Implement 1084 // WriteSetFalseBoldWidth(font.FalseBoldWidth()); 1085 } 1086 1087 if (mask & B_FONT_SPACING) { 1088 WriteSetFontSpacing(font.Spacing()); 1089 } 1090 1091 if (mask & B_FONT_ENCODING) { 1092 WriteSetFontEncoding(font.Encoding()); 1093 } 1094 1095 if (mask & B_FONT_FACE) { 1096 WriteSetFontFace(font.Face()); 1097 } 1098 1099 if (mask & B_FONT_FLAGS) { 1100 WriteSetFontFlags(font.Flags()); 1101 } 1102 1103 EndOp(); 1104 } 1105 1106 1107 void 1108 ServerPicture::Play(Canvas* target) 1109 { 1110 // TODO: for now: then change PicturePlayer 1111 // to accept a BPositionIO object 1112 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData); 1113 if (mallocIO == NULL) 1114 return; 1115 1116 BPrivate::PicturePlayer player(mallocIO->Buffer(), 1117 mallocIO->BufferLength(), PictureList::Private(fPictures).AsBList()); 1118 player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks), 1119 target); 1120 } 1121 1122 1123 /*! Acquires a reference to the pushed picture. 1124 */ 1125 void 1126 ServerPicture::PushPicture(ServerPicture* picture) 1127 { 1128 if (fPushed != NULL) 1129 debugger("already pushed a picture"); 1130 1131 fPushed = picture; 1132 fPushed->AcquireReference(); 1133 } 1134 1135 1136 /*! Returns a reference with the popped picture. 1137 */ 1138 ServerPicture* 1139 ServerPicture::PopPicture() 1140 { 1141 ServerPicture* old = fPushed; 1142 fPushed = NULL; 1143 return old; 1144 } 1145 1146 1147 void 1148 ServerPicture::AppendPicture(ServerPicture* picture) 1149 { 1150 // A pushed picture is the same as an appended one 1151 PushPicture(picture); 1152 } 1153 1154 1155 bool 1156 ServerPicture::NestPicture(ServerPicture* picture) 1157 { 1158 if (fPictures == NULL) 1159 fPictures = new(std::nothrow) PictureList; 1160 1161 if (fPictures == NULL || !fPictures->AddItem(picture)) 1162 return false; 1163 1164 picture->AcquireReference(); 1165 return true; 1166 } 1167 1168 1169 off_t 1170 ServerPicture::DataLength() const 1171 { 1172 if (fData == NULL) 1173 return 0; 1174 off_t size; 1175 fData->GetSize(&size); 1176 return size; 1177 } 1178 1179 1180 status_t 1181 ServerPicture::ImportData(BPrivate::LinkReceiver& link) 1182 { 1183 int32 size = 0; 1184 link.Read<int32>(&size); 1185 1186 off_t oldPosition = fData->Position(); 1187 fData->Seek(0, SEEK_SET); 1188 1189 status_t status = B_NO_MEMORY; 1190 char* buffer = new(std::nothrow) char[size]; 1191 if (buffer) { 1192 status = B_OK; 1193 ssize_t read = link.Read(buffer, size); 1194 if (read < B_OK || fData->Write(buffer, size) < B_OK) 1195 status = B_ERROR; 1196 delete [] buffer; 1197 } 1198 1199 fData->Seek(oldPosition, SEEK_SET); 1200 return status; 1201 } 1202 1203 1204 status_t 1205 ServerPicture::ExportData(BPrivate::PortLink& link) 1206 { 1207 link.StartMessage(B_OK); 1208 1209 off_t oldPosition = fData->Position(); 1210 fData->Seek(0, SEEK_SET); 1211 1212 int32 subPicturesCount = 0; 1213 if (fPictures != NULL) 1214 subPicturesCount = fPictures->CountItems(); 1215 link.Attach<int32>(subPicturesCount); 1216 if (subPicturesCount > 0) { 1217 for (int32 i = 0; i < subPicturesCount; i++) { 1218 ServerPicture* subPicture = fPictures->ItemAt(i); 1219 link.Attach<int32>(subPicture->Token()); 1220 } 1221 } 1222 1223 off_t size = 0; 1224 fData->GetSize(&size); 1225 link.Attach<int32>((int32)size); 1226 1227 status_t status = B_NO_MEMORY; 1228 char* buffer = new(std::nothrow) char[size]; 1229 if (buffer) { 1230 status = B_OK; 1231 ssize_t read = fData->Read(buffer, size); 1232 if (read < B_OK || link.Attach(buffer, read) < B_OK) 1233 status = B_ERROR; 1234 delete [] buffer; 1235 } 1236 1237 if (status != B_OK) { 1238 link.CancelMessage(); 1239 link.StartMessage(B_ERROR); 1240 } 1241 1242 fData->Seek(oldPosition, SEEK_SET); 1243 return status; 1244 } 1245