xref: /haiku/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp (revision b2acee1cb986b696adfad7daabfe9279949a3e54)
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 
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 
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 	delete fBitmapDrawingEngine;
53 
54 	if (fCallbackAdded)
55 		fHWInterface->RemoveCallback(fToken);
56 	if (fResultNotify >= 0)
57 		delete_sem(fResultNotify);
58 }
59 
60 
61 // #pragma mark -
62 
63 
64 void
65 RemoteDrawingEngine::FrameBufferChanged()
66 {
67 	// Not allowed
68 }
69 
70 
71 // #pragma mark -
72 
73 
74 void
75 RemoteDrawingEngine::SetCopyToFrontEnabled(bool enabled)
76 {
77 	DrawingEngine::SetCopyToFrontEnabled(enabled);
78 
79 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
80 	message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING);
81 	message.Add(fToken);
82 }
83 
84 
85 // #pragma mark -
86 
87 
88 //! the RemoteDrawingEngine needs to be locked!
89 void
90 RemoteDrawingEngine::ConstrainClippingRegion(const BRegion* region)
91 {
92 	if (fClippingRegion == *region)
93 		return;
94 
95 	fClippingRegion = *region;
96 
97 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
98 	message.Start(RP_CONSTRAIN_CLIPPING_REGION);
99 	message.Add(fToken);
100 	message.AddRegion(*region);
101 }
102 
103 
104 void
105 RemoteDrawingEngine::SetDrawState(const DrawState* state, int32 xOffset,
106 	int32 yOffset)
107 {
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());
118 
119 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
120 	message.Start(RP_SET_OFFSETS);
121 	message.Add(fToken);
122 	message.Add(xOffset);
123 	message.Add(yOffset);
124 }
125 
126 
127 void
128 RemoteDrawingEngine::SetHighColor(const rgb_color& color)
129 {
130 	if (fState.HighColor() == color)
131 		return;
132 
133 	fState.SetHighColor(color);
134 
135 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
136 	message.Start(RP_SET_HIGH_COLOR);
137 	message.Add(fToken);
138 	message.Add(color);
139 }
140 
141 
142 void
143 RemoteDrawingEngine::SetLowColor(const rgb_color& color)
144 {
145 	if (fState.LowColor() == color)
146 		return;
147 
148 	fState.SetLowColor(color);
149 
150 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
151 	message.Start(RP_SET_LOW_COLOR);
152 	message.Add(fToken);
153 	message.Add(color);
154 }
155 
156 
157 void
158 RemoteDrawingEngine::SetPenSize(float size)
159 {
160 	if (fState.PenSize() == size)
161 		return;
162 
163 	fState.SetPenSize(size);
164 	fExtendWidth = -(size / 2);
165 
166 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
167 	message.Start(RP_SET_PEN_SIZE);
168 	message.Add(fToken);
169 	message.Add(size);
170 }
171 
172 
173 void
174 RemoteDrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode,
175 	float miterLimit)
176 {
177 	if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode
178 		&& fState.MiterLimit() == miterLimit)
179 		return;
180 
181 	fState.SetLineCapMode(lineCap);
182 	fState.SetLineJoinMode(joinMode);
183 	fState.SetMiterLimit(miterLimit);
184 
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);
191 }
192 
193 
194 void
195 RemoteDrawingEngine::SetBlendingMode(source_alpha sourceAlpha,
196 	alpha_function alphaFunc)
197 {
198 	if (fState.AlphaSrcMode() == sourceAlpha
199 		&& fState.AlphaFncMode() == alphaFunc)
200 		return;
201 
202 	fState.SetBlendingMode(sourceAlpha, alphaFunc);
203 
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);
209 }
210 
211 
212 void
213 RemoteDrawingEngine::SetPattern(const struct pattern& pattern)
214 {
215 	if (fState.GetPattern() == pattern)
216 		return;
217 
218 	fState.SetPattern(pattern);
219 
220 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
221 	message.Start(RP_SET_PATTERN);
222 	message.Add(fToken);
223 	message.Add(pattern);
224 }
225 
226 
227 void
228 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode)
229 {
230 	if (fState.GetDrawingMode() == mode)
231 		return;
232 
233 	fState.SetDrawingMode(mode);
234 
235 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
236 	message.Start(RP_SET_DRAWING_MODE);
237 	message.Add(fToken);
238 	message.Add(mode);
239 }
240 
241 
242 void
243 RemoteDrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode)
244 {
245 	oldMode = fState.GetDrawingMode();
246 	SetDrawingMode(mode);
247 }
248 
249 
250 void
251 RemoteDrawingEngine::SetFont(const ServerFont& font)
252 {
253 	if (fState.Font() == font)
254 		return;
255 
256 	fState.SetFont(font);
257 
258 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
259 	message.Start(RP_SET_FONT);
260 	message.Add(fToken);
261 	message.AddFont(font);
262 }
263 
264 
265 void
266 RemoteDrawingEngine::SetFont(const DrawState* state)
267 {
268 	SetFont(state->Font());
269 }
270 
271 
272 void
273 RemoteDrawingEngine::SetTransform(const BAffineTransform& transform)
274 {
275 	if (fState.Transform() == transform)
276 		return;
277 
278 	fState.SetTransform(transform);
279 
280 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
281 	message.Start(RP_SET_TRANSFORM);
282 	message.Add(fToken);
283 	message.AddTransform(transform);
284 }
285 
286 
287 // #pragma mark -
288 
289 
290 BRect
291 RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const
292 {
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);
299 }
300 
301 
302 void
303 RemoteDrawingEngine::InvertRect(BRect rect)
304 {
305 	if (!fClippingRegion.Intersects(rect))
306 		return;
307 
308 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
309 	message.Start(RP_INVERT_RECT);
310 	message.Add(fToken);
311 	message.Add(rect);
312 }
313 
314 
315 void
316 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
317 	const BRect& _viewRect, uint32 options)
318 {
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);
323 
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;
331 	}
332 	if (bitmapRect.top < actualBitmapRect.top) {
333 		float diff = actualBitmapRect.top - bitmapRect.top;
334 		viewRect.top += diff / yScale;
335 		bitmapRect.top = actualBitmapRect.top;
336 	}
337 	if (bitmapRect.right > actualBitmapRect.right) {
338 		float diff = bitmapRect.right - actualBitmapRect.right;
339 		viewRect.right -= diff / xScale;
340 		bitmapRect.right = actualBitmapRect.right;
341 	}
342 	if (bitmapRect.bottom > actualBitmapRect.bottom) {
343 		float diff = bitmapRect.bottom - actualBitmapRect.bottom;
344 		viewRect.bottom -= diff / yScale;
345 		bitmapRect.bottom = actualBitmapRect.bottom;
346 	}
347 
348 	BRegion clippedRegion(viewRect);
349 	clippedRegion.IntersectWith(&fClippingRegion);
350 
351 	int32 rectCount = clippedRegion.CountRects();
352 	if (rectCount == 0)
353 		return;
354 
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;
362 		}
363 
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);
371 
372 		for (int32 i = 0; i < rectCount; i++) {
373 			message.Add(clippedRegion.RectAt(i));
374 			message.AddBitmap(*bitmaps[i], true);
375 			delete bitmaps[i];
376 		}
377 
378 		free(bitmaps);
379 		return;
380 	}
381 
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);
390 }
391 
392 
393 void
394 RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span,
395 	bool filled)
396 {
397 	BRect bounds = rect;
398 	if (!filled)
399 		bounds.InsetBy(fExtendWidth, fExtendWidth);
400 
401 	if (!fClippingRegion.Intersects(bounds))
402 		return;
403 
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);
410 }
411 
412 void
413 RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span,
414 	const BGradient& gradient)
415 {
416 	if (!fClippingRegion.Intersects(rect))
417 		return;
418 
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);
426 }
427 
428 
429 void
430 RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled)
431 {
432 	BRect bounds = _BuildBounds(points, 4);
433 	if (!filled)
434 		bounds.InsetBy(fExtendWidth, fExtendWidth);
435 
436 	if (!fClippingRegion.Intersects(bounds))
437 		return;
438 
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);
443 }
444 
445 
446 void
447 RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient)
448 {
449 	BRect bounds = _BuildBounds(points, 4);
450 	if (!fClippingRegion.Intersects(bounds))
451 		return;
452 
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);
458 }
459 
460 
461 void
462 RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled)
463 {
464 	BRect bounds = rect;
465 	if (!filled)
466 		bounds.InsetBy(fExtendWidth, fExtendWidth);
467 
468 	if (!fClippingRegion.Intersects(bounds))
469 		return;
470 
471 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
472 	message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE);
473 	message.Add(fToken);
474 	message.Add(rect);
475 }
476 
477 
478 void
479 RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient)
480 {
481 	if (!fClippingRegion.Intersects(rect))
482 		return;
483 
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);
489 }
490 
491 
492 void
493 RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints,
494 	BRect bounds, bool filled, bool closed)
495 {
496 	BRect clipBounds = bounds;
497 	if (!filled)
498 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
499 
500 	if (!fClippingRegion.Intersects(clipBounds))
501 		return;
502 
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]);
511 }
512 
513 
514 void
515 RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints,
516 	BRect bounds, const BGradient& gradient, bool closed)
517 {
518 	if (!fClippingRegion.Intersects(bounds))
519 		return;
520 
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);
530 }
531 
532 
533 // #pragma mark - rgb_color versions
534 
535 
536 void
537 RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color)
538 {
539 	BRect bounds(point, point);
540 	bounds.InsetBy(fExtendWidth, fExtendWidth);
541 
542 	if (!fClippingRegion.Intersects(bounds))
543 		return;
544 
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);
550 }
551 
552 
553 void
554 RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
555 	const rgb_color& color)
556 {
557 	BPoint points[2] = { start, end };
558 	BRect bounds = _BuildBounds(points, 2);
559 
560 	if (!fClippingRegion.Intersects(bounds))
561 		return;
562 
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);
568 }
569 
570 
571 void
572 RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color)
573 {
574 	BRect bounds = rect;
575 	bounds.InsetBy(fExtendWidth, fExtendWidth);
576 
577 	if (!fClippingRegion.Intersects(bounds))
578 		return;
579 
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);
585 }
586 
587 
588 void
589 RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color)
590 {
591 	if (!fClippingRegion.Intersects(rect))
592 		return;
593 
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);
599 }
600 
601 
602 void
603 RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color)
604 {
605 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
606 	message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING);
607 	message.AddRegion(region);
608 	message.Add(color);
609 }
610 
611 
612 // #pragma mark - DrawState versions
613 
614 
615 void
616 RemoteDrawingEngine::StrokeRect(BRect rect)
617 {
618 	BRect bounds = rect;
619 	bounds.InsetBy(fExtendWidth, fExtendWidth);
620 
621 	if (!fClippingRegion.Intersects(bounds))
622 		return;
623 
624 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
625 	message.Start(RP_STROKE_RECT);
626 	message.Add(fToken);
627 	message.Add(rect);
628 }
629 
630 
631 void
632 RemoteDrawingEngine::FillRect(BRect rect)
633 {
634 	if (!fClippingRegion.Intersects(rect))
635 		return;
636 
637 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
638 	message.Start(RP_FILL_RECT);
639 	message.Add(fToken);
640 	message.Add(rect);
641 }
642 
643 
644 void
645 RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient)
646 {
647 	if (!fClippingRegion.Intersects(rect))
648 		return;
649 
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);
655 }
656 
657 
658 void
659 RemoteDrawingEngine::FillRegion(BRegion& region)
660 {
661 	BRegion clippedRegion = region;
662 	clippedRegion.IntersectWith(&fClippingRegion);
663 	if (clippedRegion.CountRects() == 0)
664 		return;
665 
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);
671 }
672 
673 
674 void
675 RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient)
676 {
677 	BRegion clippedRegion = region;
678 	clippedRegion.IntersectWith(&fClippingRegion);
679 	if (clippedRegion.CountRects() == 0)
680 		return;
681 
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);
688 }
689 
690 
691 void
692 RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius,
693 	bool filled)
694 {
695 	BRect bounds = rect;
696 	if (!filled)
697 		bounds.InsetBy(fExtendWidth, fExtendWidth);
698 
699 	if (!fClippingRegion.Intersects(bounds))
700 		return;
701 
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);
708 }
709 
710 
711 void
712 RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
713 	const BGradient& gradient)
714 {
715 	if (!fClippingRegion.Intersects(rect))
716 		return;
717 
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);
725 }
726 
727 
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)
732 {
733 	BRect clipBounds = bounds;
734 	if (!filled)
735 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
736 
737 	if (!fClippingRegion.Intersects(clipBounds))
738 		return;
739 
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);
750 }
751 
752 
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)
758 {
759 	if (!fClippingRegion.Intersects(bounds))
760 		return;
761 
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);
773 }
774 
775 
776 void
777 RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds,
778 	bool filled)
779 {
780 	BRect clipBounds = bounds;
781 	if (!filled)
782 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
783 
784 	if (!fClippingRegion.Intersects(clipBounds))
785 		return;
786 
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);
792 }
793 
794 
795 void
796 RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds,
797 	const BGradient& gradient)
798 {
799 	if (!fClippingRegion.Intersects(bounds))
800 		return;
801 
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);
808 }
809 
810 
811 void
812 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
813 {
814 	BPoint points[2] = { start, end };
815 	BRect bounds = _BuildBounds(points, 2);
816 
817 	if (!fClippingRegion.Intersects(bounds))
818 		return;
819 
820 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
821 	message.Start(RP_STROKE_LINE);
822 	message.Add(fToken);
823 	message.AddList(points, 2);
824 }
825 
826 
827 void
828 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
829 	const ViewLineArrayInfo *lineData)
830 {
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]);
837 }
838 
839 
840 // #pragma mark - string functions
841 
842 
843 BPoint
844 RemoteDrawingEngine::DrawString(const char* string, int32 length,
845 	const BPoint& point, escapement_delta* delta)
846 {
847 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
848 
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);
856 
857 	status_t result = _AddCallback();
858 	if (message.Flush() != B_OK)
859 		return point;
860 
861 	if (result != B_OK)
862 		return point;
863 
864 	do {
865 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
866 			1 * 1000 * 1000);
867 	} while (result == B_INTERRUPTED);
868 
869 	if (result != B_OK)
870 		return point;
871 
872 	return fDrawStringResult;
873 }
874 
875 
876 BPoint
877 RemoteDrawingEngine::DrawString(const char* string, int32 length,
878 	const BPoint* offsets)
879 {
880 	// Guaranteed to have at least one point.
881 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
882 
883 	message.Start(RP_DRAW_STRING_WITH_OFFSETS);
884 	message.Add(fToken);
885 	message.AddString(string, length);
886 	message.AddList(offsets, UTF8CountChars(string, length));
887 
888 	status_t result = _AddCallback();
889 	if (message.Flush() != B_OK)
890 		return offsets[0];
891 
892 	if (result != B_OK)
893 		return offsets[0];
894 
895 	do {
896 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
897 			1 * 1000 * 1000);
898 	} while (result == B_INTERRUPTED);
899 
900 	if (result != B_OK)
901 		return offsets[0];
902 
903 	return fDrawStringResult;
904 }
905 
906 
907 float
908 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
909 	escapement_delta* delta)
910 {
911 	// TODO: Decide if really needed.
912 
913 	while (true) {
914 		if (_AddCallback() != B_OK)
915 			break;
916 
917 		RemoteMessage message(NULL, fHWInterface->SendBuffer());
918 
919 		message.Start(RP_STRING_WIDTH);
920 		message.Add(fToken);
921 		message.AddString(string, length);
922 			// TODO: Support escapement delta.
923 
924 		if (message.Flush() != B_OK)
925 			break;
926 
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);
932 
933 		if (result != B_OK)
934 			break;
935 
936 		return fStringWidthResult;
937 	}
938 
939 	// Fall back to local calculation.
940 	return fState.Font().StringWidth(string, length, delta);
941 }
942 
943 
944 // #pragma mark -
945 
946 
947 status_t
948 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
949 	BRect bounds)
950 {
951 	if (_AddCallback() != B_OK)
952 		return B_UNSUPPORTED;
953 
954 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
955 
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;
962 
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);
968 
969 	if (result != B_OK)
970 		return result;
971 
972 	BBitmap* read = fReadBitmapResult;
973 	if (read == NULL)
974 		return B_UNSUPPORTED;
975 
976 	result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
977 		read->BytesPerRow(), read->ColorSpace());
978 	delete read;
979 	return result;
980 }
981 
982 
983 // #pragma mark -
984 
985 
986 status_t
987 RemoteDrawingEngine::_AddCallback()
988 {
989 	if (fCallbackAdded)
990 		return B_OK;
991 
992 	if (fResultNotify < 0)
993 		fResultNotify = create_sem(0, "drawing engine result");
994 	if (fResultNotify < 0)
995 		return fResultNotify;
996 
997 	status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
998 		this);
999 
1000 	fCallbackAdded = result == B_OK;
1001 	return result;
1002 }
1003 
1004 
1005 bool
1006 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
1007 {
1008 	RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
1009 
1010 	switch (message.Code()) {
1011 		case RP_DRAW_STRING_RESULT:
1012 		{
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;
1018 			}
1019 
1020 			break;
1021 		}
1022 
1023 		case RP_STRING_WIDTH_RESULT:
1024 		{
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;
1030 			}
1031 
1032 			break;
1033 		}
1034 
1035 		case RP_READ_BITMAP_RESULT:
1036 		{
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;
1042 			}
1043 
1044 			break;
1045 		}
1046 
1047 		default:
1048 			return false;
1049 	}
1050 
1051 	release_sem(engine->fResultNotify);
1052 	return true;
1053 }
1054 
1055 
1056 BRect
1057 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1058 {
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);
1065 	}
1066 
1067 	return bounds;
1068 }
1069 
1070 
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)
1075 {
1076 	int32 rectCount = region.CountRects();
1077 	bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1078 	if (bitmaps == NULL)
1079 		return B_NO_MEMORY;
1080 
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);
1085 
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);
1091 		}
1092 
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);
1098 		}
1099 
1100 		sourceRect.OffsetBy(bitmapRect.LeftTop());
1101 			// sourceRect is now the part of the bitmap we want copied
1102 
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;
1114 			}
1115 
1116 			if (result == B_OK) {
1117 				result = fBitmapDrawingEngine->SetSize(targetWidth,
1118 					targetHeight);
1119 			}
1120 
1121 			if (result == B_OK) {
1122 				fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1123 
1124 				switch (bitmap.ColorSpace()) {
1125 					case B_RGBA32:
1126 					case B_RGBA32_BIG:
1127 					case B_RGBA15:
1128 					case B_RGBA15_BIG:
1129 						break;
1130 
1131 					default:
1132 					{
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;
1147 					}
1148 				}
1149 
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;
1156 			}
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);
1162 
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;
1176 				}
1177 			}
1178 		}
1179 
1180 		if (result != B_OK) {
1181 			for (int32 j = 0; j < i; j++)
1182 				delete bitmaps[j];
1183 			free(bitmaps);
1184 			return result;
1185 		}
1186 	}
1187 
1188 	return B_OK;
1189 }
1190