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