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