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