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