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 ServerPicture* picture = canvas->GetPicture(token); 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 picture->ReleaseReference(); 604 } 605 } 606 607 608 static void 609 set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[]) 610 { 611 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 612 613 if (numRects == 0) 614 canvas->SetUserClipping(NULL); 615 else { 616 // TODO: This might be too slow, we should copy the rects 617 // directly to BRegion's internal data 618 BRegion region; 619 for (uint32 c = 0; c < numRects; c++) 620 region.Include(rects[c]); 621 canvas->SetUserClipping(®ion); 622 } 623 canvas->UpdateCurrentDrawingRegion(); 624 } 625 626 627 static void 628 clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where, 629 bool clipToInverse) 630 { 631 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 632 633 ServerPicture* picture = canvas->GetPicture(pictureToken); 634 if (picture == NULL) 635 return; 636 AlphaMask* mask = new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(), 637 picture, *canvas->CurrentState(), where, clipToInverse); 638 canvas->SetAlphaMask(mask); 639 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 640 canvas->Bounds()); 641 canvas->ResyncDrawState(); 642 if (mask != NULL) 643 mask->ReleaseReference(); 644 645 picture->ReleaseReference(); 646 } 647 648 649 static void 650 push_state(void* _canvas) 651 { 652 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 653 canvas->PushState(); 654 } 655 656 657 static void 658 pop_state(void* _canvas) 659 { 660 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 661 canvas->PopState(); 662 663 BPoint p(0, 0); 664 canvas->PenToScreenTransform().Apply(&p); 665 canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(), 666 (int32)p.x, (int32)p.y); 667 } 668 669 670 // TODO: Be smart and actually take advantage of these methods: 671 // only apply state changes when they are called 672 static void 673 enter_state_change(void* _canvas) 674 { 675 } 676 677 678 static void 679 exit_state_change(void* _canvas) 680 { 681 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 682 canvas->ResyncDrawState(); 683 } 684 685 686 static void 687 enter_font_state(void* _canvas) 688 { 689 } 690 691 692 static void 693 exit_font_state(void* _canvas) 694 { 695 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 696 canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font()); 697 } 698 699 700 static void 701 set_origin(void* _canvas, const BPoint& pt) 702 { 703 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 704 canvas->CurrentState()->SetOrigin(pt); 705 } 706 707 708 static void 709 set_pen_location(void* _canvas, const BPoint& pt) 710 { 711 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 712 canvas->CurrentState()->SetPenLocation(pt); 713 // the DrawingEngine/Painter does not need to be updated, since this 714 // effects only the view->screen coord conversion, which is handled 715 // by the view only 716 } 717 718 719 static void 720 set_drawing_mode(void* _canvas, drawing_mode mode) 721 { 722 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 723 if (canvas->CurrentState()->SetDrawingMode(mode)) 724 canvas->GetDrawingEngine()->SetDrawingMode(mode); 725 } 726 727 728 static void 729 set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode, 730 float miterLimit) 731 { 732 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 733 DrawState* state = canvas->CurrentState(); 734 state->SetLineCapMode(capMode); 735 state->SetLineJoinMode(joinMode); 736 state->SetMiterLimit(miterLimit); 737 canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit); 738 } 739 740 741 static void 742 set_pen_size(void* _canvas, float size) 743 { 744 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 745 canvas->CurrentState()->SetPenSize(size); 746 canvas->GetDrawingEngine()->SetPenSize( 747 canvas->CurrentState()->PenSize()); 748 // DrawState::PenSize() returns the scaled pen size, so we 749 // need to use that value to set the drawing engine pen size. 750 } 751 752 753 static void 754 set_fore_color(void* _canvas, const rgb_color& color) 755 { 756 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 757 canvas->CurrentState()->SetHighColor(color); 758 canvas->GetDrawingEngine()->SetHighColor(color); 759 } 760 761 762 static void 763 set_back_color(void* _canvas, const rgb_color& color) 764 { 765 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 766 canvas->CurrentState()->SetLowColor(color); 767 canvas->GetDrawingEngine()->SetLowColor(color); 768 } 769 770 771 static void 772 set_stipple_pattern(void* _canvas, const pattern& pattern) 773 { 774 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 775 canvas->CurrentState()->SetPattern(Pattern(pattern)); 776 canvas->GetDrawingEngine()->SetPattern(pattern); 777 } 778 779 780 static void 781 set_scale(void* _canvas, float scale) 782 { 783 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 784 canvas->CurrentState()->SetScale(scale); 785 canvas->ResyncDrawState(); 786 787 // Update the drawing engine draw state, since some stuff 788 // (for example the pen size) needs to be recalculated. 789 } 790 791 792 static void 793 set_font_family(void* _canvas, const char* _family, size_t length) 794 { 795 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 796 BString family(_family, length); 797 798 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); 799 ServerFont font; 800 font.SetStyle(fontStyle); 801 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 802 } 803 804 805 static void 806 set_font_style(void* _canvas, const char* _style, size_t length) 807 { 808 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 809 BString style(_style, length); 810 811 ServerFont font(canvas->CurrentState()->Font()); 812 813 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); 814 815 font.SetStyle(fontStyle); 816 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); 817 } 818 819 820 static void 821 set_font_spacing(void* _canvas, uint8 spacing) 822 { 823 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 824 ServerFont font; 825 font.SetSpacing(spacing); 826 canvas->CurrentState()->SetFont(font, B_FONT_SPACING); 827 } 828 829 830 static void 831 set_font_size(void* _canvas, float size) 832 { 833 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 834 ServerFont font; 835 font.SetSize(size); 836 canvas->CurrentState()->SetFont(font, B_FONT_SIZE); 837 } 838 839 840 static void 841 set_font_rotation(void* _canvas, float rotation) 842 { 843 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 844 ServerFont font; 845 font.SetRotation(rotation); 846 canvas->CurrentState()->SetFont(font, B_FONT_ROTATION); 847 } 848 849 850 static void 851 set_font_encoding(void* _canvas, uint8 encoding) 852 { 853 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 854 ServerFont font; 855 font.SetEncoding(encoding); 856 canvas->CurrentState()->SetFont(font, B_FONT_ENCODING); 857 } 858 859 860 static void 861 set_font_flags(void* _canvas, uint32 flags) 862 { 863 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 864 ServerFont font; 865 font.SetFlags(flags); 866 canvas->CurrentState()->SetFont(font, B_FONT_FLAGS); 867 } 868 869 870 static void 871 set_font_shear(void* _canvas, float shear) 872 { 873 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 874 ServerFont font; 875 font.SetShear(shear); 876 canvas->CurrentState()->SetFont(font, B_FONT_SHEAR); 877 } 878 879 880 static void 881 set_font_face(void* _canvas, uint16 face) 882 { 883 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 884 ServerFont font; 885 font.SetFace(face); 886 canvas->CurrentState()->SetFont(font, B_FONT_FACE); 887 } 888 889 890 static void 891 set_blending_mode(void* _canvas, source_alpha alphaSrcMode, 892 alpha_function alphaFncMode) 893 { 894 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 895 canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode); 896 } 897 898 899 static void 900 set_fill_rule(void* _canvas, int32 fillRule) 901 { 902 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 903 canvas->CurrentState()->SetFillRule(fillRule); 904 canvas->GetDrawingEngine()->SetFillRule(fillRule); 905 } 906 907 908 static void 909 set_transform(void* _canvas, const BAffineTransform& transform) 910 { 911 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 912 913 BPoint leftTop(0, 0); 914 canvas->PenToScreenTransform().Apply(&leftTop); 915 916 canvas->CurrentState()->SetTransform(transform); 917 canvas->GetDrawingEngine()->SetTransform( 918 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); 919 } 920 921 922 static void 923 translate_by(void* _canvas, double x, double y) 924 { 925 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 926 927 BPoint leftTop(0, 0); 928 canvas->PenToScreenTransform().Apply(&leftTop); 929 930 BAffineTransform transform = canvas->CurrentState()->Transform(); 931 transform.PreTranslateBy(x, y); 932 canvas->CurrentState()->SetTransform(transform); 933 canvas->GetDrawingEngine()->SetTransform( 934 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); 935 } 936 937 938 static void 939 scale_by(void* _canvas, double x, double y) 940 { 941 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 942 943 BPoint leftTop(0, 0); 944 canvas->PenToScreenTransform().Apply(&leftTop); 945 946 BAffineTransform transform = canvas->CurrentState()->Transform(); 947 transform.PreScaleBy(x, y); 948 canvas->CurrentState()->SetTransform(transform); 949 canvas->GetDrawingEngine()->SetTransform( 950 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); 951 } 952 953 954 static void 955 rotate_by(void* _canvas, double angleRadians) 956 { 957 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 958 959 BPoint leftTop(0, 0); 960 canvas->PenToScreenTransform().Apply(&leftTop); 961 962 BAffineTransform transform = canvas->CurrentState()->Transform(); 963 transform.PreRotateBy(angleRadians); 964 canvas->CurrentState()->SetTransform(transform); 965 canvas->GetDrawingEngine()->SetTransform( 966 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); 967 } 968 969 970 static void 971 blend_layer(void* _canvas, Layer* layer) 972 { 973 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 974 canvas->BlendLayer(layer); 975 } 976 977 978 static void 979 clip_to_rect(void* _canvas, const BRect& rect, bool inverse) 980 { 981 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 982 bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse); 983 if (needDrawStateUpdate) { 984 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 985 canvas->Bounds()); 986 canvas->ResyncDrawState(); 987 } 988 canvas->UpdateCurrentDrawingRegion(); 989 } 990 991 992 static void 993 clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[], 994 int32 ptCount, const BPoint ptList[], bool inverse) 995 { 996 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas); 997 shape_data shapeData; 998 999 // TODO: avoid copies 1000 shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32)); 1001 memcpy(shapeData.opList, opList, opCount * sizeof(uint32)); 1002 shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint)); 1003 memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint)); 1004 1005 shapeData.opCount = opCount; 1006 shapeData.opSize = opCount * sizeof(uint32); 1007 shapeData.ptCount = ptCount; 1008 shapeData.ptSize = ptCount * sizeof(BPoint); 1009 1010 canvas->ClipToShape(&shapeData, inverse); 1011 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0), 1012 canvas->Bounds()); 1013 canvas->ResyncDrawState(); 1014 1015 free(shapeData.opList); 1016 free(shapeData.ptList); 1017 } 1018 1019 1020 static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = { 1021 move_pen_by, 1022 stroke_line, 1023 draw_rect, 1024 draw_round_rect, 1025 draw_bezier, 1026 draw_arc, 1027 draw_ellipse, 1028 draw_polygon, 1029 draw_shape, 1030 draw_string, 1031 draw_pixels, 1032 draw_picture, 1033 set_clipping_rects, 1034 clip_to_picture, 1035 push_state, 1036 pop_state, 1037 enter_state_change, 1038 exit_state_change, 1039 enter_font_state, 1040 exit_font_state, 1041 set_origin, 1042 set_pen_location, 1043 set_drawing_mode, 1044 set_line_mode, 1045 set_pen_size, 1046 set_fore_color, 1047 set_back_color, 1048 set_stipple_pattern, 1049 set_scale, 1050 set_font_family, 1051 set_font_style, 1052 set_font_spacing, 1053 set_font_size, 1054 set_font_rotation, 1055 set_font_encoding, 1056 set_font_flags, 1057 set_font_shear, 1058 set_font_face, 1059 set_blending_mode, 1060 set_transform, 1061 translate_by, 1062 scale_by, 1063 rotate_by, 1064 blend_layer, 1065 clip_to_rect, 1066 clip_to_shape, 1067 draw_string_locations, 1068 draw_rect_gradient, 1069 draw_round_rect_gradient, 1070 draw_bezier_gradient, 1071 draw_arc_gradient, 1072 draw_ellipse_gradient, 1073 draw_polygon_gradient, 1074 draw_shape_gradient, 1075 set_fill_rule 1076 }; 1077 1078 1079 // #pragma mark - ServerPicture 1080 1081 1082 ServerPicture::ServerPicture() 1083 : 1084 fFile(NULL), 1085 fPictures(NULL), 1086 fPushed(NULL), 1087 fOwner(NULL) 1088 { 1089 fToken = gTokenSpace.NewToken(kPictureToken, this); 1090 fData = new(std::nothrow) BMallocIO(); 1091 1092 PictureDataWriter::SetTo(fData); 1093 } 1094 1095 1096 ServerPicture::ServerPicture(const ServerPicture& picture) 1097 : 1098 fFile(NULL), 1099 fData(NULL), 1100 fPictures(NULL), 1101 fPushed(NULL), 1102 fOwner(NULL) 1103 { 1104 fToken = gTokenSpace.NewToken(kPictureToken, this); 1105 1106 BMallocIO* mallocIO = new(std::nothrow) BMallocIO(); 1107 if (mallocIO == NULL) 1108 return; 1109 1110 fData = mallocIO; 1111 1112 const off_t size = picture.DataLength(); 1113 if (mallocIO->SetSize(size) < B_OK) 1114 return; 1115 1116 picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()), 1117 size); 1118 1119 PictureDataWriter::SetTo(fData); 1120 } 1121 1122 1123 ServerPicture::ServerPicture(const char* fileName, int32 offset) 1124 : 1125 fFile(NULL), 1126 fData(NULL), 1127 fPictures(NULL), 1128 fPushed(NULL), 1129 fOwner(NULL) 1130 { 1131 fToken = gTokenSpace.NewToken(kPictureToken, this); 1132 1133 fFile = new(std::nothrow) BFile(fileName, B_READ_WRITE); 1134 if (fFile == NULL) 1135 return; 1136 1137 BPrivate::Storage::OffsetFile* offsetFile 1138 = new(std::nothrow) BPrivate::Storage::OffsetFile(fFile, offset); 1139 if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) { 1140 delete offsetFile; 1141 return; 1142 } 1143 1144 fData = offsetFile; 1145 1146 PictureDataWriter::SetTo(fData); 1147 } 1148 1149 1150 ServerPicture::~ServerPicture() 1151 { 1152 ASSERT(fOwner == NULL); 1153 1154 delete fData; 1155 delete fFile; 1156 gTokenSpace.RemoveToken(fToken); 1157 1158 if (fPictures != NULL) { 1159 for (int32 i = fPictures->CountItems(); i-- > 0;) { 1160 ServerPicture* picture = fPictures->ItemAt(i); 1161 picture->SetOwner(NULL); 1162 picture->ReleaseReference(); 1163 } 1164 1165 delete fPictures; 1166 } 1167 1168 if (fPushed != NULL) { 1169 fPushed->SetOwner(NULL); 1170 fPushed->ReleaseReference(); 1171 } 1172 } 1173 1174 1175 bool 1176 ServerPicture::SetOwner(ServerApp* owner) 1177 { 1178 if (owner == fOwner) 1179 return true; 1180 1181 // Acquire an extra reference, since calling RemovePicture() 1182 // May remove the last reference and then we will self-destruct right then. 1183 // Setting fOwner to NULL would access free'd memory. If owner is another 1184 // ServerApp, it's expected to already have a reference of course. 1185 BReference<ServerPicture> _(this); 1186 1187 if (fOwner != NULL) 1188 fOwner->RemovePicture(this); 1189 1190 fOwner = NULL; 1191 if (owner == NULL) 1192 return true; 1193 1194 if (!owner->AddPicture(this)) 1195 return false; 1196 1197 fOwner = owner; 1198 return true; 1199 } 1200 1201 1202 void 1203 ServerPicture::EnterStateChange() 1204 { 1205 BeginOp(B_PIC_ENTER_STATE_CHANGE); 1206 } 1207 1208 1209 void 1210 ServerPicture::ExitStateChange() 1211 { 1212 EndOp(); 1213 } 1214 1215 1216 void 1217 ServerPicture::SyncState(Canvas* canvas) 1218 { 1219 // TODO: Finish this 1220 EnterStateChange(); 1221 1222 WriteSetOrigin(canvas->CurrentState()->Origin()); 1223 WriteSetPenLocation(canvas->CurrentState()->PenLocation()); 1224 WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize()); 1225 WriteSetScale(canvas->CurrentState()->Scale()); 1226 WriteSetLineMode(canvas->CurrentState()->LineCapMode(), 1227 canvas->CurrentState()->LineJoinMode(), 1228 canvas->CurrentState()->MiterLimit()); 1229 //WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8()); 1230 WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode()); 1231 1232 WriteSetHighColor(canvas->CurrentState()->HighColor()); 1233 WriteSetLowColor(canvas->CurrentState()->LowColor()); 1234 1235 ExitStateChange(); 1236 } 1237 1238 1239 void 1240 ServerPicture::WriteFontState(const ServerFont& font, uint16 mask) 1241 { 1242 BeginOp(B_PIC_ENTER_FONT_STATE); 1243 1244 if (mask & B_FONT_FAMILY_AND_STYLE) { 1245 WriteSetFontFamily(font.Family()); 1246 WriteSetFontStyle(font.Style()); 1247 } 1248 1249 if (mask & B_FONT_SIZE) { 1250 WriteSetFontSize(font.Size()); 1251 } 1252 1253 if (mask & B_FONT_SHEAR) { 1254 WriteSetFontShear(font.Shear()); 1255 } 1256 1257 if (mask & B_FONT_ROTATION) { 1258 WriteSetFontRotation(font.Rotation()); 1259 } 1260 1261 if (mask & B_FONT_FALSE_BOLD_WIDTH) { 1262 // TODO: Implement 1263 // WriteSetFalseBoldWidth(font.FalseBoldWidth()); 1264 } 1265 1266 if (mask & B_FONT_SPACING) { 1267 WriteSetFontSpacing(font.Spacing()); 1268 } 1269 1270 if (mask & B_FONT_ENCODING) { 1271 WriteSetFontEncoding(font.Encoding()); 1272 } 1273 1274 if (mask & B_FONT_FACE) { 1275 WriteSetFontFace(font.Face()); 1276 } 1277 1278 if (mask & B_FONT_FLAGS) { 1279 WriteSetFontFlags(font.Flags()); 1280 } 1281 1282 EndOp(); 1283 } 1284 1285 1286 void 1287 ServerPicture::Play(Canvas* target) 1288 { 1289 // TODO: for now: then change PicturePlayer 1290 // to accept a BPositionIO object 1291 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData); 1292 if (mallocIO == NULL) 1293 return; 1294 1295 BPrivate::PicturePlayer player(mallocIO->Buffer(), 1296 mallocIO->BufferLength(), PictureList::Private(fPictures).AsBList()); 1297 player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks), 1298 target); 1299 } 1300 1301 1302 /*! Acquires a reference to the pushed picture. 1303 */ 1304 void 1305 ServerPicture::PushPicture(ServerPicture* picture) 1306 { 1307 if (fPushed != NULL) 1308 debugger("already pushed a picture"); 1309 1310 fPushed = picture; 1311 fPushed->AcquireReference(); 1312 } 1313 1314 1315 /*! Returns a reference with the popped picture. 1316 */ 1317 ServerPicture* 1318 ServerPicture::PopPicture() 1319 { 1320 ServerPicture* old = fPushed; 1321 fPushed = NULL; 1322 return old; 1323 } 1324 1325 1326 void 1327 ServerPicture::AppendPicture(ServerPicture* picture) 1328 { 1329 // A pushed picture is the same as an appended one 1330 PushPicture(picture); 1331 } 1332 1333 1334 bool 1335 ServerPicture::NestPicture(ServerPicture* picture) 1336 { 1337 if (fPictures == NULL) 1338 fPictures = new(std::nothrow) PictureList; 1339 1340 if (fPictures == NULL || !fPictures->AddItem(picture)) 1341 return false; 1342 1343 picture->AcquireReference(); 1344 return true; 1345 } 1346 1347 1348 off_t 1349 ServerPicture::DataLength() const 1350 { 1351 if (fData == NULL) 1352 return 0; 1353 off_t size; 1354 fData->GetSize(&size); 1355 return size; 1356 } 1357 1358 1359 status_t 1360 ServerPicture::ImportData(BPrivate::LinkReceiver& link) 1361 { 1362 int32 size = 0; 1363 link.Read<int32>(&size); 1364 1365 off_t oldPosition = fData->Position(); 1366 fData->Seek(0, SEEK_SET); 1367 1368 status_t status = B_NO_MEMORY; 1369 char* buffer = new(std::nothrow) char[size]; 1370 if (buffer) { 1371 status = B_OK; 1372 ssize_t read = link.Read(buffer, size); 1373 if (read < B_OK || fData->Write(buffer, size) < B_OK) 1374 status = B_ERROR; 1375 delete [] buffer; 1376 } 1377 1378 fData->Seek(oldPosition, SEEK_SET); 1379 return status; 1380 } 1381 1382 1383 status_t 1384 ServerPicture::ExportData(BPrivate::PortLink& link) 1385 { 1386 link.StartMessage(B_OK); 1387 1388 off_t oldPosition = fData->Position(); 1389 fData->Seek(0, SEEK_SET); 1390 1391 int32 subPicturesCount = 0; 1392 if (fPictures != NULL) 1393 subPicturesCount = fPictures->CountItems(); 1394 link.Attach<int32>(subPicturesCount); 1395 if (subPicturesCount > 0) { 1396 for (int32 i = 0; i < subPicturesCount; i++) { 1397 ServerPicture* subPicture = fPictures->ItemAt(i); 1398 link.Attach<int32>(subPicture->Token()); 1399 } 1400 } 1401 1402 off_t size = 0; 1403 fData->GetSize(&size); 1404 link.Attach<int32>((int32)size); 1405 1406 status_t status = B_NO_MEMORY; 1407 char* buffer = new(std::nothrow) char[size]; 1408 if (buffer) { 1409 status = B_OK; 1410 ssize_t read = fData->Read(buffer, size); 1411 if (read < B_OK || link.Attach(buffer, read) < B_OK) 1412 status = B_ERROR; 1413 delete [] buffer; 1414 } 1415 1416 if (status != B_OK) { 1417 link.CancelMessage(); 1418 link.StartMessage(B_ERROR); 1419 } 1420 1421 fData->Seek(oldPosition, SEEK_SET); 1422 return status; 1423 } 1424