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
RemoteView(BRect frame,const char * remoteHost,uint16 remotePort)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
~RemoteView()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
InitCheck()180 RemoteView::InitCheck()
181 {
182 return fInitStatus;
183 }
184
185
186 void
AttachedToWindow()187 RemoteView::AttachedToWindow()
188 {
189 SetViewColor(B_TRANSPARENT_COLOR);
190 SetViewCursor(&fViewCursor);
191 }
192
193
194 void
Draw(BRect updateRect)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
MouseMoved(BPoint where,uint32 code,const BMessage * dragMessage)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
MouseDown(BPoint where)225 RemoteView::MouseDown(BPoint where)
226 {
227 if (!fIsConnected)
228 return;
229
230 _SendMouseMessage(RP_MOUSE_DOWN, where);
231 }
232
233
234 void
MouseUp(BPoint where)235 RemoteView::MouseUp(BPoint where)
236 {
237 if (!fIsConnected)
238 return;
239
240 _SendMouseMessage(RP_MOUSE_UP, where);
241 }
242
243
244 void
KeyDown(const char * bytes,int32 numBytes)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
KeyUp(const char * bytes,int32 numBytes)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
MessageReceived(BMessage * message)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
_SendMouseMessage(uint16 code,BPoint where)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
_SendKeyMessage(uint16 code,const char * bytes,int32 numBytes)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
_StateCompareByKey(const uint32 * key,const engine_state * state)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 *
_CreateState(uint32 token)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
_DeleteState(uint32 token)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 *
_FindState(uint32 token)422 RemoteView::_FindState(uint32 token)
423 {
424 return fStates.BinarySearchByKey(token, &_StateCompareByKey);
425 }
426
427
428 int32
_DrawEntry(void * data)429 RemoteView::_DrawEntry(void *data)
430 {
431 ((RemoteView *)data)->_DrawThread();
432 return 0;
433 }
434
435
436 void
_DrawThread()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
_BuildInvalidateRect(BPoint * points,int32 pointCount)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