RemoteDesktop: Implement support for BAffineTransform.
[haiku.git] / src / servers / app / drawing / interface / remote / RemoteDrawingEngine.cpp
blobfc1a0b3dc4d2980e0f62a17e74a093c1e5dac6da
1 /*
2 * Copyright 2009-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
9 #include "RemoteDrawingEngine.h"
10 #include "RemoteMessage.h"
12 #include "BitmapDrawingEngine.h"
13 #include "DrawState.h"
14 #include "ServerTokenSpace.h"
16 #include <Bitmap.h>
17 #include <utf8_functions.h>
19 #include <new>
22 #define TRACE(x...) /*debug_printf("RemoteDrawingEngine: " x)*/
23 #define TRACE_ALWAYS(x...) debug_printf("RemoteDrawingEngine: " x)
24 #define TRACE_ERROR(x...) debug_printf("RemoteDrawingEngine: " x)
27 RemoteDrawingEngine::RemoteDrawingEngine(RemoteHWInterface* interface)
29 DrawingEngine(interface),
30 fHWInterface(interface),
31 fToken(gTokenSpace.NewToken(kRemoteDrawingEngineToken, this)),
32 fExtendWidth(0),
33 fCallbackAdded(false),
34 fResultNotify(-1),
35 fStringWidthResult(0.0f),
36 fReadBitmapResult(NULL),
37 fBitmapDrawingEngine(NULL)
39 RemoteMessage message(NULL, fHWInterface->SendBuffer());
40 message.Start(RP_CREATE_STATE);
41 message.Add(fToken);
45 RemoteDrawingEngine::~RemoteDrawingEngine()
47 RemoteMessage message(NULL, fHWInterface->SendBuffer());
48 message.Start(RP_DELETE_STATE);
49 message.Add(fToken);
50 message.Flush();
52 delete fBitmapDrawingEngine;
54 if (fCallbackAdded)
55 fHWInterface->RemoveCallback(fToken);
56 if (fResultNotify >= 0)
57 delete_sem(fResultNotify);
61 // #pragma mark -
64 void
65 RemoteDrawingEngine::FrameBufferChanged()
67 // Not allowed
71 // #pragma mark -
74 void
75 RemoteDrawingEngine::SetCopyToFrontEnabled(bool enabled)
77 DrawingEngine::SetCopyToFrontEnabled(enabled);
79 RemoteMessage message(NULL, fHWInterface->SendBuffer());
80 message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING);
81 message.Add(fToken);
85 // #pragma mark -
88 //! the RemoteDrawingEngine needs to be locked!
89 void
90 RemoteDrawingEngine::ConstrainClippingRegion(const BRegion* region)
92 if (fClippingRegion == *region)
93 return;
95 fClippingRegion = *region;
97 RemoteMessage message(NULL, fHWInterface->SendBuffer());
98 message.Start(RP_CONSTRAIN_CLIPPING_REGION);
99 message.Add(fToken);
100 message.AddRegion(*region);
104 void
105 RemoteDrawingEngine::SetDrawState(const DrawState* state, int32 xOffset,
106 int32 yOffset)
108 SetPenSize(state->PenSize());
109 SetDrawingMode(state->GetDrawingMode());
110 SetBlendingMode(state->AlphaSrcMode(), state->AlphaFncMode());
111 SetPattern(state->GetPattern().GetPattern());
112 SetStrokeMode(state->LineCapMode(), state->LineJoinMode(),
113 state->MiterLimit());
114 SetHighColor(state->HighColor());
115 SetLowColor(state->LowColor());
116 SetFont(state->Font());
117 SetTransform(state->CombinedTransform());
119 RemoteMessage message(NULL, fHWInterface->SendBuffer());
120 message.Start(RP_SET_OFFSETS);
121 message.Add(fToken);
122 message.Add(xOffset);
123 message.Add(yOffset);
127 void
128 RemoteDrawingEngine::SetHighColor(const rgb_color& color)
130 if (fState.HighColor() == color)
131 return;
133 fState.SetHighColor(color);
135 RemoteMessage message(NULL, fHWInterface->SendBuffer());
136 message.Start(RP_SET_HIGH_COLOR);
137 message.Add(fToken);
138 message.Add(color);
142 void
143 RemoteDrawingEngine::SetLowColor(const rgb_color& color)
145 if (fState.LowColor() == color)
146 return;
148 fState.SetLowColor(color);
150 RemoteMessage message(NULL, fHWInterface->SendBuffer());
151 message.Start(RP_SET_LOW_COLOR);
152 message.Add(fToken);
153 message.Add(color);
157 void
158 RemoteDrawingEngine::SetPenSize(float size)
160 if (fState.PenSize() == size)
161 return;
163 fState.SetPenSize(size);
164 fExtendWidth = -(size / 2);
166 RemoteMessage message(NULL, fHWInterface->SendBuffer());
167 message.Start(RP_SET_PEN_SIZE);
168 message.Add(fToken);
169 message.Add(size);
173 void
174 RemoteDrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode,
175 float miterLimit)
177 if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode
178 && fState.MiterLimit() == miterLimit)
179 return;
181 fState.SetLineCapMode(lineCap);
182 fState.SetLineJoinMode(joinMode);
183 fState.SetMiterLimit(miterLimit);
185 RemoteMessage message(NULL, fHWInterface->SendBuffer());
186 message.Start(RP_SET_STROKE_MODE);
187 message.Add(fToken);
188 message.Add(lineCap);
189 message.Add(joinMode);
190 message.Add(miterLimit);
194 void
195 RemoteDrawingEngine::SetBlendingMode(source_alpha sourceAlpha,
196 alpha_function alphaFunc)
198 if (fState.AlphaSrcMode() == sourceAlpha
199 && fState.AlphaFncMode() == alphaFunc)
200 return;
202 fState.SetBlendingMode(sourceAlpha, alphaFunc);
204 RemoteMessage message(NULL, fHWInterface->SendBuffer());
205 message.Start(RP_SET_BLENDING_MODE);
206 message.Add(fToken);
207 message.Add(sourceAlpha);
208 message.Add(alphaFunc);
212 void
213 RemoteDrawingEngine::SetPattern(const struct pattern& pattern)
215 if (fState.GetPattern() == pattern)
216 return;
218 fState.SetPattern(pattern);
220 RemoteMessage message(NULL, fHWInterface->SendBuffer());
221 message.Start(RP_SET_PATTERN);
222 message.Add(fToken);
223 message.Add(pattern);
227 void
228 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode)
230 if (fState.GetDrawingMode() == mode)
231 return;
233 fState.SetDrawingMode(mode);
235 RemoteMessage message(NULL, fHWInterface->SendBuffer());
236 message.Start(RP_SET_DRAWING_MODE);
237 message.Add(fToken);
238 message.Add(mode);
242 void
243 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode)
245 oldMode = fState.GetDrawingMode();
246 SetDrawingMode(mode);
250 void
251 RemoteDrawingEngine::SetFont(const ServerFont& font)
253 if (fState.Font() == font)
254 return;
256 fState.SetFont(font);
258 RemoteMessage message(NULL, fHWInterface->SendBuffer());
259 message.Start(RP_SET_FONT);
260 message.Add(fToken);
261 message.AddFont(font);
265 void
266 RemoteDrawingEngine::SetFont(const DrawState* state)
268 SetFont(state->Font());
272 void
273 RemoteDrawingEngine::SetTransform(const BAffineTransform& transform)
275 if (fState.Transform() == transform)
276 return;
278 fState.SetTransform(transform);
280 RemoteMessage message(NULL, fHWInterface->SendBuffer());
281 message.Start(RP_SET_TRANSFORM);
282 message.Add(fToken);
283 message.AddTransform(transform);
287 // #pragma mark -
290 BRect
291 RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const
293 RemoteMessage message(NULL, fHWInterface->SendBuffer());
294 message.Start(RP_COPY_RECT_NO_CLIPPING);
295 message.Add(xOffset);
296 message.Add(yOffset);
297 message.Add(rect);
298 return rect.OffsetBySelf(xOffset, yOffset);
302 void
303 RemoteDrawingEngine::InvertRect(BRect rect)
305 if (!fClippingRegion.Intersects(rect))
306 return;
308 RemoteMessage message(NULL, fHWInterface->SendBuffer());
309 message.Start(RP_INVERT_RECT);
310 message.Add(fToken);
311 message.Add(rect);
315 void
316 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
317 const BRect& _viewRect, uint32 options)
319 BRect bitmapRect = _bitmapRect;
320 BRect viewRect = _viewRect;
321 double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1);
322 double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1);
324 // constrain rect to passed bitmap bounds
325 // and transfer the changes to the viewRect with the right scale
326 BRect actualBitmapRect = bitmap->Bounds();
327 if (bitmapRect.left < actualBitmapRect.left) {
328 float diff = actualBitmapRect.left - bitmapRect.left;
329 viewRect.left += diff / xScale;
330 bitmapRect.left = actualBitmapRect.left;
332 if (bitmapRect.top < actualBitmapRect.top) {
333 float diff = actualBitmapRect.top - bitmapRect.top;
334 viewRect.top += diff / yScale;
335 bitmapRect.top = actualBitmapRect.top;
337 if (bitmapRect.right > actualBitmapRect.right) {
338 float diff = bitmapRect.right - actualBitmapRect.right;
339 viewRect.right -= diff / xScale;
340 bitmapRect.right = actualBitmapRect.right;
342 if (bitmapRect.bottom > actualBitmapRect.bottom) {
343 float diff = bitmapRect.bottom - actualBitmapRect.bottom;
344 viewRect.bottom -= diff / yScale;
345 bitmapRect.bottom = actualBitmapRect.bottom;
348 BRegion clippedRegion(viewRect);
349 clippedRegion.IntersectWith(&fClippingRegion);
351 int32 rectCount = clippedRegion.CountRects();
352 if (rectCount == 0)
353 return;
355 if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != viewRect)
356 || viewRect.Width() < bitmapRect.Width()
357 || viewRect.Height() < bitmapRect.Height()) {
358 UtilityBitmap** bitmaps;
359 if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, viewRect,
360 xScale, yScale, clippedRegion, bitmaps) != B_OK) {
361 return;
364 RemoteMessage message(NULL, fHWInterface->SendBuffer());
365 message.Start(RP_DRAW_BITMAP_RECTS);
366 message.Add(fToken);
367 message.Add(options);
368 message.Add(bitmap->ColorSpace());
369 message.Add(bitmap->Flags());
370 message.Add(rectCount);
372 for (int32 i = 0; i < rectCount; i++) {
373 message.Add(clippedRegion.RectAt(i));
374 message.AddBitmap(*bitmaps[i], true);
375 delete bitmaps[i];
378 free(bitmaps);
379 return;
382 // TODO: we may want to cache/checksum bitmaps
383 RemoteMessage message(NULL, fHWInterface->SendBuffer());
384 message.Start(RP_DRAW_BITMAP);
385 message.Add(fToken);
386 message.Add(bitmapRect);
387 message.Add(viewRect);
388 message.Add(options);
389 message.AddBitmap(*bitmap);
393 void
394 RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span,
395 bool filled)
397 BRect bounds = rect;
398 if (!filled)
399 bounds.InsetBy(fExtendWidth, fExtendWidth);
401 if (!fClippingRegion.Intersects(bounds))
402 return;
404 RemoteMessage message(NULL, fHWInterface->SendBuffer());
405 message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC);
406 message.Add(fToken);
407 message.Add(rect);
408 message.Add(angle);
409 message.Add(span);
412 void
413 RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span,
414 const BGradient& gradient)
416 if (!fClippingRegion.Intersects(rect))
417 return;
419 RemoteMessage message(NULL, fHWInterface->SendBuffer());
420 message.Start(RP_FILL_ARC_GRADIENT);
421 message.Add(fToken);
422 message.Add(rect);
423 message.Add(angle);
424 message.Add(span);
425 message.AddGradient(gradient);
429 void
430 RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled)
432 BRect bounds = _BuildBounds(points, 4);
433 if (!filled)
434 bounds.InsetBy(fExtendWidth, fExtendWidth);
436 if (!fClippingRegion.Intersects(bounds))
437 return;
439 RemoteMessage message(NULL, fHWInterface->SendBuffer());
440 message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER);
441 message.Add(fToken);
442 message.AddList(points, 4);
446 void
447 RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient)
449 BRect bounds = _BuildBounds(points, 4);
450 if (!fClippingRegion.Intersects(bounds))
451 return;
453 RemoteMessage message(NULL, fHWInterface->SendBuffer());
454 message.Start(RP_FILL_BEZIER_GRADIENT);
455 message.Add(fToken);
456 message.AddList(points, 4);
457 message.AddGradient(gradient);
461 void
462 RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled)
464 BRect bounds = rect;
465 if (!filled)
466 bounds.InsetBy(fExtendWidth, fExtendWidth);
468 if (!fClippingRegion.Intersects(bounds))
469 return;
471 RemoteMessage message(NULL, fHWInterface->SendBuffer());
472 message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE);
473 message.Add(fToken);
474 message.Add(rect);
478 void
479 RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient)
481 if (!fClippingRegion.Intersects(rect))
482 return;
484 RemoteMessage message(NULL, fHWInterface->SendBuffer());
485 message.Start(RP_FILL_ELLIPSE_GRADIENT);
486 message.Add(fToken);
487 message.Add(rect);
488 message.AddGradient(gradient);
492 void
493 RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints,
494 BRect bounds, bool filled, bool closed)
496 BRect clipBounds = bounds;
497 if (!filled)
498 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
500 if (!fClippingRegion.Intersects(clipBounds))
501 return;
503 RemoteMessage message(NULL, fHWInterface->SendBuffer());
504 message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON);
505 message.Add(fToken);
506 message.Add(bounds);
507 message.Add(closed);
508 message.Add(numPoints);
509 for (int32 i = 0; i < numPoints; i++)
510 message.Add(pointList[i]);
514 void
515 RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints,
516 BRect bounds, const BGradient& gradient, bool closed)
518 if (!fClippingRegion.Intersects(bounds))
519 return;
521 RemoteMessage message(NULL, fHWInterface->SendBuffer());
522 message.Start(RP_FILL_POLYGON_GRADIENT);
523 message.Add(fToken);
524 message.Add(bounds);
525 message.Add(closed);
526 message.Add(numPoints);
527 for (int32 i = 0; i < numPoints; i++)
528 message.Add(pointList[i]);
529 message.AddGradient(gradient);
533 // #pragma mark - rgb_color versions
536 void
537 RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color)
539 BRect bounds(point, point);
540 bounds.InsetBy(fExtendWidth, fExtendWidth);
542 if (!fClippingRegion.Intersects(bounds))
543 return;
545 RemoteMessage message(NULL, fHWInterface->SendBuffer());
546 message.Start(RP_STROKE_POINT_COLOR);
547 message.Add(fToken);
548 message.Add(point);
549 message.Add(color);
553 void
554 RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
555 const rgb_color& color)
557 BPoint points[2] = { start, end };
558 BRect bounds = _BuildBounds(points, 2);
560 if (!fClippingRegion.Intersects(bounds))
561 return;
563 RemoteMessage message(NULL, fHWInterface->SendBuffer());
564 message.Start(RP_STROKE_LINE_1PX_COLOR);
565 message.Add(fToken);
566 message.AddList(points, 2);
567 message.Add(color);
571 void
572 RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color)
574 BRect bounds = rect;
575 bounds.InsetBy(fExtendWidth, fExtendWidth);
577 if (!fClippingRegion.Intersects(bounds))
578 return;
580 RemoteMessage message(NULL, fHWInterface->SendBuffer());
581 message.Start(RP_STROKE_RECT_1PX_COLOR);
582 message.Add(fToken);
583 message.Add(rect);
584 message.Add(color);
588 void
589 RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color)
591 if (!fClippingRegion.Intersects(rect))
592 return;
594 RemoteMessage message(NULL, fHWInterface->SendBuffer());
595 message.Start(RP_FILL_RECT_COLOR);
596 message.Add(fToken);
597 message.Add(rect);
598 message.Add(color);
602 void
603 RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color)
605 RemoteMessage message(NULL, fHWInterface->SendBuffer());
606 message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING);
607 message.AddRegion(region);
608 message.Add(color);
612 // #pragma mark - DrawState versions
615 void
616 RemoteDrawingEngine::StrokeRect(BRect rect)
618 BRect bounds = rect;
619 bounds.InsetBy(fExtendWidth, fExtendWidth);
621 if (!fClippingRegion.Intersects(bounds))
622 return;
624 RemoteMessage message(NULL, fHWInterface->SendBuffer());
625 message.Start(RP_STROKE_RECT);
626 message.Add(fToken);
627 message.Add(rect);
631 void
632 RemoteDrawingEngine::FillRect(BRect rect)
634 if (!fClippingRegion.Intersects(rect))
635 return;
637 RemoteMessage message(NULL, fHWInterface->SendBuffer());
638 message.Start(RP_FILL_RECT);
639 message.Add(fToken);
640 message.Add(rect);
644 void
645 RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient)
647 if (!fClippingRegion.Intersects(rect))
648 return;
650 RemoteMessage message(NULL, fHWInterface->SendBuffer());
651 message.Start(RP_FILL_RECT_GRADIENT);
652 message.Add(fToken);
653 message.Add(rect);
654 message.AddGradient(gradient);
658 void
659 RemoteDrawingEngine::FillRegion(BRegion& region)
661 BRegion clippedRegion = region;
662 clippedRegion.IntersectWith(&fClippingRegion);
663 if (clippedRegion.CountRects() == 0)
664 return;
666 RemoteMessage message(NULL, fHWInterface->SendBuffer());
667 message.Start(RP_FILL_REGION);
668 message.Add(fToken);
669 message.AddRegion(clippedRegion.CountRects() < region.CountRects()
670 ? clippedRegion : region);
674 void
675 RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient)
677 BRegion clippedRegion = region;
678 clippedRegion.IntersectWith(&fClippingRegion);
679 if (clippedRegion.CountRects() == 0)
680 return;
682 RemoteMessage message(NULL, fHWInterface->SendBuffer());
683 message.Start(RP_FILL_REGION_GRADIENT);
684 message.Add(fToken);
685 message.AddRegion(clippedRegion.CountRects() < region.CountRects()
686 ? clippedRegion : region);
687 message.AddGradient(gradient);
691 void
692 RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius,
693 bool filled)
695 BRect bounds = rect;
696 if (!filled)
697 bounds.InsetBy(fExtendWidth, fExtendWidth);
699 if (!fClippingRegion.Intersects(bounds))
700 return;
702 RemoteMessage message(NULL, fHWInterface->SendBuffer());
703 message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT);
704 message.Add(fToken);
705 message.Add(rect);
706 message.Add(xRadius);
707 message.Add(yRadius);
711 void
712 RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
713 const BGradient& gradient)
715 if (!fClippingRegion.Intersects(rect))
716 return;
718 RemoteMessage message(NULL, fHWInterface->SendBuffer());
719 message.Start(RP_FILL_ROUND_RECT_GRADIENT);
720 message.Add(fToken);
721 message.Add(rect);
722 message.Add(xRadius);
723 message.Add(yRadius);
724 message.AddGradient(gradient);
728 void
729 RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
730 const uint32* opList, int32 pointCount, const BPoint* pointList,
731 bool filled, const BPoint& viewToScreenOffset, float viewScale)
733 BRect clipBounds = bounds;
734 if (!filled)
735 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
737 if (!fClippingRegion.Intersects(clipBounds))
738 return;
740 RemoteMessage message(NULL, fHWInterface->SendBuffer());
741 message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE);
742 message.Add(fToken);
743 message.Add(bounds);
744 message.Add(opCount);
745 message.AddList(opList, opCount);
746 message.Add(pointCount);
747 message.AddList(pointList, pointCount);
748 message.Add(viewToScreenOffset);
749 message.Add(viewScale);
753 void
754 RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
755 const uint32* opList, int32 pointCount, const BPoint* pointList,
756 const BGradient& gradient, const BPoint& viewToScreenOffset,
757 float viewScale)
759 if (!fClippingRegion.Intersects(bounds))
760 return;
762 RemoteMessage message(NULL, fHWInterface->SendBuffer());
763 message.Start(RP_FILL_SHAPE_GRADIENT);
764 message.Add(fToken);
765 message.Add(bounds);
766 message.Add(opCount);
767 message.AddList(opList, opCount);
768 message.Add(pointCount);
769 message.AddList(pointList, pointCount);
770 message.AddGradient(gradient);
771 message.Add(viewToScreenOffset);
772 message.Add(viewScale);
776 void
777 RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds,
778 bool filled)
780 BRect clipBounds = bounds;
781 if (!filled)
782 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
784 if (!fClippingRegion.Intersects(clipBounds))
785 return;
787 RemoteMessage message(NULL, fHWInterface->SendBuffer());
788 message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE);
789 message.Add(fToken);
790 message.AddList(points, 3);
791 message.Add(bounds);
795 void
796 RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds,
797 const BGradient& gradient)
799 if (!fClippingRegion.Intersects(bounds))
800 return;
802 RemoteMessage message(NULL, fHWInterface->SendBuffer());
803 message.Start(RP_FILL_TRIANGLE_GRADIENT);
804 message.Add(fToken);
805 message.Add(points[0]);
806 message.Add(points[1]);
807 message.Add(points[2]);
808 message.Add(bounds);
809 message.AddGradient(gradient);
813 void
814 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
816 BPoint points[2] = { start, end };
817 BRect bounds = _BuildBounds(points, 2);
819 if (!fClippingRegion.Intersects(bounds))
820 return;
822 RemoteMessage message(NULL, fHWInterface->SendBuffer());
823 message.Start(RP_STROKE_LINE);
824 message.Add(fToken);
825 message.AddList(points, 2);
829 void
830 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
831 const ViewLineArrayInfo *lineData)
833 RemoteMessage message(NULL, fHWInterface->SendBuffer());
834 message.Start(RP_STROKE_LINE_ARRAY);
835 message.Add(fToken);
836 message.Add(numLines);
837 for (int32 i = 0; i < numLines; i++)
838 message.AddArrayLine(lineData[i]);
842 // #pragma mark - string functions
845 BPoint
846 RemoteDrawingEngine::DrawString(const char* string, int32 length,
847 const BPoint& point, escapement_delta* delta)
849 RemoteMessage message(NULL, fHWInterface->SendBuffer());
851 message.Start(RP_DRAW_STRING);
852 message.Add(fToken);
853 message.Add(point);
854 message.AddString(string, length);
855 message.Add(delta != NULL);
856 if (delta != NULL)
857 message.AddList(delta, length);
859 status_t result = _AddCallback();
860 if (message.Flush() != B_OK)
861 return point;
863 if (result != B_OK)
864 return point;
866 do {
867 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
868 1 * 1000 * 1000);
869 } while (result == B_INTERRUPTED);
871 if (result != B_OK)
872 return point;
874 return fDrawStringResult;
878 BPoint
879 RemoteDrawingEngine::DrawString(const char* string, int32 length,
880 const BPoint* offsets)
882 // Guaranteed to have at least one point.
883 RemoteMessage message(NULL, fHWInterface->SendBuffer());
885 message.Start(RP_DRAW_STRING_WITH_OFFSETS);
886 message.Add(fToken);
887 message.AddString(string, length);
888 message.AddList(offsets, UTF8CountChars(string, length));
890 status_t result = _AddCallback();
891 if (message.Flush() != B_OK)
892 return offsets[0];
894 if (result != B_OK)
895 return offsets[0];
897 do {
898 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
899 1 * 1000 * 1000);
900 } while (result == B_INTERRUPTED);
902 if (result != B_OK)
903 return offsets[0];
905 return fDrawStringResult;
909 float
910 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
911 escapement_delta* delta)
913 // TODO: decide if really needed and use callback if so
914 return fState.Font().StringWidth(string, length, delta);
918 // #pragma mark -
921 status_t
922 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
923 BRect bounds)
925 if (_AddCallback() != B_OK)
926 return B_UNSUPPORTED;
928 RemoteMessage message(NULL, fHWInterface->SendBuffer());
930 message.Start(RP_READ_BITMAP);
931 message.Add(fToken);
932 message.Add(bounds);
933 message.Add(drawCursor);
934 if (message.Flush() != B_OK)
935 return B_UNSUPPORTED;
937 status_t result;
938 do {
939 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
940 100 * 1000 * 1000);
941 } while (result == B_INTERRUPTED);
943 if (result != B_OK)
944 return result;
946 BBitmap* read = fReadBitmapResult;
947 if (read == NULL)
948 return B_UNSUPPORTED;
950 result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
951 read->BytesPerRow(), read->ColorSpace());
952 delete read;
953 return result;
957 // #pragma mark -
960 status_t
961 RemoteDrawingEngine::_AddCallback()
963 if (fCallbackAdded)
964 return B_OK;
966 if (fResultNotify < 0)
967 fResultNotify = create_sem(0, "drawing engine result");
968 if (fResultNotify < 0)
969 return fResultNotify;
971 status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
972 this);
974 fCallbackAdded = result == B_OK;
975 return result;
979 bool
980 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
982 RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
984 switch (message.Code()) {
985 case RP_DRAW_STRING_RESULT:
986 if (message.Read(engine->fDrawStringResult) != B_OK)
987 return false;
988 break;
990 case RP_STRING_WIDTH_RESULT:
991 if (message.Read(engine->fStringWidthResult) != B_OK)
992 return false;
993 break;
995 case RP_READ_BITMAP_RESULT:
996 if (message.ReadBitmap(&engine->fReadBitmapResult) != B_OK)
997 return false;
998 break;
1000 default:
1001 return false;
1004 release_sem(engine->fResultNotify);
1005 return true;
1009 BRect
1010 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1012 BRect bounds(1000000, 1000000, 0, 0);
1013 for (int32 i = 0; i < pointCount; i++) {
1014 bounds.left = min_c(bounds.left, points[i].x);
1015 bounds.top = min_c(bounds.top, points[i].y);
1016 bounds.right = max_c(bounds.right, points[i].x);
1017 bounds.bottom = max_c(bounds.bottom, points[i].y);
1020 return bounds;
1024 status_t
1025 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options,
1026 const BRect& bitmapRect, const BRect& viewRect, double xScale,
1027 double yScale, BRegion& region, UtilityBitmap**& bitmaps)
1029 int32 rectCount = region.CountRects();
1030 bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1031 if (bitmaps == NULL)
1032 return B_NO_MEMORY;
1034 for (int32 i = 0; i < rectCount; i++) {
1035 BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
1036 int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
1037 int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
1039 if (xScale != 1.0) {
1040 sourceRect.left = (int32)(sourceRect.left * xScale + 0.5);
1041 sourceRect.right = (int32)(sourceRect.right * xScale + 0.5);
1042 if (xScale < 1.0)
1043 targetWidth = (int32)(sourceRect.Width() + 1.5);
1046 if (yScale != 1.0) {
1047 sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
1048 sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5);
1049 if (yScale < 1.0)
1050 targetHeight = (int32)(sourceRect.Height() + 1.5);
1053 sourceRect.OffsetBy(bitmapRect.LeftTop());
1054 // sourceRect is now the part of the bitmap we want copied
1056 status_t result = B_OK;
1057 if ((xScale > 1.0 || yScale > 1.0)
1058 && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5)
1059 * (int32)(sourceRect.Height() + 1.5))) {
1060 // the target bitmap is smaller than the source, scale it locally
1061 // and send over the smaller version to avoid sending any extra data
1062 if (fBitmapDrawingEngine == NULL) {
1063 fBitmapDrawingEngine
1064 = new(std::nothrow) BitmapDrawingEngine(B_RGBA32);
1065 if (fBitmapDrawingEngine == NULL)
1066 result = B_NO_MEMORY;
1069 if (result == B_OK) {
1070 result = fBitmapDrawingEngine->SetSize(targetWidth,
1071 targetHeight);
1074 if (result == B_OK) {
1075 fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1077 switch (bitmap.ColorSpace()) {
1078 case B_RGBA32:
1079 case B_RGBA32_BIG:
1080 case B_RGBA15:
1081 case B_RGBA15_BIG:
1082 break;
1084 default:
1086 // we need to clear the background if there may be
1087 // transparency through transparent magic (we use
1088 // B_OP_COPY when we draw alpha enabled bitmaps, so we
1089 // don't need to clear there)
1090 // TODO: this is not actually correct, as we're going to
1091 // loose the transparency with the conversion to the
1092 // original non-alpha colorspace happening in
1093 // ExportToBitmap
1094 rgb_color background = { 0, 0, 0, 0 };
1095 fBitmapDrawingEngine->FillRect(
1096 BRect(0, 0, targetWidth - 1, targetHeight -1),
1097 background);
1098 fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1099 break;
1103 fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect,
1104 BRect(0, 0, targetWidth - 1, targetHeight - 1), options);
1105 bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth,
1106 targetHeight, bitmap.ColorSpace());
1107 if (bitmaps[i] == NULL)
1108 result = B_NO_MEMORY;
1110 } else {
1111 // source is smaller or equal target, extract the relevant rects
1112 // directly without any scaling and conversion
1113 targetWidth = (int32)(sourceRect.Width() + 1.5);
1114 targetHeight = (int32)(sourceRect.Height() + 1.5);
1116 bitmaps[i] = new(std::nothrow) UtilityBitmap(
1117 BRect(0, 0, targetWidth - 1, targetHeight - 1),
1118 bitmap.ColorSpace(), 0);
1119 if (bitmaps[i] == NULL) {
1120 result = B_NO_MEMORY;
1121 } else {
1122 result = bitmaps[i]->ImportBits(bitmap.Bits(),
1123 bitmap.BitsLength(), bitmap.BytesPerRow(),
1124 bitmap.ColorSpace(), sourceRect.LeftTop(),
1125 BPoint(0, 0), targetWidth, targetHeight);
1126 if (result != B_OK) {
1127 delete bitmaps[i];
1128 bitmaps[i] = NULL;
1133 if (result != B_OK) {
1134 for (int32 j = 0; j < i; j++)
1135 delete bitmaps[j];
1136 free(bitmaps);
1137 return result;
1141 return B_OK;