1 /* 2 * Copyright 2009-2010, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include "RemoteDrawingEngine.h" 10 #include "RemoteMessage.h" 11 12 #include "BitmapDrawingEngine.h" 13 #include "DrawState.h" 14 15 #include <Bitmap.h> 16 #include <utf8_functions.h> 17 18 #include <new> 19 20 21 RemoteDrawingEngine::RemoteDrawingEngine(RemoteHWInterface* interface) 22 : 23 DrawingEngine(interface), 24 fHWInterface(interface), 25 fToken((uint32)this), // TODO: need to redo that for 64 bit 26 fExtendWidth(0), 27 fCallbackAdded(false), 28 fResultNotify(-1), 29 fStringWidthResult(0.0f), 30 fReadBitmapResult(NULL), 31 fBitmapDrawingEngine(NULL) 32 { 33 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 34 message.Start(RP_CREATE_STATE); 35 message.Add(fToken); 36 } 37 38 39 RemoteDrawingEngine::~RemoteDrawingEngine() 40 { 41 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 42 message.Start(RP_DELETE_STATE); 43 message.Add(fToken); 44 message.Flush(); 45 46 delete fBitmapDrawingEngine; 47 48 if (fCallbackAdded) 49 fHWInterface->RemoveCallback(fToken); 50 if (fResultNotify >= 0) 51 delete_sem(fResultNotify); 52 } 53 54 55 // #pragma mark - 56 57 58 void 59 RemoteDrawingEngine::FrameBufferChanged() 60 { 61 // Not allowed 62 } 63 64 65 // #pragma mark - 66 67 68 void 69 RemoteDrawingEngine::SetCopyToFrontEnabled(bool enabled) 70 { 71 DrawingEngine::SetCopyToFrontEnabled(enabled); 72 73 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 74 message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING); 75 message.Add(fToken); 76 } 77 78 79 // #pragma mark - 80 81 82 //! the RemoteDrawingEngine needs to be locked! 83 void 84 RemoteDrawingEngine::ConstrainClippingRegion(const BRegion* region) 85 { 86 if (fClippingRegion == *region) 87 return; 88 89 fClippingRegion = *region; 90 91 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 92 message.Start(RP_CONSTRAIN_CLIPPING_REGION); 93 message.Add(fToken); 94 message.AddRegion(*region); 95 } 96 97 98 void 99 RemoteDrawingEngine::SetDrawState(const DrawState* state, int32 xOffset, 100 int32 yOffset) 101 { 102 SetPenSize(state->PenSize()); 103 SetDrawingMode(state->GetDrawingMode()); 104 SetBlendingMode(state->AlphaSrcMode(), state->AlphaFncMode()); 105 SetPattern(state->GetPattern().GetPattern()); 106 SetStrokeMode(state->LineCapMode(), state->LineJoinMode(), 107 state->MiterLimit()); 108 SetHighColor(state->HighColor()); 109 SetLowColor(state->LowColor()); 110 SetFont(state->Font()); 111 112 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 113 message.Start(RP_SET_OFFSETS); 114 message.Add(fToken); 115 message.Add(xOffset); 116 message.Add(yOffset); 117 } 118 119 120 void 121 RemoteDrawingEngine::SetHighColor(const rgb_color& color) 122 { 123 if (fState.HighColor() == color) 124 return; 125 126 fState.SetHighColor(color); 127 128 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 129 message.Start(RP_SET_HIGH_COLOR); 130 message.Add(fToken); 131 message.Add(color); 132 } 133 134 135 void 136 RemoteDrawingEngine::SetLowColor(const rgb_color& color) 137 { 138 if (fState.LowColor() == color) 139 return; 140 141 fState.SetLowColor(color); 142 143 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 144 message.Start(RP_SET_LOW_COLOR); 145 message.Add(fToken); 146 message.Add(color); 147 } 148 149 150 void 151 RemoteDrawingEngine::SetPenSize(float size) 152 { 153 if (fState.PenSize() == size) 154 return; 155 156 fState.SetPenSize(size); 157 fExtendWidth = -(size / 2); 158 159 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 160 message.Start(RP_SET_PEN_SIZE); 161 message.Add(fToken); 162 message.Add(size); 163 } 164 165 166 void 167 RemoteDrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode, 168 float miterLimit) 169 { 170 if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode 171 && fState.MiterLimit() == miterLimit) 172 return; 173 174 fState.SetLineCapMode(lineCap); 175 fState.SetLineJoinMode(joinMode); 176 fState.SetMiterLimit(miterLimit); 177 178 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 179 message.Start(RP_SET_STROKE_MODE); 180 message.Add(fToken); 181 message.Add(lineCap); 182 message.Add(joinMode); 183 message.Add(miterLimit); 184 } 185 186 187 void 188 RemoteDrawingEngine::SetBlendingMode(source_alpha sourceAlpha, 189 alpha_function alphaFunc) 190 { 191 if (fState.AlphaSrcMode() == sourceAlpha 192 && fState.AlphaFncMode() == alphaFunc) 193 return; 194 195 fState.SetBlendingMode(sourceAlpha, alphaFunc); 196 197 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 198 message.Start(RP_SET_BLENDING_MODE); 199 message.Add(fToken); 200 message.Add(sourceAlpha); 201 message.Add(alphaFunc); 202 } 203 204 205 void 206 RemoteDrawingEngine::SetPattern(const struct pattern& pattern) 207 { 208 if (fState.GetPattern() == pattern) 209 return; 210 211 fState.SetPattern(pattern); 212 213 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 214 message.Start(RP_SET_PATTERN); 215 message.Add(fToken); 216 message.Add(pattern); 217 } 218 219 220 void 221 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode) 222 { 223 if (fState.GetDrawingMode() == mode) 224 return; 225 226 fState.SetDrawingMode(mode); 227 228 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 229 message.Start(RP_SET_DRAWING_MODE); 230 message.Add(fToken); 231 message.Add(mode); 232 } 233 234 235 void 236 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode) 237 { 238 oldMode = fState.GetDrawingMode(); 239 SetDrawingMode(mode); 240 } 241 242 243 void 244 RemoteDrawingEngine::SetFont(const ServerFont& font) 245 { 246 if (fState.Font() == font) 247 return; 248 249 fState.SetFont(font); 250 251 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 252 message.Start(RP_SET_FONT); 253 message.Add(fToken); 254 message.AddFont(font); 255 } 256 257 258 void 259 RemoteDrawingEngine::SetFont(const DrawState* state) 260 { 261 SetFont(state->Font()); 262 } 263 264 265 // #pragma mark - 266 267 268 BRect 269 RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const 270 { 271 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 272 message.Start(RP_COPY_RECT_NO_CLIPPING); 273 message.Add(xOffset); 274 message.Add(yOffset); 275 message.Add(rect); 276 return rect.OffsetBySelf(xOffset, yOffset); 277 } 278 279 280 void 281 RemoteDrawingEngine::InvertRect(BRect rect) 282 { 283 if (!fClippingRegion.Intersects(rect)) 284 return; 285 286 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 287 message.Start(RP_INVERT_RECT); 288 message.Add(fToken); 289 message.Add(rect); 290 } 291 292 293 void 294 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect, 295 const BRect& _viewRect, uint32 options) 296 { 297 BRect bitmapRect = _bitmapRect; 298 BRect viewRect = _viewRect; 299 double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1); 300 double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1); 301 302 // constrain rect to passed bitmap bounds 303 // and transfer the changes to the viewRect with the right scale 304 BRect actualBitmapRect = bitmap->Bounds(); 305 if (bitmapRect.left < actualBitmapRect.left) { 306 float diff = actualBitmapRect.left - bitmapRect.left; 307 viewRect.left += diff / xScale; 308 bitmapRect.left = actualBitmapRect.left; 309 } 310 if (bitmapRect.top < actualBitmapRect.top) { 311 float diff = actualBitmapRect.top - bitmapRect.top; 312 viewRect.top += diff / yScale; 313 bitmapRect.top = actualBitmapRect.top; 314 } 315 if (bitmapRect.right > actualBitmapRect.right) { 316 float diff = bitmapRect.right - actualBitmapRect.right; 317 viewRect.right -= diff / xScale; 318 bitmapRect.right = actualBitmapRect.right; 319 } 320 if (bitmapRect.bottom > actualBitmapRect.bottom) { 321 float diff = bitmapRect.bottom - actualBitmapRect.bottom; 322 viewRect.bottom -= diff / yScale; 323 bitmapRect.bottom = actualBitmapRect.bottom; 324 } 325 326 BRegion clippedRegion(viewRect); 327 clippedRegion.IntersectWith(&fClippingRegion); 328 329 int32 rectCount = clippedRegion.CountRects(); 330 if (rectCount == 0) 331 return; 332 333 if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != viewRect) 334 || viewRect.Width() < bitmapRect.Width() 335 || viewRect.Height() < bitmapRect.Height()) { 336 UtilityBitmap** bitmaps; 337 if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, viewRect, 338 xScale, yScale, clippedRegion, bitmaps) != B_OK) { 339 return; 340 } 341 342 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 343 message.Start(RP_DRAW_BITMAP_RECTS); 344 message.Add(fToken); 345 message.Add(options); 346 message.Add(bitmap->ColorSpace()); 347 message.Add(bitmap->Flags()); 348 message.Add(rectCount); 349 350 for (int32 i = 0; i < rectCount; i++) { 351 message.Add(clippedRegion.RectAt(i)); 352 message.AddBitmap(*bitmaps[i], true); 353 delete bitmaps[i]; 354 } 355 356 free(bitmaps); 357 return; 358 } 359 360 // TODO: we may want to cache/checksum bitmaps 361 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 362 message.Start(RP_DRAW_BITMAP); 363 message.Add(fToken); 364 message.Add(bitmapRect); 365 message.Add(viewRect); 366 message.Add(options); 367 message.AddBitmap(*bitmap); 368 } 369 370 371 void 372 RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span, 373 bool filled) 374 { 375 BRect bounds = rect; 376 if (!filled) 377 bounds.InsetBy(fExtendWidth, fExtendWidth); 378 379 if (!fClippingRegion.Intersects(bounds)) 380 return; 381 382 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 383 message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC); 384 message.Add(fToken); 385 message.Add(rect); 386 message.Add(angle); 387 message.Add(span); 388 } 389 390 void 391 RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span, 392 const BGradient& gradient) 393 { 394 if (!fClippingRegion.Intersects(rect)) 395 return; 396 397 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 398 message.Start(RP_FILL_ARC_GRADIENT); 399 message.Add(fToken); 400 message.Add(rect); 401 message.Add(angle); 402 message.Add(span); 403 message.AddGradient(gradient); 404 } 405 406 407 void 408 RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled) 409 { 410 BRect bounds = _BuildBounds(points, 4); 411 if (!filled) 412 bounds.InsetBy(fExtendWidth, fExtendWidth); 413 414 if (!fClippingRegion.Intersects(bounds)) 415 return; 416 417 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 418 message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER); 419 message.Add(fToken); 420 message.AddList(points, 4); 421 } 422 423 424 void 425 RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient) 426 { 427 BRect bounds = _BuildBounds(points, 4); 428 if (!fClippingRegion.Intersects(bounds)) 429 return; 430 431 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 432 message.Start(RP_FILL_BEZIER_GRADIENT); 433 message.Add(fToken); 434 message.AddList(points, 4); 435 message.AddGradient(gradient); 436 } 437 438 439 void 440 RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled) 441 { 442 BRect bounds = rect; 443 if (!filled) 444 bounds.InsetBy(fExtendWidth, fExtendWidth); 445 446 if (!fClippingRegion.Intersects(bounds)) 447 return; 448 449 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 450 message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE); 451 message.Add(fToken); 452 message.Add(rect); 453 } 454 455 456 void 457 RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient) 458 { 459 if (!fClippingRegion.Intersects(rect)) 460 return; 461 462 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 463 message.Start(RP_FILL_ELLIPSE_GRADIENT); 464 message.Add(fToken); 465 message.Add(rect); 466 message.AddGradient(gradient); 467 } 468 469 470 void 471 RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints, 472 BRect bounds, bool filled, bool closed) 473 { 474 BRect clipBounds = bounds; 475 if (!filled) 476 clipBounds.InsetBy(fExtendWidth, fExtendWidth); 477 478 if (!fClippingRegion.Intersects(clipBounds)) 479 return; 480 481 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 482 message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON); 483 message.Add(fToken); 484 message.Add(bounds); 485 message.Add(closed); 486 message.Add(numPoints); 487 for (int32 i = 0; i < numPoints; i++) 488 message.Add(pointList[i]); 489 } 490 491 492 void 493 RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints, 494 BRect bounds, const BGradient& gradient, bool closed) 495 { 496 if (!fClippingRegion.Intersects(bounds)) 497 return; 498 499 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 500 message.Start(RP_FILL_POLYGON_GRADIENT); 501 message.Add(fToken); 502 message.Add(bounds); 503 message.Add(closed); 504 message.Add(numPoints); 505 for (int32 i = 0; i < numPoints; i++) 506 message.Add(pointList[i]); 507 message.AddGradient(gradient); 508 } 509 510 511 // #pragma mark - rgb_color versions 512 513 514 void 515 RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color) 516 { 517 BRect bounds(point, point); 518 bounds.InsetBy(fExtendWidth, fExtendWidth); 519 520 if (!fClippingRegion.Intersects(bounds)) 521 return; 522 523 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 524 message.Start(RP_STROKE_POINT_COLOR); 525 message.Add(fToken); 526 message.Add(point); 527 message.Add(color); 528 } 529 530 531 void 532 RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end, 533 const rgb_color& color) 534 { 535 BPoint points[2] = { start, end }; 536 BRect bounds = _BuildBounds(points, 2); 537 538 if (!fClippingRegion.Intersects(bounds)) 539 return; 540 541 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 542 message.Start(RP_STROKE_LINE_1PX_COLOR); 543 message.Add(fToken); 544 message.AddList(points, 2); 545 message.Add(color); 546 } 547 548 549 void 550 RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color) 551 { 552 BRect bounds = rect; 553 bounds.InsetBy(fExtendWidth, fExtendWidth); 554 555 if (!fClippingRegion.Intersects(bounds)) 556 return; 557 558 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 559 message.Start(RP_STROKE_RECT_1PX_COLOR); 560 message.Add(fToken); 561 message.Add(rect); 562 message.Add(color); 563 } 564 565 566 void 567 RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color) 568 { 569 if (!fClippingRegion.Intersects(rect)) 570 return; 571 572 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 573 message.Start(RP_FILL_RECT_COLOR); 574 message.Add(fToken); 575 message.Add(rect); 576 message.Add(color); 577 } 578 579 580 void 581 RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color) 582 { 583 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 584 message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING); 585 message.AddRegion(region); 586 message.Add(color); 587 } 588 589 590 // #pragma mark - DrawState versions 591 592 593 void 594 RemoteDrawingEngine::StrokeRect(BRect rect) 595 { 596 BRect bounds = rect; 597 bounds.InsetBy(fExtendWidth, fExtendWidth); 598 599 if (!fClippingRegion.Intersects(bounds)) 600 return; 601 602 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 603 message.Start(RP_STROKE_RECT); 604 message.Add(fToken); 605 message.Add(rect); 606 } 607 608 609 void 610 RemoteDrawingEngine::FillRect(BRect rect) 611 { 612 if (!fClippingRegion.Intersects(rect)) 613 return; 614 615 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 616 message.Start(RP_FILL_RECT); 617 message.Add(fToken); 618 message.Add(rect); 619 } 620 621 622 void 623 RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient) 624 { 625 if (!fClippingRegion.Intersects(rect)) 626 return; 627 628 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 629 message.Start(RP_FILL_RECT_GRADIENT); 630 message.Add(fToken); 631 message.Add(rect); 632 message.AddGradient(gradient); 633 } 634 635 636 void 637 RemoteDrawingEngine::FillRegion(BRegion& region) 638 { 639 BRegion clippedRegion = region; 640 clippedRegion.IntersectWith(&fClippingRegion); 641 if (clippedRegion.CountRects() == 0) 642 return; 643 644 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 645 message.Start(RP_FILL_REGION); 646 message.Add(fToken); 647 message.AddRegion(clippedRegion.CountRects() < region.CountRects() 648 ? clippedRegion : region); 649 } 650 651 652 void 653 RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient) 654 { 655 BRegion clippedRegion = region; 656 clippedRegion.IntersectWith(&fClippingRegion); 657 if (clippedRegion.CountRects() == 0) 658 return; 659 660 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 661 message.Start(RP_FILL_REGION_GRADIENT); 662 message.Add(fToken); 663 message.AddRegion(clippedRegion.CountRects() < region.CountRects() 664 ? clippedRegion : region); 665 message.AddGradient(gradient); 666 } 667 668 669 void 670 RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius, 671 bool filled) 672 { 673 BRect bounds = rect; 674 if (!filled) 675 bounds.InsetBy(fExtendWidth, fExtendWidth); 676 677 if (!fClippingRegion.Intersects(bounds)) 678 return; 679 680 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 681 message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT); 682 message.Add(fToken); 683 message.Add(rect); 684 message.Add(xRadius); 685 message.Add(yRadius); 686 } 687 688 689 void 690 RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius, 691 const BGradient& gradient) 692 { 693 if (!fClippingRegion.Intersects(rect)) 694 return; 695 696 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 697 message.Start(RP_FILL_ROUND_RECT_GRADIENT); 698 message.Add(fToken); 699 message.Add(rect); 700 message.Add(xRadius); 701 message.Add(yRadius); 702 message.AddGradient(gradient); 703 } 704 705 706 void 707 RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount, 708 const uint32* opList, int32 pointCount, const BPoint* pointList, 709 bool filled, const BPoint& viewToScreenOffset, float viewScale) 710 { 711 BRect clipBounds = bounds; 712 if (!filled) 713 clipBounds.InsetBy(fExtendWidth, fExtendWidth); 714 715 if (!fClippingRegion.Intersects(clipBounds)) 716 return; 717 718 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 719 message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE); 720 message.Add(fToken); 721 message.Add(bounds); 722 message.Add(opCount); 723 message.AddList(opList, opCount); 724 message.Add(pointCount); 725 message.AddList(pointList, pointCount); 726 message.Add(viewToScreenOffset); 727 message.Add(viewScale); 728 } 729 730 731 void 732 RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount, 733 const uint32* opList, int32 pointCount, const BPoint* pointList, 734 const BGradient& gradient, const BPoint& viewToScreenOffset, 735 float viewScale) 736 { 737 if (!fClippingRegion.Intersects(bounds)) 738 return; 739 740 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 741 message.Start(RP_FILL_SHAPE_GRADIENT); 742 message.Add(fToken); 743 message.Add(bounds); 744 message.Add(opCount); 745 message.AddList(opList, opCount); 746 message.Add(pointCount); 747 message.AddList(pointList, pointCount); 748 message.AddGradient(gradient); 749 message.Add(viewToScreenOffset); 750 message.Add(viewScale); 751 } 752 753 754 void 755 RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds, 756 bool filled) 757 { 758 BRect clipBounds = bounds; 759 if (!filled) 760 clipBounds.InsetBy(fExtendWidth, fExtendWidth); 761 762 if (!fClippingRegion.Intersects(clipBounds)) 763 return; 764 765 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 766 message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE); 767 message.Add(fToken); 768 message.AddList(points, 3); 769 message.Add(bounds); 770 } 771 772 773 void 774 RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds, 775 const BGradient& gradient) 776 { 777 if (!fClippingRegion.Intersects(bounds)) 778 return; 779 780 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 781 message.Start(RP_FILL_TRIANGLE_GRADIENT); 782 message.Add(fToken); 783 message.Add(points[0]); 784 message.Add(points[1]); 785 message.Add(points[2]); 786 message.Add(bounds); 787 message.AddGradient(gradient); 788 } 789 790 791 void 792 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end) 793 { 794 BPoint points[2] = { start, end }; 795 BRect bounds = _BuildBounds(points, 2); 796 797 if (!fClippingRegion.Intersects(bounds)) 798 return; 799 800 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 801 message.Start(RP_STROKE_LINE); 802 message.Add(fToken); 803 message.AddList(points, 2); 804 } 805 806 807 void 808 RemoteDrawingEngine::StrokeLineArray(int32 numLines, 809 const ViewLineArrayInfo *lineData) 810 { 811 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 812 message.Start(RP_STROKE_LINE_ARRAY); 813 message.Add(fToken); 814 message.Add(numLines); 815 for (int32 i = 0; i < numLines; i++) 816 message.AddArrayLine(lineData[i]); 817 } 818 819 820 // #pragma mark - string functions 821 822 823 BPoint 824 RemoteDrawingEngine::DrawString(const char* string, int32 length, 825 const BPoint& point, escapement_delta* delta) 826 { 827 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 828 829 message.Start(RP_DRAW_STRING); 830 message.Add(fToken); 831 message.Add(point); 832 message.AddString(string, length); 833 message.Add(delta != NULL); 834 if (delta != NULL) 835 message.AddList(delta, length); 836 837 status_t result = _AddCallback(); 838 if (message.Flush() != B_OK) 839 return point; 840 841 if (result != B_OK) 842 return point; 843 844 do { 845 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 846 1 * 1000 * 1000); 847 } while (result == B_INTERRUPTED); 848 849 if (result != B_OK) 850 return point; 851 852 return fDrawStringResult; 853 } 854 855 856 BPoint 857 RemoteDrawingEngine::DrawString(const char* string, int32 length, 858 const BPoint* offsets) 859 { 860 // Guaranteed to have at least one point. 861 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 862 863 message.Start(RP_DRAW_STRING_WITH_OFFSETS); 864 message.Add(fToken); 865 message.AddString(string, length); 866 message.AddList(offsets, UTF8CountChars(string, length)); 867 868 status_t result = _AddCallback(); 869 if (message.Flush() != B_OK) 870 return offsets[0]; 871 872 if (result != B_OK) 873 return offsets[0]; 874 875 do { 876 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 877 1 * 1000 * 1000); 878 } while (result == B_INTERRUPTED); 879 880 if (result != B_OK) 881 return offsets[0]; 882 883 return fDrawStringResult; 884 } 885 886 887 float 888 RemoteDrawingEngine::StringWidth(const char* string, int32 length, 889 escapement_delta* delta) 890 { 891 // TODO: decide if really needed and use callback if so 892 return fState.Font().StringWidth(string, length, delta); 893 } 894 895 896 // #pragma mark - 897 898 899 status_t 900 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, 901 BRect bounds) 902 { 903 if (_AddCallback() != B_OK) 904 return B_UNSUPPORTED; 905 906 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 907 908 message.Start(RP_READ_BITMAP); 909 message.Add(fToken); 910 message.Add(bounds); 911 message.Add(drawCursor); 912 if (message.Flush() != B_OK) 913 return B_UNSUPPORTED; 914 915 status_t result; 916 do { 917 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 918 100 * 1000 * 1000); 919 } while (result == B_INTERRUPTED); 920 921 if (result != B_OK) 922 return result; 923 924 BBitmap* read = fReadBitmapResult; 925 if (read == NULL) 926 return B_UNSUPPORTED; 927 928 result = bitmap->ImportBits(read->Bits(), read->BitsLength(), 929 read->BytesPerRow(), read->ColorSpace()); 930 delete read; 931 return result; 932 } 933 934 935 // #pragma mark - 936 937 938 status_t 939 RemoteDrawingEngine::_AddCallback() 940 { 941 if (fCallbackAdded) 942 return B_OK; 943 944 if (fResultNotify < 0) 945 fResultNotify = create_sem(0, "drawing engine result"); 946 if (fResultNotify < 0) 947 return fResultNotify; 948 949 status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult, 950 this); 951 952 fCallbackAdded = result == B_OK; 953 return result; 954 } 955 956 957 bool 958 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message) 959 { 960 RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie; 961 962 switch (message.Code()) { 963 case RP_DRAW_STRING_RESULT: 964 if (message.Read(engine->fDrawStringResult) != B_OK) 965 return false; 966 break; 967 968 case RP_STRING_WIDTH_RESULT: 969 if (message.Read(engine->fStringWidthResult) != B_OK) 970 return false; 971 break; 972 973 case RP_READ_BITMAP_RESULT: 974 if (message.ReadBitmap(&engine->fReadBitmapResult) != B_OK) 975 return false; 976 break; 977 978 default: 979 return false; 980 } 981 982 release_sem(engine->fResultNotify); 983 return true; 984 } 985 986 987 BRect 988 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount) 989 { 990 BRect bounds(1000000, 1000000, 0, 0); 991 for (int32 i = 0; i < pointCount; i++) { 992 bounds.left = min_c(bounds.left, points[i].x); 993 bounds.top = min_c(bounds.top, points[i].y); 994 bounds.right = max_c(bounds.right, points[i].x); 995 bounds.bottom = max_c(bounds.bottom, points[i].y); 996 } 997 998 return bounds; 999 } 1000 1001 1002 status_t 1003 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options, 1004 const BRect& bitmapRect, const BRect& viewRect, double xScale, 1005 double yScale, BRegion& region, UtilityBitmap**& bitmaps) 1006 { 1007 int32 rectCount = region.CountRects(); 1008 bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*)); 1009 if (bitmaps == NULL) 1010 return B_NO_MEMORY; 1011 1012 for (int32 i = 0; i < rectCount; i++) { 1013 BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop()); 1014 int32 targetWidth = (int32)(sourceRect.Width() + 1.5); 1015 int32 targetHeight = (int32)(sourceRect.Height() + 1.5); 1016 1017 if (xScale != 1.0) { 1018 sourceRect.left = (int32)(sourceRect.left * xScale + 0.5); 1019 sourceRect.right = (int32)(sourceRect.right * xScale + 0.5); 1020 if (xScale < 1.0) 1021 targetWidth = (int32)(sourceRect.Width() + 1.5); 1022 } 1023 1024 if (yScale != 1.0) { 1025 sourceRect.top = (int32)(sourceRect.top * yScale + 0.5); 1026 sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5); 1027 if (yScale < 1.0) 1028 targetHeight = (int32)(sourceRect.Height() + 1.5); 1029 } 1030 1031 sourceRect.OffsetBy(bitmapRect.LeftTop()); 1032 // sourceRect is now the part of the bitmap we want copied 1033 1034 status_t result = B_OK; 1035 if ((xScale > 1.0 || yScale > 1.0) 1036 && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5) 1037 * (int32)(sourceRect.Height() + 1.5))) { 1038 // the target bitmap is smaller than the source, scale it locally 1039 // and send over the smaller version to avoid sending any extra data 1040 if (fBitmapDrawingEngine == NULL) { 1041 fBitmapDrawingEngine 1042 = new(std::nothrow) BitmapDrawingEngine(B_RGBA32); 1043 if (fBitmapDrawingEngine == NULL) 1044 result = B_NO_MEMORY; 1045 } 1046 1047 if (result == B_OK) { 1048 result = fBitmapDrawingEngine->SetSize(targetWidth, 1049 targetHeight); 1050 } 1051 1052 if (result == B_OK) { 1053 fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); 1054 1055 switch (bitmap.ColorSpace()) { 1056 case B_RGBA32: 1057 case B_RGBA32_BIG: 1058 case B_RGBA15: 1059 case B_RGBA15_BIG: 1060 break; 1061 1062 default: 1063 { 1064 // we need to clear the background if there may be 1065 // transparency through transparent magic (we use 1066 // B_OP_COPY when we draw alpha enabled bitmaps, so we 1067 // don't need to clear there) 1068 // TODO: this is not actually correct, as we're going to 1069 // loose the transparency with the conversion to the 1070 // original non-alpha colorspace happening in 1071 // ExportToBitmap 1072 rgb_color background = { 0, 0, 0, 0 }; 1073 fBitmapDrawingEngine->FillRect( 1074 BRect(0, 0, targetWidth - 1, targetHeight -1), 1075 background); 1076 fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER); 1077 break; 1078 } 1079 } 1080 1081 fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect, 1082 BRect(0, 0, targetWidth - 1, targetHeight - 1), options); 1083 bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth, 1084 targetHeight, bitmap.ColorSpace()); 1085 if (bitmaps[i] == NULL) 1086 result = B_NO_MEMORY; 1087 } 1088 } else { 1089 // source is smaller or equal target, extract the relevant rects 1090 // directly without any scaling and conversion 1091 targetWidth = (int32)(sourceRect.Width() + 1.5); 1092 targetHeight = (int32)(sourceRect.Height() + 1.5); 1093 1094 bitmaps[i] = new(std::nothrow) UtilityBitmap( 1095 BRect(0, 0, targetWidth - 1, targetHeight - 1), 1096 bitmap.ColorSpace(), 0); 1097 if (bitmaps[i] == NULL) { 1098 result = B_NO_MEMORY; 1099 } else { 1100 result = bitmaps[i]->ImportBits(bitmap.Bits(), 1101 bitmap.BitsLength(), bitmap.BytesPerRow(), 1102 bitmap.ColorSpace(), sourceRect.LeftTop(), 1103 BPoint(0, 0), targetWidth, targetHeight); 1104 if (result != B_OK) { 1105 delete bitmaps[i]; 1106 bitmaps[i] = NULL; 1107 } 1108 } 1109 } 1110 1111 if (result != B_OK) { 1112 for (int32 j = 0; j < i; j++) 1113 delete bitmaps[j]; 1114 free(bitmaps); 1115 return result; 1116 } 1117 } 1118 1119 return B_OK; 1120 } 1121