1 /* 2 * Copyright 2001-2018, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 * Julian Harnath <julian.harnath@rwth-aachen.de> 8 */ 9 10 11 #include "DrawingEngine.h" 12 13 #include <Bitmap.h> 14 #include <StackOrHeapArray.h> 15 16 #include <stdio.h> 17 18 #include <algorithm> 19 #include <stack> 20 21 #include "DrawState.h" 22 #include "GlyphLayoutEngine.h" 23 #include "Painter.h" 24 #include "ServerBitmap.h" 25 #include "ServerCursor.h" 26 #include "RenderingBuffer.h" 27 28 #include "drawing_support.h" 29 30 31 #if DEBUG 32 # define ASSERT_PARALLEL_LOCKED() \ 33 { if (!IsParallelAccessLocked()) debugger("not parallel locked!"); } 34 # define ASSERT_EXCLUSIVE_LOCKED() \ 35 { if (!IsExclusiveAccessLocked()) debugger("not exclusive locked!"); } 36 #else 37 # define ASSERT_PARALLEL_LOCKED() 38 # define ASSERT_EXCLUSIVE_LOCKED() 39 #endif 40 41 42 static inline void 43 make_rect_valid(BRect& rect) 44 { 45 if (rect.left > rect.right) { 46 float temp = rect.left; 47 rect.left = rect.right; 48 rect.right = temp; 49 } 50 if (rect.top > rect.bottom) { 51 float temp = rect.top; 52 rect.top = rect.bottom; 53 rect.bottom = temp; 54 } 55 } 56 57 58 static inline void 59 extend_by_stroke_width(BRect& rect, float penSize) 60 { 61 // "- 0.5" because if stroke width == 1, we don't need to extend 62 float inset = -ceilf(penSize / 2.0 - 0.5); 63 rect.InsetBy(inset, inset); 64 } 65 66 67 class AutoFloatingOverlaysHider { 68 public: 69 AutoFloatingOverlaysHider(HWInterface* interface, const BRect& area) 70 : 71 fInterface(interface), 72 fHidden(interface->HideFloatingOverlays(area)) 73 { 74 } 75 76 AutoFloatingOverlaysHider(HWInterface* interface) 77 : 78 fInterface(interface), 79 fHidden(fInterface->HideFloatingOverlays()) 80 { 81 } 82 83 ~AutoFloatingOverlaysHider() 84 { 85 if (fHidden) 86 fInterface->ShowFloatingOverlays(); 87 } 88 89 bool WasHidden() const 90 { 91 return fHidden; 92 } 93 94 private: 95 HWInterface* fInterface; 96 bool fHidden; 97 98 }; 99 100 class DrawTransaction { 101 public: 102 DrawTransaction(DrawingEngine *engine, const BRect &bounds) 103 : 104 fEngine(engine), 105 fOverlaysHidden(false) 106 { 107 fDirty.Set(bounds); 108 fDirty.IntersectWith(fEngine->fPainter->ClippingRegion()); 109 if (fDirty.CountRects() == 0) 110 return; 111 fOverlaysHidden 112 = fEngine->fGraphicsCard->HideFloatingOverlays(fDirty.Frame()); 113 } 114 115 DrawTransaction(DrawingEngine *engine) 116 : 117 fEngine(engine), 118 fOverlaysHidden(false) 119 { 120 fDirty = *fEngine->fPainter->ClippingRegion(); 121 if (fDirty.CountRects() == 0) 122 return; 123 fOverlaysHidden 124 = fEngine->fGraphicsCard->HideFloatingOverlays(fDirty.Frame()); 125 } 126 127 DrawTransaction(DrawingEngine *engine, const BRegion ®ion) 128 : 129 fEngine(engine), 130 fOverlaysHidden(false) 131 { 132 // region is already clipped 133 fDirty = region; 134 if (fDirty.CountRects() == 0) 135 return; 136 fOverlaysHidden 137 = fEngine->fGraphicsCard->HideFloatingOverlays(fDirty.Frame()); 138 } 139 140 ~DrawTransaction() 141 { 142 if (fEngine->fCopyToFront) 143 fEngine->fGraphicsCard->InvalidateRegion(fDirty); 144 if (fOverlaysHidden) 145 fEngine->fGraphicsCard->ShowFloatingOverlays(); 146 } 147 148 bool IsDirty() const 149 { 150 return fDirty.CountRects() > 0; 151 } 152 153 void SetDirty(const BRect &rect) 154 { 155 fDirty.Set(rect); 156 fDirty.IntersectWith(fEngine->fPainter->ClippingRegion()); 157 } 158 159 const BRegion &DirtyRegion() const 160 { 161 return fDirty; 162 } 163 164 bool WasOverlaysHidden() const 165 { 166 return fOverlaysHidden; 167 } 168 169 private: 170 DrawingEngine *fEngine; 171 bool fOverlaysHidden; 172 BRegion fDirty; 173 }; 174 175 176 // #pragma mark - 177 178 179 DrawingEngine::DrawingEngine(HWInterface* interface) 180 : 181 fPainter(new Painter()), 182 fGraphicsCard(NULL), 183 fAvailableHWAccleration(0), 184 fSuspendSyncLevel(0), 185 fCopyToFront(true) 186 { 187 SetHWInterface(interface); 188 } 189 190 191 DrawingEngine::~DrawingEngine() 192 { 193 SetHWInterface(NULL); 194 } 195 196 197 // #pragma mark - locking 198 199 200 bool 201 DrawingEngine::LockParallelAccess() 202 { 203 return fGraphicsCard->LockParallelAccess(); 204 } 205 206 207 #if DEBUG 208 bool 209 DrawingEngine::IsParallelAccessLocked() const 210 { 211 return fGraphicsCard->IsParallelAccessLocked(); 212 } 213 #endif 214 215 216 void 217 DrawingEngine::UnlockParallelAccess() 218 { 219 fGraphicsCard->UnlockParallelAccess(); 220 } 221 222 223 bool 224 DrawingEngine::LockExclusiveAccess() 225 { 226 return fGraphicsCard->LockExclusiveAccess(); 227 } 228 229 230 bool 231 DrawingEngine::IsExclusiveAccessLocked() const 232 { 233 return fGraphicsCard->IsExclusiveAccessLocked(); 234 } 235 236 237 void 238 DrawingEngine::UnlockExclusiveAccess() 239 { 240 fGraphicsCard->UnlockExclusiveAccess(); 241 } 242 243 244 // #pragma mark - 245 246 247 void 248 DrawingEngine::FrameBufferChanged() 249 { 250 if (!fGraphicsCard) { 251 fPainter->DetachFromBuffer(); 252 fAvailableHWAccleration = 0; 253 return; 254 } 255 256 // NOTE: locking is probably bogus, since we are called 257 // in the thread that changed the frame buffer... 258 if (LockExclusiveAccess()) { 259 fPainter->AttachToBuffer(fGraphicsCard->DrawingBuffer()); 260 // available HW acceleration might have changed 261 fAvailableHWAccleration = fGraphicsCard->AvailableHWAcceleration(); 262 UnlockExclusiveAccess(); 263 } 264 } 265 266 267 void 268 DrawingEngine::SetHWInterface(HWInterface* interface) 269 { 270 if (fGraphicsCard == interface) 271 return; 272 273 if (fGraphicsCard) 274 fGraphicsCard->RemoveListener(this); 275 276 fGraphicsCard = interface; 277 278 if (fGraphicsCard) 279 fGraphicsCard->AddListener(this); 280 281 FrameBufferChanged(); 282 } 283 284 285 void 286 DrawingEngine::SetCopyToFrontEnabled(bool enable) 287 { 288 fCopyToFront = enable; 289 } 290 291 292 void 293 DrawingEngine::CopyToFront(/*const*/ BRegion& region) 294 { 295 fGraphicsCard->InvalidateRegion(region); 296 } 297 298 299 // #pragma mark - 300 301 302 //! the DrawingEngine needs to be locked! 303 void 304 DrawingEngine::ConstrainClippingRegion(const BRegion* region) 305 { 306 ASSERT_PARALLEL_LOCKED(); 307 308 fPainter->ConstrainClipping(region); 309 } 310 311 312 void 313 DrawingEngine::SetDrawState(const DrawState* state, int32 xOffset, 314 int32 yOffset) 315 { 316 fPainter->SetDrawState(state, xOffset, yOffset); 317 } 318 319 320 void 321 DrawingEngine::SetHighColor(const rgb_color& color) 322 { 323 fPainter->SetHighColor(color); 324 } 325 326 327 void 328 DrawingEngine::SetLowColor(const rgb_color& color) 329 { 330 fPainter->SetLowColor(color); 331 } 332 333 334 void 335 DrawingEngine::SetPenSize(float size) 336 { 337 fPainter->SetPenSize(size); 338 } 339 340 341 void 342 DrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode, 343 float miterLimit) 344 { 345 fPainter->SetStrokeMode(lineCap, joinMode, miterLimit); 346 } 347 348 349 void 350 DrawingEngine::SetFillRule(int32 fillRule) 351 { 352 fPainter->SetFillRule(fillRule); 353 } 354 355 356 void 357 DrawingEngine::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc) 358 { 359 fPainter->SetBlendingMode(srcAlpha, alphaFunc); 360 } 361 362 363 void 364 DrawingEngine::SetPattern(const struct pattern& pattern) 365 { 366 fPainter->SetPattern(pattern, false); 367 } 368 369 370 void 371 DrawingEngine::SetDrawingMode(drawing_mode mode) 372 { 373 fPainter->SetDrawingMode(mode); 374 } 375 376 377 void 378 DrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode) 379 { 380 oldMode = fPainter->DrawingMode(); 381 fPainter->SetDrawingMode(mode); 382 } 383 384 385 void 386 DrawingEngine::SetFont(const ServerFont& font) 387 { 388 fPainter->SetFont(font); 389 } 390 391 392 void 393 DrawingEngine::SetFont(const DrawState* state) 394 { 395 fPainter->SetFont(state); 396 } 397 398 399 void 400 DrawingEngine::SetTransform(const BAffineTransform& transform, int32 xOffset, 401 int32 yOffset) 402 { 403 fPainter->SetTransform(transform, xOffset, yOffset); 404 } 405 406 407 // #pragma mark - 408 409 410 void 411 DrawingEngine::SuspendAutoSync() 412 { 413 ASSERT_PARALLEL_LOCKED(); 414 415 fSuspendSyncLevel++; 416 } 417 418 419 void 420 DrawingEngine::Sync() 421 { 422 ASSERT_PARALLEL_LOCKED(); 423 424 fSuspendSyncLevel--; 425 if (fSuspendSyncLevel == 0) 426 fGraphicsCard->Sync(); 427 } 428 429 430 // #pragma mark - 431 432 433 // CopyRegion() does a topological sort of the rects in the 434 // region. The algorithm was suggested by Ingo Weinhold. 435 // It compares each rect with each rect and builds a tree 436 // of successors so we know the order in which they can be copied. 437 // For example, let's suppose these rects are in a BRegion: 438 // ************ 439 // * B * 440 // ************ 441 // ************* 442 // * * 443 // * A **************** 444 // * ** * 445 // ************** * 446 // * C * 447 // * * 448 // * * 449 // *************** 450 // When copying stuff from LEFT TO RIGHT, TOP TO BOTTOM, the 451 // result of the sort will be C, A, B. For this direction, we search 452 // for the rects that have no neighbors to their right and to their 453 // bottom, These can be copied without drawing into the area of 454 // rects yet to be copied. If you move from RIGHT TO LEFT, BOTTOM TO TOP, 455 // you go look for the ones that have no neighbors to their top and left. 456 // 457 // Here I draw some rays to illustrate LEFT TO RIGHT, TOP TO BOTTOM: 458 // ************ 459 // * B * 460 // ************ 461 // ************* 462 // * * 463 // * A ****************----------------- 464 // * ** * 465 // ************** * 466 // * C * 467 // * * 468 // * * 469 // *************** 470 // | 471 // | 472 // | 473 // | 474 // There are no rects in the area defined by the rays to the right 475 // and bottom of rect C, so that's the one we want to copy first 476 // (for positive x and y offsets). 477 // Since A is to the left of C and B is to the top of C, The "node" 478 // for C will point to the nodes of A and B as its "successors". Therefor, 479 // A and B will have an "indegree" of 1 for C pointing to them. C will 480 // have an "indegree" of 0, because there was no rect to which C 481 // was to the left or top of. When comparing A and B, neither is left 482 // or top from the other and in the sense that the algorithm cares about. 483 484 // NOTE: comparison of coordinates assumes that rects don't overlap 485 // and don't share the actual edge either (as is the case in BRegions). 486 487 struct node { 488 node() 489 { 490 pointers = NULL; 491 } 492 493 node(const BRect& r, int32 maxPointers) 494 { 495 init(r, maxPointers); 496 } 497 498 ~node() 499 { 500 delete [] pointers; 501 } 502 503 void init(const BRect& r, int32 maxPointers) 504 { 505 rect = r; 506 pointers = new(std::nothrow) node*[maxPointers]; 507 in_degree = 0; 508 next_pointer = 0; 509 } 510 511 void push(node* node) 512 { 513 pointers[next_pointer] = node; 514 next_pointer++; 515 } 516 517 node* top() 518 { 519 return pointers[next_pointer]; 520 } 521 522 node* pop() 523 { 524 node* ret = top(); 525 next_pointer--; 526 return ret; 527 } 528 529 BRect rect; 530 int32 in_degree; 531 node** pointers; 532 int32 next_pointer; 533 }; 534 535 536 static bool 537 is_left_of(const BRect& a, const BRect& b) 538 { 539 return (a.right < b.left); 540 } 541 542 543 static bool 544 is_above(const BRect& a, const BRect& b) 545 { 546 return (a.bottom < b.top); 547 } 548 549 550 void 551 DrawingEngine::CopyRegion(/*const*/ BRegion* region, int32 xOffset, 552 int32 yOffset) 553 { 554 // NOTE: region is already clipped 555 ASSERT_PARALLEL_LOCKED(); 556 557 BRect frame = region->Frame(); 558 frame = frame | frame.OffsetByCopy(xOffset, yOffset); 559 560 AutoFloatingOverlaysHider _(fGraphicsCard, frame); 561 562 int32 count = region->CountRects(); 563 564 // TODO: make this step unnecessary 565 // (by using different stack impl inside node) 566 BStackOrHeapArray<node, 64> nodes(count); 567 for (int32 i= 0; i < count; i++) { 568 nodes[i].init(region->RectAt(i), count); 569 if (nodes[i].pointers == NULL) 570 return; 571 } 572 573 for (int32 i = 0; i < count; i++) { 574 BRect a = region->RectAt(i); 575 for (int32 k = i + 1; k < count; k++) { 576 BRect b = region->RectAt(k); 577 int cmp = 0; 578 // compare horizontally 579 if (xOffset > 0) { 580 if (is_left_of(a, b)) { 581 cmp -= 1; 582 } else if (is_left_of(b, a)) { 583 cmp += 1; 584 } 585 } else if (xOffset < 0) { 586 if (is_left_of(a, b)) { 587 cmp += 1; 588 } else if (is_left_of(b, a)) { 589 cmp -= 1; 590 } 591 } 592 // compare vertically 593 if (yOffset > 0) { 594 if (is_above(a, b)) { 595 cmp -= 1; 596 } else if (is_above(b, a)) { 597 cmp += 1; 598 } 599 } else if (yOffset < 0) { 600 if (is_above(a, b)) { 601 cmp += 1; 602 } else if (is_above(b, a)) { 603 cmp -= 1; 604 } 605 } 606 // add appropriate node as successor 607 if (cmp > 0) { 608 nodes[i].push(&nodes[k]); 609 nodes[k].in_degree++; 610 } else if (cmp < 0) { 611 nodes[k].push(&nodes[i]); 612 nodes[i].in_degree++; 613 } 614 } 615 } 616 // put all nodes onto a stack that have an "indegree" count of zero 617 std::stack<node*> inDegreeZeroNodes; 618 for (int32 i = 0; i < count; i++) { 619 if (nodes[i].in_degree == 0) { 620 inDegreeZeroNodes.push(&nodes[i]); 621 } 622 } 623 // pop the rects from the stack, do the actual copy operation 624 // and decrease the "indegree" count of the other rects not 625 // currently on the stack and to which the current rect pointed 626 // to. If their "indegree" count reaches zero, put them onto the 627 // stack as well. 628 629 clipping_rect* sortedRectList = NULL; 630 int32 nextSortedIndex = 0; 631 632 if (fAvailableHWAccleration & HW_ACC_COPY_REGION) { 633 sortedRectList = new(std::nothrow) clipping_rect[count]; 634 if (sortedRectList == NULL) 635 return; 636 } 637 638 while (!inDegreeZeroNodes.empty()) { 639 node* n = inDegreeZeroNodes.top(); 640 inDegreeZeroNodes.pop(); 641 642 // do the software implementation or add to sorted 643 // rect list for using the HW accelerated version 644 // later 645 if (sortedRectList) { 646 sortedRectList[nextSortedIndex].left = (int32)n->rect.left; 647 sortedRectList[nextSortedIndex].top = (int32)n->rect.top; 648 sortedRectList[nextSortedIndex].right = (int32)n->rect.right; 649 sortedRectList[nextSortedIndex].bottom = (int32)n->rect.bottom; 650 nextSortedIndex++; 651 } else { 652 BRect touched = CopyRect(n->rect, xOffset, yOffset); 653 fGraphicsCard->Invalidate(touched); 654 } 655 656 for (int32 k = 0; k < n->next_pointer; k++) { 657 n->pointers[k]->in_degree--; 658 if (n->pointers[k]->in_degree == 0) 659 inDegreeZeroNodes.push(n->pointers[k]); 660 } 661 } 662 663 // trigger the HW accelerated version if it was available 664 if (sortedRectList) { 665 fGraphicsCard->CopyRegion(sortedRectList, count, xOffset, yOffset); 666 if (fGraphicsCard->IsDoubleBuffered()) { 667 fGraphicsCard->Invalidate( 668 region->Frame().OffsetByCopy(xOffset, yOffset)); 669 } 670 } 671 672 delete[] sortedRectList; 673 } 674 675 676 void 677 DrawingEngine::InvertRect(BRect r) 678 { 679 ASSERT_PARALLEL_LOCKED(); 680 681 make_rect_valid(r); 682 // NOTE: Currently ignores view transformation, so no TransformAndClipRect() 683 DrawTransaction transaction(this, fPainter->ClipRect(r)); 684 if (!transaction.IsDirty()) 685 return; 686 687 // try hardware optimized version first 688 if (fAvailableHWAccleration & HW_ACC_INVERT_REGION) { 689 BRegion region(r); 690 region.IntersectWith(fPainter->ClippingRegion()); 691 fGraphicsCard->InvertRegion(region); 692 } else { 693 fPainter->InvertRect(r); 694 } 695 } 696 697 698 void 699 DrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& bitmapRect, 700 const BRect& viewRect, uint32 options) 701 { 702 ASSERT_PARALLEL_LOCKED(); 703 704 DrawTransaction transaction(this, fPainter->TransformAndClipRect(viewRect)); 705 if (transaction.IsDirty()) 706 fPainter->DrawBitmap(bitmap, bitmapRect, viewRect, options); 707 } 708 709 710 void 711 DrawingEngine::DrawArc(BRect r, const float& angle, const float& span, 712 bool filled) 713 { 714 ASSERT_PARALLEL_LOCKED(); 715 716 make_rect_valid(r); 717 fPainter->AlignEllipseRect(&r, filled); 718 719 BRect clipped(r); 720 if (!filled) 721 extend_by_stroke_width(clipped, fPainter->PenSize()); 722 DrawTransaction transaction(this, fPainter->TransformAndClipRect(clipped)); 723 if (!transaction.IsDirty()) 724 return; 725 726 float xRadius = r.Width() / 2.0; 727 float yRadius = r.Height() / 2.0; 728 BPoint center(r.left + xRadius, 729 r.top + yRadius); 730 731 if (filled) 732 fPainter->FillArc(center, xRadius, yRadius, angle, span); 733 else 734 fPainter->StrokeArc(center, xRadius, yRadius, angle, span); 735 } 736 737 738 void 739 DrawingEngine::FillArc(BRect r, const float& angle, const float& span, 740 const BGradient& gradient) 741 { 742 ASSERT_PARALLEL_LOCKED(); 743 744 make_rect_valid(r); 745 fPainter->AlignEllipseRect(&r, true); 746 DrawTransaction transaction(this, fPainter->TransformAndClipRect(r)); 747 if (!transaction.IsDirty()) 748 return; 749 750 float xRadius = r.Width() / 2.0; 751 float yRadius = r.Height() / 2.0; 752 BPoint center(r.left + xRadius, 753 r.top + yRadius); 754 755 fPainter->FillArc(center, xRadius, yRadius, angle, span, gradient); 756 } 757 758 759 void 760 DrawingEngine::DrawBezier(BPoint* pts, bool filled) 761 { 762 ASSERT_PARALLEL_LOCKED(); 763 764 // TODO: figure out bounds and hide cursor depending on that 765 DrawTransaction transaction(this); 766 767 transaction.SetDirty(fPainter->DrawBezier(pts, filled)); 768 } 769 770 771 void 772 DrawingEngine::FillBezier(BPoint* pts, const BGradient& gradient) 773 { 774 ASSERT_PARALLEL_LOCKED(); 775 776 // TODO: figure out bounds and hide cursor depending on that 777 DrawTransaction transaction(this); 778 779 transaction.SetDirty(fPainter->FillBezier(pts, gradient)); 780 } 781 782 783 void 784 DrawingEngine::DrawEllipse(BRect r, bool filled) 785 { 786 ASSERT_PARALLEL_LOCKED(); 787 788 make_rect_valid(r); 789 BRect clipped = r; 790 fPainter->AlignEllipseRect(&clipped, filled); 791 792 if (!filled) 793 extend_by_stroke_width(clipped, fPainter->PenSize()); 794 795 clipped.left = floorf(clipped.left); 796 clipped.top = floorf(clipped.top); 797 clipped.right = ceilf(clipped.right); 798 clipped.bottom = ceilf(clipped.bottom); 799 800 DrawTransaction transaction(this, fPainter->TransformAndClipRect(clipped)); 801 if (!transaction.IsDirty()) 802 return; 803 804 fPainter->DrawEllipse(r, filled); 805 } 806 807 808 void 809 DrawingEngine::FillEllipse(BRect r, const BGradient& gradient) 810 { 811 ASSERT_PARALLEL_LOCKED(); 812 813 make_rect_valid(r); 814 BRect clipped = r; 815 fPainter->AlignEllipseRect(&clipped, true); 816 817 clipped.left = floorf(clipped.left); 818 clipped.top = floorf(clipped.top); 819 clipped.right = ceilf(clipped.right); 820 clipped.bottom = ceilf(clipped.bottom); 821 822 DrawTransaction transaction(this, fPainter->TransformAndClipRect(clipped)); 823 if (!transaction.IsDirty()) 824 return; 825 826 fPainter->FillEllipse(r, gradient); 827 } 828 829 830 void 831 DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, BRect bounds, 832 bool filled, bool closed) 833 { 834 ASSERT_PARALLEL_LOCKED(); 835 836 make_rect_valid(bounds); 837 if (!filled) 838 extend_by_stroke_width(bounds, fPainter->PenSize()); 839 DrawTransaction transaction(this, fPainter->TransformAndClipRect(bounds)); 840 if (!transaction.IsDirty()) 841 return; 842 843 fPainter->DrawPolygon(ptlist, numpts, filled, closed); 844 } 845 846 847 void 848 DrawingEngine::FillPolygon(BPoint* ptlist, int32 numpts, BRect bounds, 849 const BGradient& gradient, bool closed) 850 { 851 ASSERT_PARALLEL_LOCKED(); 852 853 make_rect_valid(bounds); 854 DrawTransaction transaction(this, fPainter->TransformAndClipRect(bounds)); 855 if (!transaction.IsDirty()) 856 return; 857 858 fPainter->FillPolygon(ptlist, numpts, gradient, closed); 859 } 860 861 862 // #pragma mark - rgb_color 863 864 865 void 866 DrawingEngine::StrokePoint(const BPoint& pt, const rgb_color& color) 867 { 868 StrokeLine(pt, pt, color); 869 } 870 871 872 /*! This function is only used by Decorators, 873 it assumes a one pixel wide line 874 */ 875 void 876 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end, 877 const rgb_color& color) 878 { 879 ASSERT_PARALLEL_LOCKED(); 880 881 BRect touched(start, end); 882 make_rect_valid(touched); 883 touched = fPainter->ClipRect(touched); 884 DrawTransaction transaction(this, touched); 885 886 if (!fPainter->StraightLine(start, end, color)) { 887 rgb_color previousColor = fPainter->HighColor(); 888 drawing_mode previousMode = fPainter->DrawingMode(); 889 890 fPainter->SetHighColor(color); 891 fPainter->SetDrawingMode(B_OP_OVER); 892 fPainter->StrokeLine(start, end); 893 894 fPainter->SetDrawingMode(previousMode); 895 fPainter->SetHighColor(previousColor); 896 } 897 } 898 899 900 //! This function is used to draw a one pixel wide rect 901 void 902 DrawingEngine::StrokeRect(BRect r, const rgb_color& color) 903 { 904 ASSERT_PARALLEL_LOCKED(); 905 906 make_rect_valid(r); 907 DrawTransaction transaction(this, fPainter->ClipRect(r)); 908 if (!transaction.IsDirty()) 909 return; 910 911 fPainter->StrokeRect(r, color); 912 } 913 914 915 void 916 DrawingEngine::FillRect(BRect r, const rgb_color& color) 917 { 918 ASSERT_PARALLEL_LOCKED(); 919 920 // NOTE: Write locking because we might use HW acceleration. 921 // This needs to be investigated, I'm doing this because of 922 // gut feeling. 923 make_rect_valid(r); 924 r = fPainter->ClipRect(r); 925 DrawTransaction transaction(this, r); 926 if (!transaction.IsDirty()) 927 return; 928 929 // try hardware optimized version first 930 if (fAvailableHWAccleration & HW_ACC_FILL_REGION) { 931 BRegion region(r); 932 region.IntersectWith(fPainter->ClippingRegion()); 933 fGraphicsCard->FillRegion(region, color, 934 fSuspendSyncLevel == 0 || transaction.WasOverlaysHidden()); 935 } else { 936 fPainter->FillRect(r, color); 937 } 938 } 939 940 941 void 942 DrawingEngine::FillRegion(BRegion& r, const rgb_color& color) 943 { 944 ASSERT_PARALLEL_LOCKED(); 945 946 // NOTE: region expected to be already clipped correctly!! 947 BRect frame = r.Frame(); 948 if (!fPainter->Bounds().Contains(frame)) { 949 // NOTE: I am not quite sure yet how this can happen, but apparently it 950 // can (see bug #634). 951 // This function is used for internal app_server painting, in the case of 952 // bug #634, the background of views is painted. But the view region 953 // should never be outside the frame buffer bounds. 954 // char message[1024]; 955 // BRect bounds = fPainter->Bounds(); 956 // sprintf(message, "FillRegion() - painter: (%d, %d)->(%d, %d), region: (%d, %d)->(%d, %d)", 957 // (int)bounds.left, (int)bounds.top, (int)bounds.right, (int)bounds.bottom, 958 // (int)frame.left, (int)frame.top, (int)frame.right, (int)frame.bottom); 959 // debugger(message); 960 return; 961 } 962 963 DrawTransaction transaction(this, r); 964 965 // try hardware optimized version first 966 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0 967 && frame.Width() * frame.Height() > 100) { 968 fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0 969 || transaction.WasOverlaysHidden()); 970 } else { 971 int32 count = r.CountRects(); 972 for (int32 i = 0; i < count; i++) 973 fPainter->FillRectNoClipping(r.RectAtInt(i), color); 974 } 975 } 976 977 978 // #pragma mark - DrawState 979 980 981 void 982 DrawingEngine::StrokeRect(BRect r) 983 { 984 ASSERT_PARALLEL_LOCKED(); 985 986 // support invalid rects 987 make_rect_valid(r); 988 BRect clipped(r); 989 extend_by_stroke_width(clipped, fPainter->PenSize()); 990 DrawTransaction transaction(this, fPainter->TransformAndClipRect(clipped)); 991 if (!transaction.IsDirty()) 992 return; 993 994 fPainter->StrokeRect(r); 995 } 996 997 998 void 999 DrawingEngine::FillRect(BRect r) 1000 { 1001 ASSERT_PARALLEL_LOCKED(); 1002 1003 make_rect_valid(r); 1004 1005 r = fPainter->AlignRect(r); 1006 1007 DrawTransaction transaction(this, fPainter->TransformAndClipRect(r)); 1008 if (!transaction.IsDirty()) 1009 return; 1010 1011 if (fPainter->IsIdentityTransform()) { 1012 // TODO the accelerated code path may also be used for transforms that 1013 // only scale and translate (but don't shear or rotate). 1014 1015 if ((r.Width() + 1) * (r.Height() + 1) > 100.0) { 1016 // try hardware optimized version first 1017 // if the rect is large enough 1018 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { 1019 if (fPainter->Pattern() == B_SOLID_HIGH 1020 && (fPainter->DrawingMode() == B_OP_COPY 1021 || fPainter->DrawingMode() == B_OP_OVER)) { 1022 BRegion region(r); 1023 region.IntersectWith(fPainter->ClippingRegion()); 1024 fGraphicsCard->FillRegion(region, fPainter->HighColor(), 1025 fSuspendSyncLevel == 0 1026 || transaction.WasOverlaysHidden()); 1027 return; 1028 } else if (fPainter->Pattern() == B_SOLID_LOW 1029 && fPainter->DrawingMode() == B_OP_COPY) { 1030 BRegion region(r); 1031 region.IntersectWith(fPainter->ClippingRegion()); 1032 fGraphicsCard->FillRegion(region, fPainter->LowColor(), 1033 fSuspendSyncLevel == 0 1034 || transaction.WasOverlaysHidden()); 1035 return; 1036 } 1037 } 1038 } 1039 1040 if ((fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 1041 && fPainter->Pattern() == B_SOLID_HIGH 1042 && fPainter->DrawingMode() == B_OP_INVERT) { 1043 BRegion region(r); 1044 region.IntersectWith(fPainter->ClippingRegion()); 1045 fGraphicsCard->InvertRegion(region); 1046 return; 1047 } 1048 } 1049 1050 fPainter->FillRect(r); 1051 } 1052 1053 1054 void 1055 DrawingEngine::FillRect(BRect r, const BGradient& gradient) 1056 { 1057 ASSERT_PARALLEL_LOCKED(); 1058 1059 make_rect_valid(r); 1060 r = fPainter->AlignRect(r); 1061 1062 DrawTransaction transaction(this, fPainter->TransformAndClipRect(r)); 1063 if (!transaction.IsDirty()) 1064 return; 1065 1066 fPainter->FillRect(r, gradient); 1067 } 1068 1069 1070 void 1071 DrawingEngine::FillRegion(BRegion& r) 1072 { 1073 ASSERT_PARALLEL_LOCKED(); 1074 1075 BRect clipped = fPainter->TransformAndClipRect(r.Frame()); 1076 DrawTransaction transaction(this, clipped); 1077 if (!transaction.IsDirty()) 1078 return; 1079 1080 if (fPainter->IsIdentityTransform()) { 1081 // try hardware optimized version first 1082 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { 1083 if (fPainter->Pattern() == B_SOLID_HIGH 1084 && (fPainter->DrawingMode() == B_OP_COPY 1085 || fPainter->DrawingMode() == B_OP_OVER)) { 1086 r.IntersectWith(fPainter->ClippingRegion()); 1087 fGraphicsCard->FillRegion(r, fPainter->HighColor(), 1088 fSuspendSyncLevel == 0 || transaction.WasOverlaysHidden()); 1089 return; 1090 } else if (fPainter->Pattern() == B_SOLID_LOW 1091 && fPainter->DrawingMode() == B_OP_COPY) { 1092 r.IntersectWith(fPainter->ClippingRegion()); 1093 fGraphicsCard->FillRegion(r, fPainter->LowColor(), 1094 fSuspendSyncLevel == 0 || transaction.WasOverlaysHidden()); 1095 return; 1096 } 1097 } 1098 1099 if ((fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 1100 && fPainter->Pattern() == B_SOLID_HIGH 1101 && fPainter->DrawingMode() == B_OP_INVERT) { 1102 r.IntersectWith(fPainter->ClippingRegion()); 1103 fGraphicsCard->InvertRegion(r); 1104 return; 1105 } 1106 } 1107 1108 int32 count = r.CountRects(); 1109 for (int32 i = 0; i < count; i++) 1110 fPainter->FillRect(r.RectAt(i)); 1111 } 1112 1113 1114 void 1115 DrawingEngine::FillRegion(BRegion& r, const BGradient& gradient) 1116 { 1117 ASSERT_PARALLEL_LOCKED(); 1118 1119 BRect clipped = fPainter->TransformAndClipRect(r.Frame()); 1120 DrawTransaction transaction(this, clipped); 1121 if (!transaction.IsDirty()) 1122 return; 1123 1124 int32 count = r.CountRects(); 1125 for (int32 i = 0; i < count; i++) 1126 fPainter->FillRect(r.RectAt(i), gradient); 1127 } 1128 1129 1130 void 1131 DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, bool filled) 1132 { 1133 ASSERT_PARALLEL_LOCKED(); 1134 1135 make_rect_valid(r); 1136 if (!filled) 1137 extend_by_stroke_width(r, fPainter->PenSize()); 1138 BRect clipped = fPainter->TransformAndClipRect(r); 1139 1140 clipped.left = floorf(clipped.left); 1141 clipped.top = floorf(clipped.top); 1142 clipped.right = ceilf(clipped.right); 1143 clipped.bottom = ceilf(clipped.bottom); 1144 1145 DrawTransaction transaction(this, clipped); 1146 if (!transaction.IsDirty()) 1147 return; 1148 1149 if (filled) 1150 fPainter->FillRoundRect(r, xrad, yrad); 1151 else 1152 fPainter->StrokeRoundRect(r, xrad, yrad); 1153 } 1154 1155 1156 void 1157 DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad, 1158 const BGradient& gradient) 1159 { 1160 ASSERT_PARALLEL_LOCKED(); 1161 1162 make_rect_valid(r); 1163 BRect clipped = fPainter->TransformAndClipRect(r); 1164 1165 clipped.left = floorf(clipped.left); 1166 clipped.top = floorf(clipped.top); 1167 clipped.right = ceilf(clipped.right); 1168 clipped.bottom = ceilf(clipped.bottom); 1169 1170 DrawTransaction transaction(this, clipped); 1171 if (!transaction.IsDirty()) 1172 return; 1173 1174 fPainter->FillRoundRect(r, xrad, yrad, gradient); 1175 } 1176 1177 1178 void 1179 DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, 1180 const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled, 1181 const BPoint& viewToScreenOffset, float viewScale) 1182 { 1183 ASSERT_PARALLEL_LOCKED(); 1184 1185 // TODO: bounds probably does not take curves and arcs into account... 1186 // BRect clipped(bounds); 1187 // if (!filled) 1188 // extend_by_stroke_width(clipped, fPainter->PenSize()); 1189 // clipped = fPainter->TransformAndClipRect(bounds); 1190 // 1191 // clipped.left = floorf(clipped.left); 1192 // clipped.top = floorf(clipped.top); 1193 // clipped.right = ceilf(clipped.right); 1194 // clipped.bottom = ceilf(clipped.bottom); 1195 // 1196 // DrawTransaction transaction(this, clipped); 1197 // if (!transaction.IsDirty()) 1198 // return; 1199 DrawTransaction transaction(this); 1200 1201 transaction.SetDirty(fPainter->DrawShape(opCount, opList, ptCount, ptList, 1202 filled, viewToScreenOffset, viewScale)); 1203 } 1204 1205 1206 void 1207 DrawingEngine::FillShape(const BRect& bounds, int32 opCount, 1208 const uint32* opList, int32 ptCount, const BPoint* ptList, 1209 const BGradient& gradient, const BPoint& viewToScreenOffset, 1210 float viewScale) 1211 { 1212 ASSERT_PARALLEL_LOCKED(); 1213 1214 // TODO: bounds probably does not take curves and arcs into account... 1215 // BRect clipped = fPainter->TransformAndClipRect(bounds); 1216 // 1217 // clipped.left = floorf(clipped.left); 1218 // clipped.top = floorf(clipped.top); 1219 // clipped.right = ceilf(clipped.right); 1220 // clipped.bottom = ceilf(clipped.bottom); 1221 // 1222 // DrawTransaction transaction(this, clipped); 1223 // if (!transaction.IsDirty()) 1224 // return; 1225 DrawTransaction transaction(this); 1226 1227 transaction.SetDirty(fPainter->FillShape(opCount, opList, ptCount, ptList, 1228 gradient, viewToScreenOffset, viewScale)); 1229 } 1230 1231 1232 void 1233 DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, bool filled) 1234 { 1235 ASSERT_PARALLEL_LOCKED(); 1236 1237 BRect clipped(bounds); 1238 if (!filled) 1239 extend_by_stroke_width(clipped, fPainter->PenSize()); 1240 DrawTransaction transaction(this, fPainter->TransformAndClipRect(clipped)); 1241 if (!transaction.IsDirty()) 1242 return; 1243 1244 if (filled) 1245 fPainter->FillTriangle(pts[0], pts[1], pts[2]); 1246 else 1247 fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); 1248 } 1249 1250 1251 void 1252 DrawingEngine::FillTriangle(BPoint* pts, const BRect& bounds, 1253 const BGradient& gradient) 1254 { 1255 ASSERT_PARALLEL_LOCKED(); 1256 1257 DrawTransaction transaction(this, fPainter->TransformAndClipRect(bounds)); 1258 if (!transaction.IsDirty()) 1259 return; 1260 1261 fPainter->FillTriangle(pts[0], pts[1], pts[2], gradient); 1262 } 1263 1264 1265 void 1266 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end) 1267 { 1268 ASSERT_PARALLEL_LOCKED(); 1269 1270 BRect touched(start, end); 1271 make_rect_valid(touched); 1272 extend_by_stroke_width(touched, fPainter->PenSize()); 1273 DrawTransaction transaction(this, fPainter->TransformAndClipRect(touched)); 1274 if (!transaction.IsDirty()) 1275 return; 1276 1277 fPainter->StrokeLine(start, end); 1278 } 1279 1280 1281 void 1282 DrawingEngine::StrokeLineArray(int32 numLines, 1283 const ViewLineArrayInfo *lineData) 1284 { 1285 ASSERT_PARALLEL_LOCKED(); 1286 1287 if (!lineData || numLines <= 0) 1288 return; 1289 1290 // figure out bounding box for line array 1291 const ViewLineArrayInfo* data = (const ViewLineArrayInfo*)&lineData[0]; 1292 BRect touched(min_c(data->startPoint.x, data->endPoint.x), 1293 min_c(data->startPoint.y, data->endPoint.y), 1294 max_c(data->startPoint.x, data->endPoint.x), 1295 max_c(data->startPoint.y, data->endPoint.y)); 1296 1297 for (int32 i = 1; i < numLines; i++) { 1298 data = (const ViewLineArrayInfo*)&lineData[i]; 1299 BRect box(min_c(data->startPoint.x, data->endPoint.x), 1300 min_c(data->startPoint.y, data->endPoint.y), 1301 max_c(data->startPoint.x, data->endPoint.x), 1302 max_c(data->startPoint.y, data->endPoint.y)); 1303 touched = touched | box; 1304 } 1305 extend_by_stroke_width(touched, fPainter->PenSize()); 1306 DrawTransaction transaction(this, fPainter->TransformAndClipRect(touched)); 1307 if (!transaction.IsDirty()) 1308 return; 1309 1310 data = (const ViewLineArrayInfo*)&(lineData[0]); 1311 1312 // store current graphics state, we mess with the 1313 // high color and pattern... 1314 rgb_color oldColor = fPainter->HighColor(); 1315 struct pattern pattern = fPainter->Pattern(); 1316 1317 fPainter->SetHighColor(data->color); 1318 fPainter->SetPattern(B_SOLID_HIGH); 1319 fPainter->StrokeLine(data->startPoint, data->endPoint); 1320 1321 for (int32 i = 1; i < numLines; i++) { 1322 data = (const ViewLineArrayInfo*)&(lineData[i]); 1323 fPainter->SetHighColor(data->color); 1324 fPainter->StrokeLine(data->startPoint, data->endPoint); 1325 } 1326 1327 // restore correct drawing state highcolor and pattern 1328 fPainter->SetHighColor(oldColor); 1329 fPainter->SetPattern(pattern); 1330 } 1331 1332 1333 // #pragma mark - 1334 1335 1336 BPoint 1337 DrawingEngine::DrawString(const char* string, int32 length, 1338 const BPoint& pt, escapement_delta* delta) 1339 { 1340 ASSERT_PARALLEL_LOCKED(); 1341 1342 BPoint penLocation = pt; 1343 1344 // try a fast clipping path 1345 if (fPainter->ClippingRegion() != NULL 1346 && fPainter->Font().Rotation() == 0.0f 1347 && fPainter->IsIdentityTransform()) { 1348 float fontSize = fPainter->Font().Size(); 1349 BRect clippingFrame = fPainter->ClippingRegion()->Frame(); 1350 if (pt.x - fontSize > clippingFrame.right 1351 || pt.y + fontSize < clippingFrame.top 1352 || pt.y - fontSize > clippingFrame.bottom) { 1353 penLocation.x += StringWidth(string, length, delta); 1354 return penLocation; 1355 } 1356 } 1357 1358 // use a FontCacheRefernece to speed up the second pass of 1359 // drawing the string 1360 FontCacheReference cacheReference; 1361 1362 //bigtime_t now = system_time(); 1363 // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. 1364 // Cursiously, the DrawString after it is actually faster!?! 1365 // TODO: make the availability of the hardware cursor part of the 1366 // HW acceleration flags and skip all calculations for HideFloatingOverlays 1367 // in case we don't have one. 1368 // TODO: Watch out about penLocation and use Painter::PenLocation() when 1369 // not using BoundindBox anymore. 1370 BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta, 1371 &cacheReference); 1372 // stop here if we're supposed to render outside of the clipping 1373 DrawTransaction transaction(this, fPainter->ClipRect(b)); 1374 if (transaction.IsDirty()) { 1375 //printf("bounding box '%s': %lld µs\n", string, system_time() - now); 1376 1377 //now = system_time(); 1378 fPainter->DrawString(string, length, pt, delta, &cacheReference); 1379 //printf("drawing string: %lld µs\n", system_time() - now); 1380 } 1381 1382 return penLocation; 1383 } 1384 1385 1386 BPoint 1387 DrawingEngine::DrawString(const char* string, int32 length, 1388 const BPoint* offsets) 1389 { 1390 ASSERT_PARALLEL_LOCKED(); 1391 1392 // use a FontCacheReference to speed up the second pass of 1393 // drawing the string 1394 FontCacheReference cacheReference; 1395 1396 BPoint penLocation; 1397 BRect b = fPainter->BoundingBox(string, length, offsets, &penLocation, 1398 &cacheReference); 1399 // stop here if we're supposed to render outside of the clipping 1400 DrawTransaction transaction(this, fPainter->ClipRect(b)); 1401 if (transaction.IsDirty()) { 1402 //printf("bounding box '%s': %lld µs\n", string, system_time() - now); 1403 1404 //now = system_time(); 1405 fPainter->DrawString(string, length, offsets, &cacheReference); 1406 //printf("drawing string: %lld µs\n", system_time() - now); 1407 } 1408 1409 return penLocation; 1410 } 1411 1412 1413 float 1414 DrawingEngine::StringWidth(const char* string, int32 length, 1415 escapement_delta* delta) 1416 { 1417 return fPainter->StringWidth(string, length, delta); 1418 } 1419 1420 1421 float 1422 DrawingEngine::StringWidth(const char* string, int32 length, 1423 const ServerFont& font, escapement_delta* delta) 1424 { 1425 return font.StringWidth(string, length, delta); 1426 } 1427 1428 1429 BPoint 1430 DrawingEngine::DrawStringDry(const char* string, int32 length, 1431 const BPoint& pt, escapement_delta* delta) 1432 { 1433 ASSERT_PARALLEL_LOCKED(); 1434 1435 BPoint penLocation = pt; 1436 1437 // try a fast path first 1438 if (fPainter->Font().Rotation() == 0.0f 1439 && fPainter->IsIdentityTransform()) { 1440 penLocation.x += StringWidth(string, length, delta); 1441 return penLocation; 1442 } 1443 1444 fPainter->BoundingBox(string, length, pt, &penLocation, delta, NULL); 1445 1446 return penLocation; 1447 } 1448 1449 1450 BPoint 1451 DrawingEngine::DrawStringDry(const char* string, int32 length, 1452 const BPoint* offsets) 1453 { 1454 ASSERT_PARALLEL_LOCKED(); 1455 1456 BPoint penLocation; 1457 fPainter->BoundingBox(string, length, offsets, &penLocation, NULL); 1458 1459 return penLocation; 1460 } 1461 1462 1463 // #pragma mark - 1464 1465 1466 ServerBitmap* 1467 DrawingEngine::DumpToBitmap() 1468 { 1469 return NULL; 1470 } 1471 1472 1473 status_t 1474 DrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, BRect bounds) 1475 { 1476 ASSERT_EXCLUSIVE_LOCKED(); 1477 1478 RenderingBuffer* buffer = fGraphicsCard->FrontBuffer(); 1479 if (buffer == NULL) 1480 return B_ERROR; 1481 1482 BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); 1483 bounds = bounds & clip; 1484 AutoFloatingOverlaysHider _(fGraphicsCard, bounds); 1485 1486 status_t result = bitmap->ImportBits(buffer->Bits(), buffer->BitsLength(), 1487 buffer->BytesPerRow(), buffer->ColorSpace(), 1488 bounds.LeftTop(), BPoint(0, 0), 1489 bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1); 1490 1491 if (drawCursor) { 1492 ServerCursorReference cursorRef = fGraphicsCard->Cursor(); 1493 ServerCursor* cursor = cursorRef.Get(); 1494 if (!cursor) 1495 return result; 1496 int32 cursorWidth = cursor->Width(); 1497 int32 cursorHeight = cursor->Height(); 1498 1499 BPoint cursorPosition = fGraphicsCard->CursorPosition(); 1500 cursorPosition -= bounds.LeftTop() + cursor->GetHotSpot(); 1501 1502 BBitmap cursorArea(BRect(0, 0, cursorWidth - 1, cursorHeight - 1), 1503 B_BITMAP_NO_SERVER_LINK, B_RGBA32); 1504 1505 cursorArea.ImportBits(bitmap->Bits(), bitmap->BitsLength(), 1506 bitmap->BytesPerRow(), bitmap->ColorSpace(), 1507 cursorPosition, BPoint(0, 0), 1508 cursorWidth, cursorHeight); 1509 1510 uint8* bits = (uint8*)cursorArea.Bits(); 1511 uint8* cursorBits = (uint8*)cursor->Bits(); 1512 for (int32 i = 0; i < cursorHeight; i++) { 1513 for (int32 j = 0; j < cursorWidth; j++) { 1514 uint8 alpha = 255 - cursorBits[3]; 1515 bits[0] = ((bits[0] * alpha) >> 8) + cursorBits[0]; 1516 bits[1] = ((bits[1] * alpha) >> 8) + cursorBits[1]; 1517 bits[2] = ((bits[2] * alpha) >> 8) + cursorBits[2]; 1518 cursorBits += 4; 1519 bits += 4; 1520 } 1521 } 1522 1523 bitmap->ImportBits(cursorArea.Bits(), cursorArea.BitsLength(), 1524 cursorArea.BytesPerRow(), cursorArea.ColorSpace(), 1525 BPoint(0, 0), cursorPosition, 1526 cursorWidth, cursorHeight); 1527 } 1528 1529 return result; 1530 } 1531 1532 1533 // #pragma mark - 1534 1535 1536 BRect 1537 DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 yOffset) const 1538 { 1539 // TODO: assumes drawing buffer is 32 bits (which it currently always is) 1540 BRect dst; 1541 RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); 1542 if (buffer) { 1543 BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); 1544 1545 dst = src; 1546 dst.OffsetBy(xOffset, yOffset); 1547 1548 if (clip.Intersects(src) && clip.Intersects(dst)) { 1549 uint32 bytesPerRow = buffer->BytesPerRow(); 1550 uint8* bits = (uint8*)buffer->Bits(); 1551 1552 // clip source rect 1553 src = src & clip; 1554 // clip dest rect 1555 dst = dst & clip; 1556 // move dest back over source and clip source to dest 1557 dst.OffsetBy(-xOffset, -yOffset); 1558 src = src & dst; 1559 1560 // calc offset in buffer 1561 bits += (ssize_t)src.left * 4 + (ssize_t)src.top * bytesPerRow; 1562 1563 uint32 width = src.IntegerWidth() + 1; 1564 uint32 height = src.IntegerHeight() + 1; 1565 1566 _CopyRect(buffer->IsGraphicsMemory(), bits, width, height, bytesPerRow, 1567 xOffset, yOffset); 1568 1569 // offset dest again, because it is return value 1570 dst.OffsetBy(xOffset, yOffset); 1571 } 1572 } 1573 return dst; 1574 } 1575 1576 1577 void 1578 DrawingEngine::SetRendererOffset(int32 offsetX, int32 offsetY) 1579 { 1580 fPainter->SetRendererOffset(offsetX, offsetY); 1581 } 1582 1583 1584 void 1585 DrawingEngine::_CopyRect(bool isGraphicsMemory, uint8* src, uint32 width, uint32 height, 1586 uint32 bytesPerRow, int32 xOffset, int32 yOffset) const 1587 { 1588 // TODO: assumes drawing buffer is 32 bits (which it currently always is) 1589 int32 yIncrement; 1590 const bool needMemmove = (yOffset == 0 && xOffset > 0 && uint32(xOffset) <= width); 1591 1592 if (yOffset > 0) { 1593 // copy from bottom to top 1594 yIncrement = -bytesPerRow; 1595 src += (height - 1) * bytesPerRow; 1596 } else { 1597 // copy from top to bottom 1598 yIncrement = bytesPerRow; 1599 } 1600 1601 uint8* dst = src + (ssize_t)yOffset * bytesPerRow + (ssize_t)xOffset * 4; 1602 1603 if (!needMemmove) { 1604 if (!isGraphicsMemory) { 1605 // NOTE: this (instead of the two pass copy below) might 1606 // speed up QEMU -> ?!? (would depend on how it emulates 1607 // the PCI bus...) 1608 for (uint32 y = 0; y < height; y++) { 1609 memcpy(dst, src, width * 4); 1610 src += yIncrement; 1611 dst += yIncrement; 1612 } 1613 } else { 1614 uint8 tmpBuffer[width * 4]; 1615 for (uint32 y = 0; y < height; y++) { 1616 // NOTE: read into temporary scanline buffer, 1617 // NOTE: **don't read and write over the PCI bus 1618 // at the same time** 1619 memcpy(tmpBuffer, src, width * 4); 1620 // write back temporary scanline buffer 1621 memcpy(dst, tmpBuffer, width * 4); 1622 src += yIncrement; 1623 dst += yIncrement; 1624 } 1625 } 1626 } else { 1627 for (uint32 y = 0; y < height; y++) { 1628 memmove(dst, src, width * 4); 1629 src += yIncrement; 1630 dst += yIncrement; 1631 } 1632 } 1633 } 1634