1 /* 2 * Copyright 2001-2005, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include <stdio.h> 10 #include <algo.h> 11 #include <stack.h> 12 13 #include "HWInterface.h" 14 #include "DrawState.h" 15 #include "Painter.h" 16 #include "PNGDump.h" 17 #include "RenderingBuffer.h" 18 19 #include "DrawingEngine.h" 20 21 22 // make_rect_valid 23 static inline void 24 make_rect_valid(BRect& rect) 25 { 26 if (rect.left > rect.right) { 27 float temp = rect.left; 28 rect.left = rect.right; 29 rect.right = temp; 30 } 31 if (rect.top > rect.bottom) { 32 float temp = rect.top; 33 rect.top = rect.bottom; 34 rect.bottom = temp; 35 } 36 } 37 38 // extend_by_stroke_width 39 static inline void 40 extend_by_stroke_width(BRect& rect, const DrawState* context) 41 { 42 // "- 1.0" because if stroke width == 1, we don't need to extend 43 float inset = -ceilf(context->PenSize() / 2.0 - 1.0); 44 rect.InsetBy(inset, inset); 45 } 46 47 48 class FontLocker { 49 public: 50 FontLocker(const DrawState* context) 51 : 52 fFont(&context->Font()) 53 { 54 fFont->Lock(); 55 } 56 57 FontLocker(const ServerFont* font) 58 : 59 fFont(font) 60 { 61 fFont->Lock(); 62 } 63 64 ~FontLocker() 65 { 66 fFont->Unlock(); 67 } 68 69 private: 70 const ServerFont* fFont; 71 }; 72 73 74 // #pragma mark - 75 76 77 // constructor 78 DrawingEngine::DrawingEngine(HWInterface* interface) 79 : fPainter(new Painter()), 80 fGraphicsCard(interface), 81 fAvailableHWAccleration(0) 82 { 83 } 84 85 // destructor 86 DrawingEngine::~DrawingEngine() 87 { 88 delete fPainter; 89 } 90 91 // Initialize 92 status_t 93 DrawingEngine::Initialize() 94 { 95 status_t err = B_ERROR; 96 if (WriteLock()) { 97 err = fGraphicsCard->Initialize(); 98 if (err < B_OK) 99 fprintf(stderr, "HWInterface::Initialize() failed: %s\n", strerror(err)); 100 WriteUnlock(); 101 } 102 return err; 103 } 104 105 // Shutdown 106 void 107 DrawingEngine::Shutdown() 108 { 109 } 110 111 // Update 112 void 113 DrawingEngine::Update() 114 { 115 if (Lock()) { 116 fPainter->AttachToBuffer(fGraphicsCard->DrawingBuffer()); 117 // available HW acceleration might have changed 118 fAvailableHWAccleration = fGraphicsCard->AvailableHWAcceleration(); 119 Unlock(); 120 } 121 } 122 123 // SetHWInterface 124 void 125 DrawingEngine::SetHWInterface(HWInterface* interface) 126 { 127 fGraphicsCard = interface; 128 } 129 130 // ConstrainClippingRegion 131 void 132 DrawingEngine::ConstrainClippingRegion(BRegion *region) 133 { 134 if (Lock()) { 135 if (!region) { 136 // BRegion empty; 137 // fPainter->ConstrainClipping(empty); 138 if (RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer()) { 139 BRegion all; 140 all.Include(BRect(0, 0, buffer->Width() - 1, buffer->Height() - 1)); 141 fPainter->ConstrainClipping(all); 142 } 143 } else { 144 fPainter->ConstrainClipping(*region); 145 } 146 Unlock(); 147 } 148 } 149 150 // CopyRegion() does a topological sort of the rects in the 151 // region. The algorithm was suggested by Ingo Weinhold. 152 // It compares each rect with each rect and builds a tree 153 // of successors so we know the order in which they can be copied. 154 // For example, let's suppose these rects are in a BRegion: 155 // ************ 156 // * B * 157 // ************ 158 // ************* 159 // * * 160 // * A **************** 161 // * ** * 162 // ************** * 163 // * C * 164 // * * 165 // * * 166 // *************** 167 // When copying stuff from LEFT TO RIGHT, TOP TO BOTTOM, the 168 // result of the sort will be C, A, B. For this direction, we search 169 // for the rects that have no neighbors to their right and to their 170 // bottom, These can be copied without drawing into the area of 171 // rects yet to be copied. If you move from RIGHT TO LEFT, BOTTOM TO TOP, 172 // you go look for the ones that have no neighbors to their top and left. 173 // 174 // Here I draw some rays to illustrate LEFT TO RIGHT, TOP TO BOTTOM: 175 // ************ 176 // * B * 177 // ************ 178 // ************* 179 // * * 180 // * A ****************----------------- 181 // * ** * 182 // ************** * 183 // * C * 184 // * * 185 // * * 186 // *************** 187 // | 188 // | 189 // | 190 // | 191 // There are no rects in the area defined by the rays to the right 192 // and bottom of rect C, so that's the one we want to copy first 193 // (for positive x and y offsets). 194 // Since A is to the left of C and B is to the top of C, The "node" 195 // for C will point to the nodes of A and B as its "successors". Therefor, 196 // A and B will have an "indegree" of 1 for C pointing to them. C will 197 // have and "indegree" of 0, because there was no rect to which C 198 // was to the left or top of. When comparing A and B, neither is left 199 // or top from the other and in the sense that the algorithm cares about. 200 201 // NOTE: comparisson of coordinates assumes that rects don't overlap 202 // and don't share the actual edge either (as is the case in BRegions). 203 204 struct node { 205 node() 206 { 207 pointers = NULL; 208 } 209 node(const BRect& r, int32 maxPointers) 210 { 211 init(r, maxPointers); 212 } 213 ~node() 214 { 215 delete [] pointers; 216 } 217 218 void init(const BRect& r, int32 maxPointers) 219 { 220 rect = r; 221 pointers = new node*[maxPointers]; 222 in_degree = 0; 223 next_pointer = 0; 224 } 225 226 void push(node* node) 227 { 228 pointers[next_pointer] = node; 229 next_pointer++; 230 } 231 node* top() 232 { 233 return pointers[next_pointer]; 234 } 235 node* pop() 236 { 237 node* ret = top(); 238 next_pointer--; 239 return ret; 240 } 241 242 BRect rect; 243 int32 in_degree; 244 node** pointers; 245 int32 next_pointer; 246 }; 247 248 bool 249 is_left_of(const BRect& a, const BRect& b) 250 { 251 return (a.right < b.left); 252 } 253 bool 254 is_above(const BRect& a, const BRect& b) 255 { 256 return (a.bottom < b.top); 257 } 258 259 // CopyRegion 260 void 261 DrawingEngine::CopyRegion(/*const*/ BRegion* region, 262 int32 xOffset, int32 yOffset) 263 { 264 // NOTE: Write locking because we might use HW acceleration. 265 // This needs to be investigated, I'm doing this because of 266 // gut feeling. 267 if (WriteLock()) { 268 fGraphicsCard->HideSoftwareCursor(region->Frame()); 269 270 int32 count = region->CountRects(); 271 272 // TODO: make this step unnecessary 273 // (by using different stack impl inside node) 274 node nodes[count]; 275 for (int32 i= 0; i < count; i++) { 276 nodes[i].init(region->RectAt(i), count); 277 } 278 279 for (int32 i = 0; i < count; i++) { 280 BRect a = region->RectAt(i); 281 for (int32 k = i + 1; k < count; k++) { 282 BRect b = region->RectAt(k); 283 int cmp = 0; 284 // compare horizontally 285 if (xOffset > 0) { 286 if (is_left_of(a, b)) { 287 cmp -= 1; 288 } else if (is_left_of(b, a)) { 289 cmp += 1; 290 } 291 } else if (xOffset < 0) { 292 if (is_left_of(a, b)) { 293 cmp += 1; 294 } else if (is_left_of(b, a)) { 295 cmp -= 1; 296 } 297 } 298 // compare vertically 299 if (yOffset > 0) { 300 if (is_above(a, b)) { 301 cmp -= 1; 302 } else if (is_above(b, a)) { 303 cmp += 1; 304 } 305 } else if (yOffset < 0) { 306 if (is_above(a, b)) { 307 cmp += 1; 308 } else if (is_above(b, a)) { 309 cmp -= 1; 310 } 311 } 312 // add appropriate node as successor 313 if (cmp > 0) { 314 nodes[i].push(&nodes[k]); 315 nodes[k].in_degree++; 316 } else if (cmp < 0) { 317 nodes[k].push(&nodes[i]); 318 nodes[i].in_degree++; 319 } 320 } 321 } 322 // put all nodes onto a stack that have an "indegree" count of zero 323 stack<node*> inDegreeZeroNodes; 324 for (int32 i = 0; i < count; i++) { 325 if (nodes[i].in_degree == 0) { 326 inDegreeZeroNodes.push(&nodes[i]); 327 } 328 } 329 // pop the rects from the stack, do the actual copy operation 330 // and decrease the "indegree" count of the other rects not 331 // currently on the stack and to which the current rect pointed 332 // to. If their "indegree" count reaches zero, put them onto the 333 // stack as well. 334 335 clipping_rect* sortedRectList = NULL; 336 int32 nextSortedIndex = 0; 337 338 if (fAvailableHWAccleration & HW_ACC_COPY_REGION) 339 sortedRectList = new clipping_rect[count]; 340 341 while (!inDegreeZeroNodes.empty()) { 342 node* n = inDegreeZeroNodes.top(); 343 inDegreeZeroNodes.pop(); 344 345 // do the software implementation or add to sorted 346 // rect list for using the HW accelerated version 347 // later 348 if (sortedRectList) { 349 sortedRectList[nextSortedIndex].left = (int32)n->rect.left; 350 sortedRectList[nextSortedIndex].top = (int32)n->rect.top; 351 sortedRectList[nextSortedIndex].right = (int32)n->rect.right; 352 sortedRectList[nextSortedIndex].bottom = (int32)n->rect.bottom; 353 nextSortedIndex++; 354 } else { 355 BRect touched = _CopyRect(n->rect, xOffset, yOffset); 356 fGraphicsCard->Invalidate(touched); 357 } 358 359 for (int32 k = 0; k < n->next_pointer; k++) { 360 n->pointers[k]->in_degree--; 361 if (n->pointers[k]->in_degree == 0) 362 inDegreeZeroNodes.push(n->pointers[k]); 363 } 364 } 365 366 // trigger the HW accelerated version if is was available 367 if (sortedRectList) 368 fGraphicsCard->CopyRegion(sortedRectList, count, xOffset, yOffset); 369 370 delete[] sortedRectList; 371 372 fGraphicsCard->ShowSoftwareCursor(); 373 374 WriteUnlock(); 375 } 376 } 377 378 // CopyRegionList 379 // 380 // * used to move windows arround on screen 381 // TODO: Since the regions are passed to CopyRegion() one by one, 382 // the case of different regions overlapping each other at source 383 // and/or dest locations is not handled. 384 // We also don't handle the case where multiple regions should have 385 // been combined into one larger region (with effectively the same 386 // rects), so that the sorting would compare them all at once. If 387 // this turns out to be a problem, we can easily rewrite the function 388 // here. In any case, to copy overlapping regions in app_server doesn't 389 // make much sense to me. 390 void 391 DrawingEngine::CopyRegionList(BList* list, BList* pList, 392 int32 rCount, BRegion* clipReg) 393 { 394 // NOTE: Write locking because we might use HW acceleration. 395 // This needs to be investigated, I'm doing this because of 396 // gut feeling. 397 if (WriteLock()) { 398 399 for (int32 i = 0; i < rCount; i++) { 400 BRegion* region = (BRegion*)list->ItemAt(i); 401 BPoint* offset = (BPoint*)pList->ItemAt(i); 402 CopyRegion(region, (int32)offset->x, (int32)offset->y); 403 } 404 405 WriteUnlock(); 406 } 407 } 408 409 // InvertRect 410 void 411 DrawingEngine::InvertRect(BRect r) 412 { 413 // NOTE: Write locking because we might use HW acceleration. 414 // This needs to be investigated, I'm doing this because of 415 // gut feeling. 416 if (WriteLock()) { 417 make_rect_valid(r); 418 r = fPainter->ClipRect(r); 419 if (r.IsValid()) { 420 fGraphicsCard->HideSoftwareCursor(r); 421 422 // try hardware optimized version first 423 if (fAvailableHWAccleration & HW_ACC_INVERT_REGION) { 424 BRegion region(r); 425 region.IntersectWith(fPainter->ClippingRegion()); 426 fGraphicsCard->InvertRegion(region); 427 } else { 428 fPainter->InvertRect(r); 429 430 fGraphicsCard->Invalidate(r); 431 } 432 433 fGraphicsCard->ShowSoftwareCursor(); 434 } 435 436 WriteUnlock(); 437 } 438 } 439 440 // DrawBitmap 441 void 442 DrawingEngine::DrawBitmap(ServerBitmap *bitmap, 443 const BRect &source, const BRect &dest, 444 const DrawState *d) 445 { 446 if (Lock()) { 447 BRect clipped = fPainter->ClipRect(dest); 448 if (clipped.IsValid()) { 449 fGraphicsCard->HideSoftwareCursor(clipped); 450 451 fPainter->SetDrawState(d); 452 fPainter->DrawBitmap(bitmap, source, dest); 453 454 fGraphicsCard->Invalidate(clipped); 455 fGraphicsCard->ShowSoftwareCursor(); 456 } 457 458 Unlock(); 459 } 460 } 461 462 // DrawArc 463 void 464 DrawingEngine::DrawArc(BRect r, const float &angle, 465 const float &span, const DrawState *d, 466 bool filled) 467 { 468 if (Lock()) { 469 make_rect_valid(r); 470 BRect clipped(r); 471 if (!filled) 472 extend_by_stroke_width(clipped, d); 473 clipped = fPainter->ClipRect(r); 474 if (clipped.IsValid()) { 475 fGraphicsCard->HideSoftwareCursor(clipped); 476 477 fPainter->SetDrawState(d); 478 479 float xRadius = r.Width() / 2.0; 480 float yRadius = r.Height() / 2.0; 481 BPoint center(r.left + xRadius, 482 r.top + yRadius); 483 484 if (filled) 485 fPainter->FillArc(center, xRadius, yRadius, angle, span); 486 else 487 fPainter->StrokeArc(center, xRadius, yRadius, angle, span); 488 489 fGraphicsCard->Invalidate(clipped); 490 fGraphicsCard->ShowSoftwareCursor(); 491 } 492 493 Unlock(); 494 } 495 } 496 497 // DrawBezier 498 void 499 DrawingEngine::DrawBezier(BPoint *pts, const DrawState *d, bool filled) 500 { 501 if (Lock()) { 502 fGraphicsCard->HideSoftwareCursor(); 503 504 fPainter->SetDrawState(d); 505 BRect touched = filled ? fPainter->FillBezier(pts) 506 : fPainter->StrokeBezier(pts); 507 508 fGraphicsCard->Invalidate(touched); 509 fGraphicsCard->ShowSoftwareCursor(); 510 511 Unlock(); 512 } 513 } 514 515 // DrawEllipse 516 void 517 DrawingEngine::DrawEllipse(BRect r, const DrawState *d, bool filled) 518 { 519 if (Lock()) { 520 make_rect_valid(r); 521 BRect clipped = r; 522 if (!filled) 523 extend_by_stroke_width(clipped, d); 524 clipped = fPainter->ClipRect(clipped); 525 if (clipped.IsValid()) { 526 fGraphicsCard->HideSoftwareCursor(r); 527 528 fPainter->SetDrawState(d); 529 530 float xRadius = r.Width() / 2.0; 531 float yRadius = r.Height() / 2.0; 532 BPoint center(r.left + xRadius, 533 r.top + yRadius); 534 535 if (filled) 536 fPainter->FillEllipse(center, xRadius, yRadius); 537 else 538 fPainter->StrokeEllipse(center, xRadius, yRadius); 539 540 fGraphicsCard->Invalidate(clipped); 541 fGraphicsCard->ShowSoftwareCursor(); 542 } 543 544 Unlock(); 545 } 546 } 547 548 // DrawPolygon 549 void 550 DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, 551 BRect bounds, const DrawState* d, 552 bool filled, bool closed) 553 { 554 if (Lock()) { 555 make_rect_valid(bounds); 556 if (!filled) 557 extend_by_stroke_width(bounds, d); 558 bounds = fPainter->ClipRect(bounds); 559 if (bounds.IsValid()) { 560 fGraphicsCard->HideSoftwareCursor(bounds); 561 562 fPainter->SetDrawState(d); 563 if (filled) 564 fPainter->FillPolygon(ptlist, numpts); 565 else 566 fPainter->StrokePolygon(ptlist, numpts, closed); 567 568 fGraphicsCard->Invalidate(bounds); 569 fGraphicsCard->ShowSoftwareCursor(); 570 } 571 572 Unlock(); 573 } 574 } 575 576 // StrokeRect 577 // 578 // this function is used to draw a one pixel wide rect 579 void 580 DrawingEngine::StrokeRect(BRect r, const RGBColor &color) 581 { 582 if (Lock()) { 583 make_rect_valid(r); 584 BRect clipped = fPainter->ClipRect(r); 585 if (clipped.IsValid()) { 586 587 fGraphicsCard->HideSoftwareCursor(clipped); 588 589 fPainter->StrokeRect(r, color.GetColor32()); 590 591 fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(r.left, r.top, 592 r.right, r.top))); 593 fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(r.left, r.top + 1, 594 r.left, r.bottom - 1))); 595 fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(r.right, r.top + 1, 596 r.right, r.bottom - 1))); 597 fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(r.left, r.bottom, 598 r.right, r.bottom))); 599 fGraphicsCard->ShowSoftwareCursor(); 600 } 601 602 Unlock(); 603 } 604 } 605 606 // FillRect 607 void 608 DrawingEngine::FillRect(BRect r, const RGBColor& color) 609 { 610 // NOTE: Write locking because we might use HW acceleration. 611 // This needs to be investigated, I'm doing this because of 612 // gut feeling. 613 if (WriteLock()) { 614 make_rect_valid(r); 615 r = fPainter->ClipRect(r); 616 if (r.IsValid()) { 617 fGraphicsCard->HideSoftwareCursor(r); 618 619 // try hardware optimized version first 620 if (fAvailableHWAccleration & HW_ACC_FILL_REGION) { 621 BRegion region(r); 622 region.IntersectWith(fPainter->ClippingRegion()); 623 fGraphicsCard->FillRegion(region, color); 624 } else { 625 fPainter->FillRect(r, color.GetColor32()); 626 627 fGraphicsCard->Invalidate(r); 628 } 629 630 fGraphicsCard->ShowSoftwareCursor(); 631 } 632 633 WriteUnlock(); 634 } 635 } 636 637 // StrokeRect 638 void 639 DrawingEngine::StrokeRect(BRect r, const DrawState *d) 640 { 641 if (Lock()) { 642 // support invalid rects 643 make_rect_valid(r); 644 BRect clipped(r); 645 extend_by_stroke_width(clipped, d); 646 clipped = fPainter->ClipRect(clipped); 647 if (clipped.IsValid()) { 648 649 fGraphicsCard->HideSoftwareCursor(clipped); 650 651 fPainter->SetDrawState(d); 652 fPainter->StrokeRect(r); 653 654 fGraphicsCard->Invalidate(clipped); 655 fGraphicsCard->ShowSoftwareCursor(); 656 } 657 658 Unlock(); 659 } 660 } 661 662 // FillRect 663 void 664 DrawingEngine::FillRect(BRect r, const DrawState *d) 665 { 666 // NOTE: Write locking because we might use HW acceleration. 667 // This needs to be investigated, I'm doing this because of 668 // gut feeling. 669 if (WriteLock()) { 670 make_rect_valid(r); 671 r = fPainter->ClipRect(r); 672 if (r.IsValid()) { 673 fGraphicsCard->HideSoftwareCursor(r); 674 675 bool doInSoftware = true; 676 // try hardware optimized version first 677 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && 678 (d->GetDrawingMode() == B_OP_COPY || 679 d->GetDrawingMode() == B_OP_OVER)) { 680 681 if (d->GetPattern() == B_SOLID_HIGH) { 682 BRegion region(r); 683 region.IntersectWith(fPainter->ClippingRegion()); 684 fGraphicsCard->FillRegion(region, d->HighColor()); 685 doInSoftware = false; 686 } else if (d->GetPattern() == B_SOLID_LOW) { 687 BRegion region(r); 688 region.IntersectWith(fPainter->ClippingRegion()); 689 fGraphicsCard->FillRegion(region, d->LowColor()); 690 doInSoftware = false; 691 } 692 } 693 if (doInSoftware) { 694 695 fPainter->SetDrawState(d); 696 fPainter->FillRect(r); 697 698 fGraphicsCard->Invalidate(r); 699 } 700 701 fGraphicsCard->ShowSoftwareCursor(); 702 } 703 704 WriteUnlock(); 705 } 706 } 707 708 // StrokeRegion 709 void 710 DrawingEngine::StrokeRegion(BRegion& r, const DrawState *d) 711 { 712 if (Lock()) { 713 BRect clipped(r.Frame()); 714 extend_by_stroke_width(clipped, d); 715 clipped = fPainter->ClipRect(clipped); 716 if (clipped.IsValid()) { 717 fGraphicsCard->HideSoftwareCursor(clipped); 718 719 fPainter->SetDrawState(d); 720 721 BRect touched = fPainter->StrokeRect(r.RectAt(0)); 722 723 int32 count = r.CountRects(); 724 for (int32 i = 1; i < count; i++) { 725 touched = touched | fPainter->StrokeRect(r.RectAt(i)); 726 } 727 728 fGraphicsCard->Invalidate(touched); 729 fGraphicsCard->ShowSoftwareCursor(); 730 } 731 732 Unlock(); 733 } 734 } 735 736 // FillRegion 737 void 738 DrawingEngine::FillRegion(BRegion& r, const DrawState *d) 739 { 740 // NOTE: Write locking because we might use HW acceleration. 741 // This needs to be investigated, I'm doing this because of 742 // gut feeling. 743 if (WriteLock()) { 744 BRect clipped = fPainter->ClipRect(r.Frame()); 745 if (clipped.IsValid()) { 746 fGraphicsCard->HideSoftwareCursor(clipped); 747 748 bool doInSoftware = true; 749 // try hardware optimized version first 750 if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && 751 (d->GetDrawingMode() == B_OP_COPY || 752 d->GetDrawingMode() == B_OP_OVER)) { 753 754 if (d->GetPattern() == B_SOLID_HIGH) { 755 fGraphicsCard->FillRegion(r, d->HighColor()); 756 doInSoftware = false; 757 } else if (d->GetPattern() == B_SOLID_LOW) { 758 fGraphicsCard->FillRegion(r, d->LowColor()); 759 doInSoftware = false; 760 } 761 } 762 if (doInSoftware) { 763 764 fPainter->SetDrawState(d); 765 766 BRect touched = fPainter->FillRect(r.RectAt(0)); 767 768 int32 count = r.CountRects(); 769 for (int32 i = 1; i < count; i++) { 770 touched = touched | fPainter->FillRect(r.RectAt(i)); 771 } 772 773 fGraphicsCard->Invalidate(touched); 774 } 775 776 fGraphicsCard->ShowSoftwareCursor(); 777 } 778 779 WriteUnlock(); 780 } 781 } 782 783 // DrawRoundRect 784 void 785 DrawingEngine::DrawRoundRect(BRect r, const float &xrad, 786 const float &yrad, const DrawState *d, 787 bool filled) 788 { 789 if (Lock()) { 790 // NOTE: the stroke does not extend past "r" in R5, 791 // though I consider this unexpected behaviour. 792 make_rect_valid(r); 793 BRect clipped = fPainter->ClipRect(r); 794 if (clipped.IsValid()) { 795 fGraphicsCard->HideSoftwareCursor(clipped); 796 797 fPainter->SetDrawState(d); 798 BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad) 799 : fPainter->StrokeRoundRect(r, xrad, yrad); 800 801 fGraphicsCard->Invalidate(touched); 802 fGraphicsCard->ShowSoftwareCursor(); 803 } 804 805 Unlock(); 806 } 807 } 808 809 // DrawShape 810 void 811 DrawingEngine::DrawShape(const BRect& bounds, const int32& opCount, 812 const uint32* opList, const int32& ptCount, 813 const BPoint* ptList, const DrawState* d, 814 bool filled) 815 { 816 if (Lock()) { 817 fGraphicsCard->HideSoftwareCursor(); 818 819 fPainter->SetDrawState(d); 820 BRect touched = fPainter->DrawShape(opCount, opList, 821 ptCount, ptList, 822 filled); 823 824 fGraphicsCard->Invalidate(touched); 825 fGraphicsCard->ShowSoftwareCursor(); 826 827 Unlock(); 828 } 829 } 830 831 // DrawTriangle 832 void 833 DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, 834 const DrawState* d, bool filled) 835 { 836 if (Lock()) { 837 BRect clipped(bounds); 838 if (!filled) 839 extend_by_stroke_width(clipped, d); 840 clipped = fPainter->ClipRect(clipped); 841 if (clipped.IsValid()) { 842 fGraphicsCard->HideSoftwareCursor(clipped); 843 844 fPainter->SetDrawState(d); 845 if (filled) 846 fPainter->FillTriangle(pts[0], pts[1], pts[2]); 847 else 848 fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); 849 850 fGraphicsCard->Invalidate(clipped); 851 fGraphicsCard->ShowSoftwareCursor(); 852 } 853 854 Unlock(); 855 } 856 } 857 858 // StrokeLine 859 // 860 // * this function is only used by Decorators 861 // * it assumes a one pixel wide line 862 void 863 DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, const RGBColor &color) 864 { 865 if (Lock()) { 866 BRect touched(start, end); 867 make_rect_valid(touched); 868 touched = fPainter->ClipRect(touched); 869 fGraphicsCard->HideSoftwareCursor(touched); 870 871 if (!fPainter->StraightLine(start, end, color.GetColor32())) { 872 static DrawState context; 873 context.SetHighColor(color); 874 context.SetDrawingMode(B_OP_OVER); 875 StrokeLine(start, end, &context); 876 } else { 877 fGraphicsCard->Invalidate(touched); 878 } 879 fGraphicsCard->ShowSoftwareCursor(); 880 Unlock(); 881 } 882 } 883 884 // StrokeLine 885 void 886 DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, DrawState* context) 887 { 888 if (Lock()) { 889 BRect touched(start, end); 890 make_rect_valid(touched); 891 extend_by_stroke_width(touched, context); 892 touched = fPainter->ClipRect(touched); 893 if (touched.IsValid()) { 894 fGraphicsCard->HideSoftwareCursor(touched); 895 896 touched = fPainter->StrokeLine(start, end, context); 897 898 fGraphicsCard->Invalidate(touched); 899 fGraphicsCard->ShowSoftwareCursor(); 900 } 901 902 Unlock(); 903 } 904 } 905 906 // StrokeLineArray 907 void 908 DrawingEngine::StrokeLineArray(const int32 &numlines, 909 const LineArrayData *linedata, 910 const DrawState *d) 911 { 912 if(!d || !linedata || numlines <= 0) 913 return; 914 915 if (Lock()) { 916 // figure out bounding box for line array 917 const LineArrayData *data = (const LineArrayData *)&(linedata[0]); 918 BRect touched(min_c(data->pt1.x, data->pt2.x), 919 min_c(data->pt1.y, data->pt2.y), 920 max_c(data->pt1.x, data->pt2.x), 921 max_c(data->pt1.y, data->pt2.y)); 922 for (int32 i = 1; i < numlines; i++) { 923 data = (const LineArrayData *)&(linedata[i]); 924 BRect box(min_c(data->pt1.x, data->pt2.x), 925 min_c(data->pt1.y, data->pt2.y), 926 max_c(data->pt1.x, data->pt2.x), 927 max_c(data->pt1.y, data->pt2.y)); 928 touched = touched | box; 929 } 930 extend_by_stroke_width(touched, d); 931 touched = fPainter->ClipRect(touched); 932 if (touched.IsValid()) { 933 fGraphicsCard->HideSoftwareCursor(touched); 934 935 DrawState context; 936 context.SetDrawingMode(B_OP_COPY); 937 938 data = (const LineArrayData *)&(linedata[0]); 939 context.SetHighColor(data->color); 940 fPainter->StrokeLine(data->pt1, data->pt2, &context); 941 942 for (int32 i = 1; i < numlines; i++) { 943 data = (const LineArrayData *)&(linedata[i]); 944 context.SetHighColor(data->color); 945 fPainter->StrokeLine(data->pt1, data->pt2, &context); 946 } 947 948 fGraphicsCard->Invalidate(touched); 949 fGraphicsCard->ShowSoftwareCursor(); 950 } 951 952 Unlock(); 953 } 954 } 955 956 // StrokePoint 957 // 958 // * this function is only used by Decorators 959 void 960 DrawingEngine::StrokePoint(const BPoint& pt, const RGBColor &color) 961 { 962 StrokeLine(pt, pt, color); 963 } 964 965 // StrokePoint 966 void 967 DrawingEngine::StrokePoint(const BPoint& pt, DrawState *context) 968 { 969 StrokeLine(pt, pt, context); 970 } 971 972 /* 973 // DrawString 974 void 975 DrawingEngine::DrawString(const char *string, const int32 &length, 976 const BPoint &pt, const RGBColor &color, 977 escapement_delta *delta) 978 { 979 static DrawState d; 980 d.SetHighColor(color); 981 982 DrawString(string, length, pt, &d, delta); 983 } 984 */ 985 // DrawString 986 BPoint 987 DrawingEngine::DrawString(const char* string, int32 length, 988 const BPoint& pt, DrawState* d, 989 escapement_delta* delta) 990 { 991 // TODO: use delta 992 BPoint penLocation = pt; 993 if (Lock()) { 994 FontLocker locker(d); 995 fPainter->SetDrawState(d); 996 //bigtime_t now = system_time(); 997 // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. 998 // Cursiously, the DrawString after it is actually faster!?! 999 // TODO: make the availability of the hardware cursor part of the 1000 // HW acceleration flags and skip all calculations for HideSoftwareCursor 1001 // in case we don't have one. 1002 // TODO: Watch out about penLocation and use Painter::PenLocation() when 1003 // not using BoundindBox anymore. 1004 BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta); 1005 // stop here if we're supposed to render outside of the clipping 1006 b = fPainter->ClipRect(b); 1007 if (b.IsValid()) { 1008 //printf("bounding box '%s': %lld µs\n", string, system_time() - now); 1009 fGraphicsCard->HideSoftwareCursor(b); 1010 1011 //now = system_time(); 1012 BRect touched = fPainter->DrawString(string, length, pt, delta); 1013 //printf("drawing string: %lld µs\n", system_time() - now); 1014 1015 fGraphicsCard->Invalidate(touched); 1016 fGraphicsCard->ShowSoftwareCursor(); 1017 } 1018 Unlock(); 1019 } 1020 return penLocation; 1021 } 1022 1023 // StringWidth 1024 float 1025 DrawingEngine::StringWidth(const char* string, int32 length, 1026 const DrawState* d, escapement_delta* delta) 1027 { 1028 // TODO: use delta 1029 float width = 0.0; 1030 if (Lock()) { 1031 FontLocker locker(d); 1032 fPainter->SetDrawState(d); 1033 width = fPainter->StringWidth(string, length); 1034 Unlock(); 1035 } 1036 return width; 1037 } 1038 1039 // StringWidth 1040 float 1041 DrawingEngine::StringWidth(const char* string, int32 length, 1042 const ServerFont& font, escapement_delta* delta) 1043 { 1044 // TODO: use delta 1045 FontLocker locker(&font); 1046 static DrawState d; 1047 d.SetFont(font); 1048 return StringWidth(string, length, &d); 1049 } 1050 1051 // StringHeight 1052 float 1053 DrawingEngine::StringHeight(const char *string, int32 length, 1054 const DrawState *d) 1055 { 1056 float height = 0.0; 1057 if (Lock()) { 1058 FontLocker locker(d); 1059 fPainter->SetDrawState(d); 1060 static BPoint dummy1(0.0, 0.0); 1061 static BPoint dummy2(0.0, 0.0); 1062 height = fPainter->BoundingBox(string, length, dummy1, &dummy2).Height(); 1063 Unlock(); 1064 } 1065 return height; 1066 } 1067 1068 // Lock 1069 bool 1070 DrawingEngine::Lock() 1071 { 1072 return fGraphicsCard->WriteLock(); 1073 } 1074 1075 // Unlock 1076 void 1077 DrawingEngine::Unlock() 1078 { 1079 fGraphicsCard->WriteUnlock(); 1080 } 1081 1082 // WriteLock 1083 bool 1084 DrawingEngine::WriteLock() 1085 { 1086 return fGraphicsCard->WriteLock(); 1087 } 1088 1089 // WriteUnlock 1090 void 1091 DrawingEngine::WriteUnlock() 1092 { 1093 fGraphicsCard->WriteUnlock(); 1094 } 1095 1096 // DumpToFile 1097 bool 1098 DrawingEngine::DumpToFile(const char *path) 1099 { 1100 if (Lock()) { 1101 RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); 1102 if (buffer) { 1103 BRect bounds(0.0, 0.0, buffer->Width() - 1, buffer->Height() - 1); 1104 // TODO: Don't assume B_RGBA32!! 1105 SaveToPNG(path, bounds, B_RGBA32, 1106 buffer->Bits(), 1107 buffer->BitsLength(), 1108 buffer->BytesPerRow()); 1109 } 1110 Unlock(); 1111 } 1112 return true; 1113 } 1114 1115 // DumpToBitmap 1116 ServerBitmap* 1117 DrawingEngine::DumpToBitmap() 1118 { 1119 return NULL; 1120 } 1121 1122 // _CopyRect 1123 BRect 1124 DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const 1125 { 1126 BRect dst; 1127 RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); 1128 if (buffer) { 1129 1130 BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); 1131 1132 dst = src; 1133 dst.OffsetBy(xOffset, yOffset); 1134 1135 if (clip.Intersects(src) && clip.Intersects(dst)) { 1136 1137 uint32 bpr = buffer->BytesPerRow(); 1138 uint8* bits = (uint8*)buffer->Bits(); 1139 1140 // clip source rect 1141 src = src & clip; 1142 // clip dest rect 1143 dst = dst & clip; 1144 // move dest back over source and clip source to dest 1145 dst.OffsetBy(-xOffset, -yOffset); 1146 src = src & dst; 1147 1148 // calc offset in buffer 1149 bits += (int32)src.left * 4 + (int32)src.top * bpr; 1150 1151 uint32 width = src.IntegerWidth() + 1; 1152 uint32 height = src.IntegerHeight() + 1; 1153 1154 _CopyRect(bits, width, height, bpr, xOffset, yOffset); 1155 1156 // offset dest again, because it is return value 1157 dst.OffsetBy(xOffset, yOffset); 1158 } 1159 } 1160 return dst; 1161 } 1162 1163 // _CopyRect 1164 void 1165 DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height, 1166 uint32 bpr, int32 xOffset, int32 yOffset) const 1167 { 1168 int32 xIncrement; 1169 int32 yIncrement; 1170 1171 if (xOffset > 0) { 1172 // copy from right to left 1173 xIncrement = -1; 1174 src += (width - 1) * 4; 1175 } else { 1176 // copy from left to right 1177 xIncrement = 1; 1178 } 1179 1180 if (yOffset > 0) { 1181 // copy from bottom to top 1182 yIncrement = -bpr; 1183 src += (height - 1) * bpr; 1184 } else { 1185 // copy from top to bottom 1186 yIncrement = bpr; 1187 } 1188 1189 uint8* dst = src + yOffset * bpr + xOffset * 4; 1190 1191 for (uint32 y = 0; y < height; y++) { 1192 uint32* srcHandle = (uint32*)src; 1193 uint32* dstHandle = (uint32*)dst; 1194 for (uint32 x = 0; x < width; x++) { 1195 *dstHandle = *srcHandle; 1196 srcHandle += xIncrement; 1197 dstHandle += xIncrement; 1198 } 1199 src += yIncrement; 1200 dst += yIncrement; 1201 } 1202 } 1203 1204