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