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