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 BRect clipped(r); 653 654 if (!filled) 655 extend_by_stroke_width(clipped, fPainter->PenSize()); 656 657 clipped = fPainter->TransformAndClipRect(r); 658 659 if (clipped.IsValid()) { 660 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 661 662 float xRadius = r.Width() / 2.0; 663 float yRadius = r.Height() / 2.0; 664 BPoint center(r.left + xRadius, 665 r.top + yRadius); 666 667 if (filled) 668 fPainter->FillArc(center, xRadius, yRadius, angle, span); 669 else 670 fPainter->StrokeArc(center, xRadius, yRadius, angle, span); 671 672 _CopyToFront(clipped); 673 } 674 } 675 676 677 void 678 DrawingEngine::FillArc(BRect r, const float& angle, const float& span, 679 const BGradient& gradient) 680 { 681 ASSERT_PARALLEL_LOCKED(); 682 683 make_rect_valid(r); 684 fPainter->AlignEllipseRect(&r, true); 685 BRect clipped(r); 686 687 clipped = fPainter->TransformAndClipRect(r); 688 689 if (clipped.IsValid()) { 690 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 691 692 float xRadius = r.Width() / 2.0; 693 float yRadius = r.Height() / 2.0; 694 BPoint center(r.left + xRadius, 695 r.top + yRadius); 696 697 fPainter->FillArc(center, xRadius, yRadius, angle, span, gradient); 698 699 _CopyToFront(clipped); 700 } 701 } 702 703 704 void 705 DrawingEngine::DrawBezier(BPoint* pts, bool filled) 706 { 707 ASSERT_PARALLEL_LOCKED(); 708 709 // TODO: figure out bounds and hide cursor depending on that 710 AutoFloatingOverlaysHider _(fGraphicsCard); 711 712 BRect touched = fPainter->DrawBezier(pts, filled); 713 714 _CopyToFront(touched); 715 } 716 717 718 void 719 DrawingEngine::FillBezier(BPoint* pts, const BGradient& gradient) 720 { 721 ASSERT_PARALLEL_LOCKED(); 722 723 // TODO: figure out bounds and hide cursor depending on that 724 AutoFloatingOverlaysHider _(fGraphicsCard); 725 726 BRect touched = fPainter->FillBezier(pts, gradient); 727 728 _CopyToFront(touched); 729 } 730 731 732 void 733 DrawingEngine::DrawEllipse(BRect r, bool filled) 734 { 735 ASSERT_PARALLEL_LOCKED(); 736 737 make_rect_valid(r); 738 BRect clipped = r; 739 fPainter->AlignEllipseRect(&clipped, filled); 740 741 if (!filled) 742 extend_by_stroke_width(clipped, fPainter->PenSize()); 743 744 clipped.left = floorf(clipped.left); 745 clipped.top = floorf(clipped.top); 746 clipped.right = ceilf(clipped.right); 747 clipped.bottom = ceilf(clipped.bottom); 748 749 clipped = fPainter->TransformAndClipRect(clipped); 750 751 if (clipped.IsValid()) { 752 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 753 754 fPainter->DrawEllipse(r, filled); 755 756 _CopyToFront(clipped); 757 } 758 } 759 760 761 void 762 DrawingEngine::FillEllipse(BRect r, const BGradient& gradient) 763 { 764 ASSERT_PARALLEL_LOCKED(); 765 766 make_rect_valid(r); 767 BRect clipped = r; 768 fPainter->AlignEllipseRect(&clipped, true); 769 770 clipped.left = floorf(clipped.left); 771 clipped.top = floorf(clipped.top); 772 clipped.right = ceilf(clipped.right); 773 clipped.bottom = ceilf(clipped.bottom); 774 775 clipped = fPainter->TransformAndClipRect(clipped); 776 777 if (clipped.IsValid()) { 778 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 779 780 fPainter->FillEllipse(r, gradient); 781 782 _CopyToFront(clipped); 783 } 784 } 785 786 787 void 788 DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, BRect bounds, 789 bool filled, bool closed) 790 { 791 ASSERT_PARALLEL_LOCKED(); 792 793 make_rect_valid(bounds); 794 if (!filled) 795 extend_by_stroke_width(bounds, fPainter->PenSize()); 796 bounds = fPainter->TransformAndClipRect(bounds); 797 if (bounds.IsValid()) { 798 AutoFloatingOverlaysHider _(fGraphicsCard, bounds); 799 800 fPainter->DrawPolygon(ptlist, numpts, filled, closed); 801 802 _CopyToFront(bounds); 803 } 804 } 805 806 807 void 808 DrawingEngine::FillPolygon(BPoint* ptlist, int32 numpts, BRect bounds, 809 const BGradient& gradient, bool closed) 810 { 811 ASSERT_PARALLEL_LOCKED(); 812 813 make_rect_valid(bounds); 814 bounds = fPainter->TransformAndClipRect(bounds); 815 if (bounds.IsValid()) { 816 AutoFloatingOverlaysHider _(fGraphicsCard, bounds); 817 818 fPainter->FillPolygon(ptlist, numpts, gradient, closed); 819 820 _CopyToFront(bounds); 821 } 822 } 823 824 825 // #pragma mark - rgb_color 826 827 828 void 829 DrawingEngine::StrokePoint(const BPoint& pt, const rgb_color& color) 830 { 831 StrokeLine(pt, pt, color); 832 } 833 834 835 /*! This function is only used by Decorators, 836 it assumes a one pixel wide line 837 */ 838 void 839 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end, 840 const rgb_color& color) 841 { 842 ASSERT_PARALLEL_LOCKED(); 843 844 BRect touched(start, end); 845 make_rect_valid(touched); 846 touched = fPainter->ClipRect(touched); 847 AutoFloatingOverlaysHider _(fGraphicsCard, touched); 848 849 if (!fPainter->StraightLine(start, end, color)) { 850 rgb_color previousColor = fPainter->HighColor(); 851 drawing_mode previousMode = fPainter->DrawingMode(); 852 853 fPainter->SetHighColor(color); 854 fPainter->SetDrawingMode(B_OP_OVER); 855 fPainter->StrokeLine(start, end); 856 857 fPainter->SetDrawingMode(previousMode); 858 fPainter->SetHighColor(previousColor); 859 } 860 861 _CopyToFront(touched); 862 } 863 864 865 //! This function is used to draw a one pixel wide rect 866 void 867 DrawingEngine::StrokeRect(BRect r, const rgb_color& color) 868 { 869 ASSERT_PARALLEL_LOCKED(); 870 871 make_rect_valid(r); 872 BRect clipped = fPainter->ClipRect(r); 873 if (clipped.IsValid()) { 874 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 875 876 fPainter->StrokeRect(r, color); 877 878 _CopyToFront(clipped); 879 } 880 } 881 882 883 void 884 DrawingEngine::FillRect(BRect r, const rgb_color& color) 885 { 886 ASSERT_PARALLEL_LOCKED(); 887 888 // NOTE: Write locking because we might use HW acceleration. 889 // This needs to be investigated, I'm doing this because of 890 // gut feeling. 891 make_rect_valid(r); 892 r = fPainter->ClipRect(r); 893 if (!r.IsValid()) 894 return; 895 896 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r); 897 898 // try hardware optimized version first 899 if (fAvailableHWAccleration & HW_ACC_FILL_REGION) { 900 BRegion region(r); 901 region.IntersectWith(fPainter->ClippingRegion()); 902 fGraphicsCard->FillRegion(region, color, 903 fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); 904 } else { 905 fPainter->FillRect(r, color); 906 } 907 908 _CopyToFront(r); 909 } 910 911 912 void 913 DrawingEngine::FillRegion(BRegion& r, const rgb_color& color) 914 { 915 ASSERT_PARALLEL_LOCKED(); 916 917 // NOTE: region expected to be already clipped correctly!! 918 BRect frame = r.Frame(); 919 if (!fPainter->Bounds().Contains(frame)) { 920 // NOTE: I am not quite sure yet how this can happen, but apparently it 921 // can (see bug #634). 922 // This function is used for internal app_server painting, in the case of 923 // bug #634, the background of views is painted. But the view region 924 // should never be outside the frame buffer bounds. 925 // char message[1024]; 926 // BRect bounds = fPainter->Bounds(); 927 // sprintf(message, "FillRegion() - painter: (%d, %d)->(%d, %d), region: (%d, %d)->(%d, %d)", 928 // (int)bounds.left, (int)bounds.top, (int)bounds.right, (int)bounds.bottom, 929 // (int)frame.left, (int)frame.top, (int)frame.right, (int)frame.bottom); 930 // debugger(message); 931 return; 932 } 933 934 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, frame); 935 936 // try hardware optimized version first 937 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0 938 && frame.Width() * frame.Height() > 100) { 939 fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0 940 || overlaysHider.WasHidden()); 941 } else { 942 int32 count = r.CountRects(); 943 for (int32 i = 0; i < count; i++) 944 fPainter->FillRectNoClipping(r.RectAtInt(i), color); 945 } 946 947 _CopyToFront(frame); 948 } 949 950 951 // #pragma mark - DrawState 952 953 954 void 955 DrawingEngine::StrokeRect(BRect r) 956 { 957 ASSERT_PARALLEL_LOCKED(); 958 959 // support invalid rects 960 make_rect_valid(r); 961 BRect clipped(r); 962 extend_by_stroke_width(clipped, fPainter->PenSize()); 963 clipped = fPainter->TransformAndClipRect(clipped); 964 if (clipped.IsValid()) { 965 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 966 967 fPainter->StrokeRect(r); 968 969 _CopyToFront(clipped); 970 } 971 } 972 973 974 void 975 DrawingEngine::FillRect(BRect r) 976 { 977 ASSERT_PARALLEL_LOCKED(); 978 979 make_rect_valid(r); 980 981 r = fPainter->AlignRect(r); 982 983 BRect dirty = fPainter->TransformAndClipRect(r); 984 if (!dirty.IsValid()) 985 return; 986 987 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, dirty); 988 989 bool doInSoftware = true; 990 991 if (fPainter->IsIdentityTransform()) { 992 // TODO the accelerated code path may also be used for transforms that 993 // only scale and translate (but don't shear or rotate). 994 995 if ((r.Width() + 1) * (r.Height() + 1) > 100.0) { 996 // try hardware optimized version first 997 // if the rect is large enough 998 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { 999 if (fPainter->Pattern() == B_SOLID_HIGH 1000 && (fPainter->DrawingMode() == B_OP_COPY 1001 || fPainter->DrawingMode() == B_OP_OVER)) { 1002 BRegion region(r); 1003 region.IntersectWith(fPainter->ClippingRegion()); 1004 fGraphicsCard->FillRegion(region, fPainter->HighColor(), 1005 fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); 1006 doInSoftware = false; 1007 } else if (fPainter->Pattern() == B_SOLID_LOW 1008 && fPainter->DrawingMode() == B_OP_COPY) { 1009 BRegion region(r); 1010 region.IntersectWith(fPainter->ClippingRegion()); 1011 fGraphicsCard->FillRegion(region, fPainter->LowColor(), 1012 fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); 1013 doInSoftware = false; 1014 } 1015 } 1016 } 1017 1018 if (doInSoftware 1019 && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 1020 && fPainter->Pattern() == B_SOLID_HIGH 1021 && fPainter->DrawingMode() == B_OP_INVERT) { 1022 BRegion region(r); 1023 region.IntersectWith(fPainter->ClippingRegion()); 1024 fGraphicsCard->InvertRegion(region); 1025 doInSoftware = false; 1026 } 1027 } 1028 1029 if (doInSoftware) 1030 fPainter->FillRect(r); 1031 1032 _CopyToFront(dirty); 1033 } 1034 1035 1036 void 1037 DrawingEngine::FillRect(BRect r, const BGradient& gradient) 1038 { 1039 ASSERT_PARALLEL_LOCKED(); 1040 1041 make_rect_valid(r); 1042 r = fPainter->AlignRect(r); 1043 1044 BRect dirty = fPainter->TransformAndClipRect(r); 1045 if (!dirty.IsValid()) 1046 return; 1047 1048 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, dirty); 1049 1050 fPainter->FillRect(r, gradient); 1051 1052 _CopyToFront(dirty); 1053 } 1054 1055 1056 void 1057 DrawingEngine::FillRegion(BRegion& r) 1058 { 1059 ASSERT_PARALLEL_LOCKED(); 1060 1061 BRect clipped = fPainter->TransformAndClipRect(r.Frame()); 1062 if (!clipped.IsValid()) 1063 return; 1064 1065 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped); 1066 1067 bool doInSoftware = true; 1068 1069 if (fPainter->IsIdentityTransform()) { 1070 // try hardware optimized version first 1071 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { 1072 if (fPainter->Pattern() == B_SOLID_HIGH 1073 && (fPainter->DrawingMode() == B_OP_COPY 1074 || fPainter->DrawingMode() == B_OP_OVER)) { 1075 r.IntersectWith(fPainter->ClippingRegion()); 1076 fGraphicsCard->FillRegion(r, fPainter->HighColor(), 1077 fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); 1078 doInSoftware = false; 1079 } else if (fPainter->Pattern() == B_SOLID_LOW 1080 && fPainter->DrawingMode() == B_OP_COPY) { 1081 r.IntersectWith(fPainter->ClippingRegion()); 1082 fGraphicsCard->FillRegion(r, fPainter->LowColor(), 1083 fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); 1084 doInSoftware = false; 1085 } 1086 } 1087 1088 if (doInSoftware 1089 && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 1090 && fPainter->Pattern() == B_SOLID_HIGH 1091 && fPainter->DrawingMode() == B_OP_INVERT) { 1092 r.IntersectWith(fPainter->ClippingRegion()); 1093 fGraphicsCard->InvertRegion(r); 1094 doInSoftware = false; 1095 } 1096 } 1097 1098 if (doInSoftware) { 1099 BRect touched = fPainter->FillRect(r.RectAt(0)); 1100 1101 int32 count = r.CountRects(); 1102 for (int32 i = 1; i < count; i++) 1103 touched = touched | fPainter->FillRect(r.RectAt(i)); 1104 } 1105 1106 _CopyToFront(r.Frame()); 1107 } 1108 1109 1110 void 1111 DrawingEngine::FillRegion(BRegion& r, const BGradient& gradient) 1112 { 1113 ASSERT_PARALLEL_LOCKED(); 1114 1115 BRect clipped = fPainter->TransformAndClipRect(r.Frame()); 1116 if (!clipped.IsValid()) 1117 return; 1118 1119 AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, clipped); 1120 1121 BRect touched = fPainter->FillRect(r.RectAt(0), gradient); 1122 1123 int32 count = r.CountRects(); 1124 for (int32 i = 1; i < count; i++) 1125 touched = touched | fPainter->FillRect(r.RectAt(i), gradient); 1126 1127 _CopyToFront(r.Frame()); 1128 } 1129 1130 1131 void 1132 DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, bool filled) 1133 { 1134 ASSERT_PARALLEL_LOCKED(); 1135 1136 make_rect_valid(r); 1137 if (!filled) 1138 extend_by_stroke_width(r, fPainter->PenSize()); 1139 BRect clipped = fPainter->TransformAndClipRect(r); 1140 1141 clipped.left = floorf(clipped.left); 1142 clipped.top = floorf(clipped.top); 1143 clipped.right = ceilf(clipped.right); 1144 clipped.bottom = ceilf(clipped.bottom); 1145 1146 if (clipped.IsValid()) { 1147 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1148 1149 BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad) 1150 : fPainter->StrokeRoundRect(r, xrad, yrad); 1151 1152 _CopyToFront(touched); 1153 } 1154 } 1155 1156 1157 void 1158 DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad, 1159 const BGradient& gradient) 1160 { 1161 ASSERT_PARALLEL_LOCKED(); 1162 1163 make_rect_valid(r); 1164 BRect clipped = fPainter->TransformAndClipRect(r); 1165 1166 clipped.left = floorf(clipped.left); 1167 clipped.top = floorf(clipped.top); 1168 clipped.right = ceilf(clipped.right); 1169 clipped.bottom = ceilf(clipped.bottom); 1170 1171 if (clipped.IsValid()) { 1172 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1173 1174 BRect touched = fPainter->FillRoundRect(r, xrad, yrad, gradient); 1175 1176 _CopyToFront(touched); 1177 } 1178 } 1179 1180 1181 void 1182 DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, 1183 const uint32* opList, int32 ptCount, const BPoint* ptList, bool filled, 1184 const BPoint& viewToScreenOffset, float viewScale) 1185 { 1186 ASSERT_PARALLEL_LOCKED(); 1187 1188 // TODO: bounds probably does not take curves and arcs into account... 1189 // BRect clipped(bounds); 1190 // if (!filled) 1191 // extend_by_stroke_width(clipped, fPainter->PenSize()); 1192 // clipped = fPainter->TransformAndClipRect(bounds); 1193 // 1194 // clipped.left = floorf(clipped.left); 1195 // clipped.top = floorf(clipped.top); 1196 // clipped.right = ceilf(clipped.right); 1197 // clipped.bottom = ceilf(clipped.bottom); 1198 // 1199 // if (!clipped.IsValid()) 1200 // return; 1201 // 1202 // AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1203 AutoFloatingOverlaysHider _(fGraphicsCard); 1204 1205 BRect touched = fPainter->DrawShape(opCount, opList, ptCount, ptList, 1206 filled, viewToScreenOffset, viewScale); 1207 1208 _CopyToFront(touched); 1209 } 1210 1211 1212 void 1213 DrawingEngine::FillShape(const BRect& bounds, int32 opCount, 1214 const uint32* opList, int32 ptCount, const BPoint* ptList, 1215 const BGradient& gradient, const BPoint& viewToScreenOffset, 1216 float viewScale) 1217 { 1218 ASSERT_PARALLEL_LOCKED(); 1219 1220 // TODO: bounds probably does not take curves and arcs into account... 1221 // BRect clipped = fPainter->TransformAndClipRect(bounds); 1222 // 1223 // clipped.left = floorf(clipped.left); 1224 // clipped.top = floorf(clipped.top); 1225 // clipped.right = ceilf(clipped.right); 1226 // clipped.bottom = ceilf(clipped.bottom); 1227 // 1228 // if (!clipped.IsValid()) 1229 // return; 1230 // 1231 // AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1232 AutoFloatingOverlaysHider _(fGraphicsCard); 1233 1234 BRect touched = fPainter->FillShape(opCount, opList, ptCount, ptList, 1235 gradient, viewToScreenOffset, viewScale); 1236 1237 _CopyToFront(touched); 1238 } 1239 1240 1241 void 1242 DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, bool filled) 1243 { 1244 ASSERT_PARALLEL_LOCKED(); 1245 1246 BRect clipped(bounds); 1247 if (!filled) 1248 extend_by_stroke_width(clipped, fPainter->PenSize()); 1249 clipped = fPainter->TransformAndClipRect(clipped); 1250 if (clipped.IsValid()) { 1251 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1252 1253 if (filled) 1254 fPainter->FillTriangle(pts[0], pts[1], pts[2]); 1255 else 1256 fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); 1257 1258 _CopyToFront(clipped); 1259 } 1260 } 1261 1262 1263 void 1264 DrawingEngine::FillTriangle(BPoint* pts, const BRect& bounds, 1265 const BGradient& gradient) 1266 { 1267 ASSERT_PARALLEL_LOCKED(); 1268 1269 BRect clipped(bounds); 1270 clipped = fPainter->TransformAndClipRect(clipped); 1271 if (clipped.IsValid()) { 1272 AutoFloatingOverlaysHider _(fGraphicsCard, clipped); 1273 1274 fPainter->FillTriangle(pts[0], pts[1], pts[2], gradient); 1275 1276 _CopyToFront(clipped); 1277 } 1278 } 1279 1280 1281 void 1282 DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end) 1283 { 1284 ASSERT_PARALLEL_LOCKED(); 1285 1286 BRect touched(start, end); 1287 make_rect_valid(touched); 1288 extend_by_stroke_width(touched, fPainter->PenSize()); 1289 touched = fPainter->TransformAndClipRect(touched); 1290 if (touched.IsValid()) { 1291 AutoFloatingOverlaysHider _(fGraphicsCard, touched); 1292 1293 fPainter->StrokeLine(start, end); 1294 1295 _CopyToFront(touched); 1296 } 1297 } 1298 1299 1300 void 1301 DrawingEngine::StrokeLineArray(int32 numLines, 1302 const ViewLineArrayInfo *lineData) 1303 { 1304 ASSERT_PARALLEL_LOCKED(); 1305 1306 if (!lineData || numLines <= 0) 1307 return; 1308 1309 // figure out bounding box for line array 1310 const ViewLineArrayInfo* data = (const ViewLineArrayInfo*)&lineData[0]; 1311 BRect touched(min_c(data->startPoint.x, data->endPoint.x), 1312 min_c(data->startPoint.y, data->endPoint.y), 1313 max_c(data->startPoint.x, data->endPoint.x), 1314 max_c(data->startPoint.y, data->endPoint.y)); 1315 1316 for (int32 i = 1; i < numLines; i++) { 1317 data = (const ViewLineArrayInfo*)&lineData[i]; 1318 BRect box(min_c(data->startPoint.x, data->endPoint.x), 1319 min_c(data->startPoint.y, data->endPoint.y), 1320 max_c(data->startPoint.x, data->endPoint.x), 1321 max_c(data->startPoint.y, data->endPoint.y)); 1322 touched = touched | box; 1323 } 1324 extend_by_stroke_width(touched, fPainter->PenSize()); 1325 touched = fPainter->TransformAndClipRect(touched); 1326 if (touched.IsValid()) { 1327 AutoFloatingOverlaysHider _(fGraphicsCard, touched); 1328 1329 data = (const ViewLineArrayInfo*)&(lineData[0]); 1330 1331 // store current graphics state, we mess with the 1332 // high color and pattern... 1333 rgb_color oldColor = fPainter->HighColor(); 1334 struct pattern pattern = fPainter->Pattern(); 1335 1336 fPainter->SetHighColor(data->color); 1337 fPainter->SetPattern(B_SOLID_HIGH); 1338 fPainter->StrokeLine(data->startPoint, data->endPoint); 1339 1340 for (int32 i = 1; i < numLines; i++) { 1341 data = (const ViewLineArrayInfo*)&(lineData[i]); 1342 fPainter->SetHighColor(data->color); 1343 fPainter->StrokeLine(data->startPoint, data->endPoint); 1344 } 1345 1346 // restore correct drawing state highcolor and pattern 1347 fPainter->SetHighColor(oldColor); 1348 fPainter->SetPattern(pattern); 1349 1350 _CopyToFront(touched); 1351 } 1352 } 1353 1354 1355 // #pragma mark - 1356 1357 1358 BPoint 1359 DrawingEngine::DrawString(const char* string, int32 length, 1360 const BPoint& pt, escapement_delta* delta) 1361 { 1362 ASSERT_PARALLEL_LOCKED(); 1363 1364 BPoint penLocation = pt; 1365 1366 // try a fast clipping path 1367 if (fPainter->ClippingRegion() != NULL 1368 && fPainter->Font().Rotation() == 0.0f 1369 && fPainter->IsIdentityTransform()) { 1370 float fontSize = fPainter->Font().Size(); 1371 BRect clippingFrame = fPainter->ClippingRegion()->Frame(); 1372 if (pt.x - fontSize > clippingFrame.right 1373 || pt.y + fontSize < clippingFrame.top 1374 || pt.y - fontSize > clippingFrame.bottom) { 1375 penLocation.x += StringWidth(string, length, delta); 1376 return penLocation; 1377 } 1378 } 1379 1380 // use a FontCacheRefernece to speed up the second pass of 1381 // drawing the string 1382 FontCacheReference cacheReference; 1383 1384 //bigtime_t now = system_time(); 1385 // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. 1386 // Cursiously, the DrawString after it is actually faster!?! 1387 // TODO: make the availability of the hardware cursor part of the 1388 // HW acceleration flags and skip all calculations for HideFloatingOverlays 1389 // in case we don't have one. 1390 // TODO: Watch out about penLocation and use Painter::PenLocation() when 1391 // not using BoundindBox anymore. 1392 BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta, 1393 &cacheReference); 1394 // stop here if we're supposed to render outside of the clipping 1395 b = fPainter->ClipRect(b); 1396 if (b.IsValid()) { 1397 //printf("bounding box '%s': %lld µs\n", string, system_time() - now); 1398 AutoFloatingOverlaysHider _(fGraphicsCard, b); 1399 1400 //now = system_time(); 1401 BRect touched = fPainter->DrawString(string, length, pt, delta, 1402 &cacheReference); 1403 //printf("drawing string: %lld µs\n", system_time() - now); 1404 1405 _CopyToFront(touched); 1406 } 1407 1408 return penLocation; 1409 } 1410 1411 1412 BPoint 1413 DrawingEngine::DrawString(const char* string, int32 length, 1414 const BPoint* offsets) 1415 { 1416 ASSERT_PARALLEL_LOCKED(); 1417 1418 // use a FontCacheReference to speed up the second pass of 1419 // drawing the string 1420 FontCacheReference cacheReference; 1421 1422 BPoint penLocation; 1423 BRect b = fPainter->BoundingBox(string, length, offsets, &penLocation, 1424 &cacheReference); 1425 // stop here if we're supposed to render outside of the clipping 1426 b = fPainter->ClipRect(b); 1427 if (b.IsValid()) { 1428 //printf("bounding box '%s': %lld µs\n", string, system_time() - now); 1429 AutoFloatingOverlaysHider _(fGraphicsCard, b); 1430 1431 //now = system_time(); 1432 BRect touched = fPainter->DrawString(string, length, offsets, 1433 &cacheReference); 1434 //printf("drawing string: %lld µs\n", system_time() - now); 1435 1436 _CopyToFront(touched); 1437 } 1438 1439 return penLocation; 1440 } 1441 1442 1443 float 1444 DrawingEngine::StringWidth(const char* string, int32 length, 1445 escapement_delta* delta) 1446 { 1447 return fPainter->StringWidth(string, length, delta); 1448 } 1449 1450 1451 float 1452 DrawingEngine::StringWidth(const char* string, int32 length, 1453 const ServerFont& font, escapement_delta* delta) 1454 { 1455 return font.StringWidth(string, length, delta); 1456 } 1457 1458 1459 BPoint 1460 DrawingEngine::DrawStringDry(const char* string, int32 length, 1461 const BPoint& pt, escapement_delta* delta) 1462 { 1463 ASSERT_PARALLEL_LOCKED(); 1464 1465 BPoint penLocation = pt; 1466 1467 // try a fast path first 1468 if (fPainter->Font().Rotation() == 0.0f 1469 && fPainter->IsIdentityTransform()) { 1470 penLocation.x += StringWidth(string, length, delta); 1471 return penLocation; 1472 } 1473 1474 fPainter->BoundingBox(string, length, pt, &penLocation, delta, NULL); 1475 1476 return penLocation; 1477 } 1478 1479 1480 BPoint 1481 DrawingEngine::DrawStringDry(const char* string, int32 length, 1482 const BPoint* offsets) 1483 { 1484 ASSERT_PARALLEL_LOCKED(); 1485 1486 BPoint penLocation; 1487 fPainter->BoundingBox(string, length, offsets, &penLocation, NULL); 1488 1489 return penLocation; 1490 } 1491 1492 1493 // #pragma mark - 1494 1495 1496 ServerBitmap* 1497 DrawingEngine::DumpToBitmap() 1498 { 1499 return NULL; 1500 } 1501 1502 1503 status_t 1504 DrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, BRect bounds) 1505 { 1506 ASSERT_EXCLUSIVE_LOCKED(); 1507 1508 RenderingBuffer* buffer = fGraphicsCard->FrontBuffer(); 1509 if (buffer == NULL) 1510 return B_ERROR; 1511 1512 BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); 1513 bounds = bounds & clip; 1514 AutoFloatingOverlaysHider _(fGraphicsCard, bounds); 1515 1516 status_t result = bitmap->ImportBits(buffer->Bits(), buffer->BitsLength(), 1517 buffer->BytesPerRow(), buffer->ColorSpace(), 1518 bounds.LeftTop(), BPoint(0, 0), 1519 bounds.IntegerWidth() + 1, bounds.IntegerHeight() + 1); 1520 1521 if (drawCursor) { 1522 ServerCursorReference cursorRef = fGraphicsCard->Cursor(); 1523 ServerCursor* cursor = cursorRef.Get(); 1524 if (!cursor) 1525 return result; 1526 int32 cursorWidth = cursor->Width(); 1527 int32 cursorHeight = cursor->Height(); 1528 1529 BPoint cursorPosition = fGraphicsCard->CursorPosition(); 1530 cursorPosition -= bounds.LeftTop() + cursor->GetHotSpot(); 1531 1532 BBitmap cursorArea(BRect(0, 0, cursorWidth - 1, cursorHeight - 1), 1533 B_BITMAP_NO_SERVER_LINK, B_RGBA32); 1534 1535 cursorArea.ImportBits(bitmap->Bits(), bitmap->BitsLength(), 1536 bitmap->BytesPerRow(), bitmap->ColorSpace(), 1537 cursorPosition, BPoint(0, 0), 1538 cursorWidth, cursorHeight); 1539 1540 uint8* bits = (uint8*)cursorArea.Bits(); 1541 uint8* cursorBits = (uint8*)cursor->Bits(); 1542 for (int32 i = 0; i < cursorHeight; i++) { 1543 for (int32 j = 0; j < cursorWidth; j++) { 1544 uint8 alpha = 255 - cursorBits[3]; 1545 bits[0] = ((bits[0] * alpha) >> 8) + cursorBits[0]; 1546 bits[1] = ((bits[1] * alpha) >> 8) + cursorBits[1]; 1547 bits[2] = ((bits[2] * alpha) >> 8) + cursorBits[2]; 1548 cursorBits += 4; 1549 bits += 4; 1550 } 1551 } 1552 1553 bitmap->ImportBits(cursorArea.Bits(), cursorArea.BitsLength(), 1554 cursorArea.BytesPerRow(), cursorArea.ColorSpace(), 1555 BPoint(0, 0), cursorPosition, 1556 cursorWidth, cursorHeight); 1557 } 1558 1559 return result; 1560 } 1561 1562 1563 // #pragma mark - 1564 1565 1566 BRect 1567 DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 yOffset) const 1568 { 1569 // TODO: assumes drawing buffer is 32 bits (which it currently always is) 1570 BRect dst; 1571 RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); 1572 if (buffer) { 1573 BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); 1574 1575 dst = src; 1576 dst.OffsetBy(xOffset, yOffset); 1577 1578 if (clip.Intersects(src) && clip.Intersects(dst)) { 1579 uint32 bytesPerRow = buffer->BytesPerRow(); 1580 uint8* bits = (uint8*)buffer->Bits(); 1581 1582 // clip source rect 1583 src = src & clip; 1584 // clip dest rect 1585 dst = dst & clip; 1586 // move dest back over source and clip source to dest 1587 dst.OffsetBy(-xOffset, -yOffset); 1588 src = src & dst; 1589 1590 // calc offset in buffer 1591 bits += (ssize_t)src.left * 4 + (ssize_t)src.top * bytesPerRow; 1592 1593 uint32 width = src.IntegerWidth() + 1; 1594 uint32 height = src.IntegerHeight() + 1; 1595 1596 _CopyRect(bits, width, height, bytesPerRow, xOffset, yOffset); 1597 1598 // offset dest again, because it is return value 1599 dst.OffsetBy(xOffset, yOffset); 1600 } 1601 } 1602 return dst; 1603 } 1604 1605 1606 void 1607 DrawingEngine::SetRendererOffset(int32 offsetX, int32 offsetY) 1608 { 1609 fPainter->SetRendererOffset(offsetX, offsetY); 1610 } 1611 1612 1613 void 1614 DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height, 1615 uint32 bytesPerRow, int32 xOffset, int32 yOffset) const 1616 { 1617 // TODO: assumes drawing buffer is 32 bits (which it currently always is) 1618 int32 xIncrement; 1619 int32 yIncrement; 1620 1621 if (yOffset == 0 && xOffset > 0) { 1622 // copy from right to left 1623 xIncrement = -1; 1624 src += (width - 1) * 4; 1625 } else { 1626 // copy from left to right 1627 xIncrement = 1; 1628 } 1629 1630 if (yOffset > 0) { 1631 // copy from bottom to top 1632 yIncrement = -bytesPerRow; 1633 src += (height - 1) * bytesPerRow; 1634 } else { 1635 // copy from top to bottom 1636 yIncrement = bytesPerRow; 1637 } 1638 1639 uint8* dst = src + (ssize_t)yOffset * bytesPerRow + (ssize_t)xOffset * 4; 1640 1641 if (xIncrement == 1) { 1642 uint8 tmpBuffer[width * 4]; 1643 for (uint32 y = 0; y < height; y++) { 1644 // NOTE: read into temporary scanline buffer, 1645 // avoid memcpy because it might be graphics card memory 1646 gfxcpy32(tmpBuffer, src, width * 4); 1647 // write back temporary scanline buffer 1648 // NOTE: **don't read and write over the PCI bus 1649 // at the same time** 1650 memcpy(dst, tmpBuffer, width * 4); 1651 // NOTE: this (instead of the two pass copy above) might 1652 // speed up QEMU -> ?!? (would depend on how it emulates 1653 // the PCI bus...) 1654 // TODO: would be nice if we actually knew 1655 // if we're operating in graphics memory or main memory... 1656 //memcpy(dst, src, width * 4); 1657 src += yIncrement; 1658 dst += yIncrement; 1659 } 1660 } else { 1661 for (uint32 y = 0; y < height; y++) { 1662 uint32* srcHandle = (uint32*)src; 1663 uint32* dstHandle = (uint32*)dst; 1664 for (uint32 x = 0; x < width; x++) { 1665 *dstHandle = *srcHandle; 1666 srcHandle += xIncrement; 1667 dstHandle += xIncrement; 1668 } 1669 src += yIncrement; 1670 dst += yIncrement; 1671 } 1672 } 1673 } 1674 1675 1676 inline void 1677 DrawingEngine::_CopyToFront(const BRect& frame) 1678 { 1679 if (fCopyToFront) 1680 fGraphicsCard->Invalidate(frame); 1681 } 1682