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