vfs: check userland buffers before reading them.
[haiku.git] / src / servers / app / drawing / interface / remote / RemoteDrawingEngine.cpp
blob5bd301859f6059dc7eddaae98c2f71875f9cc759
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.Add(viewToScreenOffset);
771 message.Add(viewScale);
772 message.AddGradient(gradient);
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.AddList(points, 3);
806 message.Add(bounds);
807 message.AddGradient(gradient);
811 void
812 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
814 BPoint points[2] = { start, end };
815 BRect bounds = _BuildBounds(points, 2);
817 if (!fClippingRegion.Intersects(bounds))
818 return;
820 RemoteMessage message(NULL, fHWInterface->SendBuffer());
821 message.Start(RP_STROKE_LINE);
822 message.Add(fToken);
823 message.AddList(points, 2);
827 void
828 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
829 const ViewLineArrayInfo *lineData)
831 RemoteMessage message(NULL, fHWInterface->SendBuffer());
832 message.Start(RP_STROKE_LINE_ARRAY);
833 message.Add(fToken);
834 message.Add(numLines);
835 for (int32 i = 0; i < numLines; i++)
836 message.AddArrayLine(lineData[i]);
840 // #pragma mark - string functions
843 BPoint
844 RemoteDrawingEngine::DrawString(const char* string, int32 length,
845 const BPoint& point, escapement_delta* delta)
847 RemoteMessage message(NULL, fHWInterface->SendBuffer());
849 message.Start(RP_DRAW_STRING);
850 message.Add(fToken);
851 message.Add(point);
852 message.AddString(string, length);
853 message.Add(delta != NULL);
854 if (delta != NULL)
855 message.AddList(delta, length);
857 status_t result = _AddCallback();
858 if (message.Flush() != B_OK)
859 return point;
861 if (result != B_OK)
862 return point;
864 do {
865 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
866 1 * 1000 * 1000);
867 } while (result == B_INTERRUPTED);
869 if (result != B_OK)
870 return point;
872 return fDrawStringResult;
876 BPoint
877 RemoteDrawingEngine::DrawString(const char* string, int32 length,
878 const BPoint* offsets)
880 // Guaranteed to have at least one point.
881 RemoteMessage message(NULL, fHWInterface->SendBuffer());
883 message.Start(RP_DRAW_STRING_WITH_OFFSETS);
884 message.Add(fToken);
885 message.AddString(string, length);
886 message.AddList(offsets, UTF8CountChars(string, length));
888 status_t result = _AddCallback();
889 if (message.Flush() != B_OK)
890 return offsets[0];
892 if (result != B_OK)
893 return offsets[0];
895 do {
896 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
897 1 * 1000 * 1000);
898 } while (result == B_INTERRUPTED);
900 if (result != B_OK)
901 return offsets[0];
903 return fDrawStringResult;
907 float
908 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
909 escapement_delta* delta)
911 // TODO: Decide if really needed.
913 while (true) {
914 if (_AddCallback() != B_OK)
915 break;
917 RemoteMessage message(NULL, fHWInterface->SendBuffer());
919 message.Start(RP_STRING_WIDTH);
920 message.Add(fToken);
921 message.AddString(string, length);
922 // TODO: Support escapement delta.
924 if (message.Flush() != B_OK)
925 break;
927 status_t result;
928 do {
929 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
930 1 * 1000 * 1000);
931 } while (result == B_INTERRUPTED);
933 if (result != B_OK)
934 break;
936 return fStringWidthResult;
939 // Fall back to local calculation.
940 return fState.Font().StringWidth(string, length, delta);
944 // #pragma mark -
947 status_t
948 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
949 BRect bounds)
951 if (_AddCallback() != B_OK)
952 return B_UNSUPPORTED;
954 RemoteMessage message(NULL, fHWInterface->SendBuffer());
956 message.Start(RP_READ_BITMAP);
957 message.Add(fToken);
958 message.Add(bounds);
959 message.Add(drawCursor);
960 if (message.Flush() != B_OK)
961 return B_UNSUPPORTED;
963 status_t result;
964 do {
965 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
966 10 * 1000 * 1000);
967 } while (result == B_INTERRUPTED);
969 if (result != B_OK)
970 return result;
972 BBitmap* read = fReadBitmapResult;
973 if (read == NULL)
974 return B_UNSUPPORTED;
976 result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
977 read->BytesPerRow(), read->ColorSpace());
978 delete read;
979 return result;
983 // #pragma mark -
986 status_t
987 RemoteDrawingEngine::_AddCallback()
989 if (fCallbackAdded)
990 return B_OK;
992 if (fResultNotify < 0)
993 fResultNotify = create_sem(0, "drawing engine result");
994 if (fResultNotify < 0)
995 return fResultNotify;
997 status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
998 this);
1000 fCallbackAdded = result == B_OK;
1001 return result;
1005 bool
1006 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
1008 RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
1010 switch (message.Code()) {
1011 case RP_DRAW_STRING_RESULT:
1013 status_t result = message.Read(engine->fDrawStringResult);
1014 if (result != B_OK) {
1015 TRACE_ERROR("failed to read draw string result: %s\n",
1016 strerror(result));
1017 return false;
1020 break;
1023 case RP_STRING_WIDTH_RESULT:
1025 status_t result = message.Read(engine->fStringWidthResult);
1026 if (result != B_OK) {
1027 TRACE_ERROR("failed to read string width result: %s\n",
1028 strerror(result));
1029 return false;
1032 break;
1035 case RP_READ_BITMAP_RESULT:
1037 status_t result = message.ReadBitmap(&engine->fReadBitmapResult);
1038 if (result != B_OK) {
1039 TRACE_ERROR("failed to read bitmap of read bitmap result: %s\n",
1040 strerror(result));
1041 return false;
1044 break;
1047 default:
1048 return false;
1051 release_sem(engine->fResultNotify);
1052 return true;
1056 BRect
1057 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1059 BRect bounds(1000000, 1000000, 0, 0);
1060 for (int32 i = 0; i < pointCount; i++) {
1061 bounds.left = min_c(bounds.left, points[i].x);
1062 bounds.top = min_c(bounds.top, points[i].y);
1063 bounds.right = max_c(bounds.right, points[i].x);
1064 bounds.bottom = max_c(bounds.bottom, points[i].y);
1067 return bounds;
1071 status_t
1072 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options,
1073 const BRect& bitmapRect, const BRect& viewRect, double xScale,
1074 double yScale, BRegion& region, UtilityBitmap**& bitmaps)
1076 int32 rectCount = region.CountRects();
1077 bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1078 if (bitmaps == NULL)
1079 return B_NO_MEMORY;
1081 for (int32 i = 0; i < rectCount; i++) {
1082 BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
1083 int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
1084 int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
1086 if (xScale != 1.0) {
1087 sourceRect.left = (int32)(sourceRect.left * xScale + 0.5);
1088 sourceRect.right = (int32)(sourceRect.right * xScale + 0.5);
1089 if (xScale < 1.0)
1090 targetWidth = (int32)(sourceRect.Width() + 1.5);
1093 if (yScale != 1.0) {
1094 sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
1095 sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5);
1096 if (yScale < 1.0)
1097 targetHeight = (int32)(sourceRect.Height() + 1.5);
1100 sourceRect.OffsetBy(bitmapRect.LeftTop());
1101 // sourceRect is now the part of the bitmap we want copied
1103 status_t result = B_OK;
1104 if ((xScale > 1.0 || yScale > 1.0)
1105 && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5)
1106 * (int32)(sourceRect.Height() + 1.5))) {
1107 // the target bitmap is smaller than the source, scale it locally
1108 // and send over the smaller version to avoid sending any extra data
1109 if (fBitmapDrawingEngine == NULL) {
1110 fBitmapDrawingEngine
1111 = new(std::nothrow) BitmapDrawingEngine(B_RGBA32);
1112 if (fBitmapDrawingEngine == NULL)
1113 result = B_NO_MEMORY;
1116 if (result == B_OK) {
1117 result = fBitmapDrawingEngine->SetSize(targetWidth,
1118 targetHeight);
1121 if (result == B_OK) {
1122 fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1124 switch (bitmap.ColorSpace()) {
1125 case B_RGBA32:
1126 case B_RGBA32_BIG:
1127 case B_RGBA15:
1128 case B_RGBA15_BIG:
1129 break;
1131 default:
1133 // we need to clear the background if there may be
1134 // transparency through transparent magic (we use
1135 // B_OP_COPY when we draw alpha enabled bitmaps, so we
1136 // don't need to clear there)
1137 // TODO: this is not actually correct, as we're going to
1138 // loose the transparency with the conversion to the
1139 // original non-alpha colorspace happening in
1140 // ExportToBitmap
1141 rgb_color background = { 0, 0, 0, 0 };
1142 fBitmapDrawingEngine->FillRect(
1143 BRect(0, 0, targetWidth - 1, targetHeight -1),
1144 background);
1145 fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1146 break;
1150 fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect,
1151 BRect(0, 0, targetWidth - 1, targetHeight - 1), options);
1152 bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth,
1153 targetHeight, bitmap.ColorSpace());
1154 if (bitmaps[i] == NULL)
1155 result = B_NO_MEMORY;
1157 } else {
1158 // source is smaller or equal target, extract the relevant rects
1159 // directly without any scaling and conversion
1160 targetWidth = (int32)(sourceRect.Width() + 1.5);
1161 targetHeight = (int32)(sourceRect.Height() + 1.5);
1163 bitmaps[i] = new(std::nothrow) UtilityBitmap(
1164 BRect(0, 0, targetWidth - 1, targetHeight - 1),
1165 bitmap.ColorSpace(), 0);
1166 if (bitmaps[i] == NULL) {
1167 result = B_NO_MEMORY;
1168 } else {
1169 result = bitmaps[i]->ImportBits(bitmap.Bits(),
1170 bitmap.BitsLength(), bitmap.BytesPerRow(),
1171 bitmap.ColorSpace(), sourceRect.LeftTop(),
1172 BPoint(0, 0), targetWidth, targetHeight);
1173 if (result != B_OK) {
1174 delete bitmaps[i];
1175 bitmaps[i] = NULL;
1180 if (result != B_OK) {
1181 for (int32 j = 0; j < i; j++)
1182 delete bitmaps[j];
1183 free(bitmaps);
1184 return result;
1188 return B_OK;