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