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