1 /*
2 * Copyright 2009-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
8
9 #include "RemoteDrawingEngine.h"
10 #include "RemoteMessage.h"
11
12 #include "BitmapDrawingEngine.h"
13 #include "DrawState.h"
14 #include "ServerTokenSpace.h"
15
16 #include <Bitmap.h>
17 #include <utf8_functions.h>
18
19 #include <new>
20
21
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)
25
26
RemoteDrawingEngine(RemoteHWInterface * interface)27 RemoteDrawingEngine::RemoteDrawingEngine(RemoteHWInterface* interface)
28 :
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)
38 {
39 RemoteMessage message(NULL, fHWInterface->SendBuffer());
40 message.Start(RP_CREATE_STATE);
41 message.Add(fToken);
42 }
43
44
~RemoteDrawingEngine()45 RemoteDrawingEngine::~RemoteDrawingEngine()
46 {
47 RemoteMessage message(NULL, fHWInterface->SendBuffer());
48 message.Start(RP_DELETE_STATE);
49 message.Add(fToken);
50 message.Flush();
51
52 if (fCallbackAdded)
53 fHWInterface->RemoveCallback(fToken);
54 if (fResultNotify >= 0)
55 delete_sem(fResultNotify);
56 }
57
58
59 // #pragma mark -
60
61
62 void
FrameBufferChanged()63 RemoteDrawingEngine::FrameBufferChanged()
64 {
65 // Not allowed
66 }
67
68
69 // #pragma mark -
70
71
72 void
SetCopyToFrontEnabled(bool enabled)73 RemoteDrawingEngine::SetCopyToFrontEnabled(bool enabled)
74 {
75 DrawingEngine::SetCopyToFrontEnabled(enabled);
76
77 RemoteMessage message(NULL, fHWInterface->SendBuffer());
78 message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING);
79 message.Add(fToken);
80 }
81
82
83 // #pragma mark -
84
85
86 //! the RemoteDrawingEngine needs to be locked!
87 void
ConstrainClippingRegion(const BRegion * region)88 RemoteDrawingEngine::ConstrainClippingRegion(const BRegion* region)
89 {
90 if (fClippingRegion == *region)
91 return;
92
93 fClippingRegion = *region;
94
95 RemoteMessage message(NULL, fHWInterface->SendBuffer());
96 message.Start(RP_CONSTRAIN_CLIPPING_REGION);
97 message.Add(fToken);
98 message.AddRegion(*region);
99 }
100
101
102 void
SetDrawState(const DrawState * state,int32 xOffset,int32 yOffset)103 RemoteDrawingEngine::SetDrawState(const DrawState* state, int32 xOffset,
104 int32 yOffset)
105 {
106 SetPenSize(state->PenSize());
107 SetDrawingMode(state->GetDrawingMode());
108 SetBlendingMode(state->AlphaSrcMode(), state->AlphaFncMode());
109 SetPattern(state->GetPattern().GetPattern());
110 SetStrokeMode(state->LineCapMode(), state->LineJoinMode(),
111 state->MiterLimit());
112 SetHighColor(state->HighColor());
113 SetLowColor(state->LowColor());
114 SetFont(state->Font());
115 SetTransform(state->CombinedTransform(), xOffset, yOffset);
116
117 RemoteMessage message(NULL, fHWInterface->SendBuffer());
118 message.Start(RP_SET_OFFSETS);
119 message.Add(fToken);
120 message.Add(xOffset);
121 message.Add(yOffset);
122 }
123
124
125 void
SetHighColor(const rgb_color & color)126 RemoteDrawingEngine::SetHighColor(const rgb_color& color)
127 {
128 if (fState.HighColor() == color)
129 return;
130
131 fState.SetHighColor(color);
132
133 RemoteMessage message(NULL, fHWInterface->SendBuffer());
134 message.Start(RP_SET_HIGH_COLOR);
135 message.Add(fToken);
136 message.Add(color);
137 }
138
139
140 void
SetLowColor(const rgb_color & color)141 RemoteDrawingEngine::SetLowColor(const rgb_color& color)
142 {
143 if (fState.LowColor() == color)
144 return;
145
146 fState.SetLowColor(color);
147
148 RemoteMessage message(NULL, fHWInterface->SendBuffer());
149 message.Start(RP_SET_LOW_COLOR);
150 message.Add(fToken);
151 message.Add(color);
152 }
153
154
155 void
SetPenSize(float size)156 RemoteDrawingEngine::SetPenSize(float size)
157 {
158 if (fState.PenSize() == size)
159 return;
160
161 fState.SetPenSize(size);
162 fExtendWidth = -(size / 2);
163
164 RemoteMessage message(NULL, fHWInterface->SendBuffer());
165 message.Start(RP_SET_PEN_SIZE);
166 message.Add(fToken);
167 message.Add(size);
168 }
169
170
171 void
SetStrokeMode(cap_mode lineCap,join_mode joinMode,float miterLimit)172 RemoteDrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode,
173 float miterLimit)
174 {
175 if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode
176 && fState.MiterLimit() == miterLimit)
177 return;
178
179 fState.SetLineCapMode(lineCap);
180 fState.SetLineJoinMode(joinMode);
181 fState.SetMiterLimit(miterLimit);
182
183 RemoteMessage message(NULL, fHWInterface->SendBuffer());
184 message.Start(RP_SET_STROKE_MODE);
185 message.Add(fToken);
186 message.Add(lineCap);
187 message.Add(joinMode);
188 message.Add(miterLimit);
189 }
190
191
192 void
SetBlendingMode(source_alpha sourceAlpha,alpha_function alphaFunc)193 RemoteDrawingEngine::SetBlendingMode(source_alpha sourceAlpha,
194 alpha_function alphaFunc)
195 {
196 if (fState.AlphaSrcMode() == sourceAlpha
197 && fState.AlphaFncMode() == alphaFunc)
198 return;
199
200 fState.SetBlendingMode(sourceAlpha, alphaFunc);
201
202 RemoteMessage message(NULL, fHWInterface->SendBuffer());
203 message.Start(RP_SET_BLENDING_MODE);
204 message.Add(fToken);
205 message.Add(sourceAlpha);
206 message.Add(alphaFunc);
207 }
208
209
210 void
SetPattern(const struct pattern & pattern)211 RemoteDrawingEngine::SetPattern(const struct pattern& pattern)
212 {
213 if (fState.GetPattern() == pattern)
214 return;
215
216 fState.SetPattern(pattern);
217
218 RemoteMessage message(NULL, fHWInterface->SendBuffer());
219 message.Start(RP_SET_PATTERN);
220 message.Add(fToken);
221 message.Add(pattern);
222 }
223
224
225 void
SetDrawingMode(drawing_mode mode)226 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode)
227 {
228 if (fState.GetDrawingMode() == mode)
229 return;
230
231 fState.SetDrawingMode(mode);
232
233 RemoteMessage message(NULL, fHWInterface->SendBuffer());
234 message.Start(RP_SET_DRAWING_MODE);
235 message.Add(fToken);
236 message.Add(mode);
237 }
238
239
240 void
SetDrawingMode(drawing_mode mode,drawing_mode & oldMode)241 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode)
242 {
243 oldMode = fState.GetDrawingMode();
244 SetDrawingMode(mode);
245 }
246
247
248 void
SetFont(const ServerFont & font)249 RemoteDrawingEngine::SetFont(const ServerFont& font)
250 {
251 if (fState.Font() == font)
252 return;
253
254 fState.SetFont(font);
255
256 RemoteMessage message(NULL, fHWInterface->SendBuffer());
257 message.Start(RP_SET_FONT);
258 message.Add(fToken);
259 message.AddFont(font);
260 }
261
262
263 void
SetFont(const DrawState * state)264 RemoteDrawingEngine::SetFont(const DrawState* state)
265 {
266 SetFont(state->Font());
267 }
268
269
270 void
SetTransform(const BAffineTransform & transform,int32 xOffset,int32 yOffset)271 RemoteDrawingEngine::SetTransform(const BAffineTransform& transform,
272 int32 xOffset, int32 yOffset)
273 {
274 // TODO: take offset into account
275
276 if (fState.Transform() == transform)
277 return;
278
279 fState.SetTransform(transform);
280
281 RemoteMessage message(NULL, fHWInterface->SendBuffer());
282 message.Start(RP_SET_TRANSFORM);
283 message.Add(fToken);
284 message.AddTransform(transform);
285 }
286
287
288 // #pragma mark -
289
290
291 BRect
CopyRect(BRect rect,int32 xOffset,int32 yOffset) const292 RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const
293 {
294 RemoteMessage message(NULL, fHWInterface->SendBuffer());
295 message.Start(RP_COPY_RECT_NO_CLIPPING);
296 message.Add(xOffset);
297 message.Add(yOffset);
298 message.Add(rect);
299 return rect.OffsetBySelf(xOffset, yOffset);
300 }
301
302
303 void
InvertRect(BRect rect)304 RemoteDrawingEngine::InvertRect(BRect rect)
305 {
306 if (!fClippingRegion.Intersects(rect))
307 return;
308
309 RemoteMessage message(NULL, fHWInterface->SendBuffer());
310 message.Start(RP_INVERT_RECT);
311 message.Add(fToken);
312 message.Add(rect);
313 }
314
315
316 void
DrawBitmap(ServerBitmap * bitmap,const BRect & _bitmapRect,const BRect & _viewRect,uint32 options)317 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
318 const BRect& _viewRect, uint32 options)
319 {
320 BRect bitmapRect = _bitmapRect;
321 BRect viewRect = _viewRect;
322 double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1);
323 double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1);
324
325 // constrain rect to passed bitmap bounds
326 // and transfer the changes to the viewRect with the right scale
327 BRect actualBitmapRect = bitmap->Bounds();
328 if (bitmapRect.left < actualBitmapRect.left) {
329 float diff = actualBitmapRect.left - bitmapRect.left;
330 viewRect.left += diff / xScale;
331 bitmapRect.left = actualBitmapRect.left;
332 }
333 if (bitmapRect.top < actualBitmapRect.top) {
334 float diff = actualBitmapRect.top - bitmapRect.top;
335 viewRect.top += diff / yScale;
336 bitmapRect.top = actualBitmapRect.top;
337 }
338 if (bitmapRect.right > actualBitmapRect.right) {
339 float diff = bitmapRect.right - actualBitmapRect.right;
340 viewRect.right -= diff / xScale;
341 bitmapRect.right = actualBitmapRect.right;
342 }
343 if (bitmapRect.bottom > actualBitmapRect.bottom) {
344 float diff = bitmapRect.bottom - actualBitmapRect.bottom;
345 viewRect.bottom -= diff / yScale;
346 bitmapRect.bottom = actualBitmapRect.bottom;
347 }
348
349 BRegion clippedRegion(viewRect);
350 clippedRegion.IntersectWith(&fClippingRegion);
351
352 int32 rectCount = clippedRegion.CountRects();
353 if (rectCount == 0)
354 return;
355
356 if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != viewRect)
357 || viewRect.Width() < bitmapRect.Width()
358 || viewRect.Height() < bitmapRect.Height()) {
359 UtilityBitmap** bitmaps;
360 if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, viewRect,
361 xScale, yScale, clippedRegion, bitmaps) != B_OK) {
362 return;
363 }
364
365 RemoteMessage message(NULL, fHWInterface->SendBuffer());
366 message.Start(RP_DRAW_BITMAP_RECTS);
367 message.Add(fToken);
368 message.Add(options);
369 message.Add(bitmap->ColorSpace());
370 message.Add(bitmap->Flags());
371 message.Add(rectCount);
372
373 for (int32 i = 0; i < rectCount; i++) {
374 message.Add(clippedRegion.RectAt(i));
375 message.AddBitmap(*bitmaps[i], true);
376 delete bitmaps[i];
377 }
378
379 free(bitmaps);
380 return;
381 }
382
383 // TODO: we may want to cache/checksum bitmaps
384 RemoteMessage message(NULL, fHWInterface->SendBuffer());
385 message.Start(RP_DRAW_BITMAP);
386 message.Add(fToken);
387 message.Add(bitmapRect);
388 message.Add(viewRect);
389 message.Add(options);
390 message.AddBitmap(*bitmap);
391 }
392
393
394 void
DrawArc(BRect rect,const float & angle,const float & span,bool filled)395 RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span,
396 bool filled)
397 {
398 BRect bounds = rect;
399 if (!filled)
400 bounds.InsetBy(fExtendWidth, fExtendWidth);
401
402 if (!fClippingRegion.Intersects(bounds))
403 return;
404
405 RemoteMessage message(NULL, fHWInterface->SendBuffer());
406 message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC);
407 message.Add(fToken);
408 message.Add(rect);
409 message.Add(angle);
410 message.Add(span);
411 }
412
413 void
FillArc(BRect rect,const float & angle,const float & span,const BGradient & gradient)414 RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span,
415 const BGradient& gradient)
416 {
417 if (!fClippingRegion.Intersects(rect))
418 return;
419
420 RemoteMessage message(NULL, fHWInterface->SendBuffer());
421 message.Start(RP_FILL_ARC_GRADIENT);
422 message.Add(fToken);
423 message.Add(rect);
424 message.Add(angle);
425 message.Add(span);
426 message.AddGradient(gradient);
427 }
428
429
430 void
DrawBezier(BPoint * points,bool filled)431 RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled)
432 {
433 BRect bounds = _BuildBounds(points, 4);
434 if (!filled)
435 bounds.InsetBy(fExtendWidth, fExtendWidth);
436
437 if (!fClippingRegion.Intersects(bounds))
438 return;
439
440 RemoteMessage message(NULL, fHWInterface->SendBuffer());
441 message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER);
442 message.Add(fToken);
443 message.AddList(points, 4);
444 }
445
446
447 void
FillBezier(BPoint * points,const BGradient & gradient)448 RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient)
449 {
450 BRect bounds = _BuildBounds(points, 4);
451 if (!fClippingRegion.Intersects(bounds))
452 return;
453
454 RemoteMessage message(NULL, fHWInterface->SendBuffer());
455 message.Start(RP_FILL_BEZIER_GRADIENT);
456 message.Add(fToken);
457 message.AddList(points, 4);
458 message.AddGradient(gradient);
459 }
460
461
462 void
DrawEllipse(BRect rect,bool filled)463 RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled)
464 {
465 BRect bounds = rect;
466 if (!filled)
467 bounds.InsetBy(fExtendWidth, fExtendWidth);
468
469 if (!fClippingRegion.Intersects(bounds))
470 return;
471
472 RemoteMessage message(NULL, fHWInterface->SendBuffer());
473 message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE);
474 message.Add(fToken);
475 message.Add(rect);
476 }
477
478
479 void
FillEllipse(BRect rect,const BGradient & gradient)480 RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient)
481 {
482 if (!fClippingRegion.Intersects(rect))
483 return;
484
485 RemoteMessage message(NULL, fHWInterface->SendBuffer());
486 message.Start(RP_FILL_ELLIPSE_GRADIENT);
487 message.Add(fToken);
488 message.Add(rect);
489 message.AddGradient(gradient);
490 }
491
492
493 void
DrawPolygon(BPoint * pointList,int32 numPoints,BRect bounds,bool filled,bool closed)494 RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints,
495 BRect bounds, bool filled, bool closed)
496 {
497 BRect clipBounds = bounds;
498 if (!filled)
499 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
500
501 if (!fClippingRegion.Intersects(clipBounds))
502 return;
503
504 RemoteMessage message(NULL, fHWInterface->SendBuffer());
505 message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON);
506 message.Add(fToken);
507 message.Add(bounds);
508 message.Add(closed);
509 message.Add(numPoints);
510 for (int32 i = 0; i < numPoints; i++)
511 message.Add(pointList[i]);
512 }
513
514
515 void
FillPolygon(BPoint * pointList,int32 numPoints,BRect bounds,const BGradient & gradient,bool closed)516 RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints,
517 BRect bounds, const BGradient& gradient, bool closed)
518 {
519 if (!fClippingRegion.Intersects(bounds))
520 return;
521
522 RemoteMessage message(NULL, fHWInterface->SendBuffer());
523 message.Start(RP_FILL_POLYGON_GRADIENT);
524 message.Add(fToken);
525 message.Add(bounds);
526 message.Add(closed);
527 message.Add(numPoints);
528 for (int32 i = 0; i < numPoints; i++)
529 message.Add(pointList[i]);
530 message.AddGradient(gradient);
531 }
532
533
534 // #pragma mark - rgb_color versions
535
536
537 void
StrokePoint(const BPoint & point,const rgb_color & color)538 RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color)
539 {
540 BRect bounds(point, point);
541 bounds.InsetBy(fExtendWidth, fExtendWidth);
542
543 if (!fClippingRegion.Intersects(bounds))
544 return;
545
546 RemoteMessage message(NULL, fHWInterface->SendBuffer());
547 message.Start(RP_STROKE_POINT_COLOR);
548 message.Add(fToken);
549 message.Add(point);
550 message.Add(color);
551 }
552
553
554 void
StrokeLine(const BPoint & start,const BPoint & end,const rgb_color & color)555 RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
556 const rgb_color& color)
557 {
558 BPoint points[2] = { start, end };
559 BRect bounds = _BuildBounds(points, 2);
560
561 if (!fClippingRegion.Intersects(bounds))
562 return;
563
564 RemoteMessage message(NULL, fHWInterface->SendBuffer());
565 message.Start(RP_STROKE_LINE_1PX_COLOR);
566 message.Add(fToken);
567 message.AddList(points, 2);
568 message.Add(color);
569 }
570
571
572 void
StrokeRect(BRect rect,const rgb_color & color)573 RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color)
574 {
575 BRect bounds = rect;
576 bounds.InsetBy(fExtendWidth, fExtendWidth);
577
578 if (!fClippingRegion.Intersects(bounds))
579 return;
580
581 RemoteMessage message(NULL, fHWInterface->SendBuffer());
582 message.Start(RP_STROKE_RECT_1PX_COLOR);
583 message.Add(fToken);
584 message.Add(rect);
585 message.Add(color);
586 }
587
588
589 void
FillRect(BRect rect,const rgb_color & color)590 RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color)
591 {
592 if (!fClippingRegion.Intersects(rect))
593 return;
594
595 RemoteMessage message(NULL, fHWInterface->SendBuffer());
596 message.Start(RP_FILL_RECT_COLOR);
597 message.Add(fToken);
598 message.Add(rect);
599 message.Add(color);
600 }
601
602
603 void
FillRegion(BRegion & region,const rgb_color & color)604 RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color)
605 {
606 RemoteMessage message(NULL, fHWInterface->SendBuffer());
607 message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING);
608 message.AddRegion(region);
609 message.Add(color);
610 }
611
612
613 // #pragma mark - DrawState versions
614
615
616 void
StrokeRect(BRect rect)617 RemoteDrawingEngine::StrokeRect(BRect rect)
618 {
619 BRect bounds = rect;
620 bounds.InsetBy(fExtendWidth, fExtendWidth);
621
622 if (!fClippingRegion.Intersects(bounds))
623 return;
624
625 RemoteMessage message(NULL, fHWInterface->SendBuffer());
626 message.Start(RP_STROKE_RECT);
627 message.Add(fToken);
628 message.Add(rect);
629 }
630
631
632 void
FillRect(BRect rect)633 RemoteDrawingEngine::FillRect(BRect rect)
634 {
635 if (!fClippingRegion.Intersects(rect))
636 return;
637
638 RemoteMessage message(NULL, fHWInterface->SendBuffer());
639 message.Start(RP_FILL_RECT);
640 message.Add(fToken);
641 message.Add(rect);
642 }
643
644
645 void
FillRect(BRect rect,const BGradient & gradient)646 RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient)
647 {
648 if (!fClippingRegion.Intersects(rect))
649 return;
650
651 RemoteMessage message(NULL, fHWInterface->SendBuffer());
652 message.Start(RP_FILL_RECT_GRADIENT);
653 message.Add(fToken);
654 message.Add(rect);
655 message.AddGradient(gradient);
656 }
657
658
659 void
FillRegion(BRegion & region)660 RemoteDrawingEngine::FillRegion(BRegion& region)
661 {
662 BRegion clippedRegion = region;
663 clippedRegion.IntersectWith(&fClippingRegion);
664 if (clippedRegion.CountRects() == 0)
665 return;
666
667 RemoteMessage message(NULL, fHWInterface->SendBuffer());
668 message.Start(RP_FILL_REGION);
669 message.Add(fToken);
670 message.AddRegion(clippedRegion.CountRects() < region.CountRects()
671 ? clippedRegion : region);
672 }
673
674
675 void
FillRegion(BRegion & region,const BGradient & gradient)676 RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient)
677 {
678 BRegion clippedRegion = region;
679 clippedRegion.IntersectWith(&fClippingRegion);
680 if (clippedRegion.CountRects() == 0)
681 return;
682
683 RemoteMessage message(NULL, fHWInterface->SendBuffer());
684 message.Start(RP_FILL_REGION_GRADIENT);
685 message.Add(fToken);
686 message.AddRegion(clippedRegion.CountRects() < region.CountRects()
687 ? clippedRegion : region);
688 message.AddGradient(gradient);
689 }
690
691
692 void
DrawRoundRect(BRect rect,float xRadius,float yRadius,bool filled)693 RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius,
694 bool filled)
695 {
696 BRect bounds = rect;
697 if (!filled)
698 bounds.InsetBy(fExtendWidth, fExtendWidth);
699
700 if (!fClippingRegion.Intersects(bounds))
701 return;
702
703 RemoteMessage message(NULL, fHWInterface->SendBuffer());
704 message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT);
705 message.Add(fToken);
706 message.Add(rect);
707 message.Add(xRadius);
708 message.Add(yRadius);
709 }
710
711
712 void
FillRoundRect(BRect rect,float xRadius,float yRadius,const BGradient & gradient)713 RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
714 const BGradient& gradient)
715 {
716 if (!fClippingRegion.Intersects(rect))
717 return;
718
719 RemoteMessage message(NULL, fHWInterface->SendBuffer());
720 message.Start(RP_FILL_ROUND_RECT_GRADIENT);
721 message.Add(fToken);
722 message.Add(rect);
723 message.Add(xRadius);
724 message.Add(yRadius);
725 message.AddGradient(gradient);
726 }
727
728
729 void
DrawShape(const BRect & bounds,int32 opCount,const uint32 * opList,int32 pointCount,const BPoint * pointList,bool filled,const BPoint & viewToScreenOffset,float viewScale)730 RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
731 const uint32* opList, int32 pointCount, const BPoint* pointList,
732 bool filled, const BPoint& viewToScreenOffset, float viewScale)
733 {
734 BRect clipBounds = bounds;
735 if (!filled)
736 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
737
738 if (!fClippingRegion.Intersects(clipBounds))
739 return;
740
741 RemoteMessage message(NULL, fHWInterface->SendBuffer());
742 message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE);
743 message.Add(fToken);
744 message.Add(bounds);
745 message.Add(opCount);
746 message.AddList(opList, opCount);
747 message.Add(pointCount);
748 message.AddList(pointList, pointCount);
749 message.Add(viewToScreenOffset);
750 message.Add(viewScale);
751 }
752
753
754 void
FillShape(const BRect & bounds,int32 opCount,const uint32 * opList,int32 pointCount,const BPoint * pointList,const BGradient & gradient,const BPoint & viewToScreenOffset,float viewScale)755 RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
756 const uint32* opList, int32 pointCount, const BPoint* pointList,
757 const BGradient& gradient, const BPoint& viewToScreenOffset,
758 float viewScale)
759 {
760 if (!fClippingRegion.Intersects(bounds))
761 return;
762
763 RemoteMessage message(NULL, fHWInterface->SendBuffer());
764 message.Start(RP_FILL_SHAPE_GRADIENT);
765 message.Add(fToken);
766 message.Add(bounds);
767 message.Add(opCount);
768 message.AddList(opList, opCount);
769 message.Add(pointCount);
770 message.AddList(pointList, pointCount);
771 message.Add(viewToScreenOffset);
772 message.Add(viewScale);
773 message.AddGradient(gradient);
774 }
775
776
777 void
DrawTriangle(BPoint * points,const BRect & bounds,bool filled)778 RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds,
779 bool filled)
780 {
781 BRect clipBounds = bounds;
782 if (!filled)
783 clipBounds.InsetBy(fExtendWidth, fExtendWidth);
784
785 if (!fClippingRegion.Intersects(clipBounds))
786 return;
787
788 RemoteMessage message(NULL, fHWInterface->SendBuffer());
789 message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE);
790 message.Add(fToken);
791 message.AddList(points, 3);
792 message.Add(bounds);
793 }
794
795
796 void
FillTriangle(BPoint * points,const BRect & bounds,const BGradient & gradient)797 RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds,
798 const BGradient& gradient)
799 {
800 if (!fClippingRegion.Intersects(bounds))
801 return;
802
803 RemoteMessage message(NULL, fHWInterface->SendBuffer());
804 message.Start(RP_FILL_TRIANGLE_GRADIENT);
805 message.Add(fToken);
806 message.AddList(points, 3);
807 message.Add(bounds);
808 message.AddGradient(gradient);
809 }
810
811
812 void
StrokeLine(const BPoint & start,const BPoint & end)813 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
814 {
815 BPoint points[2] = { start, end };
816 BRect bounds = _BuildBounds(points, 2);
817
818 if (!fClippingRegion.Intersects(bounds))
819 return;
820
821 RemoteMessage message(NULL, fHWInterface->SendBuffer());
822 message.Start(RP_STROKE_LINE);
823 message.Add(fToken);
824 message.AddList(points, 2);
825 }
826
827
828 void
StrokeLineArray(int32 numLines,const ViewLineArrayInfo * lineData)829 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
830 const ViewLineArrayInfo *lineData)
831 {
832 RemoteMessage message(NULL, fHWInterface->SendBuffer());
833 message.Start(RP_STROKE_LINE_ARRAY);
834 message.Add(fToken);
835 message.Add(numLines);
836 for (int32 i = 0; i < numLines; i++)
837 message.AddArrayLine(lineData[i]);
838 }
839
840
841 // #pragma mark - string functions
842
843
844 BPoint
DrawString(const char * string,int32 length,const BPoint & point,escapement_delta * delta)845 RemoteDrawingEngine::DrawString(const char* string, int32 length,
846 const BPoint& point, escapement_delta* delta)
847 {
848 RemoteMessage message(NULL, fHWInterface->SendBuffer());
849
850 message.Start(RP_DRAW_STRING);
851 message.Add(fToken);
852 message.Add(point);
853 message.AddString(string, length);
854 message.Add(delta != NULL);
855 if (delta != NULL)
856 message.AddList(delta, length);
857
858 status_t result = _AddCallback();
859 if (message.Flush() != B_OK)
860 return point;
861
862 if (result != B_OK)
863 return point;
864
865 do {
866 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
867 1 * 1000 * 1000);
868 } while (result == B_INTERRUPTED);
869
870 if (result != B_OK)
871 return point;
872
873 return fDrawStringResult;
874 }
875
876
877 BPoint
DrawString(const char * string,int32 length,const BPoint * offsets)878 RemoteDrawingEngine::DrawString(const char* string, int32 length,
879 const BPoint* offsets)
880 {
881 // Guaranteed to have at least one point.
882 RemoteMessage message(NULL, fHWInterface->SendBuffer());
883
884 message.Start(RP_DRAW_STRING_WITH_OFFSETS);
885 message.Add(fToken);
886 message.AddString(string, length);
887 message.AddList(offsets, UTF8CountChars(string, length));
888
889 status_t result = _AddCallback();
890 if (message.Flush() != B_OK)
891 return offsets[0];
892
893 if (result != B_OK)
894 return offsets[0];
895
896 do {
897 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
898 1 * 1000 * 1000);
899 } while (result == B_INTERRUPTED);
900
901 if (result != B_OK)
902 return offsets[0];
903
904 return fDrawStringResult;
905 }
906
907
908 float
StringWidth(const char * string,int32 length,escapement_delta * delta)909 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
910 escapement_delta* delta)
911 {
912 // TODO: Decide if really needed.
913
914 while (true) {
915 if (_AddCallback() != B_OK)
916 break;
917
918 RemoteMessage message(NULL, fHWInterface->SendBuffer());
919
920 message.Start(RP_STRING_WIDTH);
921 message.Add(fToken);
922 message.AddString(string, length);
923 // TODO: Support escapement delta.
924
925 if (message.Flush() != B_OK)
926 break;
927
928 status_t result;
929 do {
930 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
931 1 * 1000 * 1000);
932 } while (result == B_INTERRUPTED);
933
934 if (result != B_OK)
935 break;
936
937 return fStringWidthResult;
938 }
939
940 // Fall back to local calculation.
941 return fState.Font().StringWidth(string, length, delta);
942 }
943
944
945 // #pragma mark -
946
947
948 status_t
ReadBitmap(ServerBitmap * bitmap,bool drawCursor,BRect bounds)949 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
950 BRect bounds)
951 {
952 if (_AddCallback() != B_OK)
953 return B_UNSUPPORTED;
954
955 RemoteMessage message(NULL, fHWInterface->SendBuffer());
956
957 message.Start(RP_READ_BITMAP);
958 message.Add(fToken);
959 message.Add(bounds);
960 message.Add(drawCursor);
961 if (message.Flush() != B_OK)
962 return B_UNSUPPORTED;
963
964 status_t result;
965 do {
966 result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
967 10 * 1000 * 1000);
968 } while (result == B_INTERRUPTED);
969
970 if (result != B_OK)
971 return result;
972
973 BBitmap* read = fReadBitmapResult;
974 if (read == NULL)
975 return B_UNSUPPORTED;
976
977 result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
978 read->BytesPerRow(), read->ColorSpace());
979 delete read;
980 return result;
981 }
982
983
984 // #pragma mark -
985
986
987 status_t
_AddCallback()988 RemoteDrawingEngine::_AddCallback()
989 {
990 if (fCallbackAdded)
991 return B_OK;
992
993 if (fResultNotify < 0)
994 fResultNotify = create_sem(0, "drawing engine result");
995 if (fResultNotify < 0)
996 return fResultNotify;
997
998 status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
999 this);
1000
1001 fCallbackAdded = result == B_OK;
1002 return result;
1003 }
1004
1005
1006 bool
_DrawingEngineResult(void * cookie,RemoteMessage & message)1007 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
1008 {
1009 RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
1010
1011 switch (message.Code()) {
1012 case RP_DRAW_STRING_RESULT:
1013 {
1014 status_t result = message.Read(engine->fDrawStringResult);
1015 if (result != B_OK) {
1016 TRACE_ERROR("failed to read draw string result: %s\n",
1017 strerror(result));
1018 return false;
1019 }
1020
1021 break;
1022 }
1023
1024 case RP_STRING_WIDTH_RESULT:
1025 {
1026 status_t result = message.Read(engine->fStringWidthResult);
1027 if (result != B_OK) {
1028 TRACE_ERROR("failed to read string width result: %s\n",
1029 strerror(result));
1030 return false;
1031 }
1032
1033 break;
1034 }
1035
1036 case RP_READ_BITMAP_RESULT:
1037 {
1038 status_t result = message.ReadBitmap(&engine->fReadBitmapResult);
1039 if (result != B_OK) {
1040 TRACE_ERROR("failed to read bitmap of read bitmap result: %s\n",
1041 strerror(result));
1042 return false;
1043 }
1044
1045 break;
1046 }
1047
1048 default:
1049 return false;
1050 }
1051
1052 release_sem(engine->fResultNotify);
1053 return true;
1054 }
1055
1056
1057 BRect
_BuildBounds(BPoint * points,int32 pointCount)1058 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1059 {
1060 BRect bounds(1000000, 1000000, 0, 0);
1061 for (int32 i = 0; i < pointCount; i++) {
1062 bounds.left = min_c(bounds.left, points[i].x);
1063 bounds.top = min_c(bounds.top, points[i].y);
1064 bounds.right = max_c(bounds.right, points[i].x);
1065 bounds.bottom = max_c(bounds.bottom, points[i].y);
1066 }
1067
1068 return bounds;
1069 }
1070
1071
1072 status_t
_ExtractBitmapRegions(ServerBitmap & bitmap,uint32 options,const BRect & bitmapRect,const BRect & viewRect,double xScale,double yScale,BRegion & region,UtilityBitmap ** & bitmaps)1073 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options,
1074 const BRect& bitmapRect, const BRect& viewRect, double xScale,
1075 double yScale, BRegion& region, UtilityBitmap**& bitmaps)
1076 {
1077 int32 rectCount = region.CountRects();
1078 bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1079 if (bitmaps == NULL)
1080 return B_NO_MEMORY;
1081
1082 for (int32 i = 0; i < rectCount; i++) {
1083 BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
1084 int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
1085 int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
1086
1087 if (xScale != 1.0) {
1088 sourceRect.left = (int32)(sourceRect.left * xScale + 0.5);
1089 sourceRect.right = (int32)(sourceRect.right * xScale + 0.5);
1090 if (xScale < 1.0)
1091 targetWidth = (int32)(sourceRect.Width() + 1.5);
1092 }
1093
1094 if (yScale != 1.0) {
1095 sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
1096 sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5);
1097 if (yScale < 1.0)
1098 targetHeight = (int32)(sourceRect.Height() + 1.5);
1099 }
1100
1101 sourceRect.OffsetBy(bitmapRect.LeftTop());
1102 // sourceRect is now the part of the bitmap we want copied
1103
1104 status_t result = B_OK;
1105 if ((xScale > 1.0 || yScale > 1.0)
1106 && (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5)
1107 * (int32)(sourceRect.Height() + 1.5))) {
1108 // the target bitmap is smaller than the source, scale it locally
1109 // and send over the smaller version to avoid sending any extra data
1110 if (!fBitmapDrawingEngine.IsSet()) {
1111 fBitmapDrawingEngine.SetTo(
1112 new(std::nothrow) BitmapDrawingEngine(B_RGBA32));
1113 if (!fBitmapDrawingEngine.IsSet())
1114 result = B_NO_MEMORY;
1115 }
1116
1117 if (result == B_OK) {
1118 result = fBitmapDrawingEngine->SetSize(targetWidth,
1119 targetHeight);
1120 }
1121
1122 if (result == B_OK) {
1123 fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1124
1125 switch (bitmap.ColorSpace()) {
1126 case B_RGBA32:
1127 case B_RGBA32_BIG:
1128 case B_RGBA15:
1129 case B_RGBA15_BIG:
1130 break;
1131
1132 default:
1133 {
1134 // we need to clear the background if there may be
1135 // transparency through transparent magic (we use
1136 // B_OP_COPY when we draw alpha enabled bitmaps, so we
1137 // don't need to clear there)
1138 // TODO: this is not actually correct, as we're going to
1139 // loose the transparency with the conversion to the
1140 // original non-alpha colorspace happening in
1141 // ExportToBitmap
1142 rgb_color background = { 0, 0, 0, 0 };
1143 fBitmapDrawingEngine->FillRect(
1144 BRect(0, 0, targetWidth - 1, targetHeight -1),
1145 background);
1146 fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1147 break;
1148 }
1149 }
1150
1151 fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect,
1152 BRect(0, 0, targetWidth - 1, targetHeight - 1), options);
1153 bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth,
1154 targetHeight, bitmap.ColorSpace());
1155 if (bitmaps[i] == NULL)
1156 result = B_NO_MEMORY;
1157 }
1158 } else {
1159 // source is smaller or equal target, extract the relevant rects
1160 // directly without any scaling and conversion
1161 targetWidth = (int32)(sourceRect.Width() + 1.5);
1162 targetHeight = (int32)(sourceRect.Height() + 1.5);
1163
1164 bitmaps[i] = new(std::nothrow) UtilityBitmap(
1165 BRect(0, 0, targetWidth - 1, targetHeight - 1),
1166 bitmap.ColorSpace(), 0);
1167 if (bitmaps[i] == NULL) {
1168 result = B_NO_MEMORY;
1169 } else {
1170 result = bitmaps[i]->ImportBits(bitmap.Bits(),
1171 bitmap.BitsLength(), bitmap.BytesPerRow(),
1172 bitmap.ColorSpace(), sourceRect.LeftTop(),
1173 BPoint(0, 0), targetWidth, targetHeight);
1174 if (result != B_OK) {
1175 delete bitmaps[i];
1176 bitmaps[i] = NULL;
1177 }
1178 }
1179 }
1180
1181 if (result != B_OK) {
1182 for (int32 j = 0; j < i; j++)
1183 delete bitmaps[j];
1184 free(bitmaps);
1185 return result;
1186 }
1187 }
1188
1189 return B_OK;
1190 }
1191