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