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