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