1 /* 2 * Copyright 2009-2014, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include "NetReceiver.h" 10 #include "NetSender.h" 11 #include "RemoteMessage.h" 12 #include "RemoteView.h" 13 #include "StreamingRingBuffer.h" 14 15 #include <Application.h> 16 #include <Autolock.h> 17 #include <Bitmap.h> 18 #include <Message.h> 19 #include <NetEndpoint.h> 20 #include <Region.h> 21 #include <Shape.h> 22 #include <Window.h> 23 #include <utf8_functions.h> 24 25 #include <new> 26 #include <stdio.h> 27 28 29 static const uint8 kCursorData[] = { 16 /* size, 16x16 */, 30 1 /* depth, 1 bit per pixel */, 0, 0, /* hot spot at 0, 0 */ 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 39 }; 40 41 42 #define TRACE(x...) /*printf("RemoteView: " x)*/ 43 #define TRACE_ALWAYS(x...) printf("RemoteView: " x) 44 #define TRACE_ERROR(x...) printf("RemoteView: " x) 45 46 47 typedef struct engine_state { 48 uint32 token; 49 BView * view; 50 ::pattern pattern; 51 BRegion clipping_region; 52 float pen_size; 53 bool sync_drawing; 54 } engine_state; 55 56 57 RemoteView::RemoteView(BRect frame, const char *remoteHost, uint16 remotePort) 58 : 59 BView(frame, "RemoteView", B_FOLLOW_NONE, B_WILL_DRAW), 60 fInitStatus(B_NO_INIT), 61 fIsConnected(false), 62 fReceiveBuffer(NULL), 63 fSendBuffer(NULL), 64 fEndpoint(NULL), 65 fReceiver(NULL), 66 fSender(NULL), 67 fStopThread(false), 68 fOffscreenBitmap(NULL), 69 fOffscreen(NULL), 70 fViewCursor(kCursorData), 71 fCursorBitmap(NULL), 72 fCursorVisible(false) 73 { 74 fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 75 if (fReceiveBuffer == NULL) { 76 fInitStatus = B_NO_MEMORY; 77 TRACE_ERROR("no memory available\n"); 78 return; 79 } 80 81 fInitStatus = fReceiveBuffer->InitCheck(); 82 if (fInitStatus != B_OK) 83 return; 84 85 fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024); 86 if (fSendBuffer == NULL) { 87 fInitStatus = B_NO_MEMORY; 88 TRACE_ERROR("no memory available\n"); 89 return; 90 } 91 92 fInitStatus = fSendBuffer->InitCheck(); 93 if (fInitStatus != B_OK) 94 return; 95 96 fEndpoint = new(std::nothrow) BNetEndpoint(); 97 if (fEndpoint == NULL) { 98 fInitStatus = B_NO_MEMORY; 99 TRACE_ERROR("no memory available\n"); 100 return; 101 } 102 103 fInitStatus = fEndpoint->Connect(remoteHost, remotePort); 104 if (fInitStatus != B_OK) { 105 TRACE_ERROR("failed to connect to %s:%" B_PRIu16 "\n", 106 remoteHost, remotePort); 107 return; 108 } 109 110 fSender = new(std::nothrow) NetSender(fEndpoint, fSendBuffer); 111 if (fSender == NULL) { 112 fInitStatus = B_NO_MEMORY; 113 TRACE_ERROR("no memory available\n"); 114 return; 115 } 116 117 fReceiver = new(std::nothrow) NetReceiver(fEndpoint, fReceiveBuffer); 118 if (fReceiver == NULL) { 119 fInitStatus = B_NO_MEMORY; 120 TRACE_ERROR("no memory available\n"); 121 return; 122 } 123 124 BRect bounds = frame.OffsetToCopy(0, 0); 125 fOffscreenBitmap = new(std::nothrow) BBitmap(bounds, B_BITMAP_ACCEPTS_VIEWS, 126 B_RGB32); 127 if (fOffscreenBitmap == NULL) { 128 fInitStatus = B_NO_MEMORY; 129 TRACE_ERROR("no memory available\n"); 130 return; 131 } 132 133 fOffscreen = new(std::nothrow) BView(bounds, "offscreen remote view", 134 B_FOLLOW_NONE, B_WILL_DRAW); 135 if (fOffscreen == NULL) { 136 fInitStatus = B_NO_MEMORY; 137 TRACE_ERROR("no memory available\n"); 138 return; 139 } 140 141 fOffscreenBitmap->AddChild(fOffscreen); 142 fOffscreen->SetDrawingMode(B_OP_COPY); 143 144 fDrawThread = spawn_thread(&_DrawEntry, "draw thread", B_NORMAL_PRIORITY, 145 this); 146 if (fDrawThread < 0) { 147 fInitStatus = fDrawThread; 148 149 TRACE_ERROR("failed to start _DrawThread()\n"); 150 TRACE_ERROR("status = %" B_PRIx32 "\n", fInitStatus); 151 152 return; 153 } 154 155 resume_thread(fDrawThread); 156 } 157 158 159 RemoteView::~RemoteView() 160 { 161 fStopThread = true; 162 163 delete fReceiver; 164 delete fReceiveBuffer; 165 166 delete fSendBuffer; 167 delete fSender; 168 169 delete fEndpoint; 170 171 delete fOffscreenBitmap; 172 delete fCursorBitmap; 173 174 int32 result; 175 wait_for_thread(fDrawThread, &result); 176 } 177 178 179 status_t 180 RemoteView::InitCheck() 181 { 182 return fInitStatus; 183 } 184 185 186 void 187 RemoteView::AttachedToWindow() 188 { 189 SetViewColor(B_TRANSPARENT_COLOR); 190 SetViewCursor(&fViewCursor); 191 } 192 193 194 void 195 RemoteView::Draw(BRect updateRect) 196 { 197 SetDrawingMode(B_OP_COPY); 198 fOffscreenBitmap->Lock(); 199 fOffscreen->Sync(); 200 201 DrawBitmap(fOffscreenBitmap, updateRect, updateRect); 202 203 if (fCursorVisible && fCursorBitmap != NULL 204 && fCursorFrame.Intersects(updateRect)) { 205 DrawBitmap(fOffscreenBitmap, fCursorFrame, fCursorFrame); 206 SetDrawingMode(B_OP_ALPHA); 207 DrawBitmap(fCursorBitmap, fCursorFrame.LeftTop()); 208 } 209 210 fOffscreenBitmap->Unlock(); 211 } 212 213 214 void 215 RemoteView::MouseMoved(BPoint where, uint32 code, const BMessage *dragMessage) 216 { 217 if (!fIsConnected) 218 return; 219 220 _SendMouseMessage(RP_MOUSE_MOVED, where); 221 } 222 223 224 void 225 RemoteView::MouseDown(BPoint where) 226 { 227 if (!fIsConnected) 228 return; 229 230 _SendMouseMessage(RP_MOUSE_DOWN, where); 231 } 232 233 234 void 235 RemoteView::MouseUp(BPoint where) 236 { 237 if (!fIsConnected) 238 return; 239 240 _SendMouseMessage(RP_MOUSE_UP, where); 241 } 242 243 244 void 245 RemoteView::KeyDown(const char *bytes, int32 numBytes) 246 { 247 if (!fIsConnected) 248 return; 249 250 _SendKeyMessage(RP_KEY_DOWN, bytes, numBytes); 251 } 252 253 254 void 255 RemoteView::KeyUp(const char *bytes, int32 numBytes) 256 { 257 if (!fIsConnected) 258 return; 259 260 _SendKeyMessage(RP_KEY_UP, bytes, numBytes); 261 } 262 263 264 void 265 RemoteView::MessageReceived(BMessage *message) 266 { 267 if (!fIsConnected) { 268 BView::MessageReceived(message); 269 return; 270 } 271 272 switch (message->what) { 273 case B_UNMAPPED_KEY_DOWN: 274 case B_UNMAPPED_KEY_UP: 275 // these are easily repeated and then cause a flood of messages 276 // so we might not want them. 277 break; 278 279 case B_MODIFIERS_CHANGED: 280 { 281 uint32 modifiers = 0; 282 message->FindInt32("modifiers", (int32 *)&modifiers); 283 RemoteMessage message(NULL, fSendBuffer); 284 message.Start(RP_MODIFIERS_CHANGED); 285 message.Add(modifiers); 286 break; 287 } 288 289 case B_MOUSE_WHEEL_CHANGED: 290 { 291 float xDelta, yDelta; 292 if (message->FindFloat("be:wheel_delta_x", &xDelta) != B_OK) 293 xDelta = 0; 294 if (message->FindFloat("be:wheel_delta_y", &yDelta) != B_OK) 295 yDelta = 0; 296 297 RemoteMessage message(NULL, fSendBuffer); 298 message.Start(RP_MOUSE_WHEEL_CHANGED); 299 message.Add(xDelta); 300 message.Add(yDelta); 301 break; 302 } 303 } 304 305 BView::MessageReceived(message); 306 } 307 308 309 void 310 RemoteView::_SendMouseMessage(uint16 code, BPoint where) 311 { 312 RemoteMessage message(NULL, fSendBuffer); 313 message.Start(code); 314 message.Add(where); 315 316 if (code == RP_MOUSE_MOVED) 317 return; 318 319 BMessage *event = Window()->CurrentMessage(); 320 321 int32 buttons = 0; 322 event->FindInt32("buttons", &buttons); 323 message.Add(buttons); 324 325 if (code == RP_MOUSE_DOWN) 326 return; 327 328 int32 clicks; 329 event->FindInt32("clicks", &clicks); 330 message.Add(clicks); 331 } 332 333 334 void 335 RemoteView::_SendKeyMessage(uint16 code, const char *bytes, int32 numBytes) 336 { 337 RemoteMessage message(NULL, fSendBuffer); 338 message.Start(code); 339 message.Add(numBytes); 340 message.AddList(bytes, numBytes); 341 342 BMessage *event = Window()->CurrentMessage(); 343 344 int32 rawChar, key; 345 event->FindInt32("raw_char", &rawChar); 346 event->FindInt32("key", &key); 347 348 message.Add(rawChar); 349 message.Add(key); 350 } 351 352 353 int 354 RemoteView::_StateCompareByKey(const uint32 *key, const engine_state *state) 355 { 356 if (state->token == *key) 357 return 0; 358 359 if (state->token < *key) 360 return -1; 361 362 return 1; 363 } 364 365 366 engine_state * 367 RemoteView::_CreateState(uint32 token) 368 { 369 int32 index = fStates.BinarySearchIndexByKey(token, &_StateCompareByKey); 370 if (index >= 0) { 371 TRACE_ERROR("state for token %" B_PRIu32 " already in list\n", token); 372 return NULL; 373 } 374 375 engine_state *state = new(std::nothrow) engine_state; 376 if (state == NULL) { 377 TRACE_ERROR("failed to allocate engine state\n"); 378 return NULL; 379 } 380 381 fOffscreenBitmap->Lock(); 382 BView *offscreen = new(std::nothrow) BView(fOffscreenBitmap->Bounds(), 383 "offscreen remote view", B_FOLLOW_NONE, B_WILL_DRAW); 384 if (offscreen == NULL) { 385 TRACE_ERROR("failed to allocate offscreen view\n"); 386 fOffscreenBitmap->Unlock(); 387 delete state; 388 return NULL; 389 } 390 391 fOffscreenBitmap->AddChild(offscreen); 392 fOffscreenBitmap->Unlock(); 393 394 state->token = token; 395 state->view = offscreen; 396 state->pattern = B_SOLID_HIGH; 397 state->clipping_region.MakeEmpty(); 398 state->pen_size = 0; 399 state->sync_drawing = true; 400 401 fStates.AddItem(state, -index - 1); 402 return state; 403 } 404 405 406 void 407 RemoteView::_DeleteState(uint32 token) 408 { 409 int32 index = fStates.BinarySearchIndexByKey(token, &_StateCompareByKey); 410 if (index < 0) 411 return; 412 413 engine_state *state = fStates.RemoveItemAt(index); 414 415 fOffscreenBitmap->RemoveChild(state->view); 416 delete state->view; 417 delete state; 418 } 419 420 421 engine_state * 422 RemoteView::_FindState(uint32 token) 423 { 424 return fStates.BinarySearchByKey(token, &_StateCompareByKey); 425 } 426 427 428 int32 429 RemoteView::_DrawEntry(void *data) 430 { 431 ((RemoteView *)data)->_DrawThread(); 432 return 0; 433 } 434 435 436 void 437 RemoteView::_DrawThread() 438 { 439 RemoteMessage reply(NULL, fSendBuffer); 440 RemoteMessage message(fReceiveBuffer, NULL); 441 442 // cursor 443 BPoint cursorHotSpot(0, 0); 444 445 reply.Start(RP_INIT_CONNECTION); 446 reply.Flush(); 447 448 while (!fStopThread) { 449 uint16 code; 450 status_t status = message.NextMessage(code); 451 452 if (status != B_OK) { 453 if (status == B_TIMED_OUT || status == -1) { 454 TRACE_ERROR("could not connect to device\n"); 455 } else { 456 TRACE_ERROR("failed to read message from receiver\n"); 457 break; 458 } 459 } 460 461 TRACE("code %u with %ld bytes data\n", code, message.DataLeft()); 462 463 BAutolock locker(this->Looper()); 464 if (!locker.IsLocked()) 465 break; 466 467 // handle stuff that doesn't go to a specific engine 468 switch (code) { 469 case RP_INIT_CONNECTION: 470 { 471 BRect bounds = fOffscreenBitmap->Bounds(); 472 reply.Start(RP_UPDATE_DISPLAY_MODE); 473 reply.Add(bounds.IntegerWidth() + 1); 474 reply.Add(bounds.IntegerHeight() + 1); 475 if (reply.Flush() == B_OK) 476 fIsConnected = true; 477 478 continue; 479 } 480 481 case RP_CLOSE_CONNECTION: 482 { 483 be_app->PostMessage(B_QUIT_REQUESTED); 484 continue; 485 } 486 487 case RP_CREATE_STATE: 488 case RP_DELETE_STATE: 489 { 490 uint32 token; 491 message.Read(token); 492 493 if (code == RP_CREATE_STATE) 494 _CreateState(token); 495 else 496 _DeleteState(token); 497 498 continue; 499 } 500 501 case RP_SET_CURSOR: 502 { 503 BBitmap *bitmap; 504 BPoint oldHotSpot = cursorHotSpot; 505 message.Read(cursorHotSpot); 506 if (message.ReadBitmap(&bitmap) != B_OK) 507 continue; 508 509 delete fCursorBitmap; 510 fCursorBitmap = bitmap; 511 512 Invalidate(fCursorFrame); 513 514 BRect bounds = fCursorBitmap->Bounds(); 515 fCursorFrame.right = fCursorFrame.left 516 + bounds.IntegerWidth() + 1; 517 fCursorFrame.bottom = fCursorFrame.bottom 518 + bounds.IntegerHeight() + 1; 519 520 fCursorFrame.OffsetBy(oldHotSpot - cursorHotSpot); 521 522 Invalidate(fCursorFrame); 523 continue; 524 } 525 526 case RP_SET_CURSOR_VISIBLE: 527 { 528 bool wasVisible = fCursorVisible; 529 message.Read(fCursorVisible); 530 if (wasVisible != fCursorVisible) 531 Invalidate(fCursorFrame); 532 continue; 533 } 534 535 case RP_MOVE_CURSOR_TO: 536 { 537 BPoint position; 538 message.Read(position); 539 540 if (fCursorVisible) 541 Invalidate(fCursorFrame); 542 543 fCursorFrame.OffsetTo(position - cursorHotSpot); 544 545 Invalidate(fCursorFrame); 546 continue; 547 } 548 549 case RP_INVALIDATE_RECT: 550 { 551 BRect rect; 552 if (message.Read(rect) != B_OK) 553 continue; 554 555 Invalidate(rect); 556 continue; 557 } 558 559 case RP_INVALIDATE_REGION: 560 { 561 BRegion region; 562 if (message.ReadRegion(region) != B_OK) 563 continue; 564 565 Invalidate(®ion); 566 continue; 567 } 568 569 case RP_FILL_REGION_COLOR_NO_CLIPPING: 570 { 571 BRegion region; 572 rgb_color color; 573 574 message.ReadRegion(region); 575 if (message.Read(color) != B_OK) 576 continue; 577 578 fOffscreen->LockLooper(); 579 fOffscreen->SetHighColor(color); 580 fOffscreen->FillRegion(®ion); 581 fOffscreen->UnlockLooper(); 582 Invalidate(®ion); 583 continue; 584 } 585 586 case RP_COPY_RECT_NO_CLIPPING: 587 { 588 int32 xOffset, yOffset; 589 BRect rect; 590 591 message.Read(xOffset); 592 message.Read(yOffset); 593 if (message.Read(rect) != B_OK) 594 continue; 595 596 BRect dest = rect.OffsetByCopy(xOffset, yOffset); 597 fOffscreen->LockLooper(); 598 fOffscreen->CopyBits(rect, dest); 599 fOffscreen->UnlockLooper(); 600 continue; 601 } 602 } 603 604 uint32 token; 605 message.Read(token); 606 607 engine_state *state = _FindState(token); 608 if (state == NULL) { 609 TRACE_ERROR("didn't find state for token %" B_PRIu32 "\n", token); 610 state = _CreateState(token); 611 if (state == NULL) { 612 TRACE_ERROR("failed to create state for unknown token\n"); 613 continue; 614 } 615 } 616 617 BView *offscreen = state->view; 618 ::pattern &pattern = state->pattern; 619 BRegion &clippingRegion = state->clipping_region; 620 float &penSize = state->pen_size; 621 bool &syncDrawing = state->sync_drawing; 622 BRegion invalidRegion; 623 624 BAutolock offscreenLocker(offscreen->Looper()); 625 if (!offscreenLocker.IsLocked()) 626 break; 627 628 switch (code) { 629 case RP_ENABLE_SYNC_DRAWING: 630 syncDrawing = true; 631 continue; 632 633 case RP_DISABLE_SYNC_DRAWING: 634 syncDrawing = false; 635 continue; 636 637 case RP_SET_OFFSETS: 638 { 639 int32 xOffset, yOffset; 640 message.Read(xOffset); 641 if (message.Read(yOffset) != B_OK) 642 continue; 643 644 offscreen->MovePenTo(xOffset, yOffset); 645 break; 646 } 647 648 case RP_SET_HIGH_COLOR: 649 case RP_SET_LOW_COLOR: 650 { 651 rgb_color color; 652 if (message.Read(color) != B_OK) 653 continue; 654 655 if (code == RP_SET_HIGH_COLOR) 656 offscreen->SetHighColor(color); 657 else 658 offscreen->SetLowColor(color); 659 660 break; 661 } 662 663 case RP_SET_PEN_SIZE: 664 { 665 float newPenSize; 666 if (message.Read(newPenSize) != B_OK) 667 continue; 668 669 offscreen->SetPenSize(newPenSize); 670 penSize = newPenSize / 2; 671 break; 672 } 673 674 case RP_SET_STROKE_MODE: 675 { 676 cap_mode capMode; 677 join_mode joinMode; 678 float miterLimit; 679 680 message.Read(capMode); 681 message.Read(joinMode); 682 if (message.Read(miterLimit) != B_OK) 683 continue; 684 685 offscreen->SetLineMode(capMode, joinMode, miterLimit); 686 break; 687 } 688 689 case RP_SET_BLENDING_MODE: 690 { 691 source_alpha sourceAlpha; 692 alpha_function alphaFunction; 693 694 message.Read(sourceAlpha); 695 if (message.Read(alphaFunction) != B_OK) 696 continue; 697 698 offscreen->SetBlendingMode(sourceAlpha, alphaFunction); 699 break; 700 } 701 702 case RP_SET_TRANSFORM: 703 { 704 BAffineTransform transform; 705 if (message.ReadTransform(transform) != B_OK) 706 continue; 707 708 offscreen->SetTransform(transform); 709 break; 710 } 711 712 case RP_SET_PATTERN: 713 { 714 if (message.Read(pattern) != B_OK) 715 continue; 716 break; 717 } 718 719 case RP_SET_DRAWING_MODE: 720 { 721 drawing_mode drawingMode; 722 if (message.Read(drawingMode) != B_OK) 723 continue; 724 725 offscreen->SetDrawingMode(drawingMode); 726 break; 727 } 728 729 case RP_SET_FONT: 730 { 731 BFont font; 732 if (message.ReadFontState(font) != B_OK) 733 continue; 734 735 offscreen->SetFont(&font); 736 break; 737 } 738 739 case RP_CONSTRAIN_CLIPPING_REGION: 740 { 741 if (message.ReadRegion(clippingRegion) != B_OK) 742 continue; 743 744 offscreen->ConstrainClippingRegion(&clippingRegion); 745 break; 746 } 747 748 case RP_INVERT_RECT: 749 { 750 BRect rect; 751 if (message.Read(rect) != B_OK) 752 continue; 753 754 offscreen->InvertRect(rect); 755 invalidRegion.Include(rect); 756 break; 757 } 758 759 case RP_DRAW_BITMAP: 760 { 761 BBitmap *bitmap; 762 BRect bitmapRect, viewRect; 763 uint32 options; 764 765 message.Read(bitmapRect); 766 message.Read(viewRect); 767 message.Read(options); 768 if (message.ReadBitmap(&bitmap) != B_OK || bitmap == NULL) 769 continue; 770 771 offscreen->DrawBitmap(bitmap, bitmapRect, viewRect, options); 772 invalidRegion.Include(viewRect); 773 delete bitmap; 774 break; 775 } 776 777 case RP_DRAW_BITMAP_RECTS: 778 { 779 color_space colorSpace; 780 int32 rectCount; 781 uint32 flags, options; 782 783 message.Read(options); 784 message.Read(colorSpace); 785 message.Read(flags); 786 message.Read(rectCount); 787 for (int32 i = 0; i < rectCount; i++) { 788 BBitmap *bitmap; 789 BRect viewRect; 790 791 message.Read(viewRect); 792 if (message.ReadBitmap(&bitmap, true, colorSpace, 793 flags) != B_OK || bitmap == NULL) { 794 continue; 795 } 796 797 offscreen->DrawBitmap(bitmap, bitmap->Bounds(), viewRect, 798 options); 799 invalidRegion.Include(viewRect); 800 delete bitmap; 801 } 802 803 break; 804 } 805 806 case RP_STROKE_ARC: 807 case RP_FILL_ARC: 808 case RP_FILL_ARC_GRADIENT: 809 { 810 BRect rect; 811 float angle, span; 812 813 message.Read(rect); 814 message.Read(angle); 815 if (message.Read(span) != B_OK) 816 continue; 817 818 if (code == RP_STROKE_ARC) { 819 offscreen->StrokeArc(rect, angle, span, pattern); 820 rect.InsetBy(-penSize, -penSize); 821 } else if (code == RP_FILL_ARC) 822 offscreen->FillArc(rect, angle, span, pattern); 823 else { 824 BGradient *gradient; 825 if (message.ReadGradient(&gradient) != B_OK) 826 continue; 827 828 offscreen->FillArc(rect, angle, span, *gradient); 829 delete gradient; 830 } 831 832 invalidRegion.Include(rect); 833 break; 834 } 835 836 case RP_STROKE_BEZIER: 837 case RP_FILL_BEZIER: 838 case RP_FILL_BEZIER_GRADIENT: 839 { 840 BPoint points[4]; 841 if (message.ReadList(points, 4) != B_OK) 842 continue; 843 844 BRect bounds = _BuildInvalidateRect(points, 4); 845 if (code == RP_STROKE_BEZIER) { 846 offscreen->StrokeBezier(points, pattern); 847 bounds.InsetBy(-penSize, -penSize); 848 } else if (code == RP_FILL_BEZIER) 849 offscreen->FillBezier(points, pattern); 850 else { 851 BGradient *gradient; 852 if (message.ReadGradient(&gradient) != B_OK) 853 continue; 854 855 offscreen->FillBezier(points, *gradient); 856 delete gradient; 857 } 858 859 invalidRegion.Include(bounds); 860 break; 861 } 862 863 case RP_STROKE_ELLIPSE: 864 case RP_FILL_ELLIPSE: 865 case RP_FILL_ELLIPSE_GRADIENT: 866 { 867 BRect rect; 868 if (message.Read(rect) != B_OK) 869 continue; 870 871 if (code == RP_STROKE_ELLIPSE) { 872 offscreen->StrokeEllipse(rect, pattern); 873 rect.InsetBy(-penSize, -penSize); 874 } else if (code == RP_FILL_ELLIPSE) 875 offscreen->FillEllipse(rect, pattern); 876 else { 877 BGradient *gradient; 878 if (message.ReadGradient(&gradient) != B_OK) 879 continue; 880 881 offscreen->FillEllipse(rect, *gradient); 882 delete gradient; 883 } 884 885 invalidRegion.Include(rect); 886 break; 887 } 888 889 case RP_STROKE_POLYGON: 890 case RP_FILL_POLYGON: 891 case RP_FILL_POLYGON_GRADIENT: 892 { 893 BRect bounds; 894 bool closed; 895 int32 numPoints; 896 897 message.Read(bounds); 898 message.Read(closed); 899 if (message.Read(numPoints) != B_OK) 900 continue; 901 902 BPoint points[numPoints]; 903 for (int32 i = 0; i < numPoints; i++) 904 message.Read(points[i]); 905 906 if (code == RP_STROKE_POLYGON) { 907 offscreen->StrokePolygon(points, numPoints, bounds, closed, 908 pattern); 909 bounds.InsetBy(-penSize, -penSize); 910 } else if (code == RP_FILL_POLYGON) 911 offscreen->FillPolygon(points, numPoints, bounds, pattern); 912 else { 913 BGradient *gradient; 914 if (message.ReadGradient(&gradient) != B_OK) 915 continue; 916 917 offscreen->FillPolygon(points, numPoints, bounds, 918 *gradient); 919 delete gradient; 920 } 921 922 invalidRegion.Include(bounds); 923 break; 924 } 925 926 case RP_STROKE_RECT: 927 case RP_FILL_RECT: 928 case RP_FILL_RECT_GRADIENT: 929 { 930 BRect rect; 931 if (message.Read(rect) != B_OK) 932 continue; 933 934 if (code == RP_STROKE_RECT) { 935 offscreen->StrokeRect(rect, pattern); 936 rect.InsetBy(-penSize, -penSize); 937 } else if (code == RP_FILL_RECT) 938 offscreen->FillRect(rect, pattern); 939 else { 940 BGradient *gradient; 941 if (message.ReadGradient(&gradient) != B_OK) 942 continue; 943 944 offscreen->FillRect(rect, *gradient); 945 delete gradient; 946 } 947 948 invalidRegion.Include(rect); 949 break; 950 } 951 952 case RP_STROKE_ROUND_RECT: 953 case RP_FILL_ROUND_RECT: 954 case RP_FILL_ROUND_RECT_GRADIENT: 955 { 956 BRect rect; 957 float xRadius, yRadius; 958 959 message.Read(rect); 960 message.Read(xRadius); 961 if (message.Read(yRadius) != B_OK) 962 continue; 963 964 if (code == RP_STROKE_ROUND_RECT) { 965 offscreen->StrokeRoundRect(rect, xRadius, yRadius, 966 pattern); 967 rect.InsetBy(-penSize, -penSize); 968 } else if (code == RP_FILL_ROUND_RECT) 969 offscreen->FillRoundRect(rect, xRadius, yRadius, pattern); 970 else { 971 BGradient *gradient; 972 if (message.ReadGradient(&gradient) != B_OK) 973 continue; 974 975 offscreen->FillRoundRect(rect, xRadius, yRadius, 976 *gradient); 977 delete gradient; 978 } 979 980 invalidRegion.Include(rect); 981 break; 982 } 983 984 case RP_STROKE_SHAPE: 985 case RP_FILL_SHAPE: 986 case RP_FILL_SHAPE_GRADIENT: 987 { 988 BRect bounds; 989 int32 opCount, pointCount; 990 991 message.Read(bounds); 992 if (message.Read(opCount) != B_OK) 993 continue; 994 995 BMessage archive; 996 for (int32 i = 0; i < opCount; i++) { 997 int32 op; 998 message.Read(op); 999 archive.AddInt32("ops", op); 1000 } 1001 1002 if (message.Read(pointCount) != B_OK) 1003 continue; 1004 1005 for (int32 i = 0; i < pointCount; i++) { 1006 BPoint point; 1007 message.Read(point); 1008 archive.AddPoint("pts", point); 1009 } 1010 1011 BPoint offset; 1012 message.Read(offset); 1013 1014 float scale; 1015 if (message.Read(scale) != B_OK) 1016 continue; 1017 1018 offscreen->PushState(); 1019 offscreen->MovePenTo(offset); 1020 offscreen->SetScale(scale); 1021 1022 BShape shape(&archive); 1023 if (code == RP_STROKE_SHAPE) { 1024 offscreen->StrokeShape(&shape, pattern); 1025 bounds.InsetBy(-penSize, -penSize); 1026 } else if (code == RP_FILL_SHAPE) 1027 offscreen->FillShape(&shape, pattern); 1028 else { 1029 BGradient *gradient; 1030 if (message.ReadGradient(&gradient) != B_OK) { 1031 offscreen->PopState(); 1032 continue; 1033 } 1034 1035 offscreen->FillShape(&shape, *gradient); 1036 delete gradient; 1037 } 1038 1039 offscreen->PopState(); 1040 invalidRegion.Include(bounds); 1041 break; 1042 } 1043 1044 case RP_STROKE_TRIANGLE: 1045 case RP_FILL_TRIANGLE: 1046 case RP_FILL_TRIANGLE_GRADIENT: 1047 { 1048 BRect bounds; 1049 BPoint points[3]; 1050 1051 message.ReadList(points, 3); 1052 if (message.Read(bounds) != B_OK) 1053 continue; 1054 1055 if (code == RP_STROKE_TRIANGLE) { 1056 offscreen->StrokeTriangle(points[0], points[1], points[2], 1057 bounds, pattern); 1058 bounds.InsetBy(-penSize, -penSize); 1059 } else if (code == RP_FILL_TRIANGLE) { 1060 offscreen->FillTriangle(points[0], points[1], points[2], 1061 bounds, pattern); 1062 } else { 1063 BGradient *gradient; 1064 if (message.ReadGradient(&gradient) != B_OK) 1065 continue; 1066 1067 offscreen->FillTriangle(points[0], points[1], points[2], 1068 bounds, *gradient); 1069 delete gradient; 1070 } 1071 1072 invalidRegion.Include(bounds); 1073 break; 1074 } 1075 1076 case RP_STROKE_LINE: 1077 { 1078 BPoint points[2]; 1079 if (message.ReadList(points, 2) != B_OK) 1080 continue; 1081 1082 offscreen->StrokeLine(points[0], points[1], pattern); 1083 1084 BRect bounds = _BuildInvalidateRect(points, 2); 1085 invalidRegion.Include(bounds.InsetBySelf(-penSize, -penSize)); 1086 break; 1087 } 1088 1089 case RP_STROKE_LINE_ARRAY: 1090 { 1091 int32 numLines; 1092 if (message.Read(numLines) != B_OK) 1093 continue; 1094 1095 BRect bounds; 1096 offscreen->BeginLineArray(numLines); 1097 for (int32 i = 0; i < numLines; i++) { 1098 rgb_color color; 1099 BPoint start, end; 1100 message.ReadArrayLine(start, end, color); 1101 offscreen->AddLine(start, end, color); 1102 1103 bounds.left = min_c(bounds.left, min_c(start.x, end.x)); 1104 bounds.top = min_c(bounds.top, min_c(start.y, end.y)); 1105 bounds.right = max_c(bounds.right, max_c(start.x, end.x)); 1106 bounds.bottom = max_c(bounds.bottom, max_c(start.y, end.y)); 1107 } 1108 1109 offscreen->EndLineArray(); 1110 invalidRegion.Include(bounds); 1111 break; 1112 } 1113 1114 case RP_FILL_REGION: 1115 case RP_FILL_REGION_GRADIENT: 1116 { 1117 BRegion region; 1118 if (message.ReadRegion(region) != B_OK) 1119 continue; 1120 1121 if (code == RP_FILL_REGION) 1122 offscreen->FillRegion(®ion, pattern); 1123 else { 1124 BGradient *gradient; 1125 if (message.ReadGradient(&gradient) != B_OK) 1126 continue; 1127 1128 offscreen->FillRegion(®ion, *gradient); 1129 delete gradient; 1130 } 1131 1132 invalidRegion.Include(®ion); 1133 break; 1134 } 1135 1136 case RP_STROKE_POINT_COLOR: 1137 { 1138 BPoint point; 1139 rgb_color color; 1140 1141 message.Read(point); 1142 if (message.Read(color) != B_OK) 1143 continue; 1144 1145 rgb_color oldColor = offscreen->HighColor(); 1146 offscreen->SetHighColor(color); 1147 offscreen->StrokeLine(point, point); 1148 offscreen->SetHighColor(oldColor); 1149 1150 invalidRegion.Include( 1151 BRect(point, point).InsetBySelf(-penSize, -penSize)); 1152 break; 1153 } 1154 1155 case RP_STROKE_LINE_1PX_COLOR: 1156 { 1157 BPoint points[2]; 1158 rgb_color color; 1159 1160 message.ReadList(points, 2); 1161 if (message.Read(color) != B_OK) 1162 continue; 1163 1164 float oldSize = offscreen->PenSize(); 1165 rgb_color oldColor = offscreen->HighColor(); 1166 drawing_mode oldMode = offscreen->DrawingMode(); 1167 offscreen->SetPenSize(1); 1168 offscreen->SetHighColor(color); 1169 offscreen->SetDrawingMode(B_OP_OVER); 1170 1171 offscreen->StrokeLine(points[0], points[1]); 1172 1173 offscreen->SetDrawingMode(oldMode); 1174 offscreen->SetHighColor(oldColor); 1175 offscreen->SetPenSize(oldSize); 1176 1177 invalidRegion.Include(_BuildInvalidateRect(points, 2)); 1178 break; 1179 } 1180 1181 case RP_STROKE_RECT_1PX_COLOR: 1182 case RP_FILL_RECT_COLOR: 1183 { 1184 BRect rect; 1185 rgb_color color; 1186 1187 message.Read(rect); 1188 if (message.Read(color) != B_OK) 1189 continue; 1190 1191 rgb_color oldColor = offscreen->HighColor(); 1192 offscreen->SetHighColor(color); 1193 1194 if (code == RP_STROKE_RECT_1PX_COLOR) { 1195 float oldSize = PenSize(); 1196 offscreen->SetPenSize(1); 1197 offscreen->StrokeRect(rect); 1198 offscreen->SetPenSize(oldSize); 1199 } else 1200 offscreen->FillRect(rect); 1201 1202 offscreen->SetHighColor(oldColor); 1203 invalidRegion.Include(rect); 1204 break; 1205 } 1206 1207 case RP_DRAW_STRING: 1208 { 1209 BPoint point; 1210 size_t length; 1211 char *string; 1212 bool hasDelta; 1213 1214 message.Read(point); 1215 message.ReadString(&string, length); 1216 if (message.Read(hasDelta) != B_OK) { 1217 free(string); 1218 continue; 1219 } 1220 1221 if (hasDelta) { 1222 escapement_delta delta[length]; 1223 message.ReadList(delta, length); 1224 offscreen->DrawString(string, point, delta); 1225 } else 1226 offscreen->DrawString(string, point); 1227 1228 free(string); 1229 reply.Start(RP_DRAW_STRING_RESULT); 1230 reply.Add(token); 1231 reply.Add(offscreen->PenLocation()); 1232 reply.Flush(); 1233 1234 font_height height; 1235 offscreen->GetFontHeight(&height); 1236 1237 BRect bounds(point, offscreen->PenLocation()); 1238 bounds.top -= height.ascent; 1239 bounds.bottom += height.descent; 1240 invalidRegion.Include(bounds); 1241 break; 1242 } 1243 1244 case RP_DRAW_STRING_WITH_OFFSETS: 1245 { 1246 size_t length; 1247 char *string; 1248 message.ReadString(&string, length); 1249 int32 count = UTF8CountChars(string, length); 1250 1251 BPoint offsets[count]; 1252 if (message.ReadList(offsets, count) != B_OK) { 1253 free(string); 1254 continue; 1255 } 1256 1257 offscreen->DrawString(string, offsets, count); 1258 1259 reply.Start(RP_DRAW_STRING_RESULT); 1260 reply.Add(token); 1261 reply.Add(offscreen->PenLocation()); 1262 reply.Flush(); 1263 1264 BFont font; 1265 offscreen->GetFont(&font); 1266 1267 BRect boxes[count]; 1268 font.GetBoundingBoxesAsGlyphs(string, count, B_SCREEN_METRIC, 1269 boxes); 1270 free(string); 1271 1272 font_height height; 1273 offscreen->GetFontHeight(&height); 1274 1275 for (int32 i = 0; i < count; i++) { 1276 // TODO: validate 1277 boxes[i].OffsetBy(offsets[i] + BPoint(0, -height.ascent)); 1278 invalidRegion.Include(boxes[i]); 1279 } 1280 1281 break; 1282 } 1283 1284 case RP_READ_BITMAP: 1285 { 1286 BRect bounds; 1287 bool drawCursor; 1288 1289 message.Read(bounds); 1290 if (message.Read(drawCursor) != B_OK) 1291 continue; 1292 1293 // TODO: support the drawCursor flag 1294 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_RGB32); 1295 bitmap.ImportBits(fOffscreenBitmap, bounds.LeftTop(), 1296 BPoint(0, 0), bounds.Size()); 1297 1298 reply.Start(RP_READ_BITMAP_RESULT); 1299 reply.Add(token); 1300 reply.AddBitmap(&bitmap); 1301 reply.Flush(); 1302 break; 1303 } 1304 1305 default: 1306 TRACE_ERROR("unknown protocol code: %u\n", code); 1307 break; 1308 } 1309 1310 if (syncDrawing) { 1311 offscreen->Sync(); 1312 Invalidate(&invalidRegion); 1313 } 1314 } 1315 } 1316 1317 1318 BRect 1319 RemoteView::_BuildInvalidateRect(BPoint *points, int32 pointCount) 1320 { 1321 BRect bounds(1000000, 1000000, 0, 0); 1322 for (int32 i = 0; i < pointCount; i++) { 1323 bounds.left = min_c(bounds.left, points[i].x); 1324 bounds.top = min_c(bounds.top, points[i].y); 1325 bounds.right = max_c(bounds.right, points[i].x); 1326 bounds.bottom = max_c(bounds.bottom, points[i].y); 1327 } 1328 1329 return bounds; 1330 } 1331