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