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.Add(points[0]); 806 message.Add(points[1]); 807 message.Add(points[2]); 808 message.Add(bounds); 809 message.AddGradient(gradient); 810 } 811 812 813 void 814 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end) 815 { 816 BPoint points[2] = { start, end }; 817 BRect bounds = _BuildBounds(points, 2); 818 819 if (!fClippingRegion.Intersects(bounds)) 820 return; 821 822 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 823 message.Start(RP_STROKE_LINE); 824 message.Add(fToken); 825 message.AddList(points, 2); 826 } 827 828 829 void 830 RemoteDrawingEngine::StrokeLineArray(int32 numLines, 831 const ViewLineArrayInfo *lineData) 832 { 833 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 834 message.Start(RP_STROKE_LINE_ARRAY); 835 message.Add(fToken); 836 message.Add(numLines); 837 for (int32 i = 0; i < numLines; i++) 838 message.AddArrayLine(lineData[i]); 839 } 840 841 842 // #pragma mark - string functions 843 844 845 BPoint 846 RemoteDrawingEngine::DrawString(const char* string, int32 length, 847 const BPoint& point, escapement_delta* delta) 848 { 849 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 850 851 message.Start(RP_DRAW_STRING); 852 message.Add(fToken); 853 message.Add(point); 854 message.AddString(string, length); 855 message.Add(delta != NULL); 856 if (delta != NULL) 857 message.AddList(delta, length); 858 859 status_t result = _AddCallback(); 860 if (message.Flush() != B_OK) 861 return point; 862 863 if (result != B_OK) 864 return point; 865 866 do { 867 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 868 1 * 1000 * 1000); 869 } while (result == B_INTERRUPTED); 870 871 if (result != B_OK) 872 return point; 873 874 return fDrawStringResult; 875 } 876 877 878 BPoint 879 RemoteDrawingEngine::DrawString(const char* string, int32 length, 880 const BPoint* offsets) 881 { 882 // Guaranteed to have at least one point. 883 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 884 885 message.Start(RP_DRAW_STRING_WITH_OFFSETS); 886 message.Add(fToken); 887 message.AddString(string, length); 888 message.AddList(offsets, UTF8CountChars(string, length)); 889 890 status_t result = _AddCallback(); 891 if (message.Flush() != B_OK) 892 return offsets[0]; 893 894 if (result != B_OK) 895 return offsets[0]; 896 897 do { 898 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 899 1 * 1000 * 1000); 900 } while (result == B_INTERRUPTED); 901 902 if (result != B_OK) 903 return offsets[0]; 904 905 return fDrawStringResult; 906 } 907 908 909 float 910 RemoteDrawingEngine::StringWidth(const char* string, int32 length, 911 escapement_delta* delta) 912 { 913 // TODO: Decide if really needed. 914 915 while (true) { 916 if (_AddCallback() != B_OK) 917 break; 918 919 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 920 921 message.Start(RP_STRING_WIDTH); 922 message.Add(fToken); 923 message.AddString(string, length); 924 // TODO: Support escapement delta. 925 926 if (message.Flush() != B_OK) 927 break; 928 929 status_t result; 930 do { 931 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 932 1 * 1000 * 1000); 933 } while (result == B_INTERRUPTED); 934 935 if (result != B_OK) 936 break; 937 938 return fStringWidthResult; 939 } 940 941 // Fall back to local calculation. 942 return fState.Font().StringWidth(string, length, delta); 943 } 944 945 946 // #pragma mark - 947 948 949 status_t 950 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor, 951 BRect bounds) 952 { 953 if (_AddCallback() != B_OK) 954 return B_UNSUPPORTED; 955 956 RemoteMessage message(NULL, fHWInterface->SendBuffer()); 957 958 message.Start(RP_READ_BITMAP); 959 message.Add(fToken); 960 message.Add(bounds); 961 message.Add(drawCursor); 962 if (message.Flush() != B_OK) 963 return B_UNSUPPORTED; 964 965 status_t result; 966 do { 967 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT, 968 100 * 1000 * 1000); 969 } while (result == B_INTERRUPTED); 970 971 if (result != B_OK) 972 return result; 973 974 BBitmap* read = fReadBitmapResult; 975 if (read == NULL) 976 return B_UNSUPPORTED; 977 978 result = bitmap->ImportBits(read->Bits(), read->BitsLength(), 979 read->BytesPerRow(), read->ColorSpace()); 980 delete read; 981 return result; 982 } 983 984 985 // #pragma mark - 986 987 988 status_t 989 RemoteDrawingEngine::_AddCallback() 990 { 991 if (fCallbackAdded) 992 return B_OK; 993 994 if (fResultNotify < 0) 995 fResultNotify = create_sem(0, "drawing engine result"); 996 if (fResultNotify < 0) 997 return fResultNotify; 998 999 status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult, 1000 this); 1001 1002 fCallbackAdded = result == B_OK; 1003 return result; 1004 } 1005 1006 1007 bool 1008 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message) 1009 { 1010 RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie; 1011 1012 switch (message.Code()) { 1013 case RP_DRAW_STRING_RESULT: 1014 if (message.Read(engine->fDrawStringResult) != B_OK) 1015 return false; 1016 break; 1017 1018 case RP_STRING_WIDTH_RESULT: 1019 if (message.Read(engine->fStringWidthResult) != B_OK) 1020 return false; 1021 break; 1022 1023 case RP_READ_BITMAP_RESULT: 1024 if (message.ReadBitmap(&engine->fReadBitmapResult) != B_OK) 1025 return false; 1026 break; 1027 1028 default: 1029 return false; 1030 } 1031 1032 release_sem(engine->fResultNotify); 1033 return true; 1034 } 1035 1036 1037 BRect 1038 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount) 1039 { 1040 BRect bounds(1000000, 1000000, 0, 0); 1041 for (int32 i = 0; i < pointCount; i++) { 1042 bounds.left = min_c(bounds.left, points[i].x); 1043 bounds.top = min_c(bounds.top, points[i].y); 1044 bounds.right = max_c(bounds.right, points[i].x); 1045 bounds.bottom = max_c(bounds.bottom, points[i].y); 1046 } 1047 1048 return bounds; 1049 } 1050 1051 1052 status_t 1053 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options, 1054 const BRect& bitmapRect, const BRect& viewRect, double xScale, 1055 double yScale, BRegion& region, UtilityBitmap**& bitmaps) 1056 { 1057 int32 rectCount = region.CountRects(); 1058 bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*)); 1059 if (bitmaps == NULL) 1060 return B_NO_MEMORY; 1061 1062 for (int32 i = 0; i < rectCount; i++) { 1063 BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop()); 1064 int32 targetWidth = (int32)(sourceRect.Width() + 1.5); 1065 int32 targetHeight = (int32)(sourceRect.Height() + 1.5); 1066 1067 if (xScale != 1.0) { 1068 sourceRect.left = (int32)(sourceRect.left * xScale + 0.5); 1069 sourceRect.right = (int32)(sourceRect.right * xScale + 0.5); 1070 if (xScale < 1.0) 1071 targetWidth = (int32)(sourceRect.Width() + 1.5); 1072 } 1073 1074 if (yScale != 1.0) { 1075 sourceRect.top = (int32)(sourceRect.top * yScale + 0.5); 1076 sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5); 1077 if (yScale < 1.0) 1078 targetHeight = (int32)(sourceRect.Height() + 1.5); 1079 } 1080 1081 sourceRect.OffsetBy(bitmapRect.LeftTop()); 1082 // sourceRect is now the part of the bitmap we want copied 1083 1084 status_t result = B_OK; 1085 if ((xScale > 1.0 || yScale > 1.0) 1086 && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5) 1087 * (int32)(sourceRect.Height() + 1.5))) { 1088 // the target bitmap is smaller than the source, scale it locally 1089 // and send over the smaller version to avoid sending any extra data 1090 if (fBitmapDrawingEngine == NULL) { 1091 fBitmapDrawingEngine 1092 = new(std::nothrow) BitmapDrawingEngine(B_RGBA32); 1093 if (fBitmapDrawingEngine == NULL) 1094 result = B_NO_MEMORY; 1095 } 1096 1097 if (result == B_OK) { 1098 result = fBitmapDrawingEngine->SetSize(targetWidth, 1099 targetHeight); 1100 } 1101 1102 if (result == B_OK) { 1103 fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY); 1104 1105 switch (bitmap.ColorSpace()) { 1106 case B_RGBA32: 1107 case B_RGBA32_BIG: 1108 case B_RGBA15: 1109 case B_RGBA15_BIG: 1110 break; 1111 1112 default: 1113 { 1114 // we need to clear the background if there may be 1115 // transparency through transparent magic (we use 1116 // B_OP_COPY when we draw alpha enabled bitmaps, so we 1117 // don't need to clear there) 1118 // TODO: this is not actually correct, as we're going to 1119 // loose the transparency with the conversion to the 1120 // original non-alpha colorspace happening in 1121 // ExportToBitmap 1122 rgb_color background = { 0, 0, 0, 0 }; 1123 fBitmapDrawingEngine->FillRect( 1124 BRect(0, 0, targetWidth - 1, targetHeight -1), 1125 background); 1126 fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER); 1127 break; 1128 } 1129 } 1130 1131 fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect, 1132 BRect(0, 0, targetWidth - 1, targetHeight - 1), options); 1133 bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth, 1134 targetHeight, bitmap.ColorSpace()); 1135 if (bitmaps[i] == NULL) 1136 result = B_NO_MEMORY; 1137 } 1138 } else { 1139 // source is smaller or equal target, extract the relevant rects 1140 // directly without any scaling and conversion 1141 targetWidth = (int32)(sourceRect.Width() + 1.5); 1142 targetHeight = (int32)(sourceRect.Height() + 1.5); 1143 1144 bitmaps[i] = new(std::nothrow) UtilityBitmap( 1145 BRect(0, 0, targetWidth - 1, targetHeight - 1), 1146 bitmap.ColorSpace(), 0); 1147 if (bitmaps[i] == NULL) { 1148 result = B_NO_MEMORY; 1149 } else { 1150 result = bitmaps[i]->ImportBits(bitmap.Bits(), 1151 bitmap.BitsLength(), bitmap.BytesPerRow(), 1152 bitmap.ColorSpace(), sourceRect.LeftTop(), 1153 BPoint(0, 0), targetWidth, targetHeight); 1154 if (result != B_OK) { 1155 delete bitmaps[i]; 1156 bitmaps[i] = NULL; 1157 } 1158 } 1159 } 1160 1161 if (result != B_OK) { 1162 for (int32 j = 0; j < i; j++) 1163 delete bitmaps[j]; 1164 free(bitmaps); 1165 return result; 1166 } 1167 } 1168 1169 return B_OK; 1170 } 1171