xref: /haiku/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp (revision 4d9e21b8244316acd9518dd1f607bd90b4a90cd2)
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.Add(points[0]);
806 	message.Add(points[1]);
807 	message.Add(points[2]);
808 	message.Add(bounds);
809 	message.AddGradient(gradient);
810 }
811 
812 
813 void
814 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
815 {
816 	BPoint points[2] = { start, end };
817 	BRect bounds = _BuildBounds(points, 2);
818 
819 	if (!fClippingRegion.Intersects(bounds))
820 		return;
821 
822 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
823 	message.Start(RP_STROKE_LINE);
824 	message.Add(fToken);
825 	message.AddList(points, 2);
826 }
827 
828 
829 void
830 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
831 	const ViewLineArrayInfo *lineData)
832 {
833 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
834 	message.Start(RP_STROKE_LINE_ARRAY);
835 	message.Add(fToken);
836 	message.Add(numLines);
837 	for (int32 i = 0; i < numLines; i++)
838 		message.AddArrayLine(lineData[i]);
839 }
840 
841 
842 // #pragma mark - string functions
843 
844 
845 BPoint
846 RemoteDrawingEngine::DrawString(const char* string, int32 length,
847 	const BPoint& point, escapement_delta* delta)
848 {
849 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
850 
851 	message.Start(RP_DRAW_STRING);
852 	message.Add(fToken);
853 	message.Add(point);
854 	message.AddString(string, length);
855 	message.Add(delta != NULL);
856 	if (delta != NULL)
857 		message.AddList(delta, length);
858 
859 	status_t result = _AddCallback();
860 	if (message.Flush() != B_OK)
861 		return point;
862 
863 	if (result != B_OK)
864 		return point;
865 
866 	do {
867 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
868 			1 * 1000 * 1000);
869 	} while (result == B_INTERRUPTED);
870 
871 	if (result != B_OK)
872 		return point;
873 
874 	return fDrawStringResult;
875 }
876 
877 
878 BPoint
879 RemoteDrawingEngine::DrawString(const char* string, int32 length,
880 	const BPoint* offsets)
881 {
882 	// Guaranteed to have at least one point.
883 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
884 
885 	message.Start(RP_DRAW_STRING_WITH_OFFSETS);
886 	message.Add(fToken);
887 	message.AddString(string, length);
888 	message.AddList(offsets, UTF8CountChars(string, length));
889 
890 	status_t result = _AddCallback();
891 	if (message.Flush() != B_OK)
892 		return offsets[0];
893 
894 	if (result != B_OK)
895 		return offsets[0];
896 
897 	do {
898 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
899 			1 * 1000 * 1000);
900 	} while (result == B_INTERRUPTED);
901 
902 	if (result != B_OK)
903 		return offsets[0];
904 
905 	return fDrawStringResult;
906 }
907 
908 
909 float
910 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
911 	escapement_delta* delta)
912 {
913 	// TODO: Decide if really needed.
914 
915 	while (true) {
916 		if (_AddCallback() != B_OK)
917 			break;
918 
919 		RemoteMessage message(NULL, fHWInterface->SendBuffer());
920 
921 		message.Start(RP_STRING_WIDTH);
922 		message.Add(fToken);
923 		message.AddString(string, length);
924 			// TODO: Support escapement delta.
925 
926 		if (message.Flush() != B_OK)
927 			break;
928 
929 		status_t result;
930 		do {
931 			result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
932 				1 * 1000 * 1000);
933 		} while (result == B_INTERRUPTED);
934 
935 		if (result != B_OK)
936 			break;
937 
938 		return fStringWidthResult;
939 	}
940 
941 	// Fall back to local calculation.
942 	return fState.Font().StringWidth(string, length, delta);
943 }
944 
945 
946 // #pragma mark -
947 
948 
949 status_t
950 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
951 	BRect bounds)
952 {
953 	if (_AddCallback() != B_OK)
954 		return B_UNSUPPORTED;
955 
956 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
957 
958 	message.Start(RP_READ_BITMAP);
959 	message.Add(fToken);
960 	message.Add(bounds);
961 	message.Add(drawCursor);
962 	if (message.Flush() != B_OK)
963 		return B_UNSUPPORTED;
964 
965 	status_t result;
966 	do {
967 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
968 			100 * 1000 * 1000);
969 	} while (result == B_INTERRUPTED);
970 
971 	if (result != B_OK)
972 		return result;
973 
974 	BBitmap* read = fReadBitmapResult;
975 	if (read == NULL)
976 		return B_UNSUPPORTED;
977 
978 	result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
979 		read->BytesPerRow(), read->ColorSpace());
980 	delete read;
981 	return result;
982 }
983 
984 
985 // #pragma mark -
986 
987 
988 status_t
989 RemoteDrawingEngine::_AddCallback()
990 {
991 	if (fCallbackAdded)
992 		return B_OK;
993 
994 	if (fResultNotify < 0)
995 		fResultNotify = create_sem(0, "drawing engine result");
996 	if (fResultNotify < 0)
997 		return fResultNotify;
998 
999 	status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
1000 		this);
1001 
1002 	fCallbackAdded = result == B_OK;
1003 	return result;
1004 }
1005 
1006 
1007 bool
1008 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
1009 {
1010 	RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
1011 
1012 	switch (message.Code()) {
1013 		case RP_DRAW_STRING_RESULT:
1014 		{
1015 			status_t result = message.Read(engine->fDrawStringResult);
1016 			if (result != B_OK) {
1017 				TRACE_ERROR("failed to read draw string result: %s\n",
1018 					strerror(result));
1019 				return false;
1020 			}
1021 
1022 			break;
1023 		}
1024 
1025 		case RP_STRING_WIDTH_RESULT:
1026 		{
1027 			status_t result = message.Read(engine->fStringWidthResult);
1028 			if (result != B_OK) {
1029 				TRACE_ERROR("failed to read string width result: %s\n",
1030 					strerror(result));
1031 				return false;
1032 			}
1033 
1034 			break;
1035 		}
1036 
1037 		case RP_READ_BITMAP_RESULT:
1038 		{
1039 			status_t result = message.ReadBitmap(&engine->fReadBitmapResult);
1040 			if (result != B_OK) {
1041 				TRACE_ERROR("failed to read bitmap of read bitmap result: %s\n",
1042 					strerror(result));
1043 				return false;
1044 			}
1045 
1046 			break;
1047 		}
1048 
1049 		default:
1050 			return false;
1051 	}
1052 
1053 	release_sem(engine->fResultNotify);
1054 	return true;
1055 }
1056 
1057 
1058 BRect
1059 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1060 {
1061 	BRect bounds(1000000, 1000000, 0, 0);
1062 	for (int32 i = 0; i < pointCount; i++) {
1063 		bounds.left = min_c(bounds.left, points[i].x);
1064 		bounds.top = min_c(bounds.top, points[i].y);
1065 		bounds.right = max_c(bounds.right, points[i].x);
1066 		bounds.bottom = max_c(bounds.bottom, points[i].y);
1067 	}
1068 
1069 	return bounds;
1070 }
1071 
1072 
1073 status_t
1074 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options,
1075 	const BRect& bitmapRect, const BRect& viewRect, double xScale,
1076 	double yScale, BRegion& region, UtilityBitmap**& bitmaps)
1077 {
1078 	int32 rectCount = region.CountRects();
1079 	bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1080 	if (bitmaps == NULL)
1081 		return B_NO_MEMORY;
1082 
1083 	for (int32 i = 0; i < rectCount; i++) {
1084 		BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
1085 		int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
1086 		int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
1087 
1088 		if (xScale != 1.0) {
1089 			sourceRect.left = (int32)(sourceRect.left * xScale + 0.5);
1090 			sourceRect.right = (int32)(sourceRect.right * xScale + 0.5);
1091 			if (xScale < 1.0)
1092 				targetWidth = (int32)(sourceRect.Width() + 1.5);
1093 		}
1094 
1095 		if (yScale != 1.0) {
1096 			sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
1097 			sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5);
1098 			if (yScale < 1.0)
1099 				targetHeight = (int32)(sourceRect.Height() + 1.5);
1100 		}
1101 
1102 		sourceRect.OffsetBy(bitmapRect.LeftTop());
1103 			// sourceRect is now the part of the bitmap we want copied
1104 
1105 		status_t result = B_OK;
1106 		if ((xScale > 1.0 || yScale > 1.0)
1107 			&& (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5)
1108 				* (int32)(sourceRect.Height() + 1.5))) {
1109 			// the target bitmap is smaller than the source, scale it locally
1110 			// and send over the smaller version to avoid sending any extra data
1111 			if (fBitmapDrawingEngine == NULL) {
1112 				fBitmapDrawingEngine
1113 					= new(std::nothrow) BitmapDrawingEngine(B_RGBA32);
1114 				if (fBitmapDrawingEngine == NULL)
1115 					result = B_NO_MEMORY;
1116 			}
1117 
1118 			if (result == B_OK) {
1119 				result = fBitmapDrawingEngine->SetSize(targetWidth,
1120 					targetHeight);
1121 			}
1122 
1123 			if (result == B_OK) {
1124 				fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1125 
1126 				switch (bitmap.ColorSpace()) {
1127 					case B_RGBA32:
1128 					case B_RGBA32_BIG:
1129 					case B_RGBA15:
1130 					case B_RGBA15_BIG:
1131 						break;
1132 
1133 					default:
1134 					{
1135 						// we need to clear the background if there may be
1136 						// transparency through transparent magic (we use
1137 						// B_OP_COPY when we draw alpha enabled bitmaps, so we
1138 						// don't need to clear there)
1139 						// TODO: this is not actually correct, as we're going to
1140 						// loose the transparency with the conversion to the
1141 						// original non-alpha colorspace happening in
1142 						// ExportToBitmap
1143 						rgb_color background = { 0, 0, 0, 0 };
1144 						fBitmapDrawingEngine->FillRect(
1145 							BRect(0, 0, targetWidth - 1, targetHeight -1),
1146 							background);
1147 						fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1148 						break;
1149 					}
1150 				}
1151 
1152 				fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect,
1153 					BRect(0, 0, targetWidth - 1, targetHeight - 1), options);
1154 				bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth,
1155 					targetHeight, bitmap.ColorSpace());
1156 				if (bitmaps[i] == NULL)
1157 					result = B_NO_MEMORY;
1158 			}
1159 		} else {
1160 			// source is smaller or equal target, extract the relevant rects
1161 			// directly without any scaling and conversion
1162 			targetWidth = (int32)(sourceRect.Width() + 1.5);
1163 			targetHeight = (int32)(sourceRect.Height() + 1.5);
1164 
1165 			bitmaps[i] = new(std::nothrow) UtilityBitmap(
1166 				BRect(0, 0, targetWidth - 1, targetHeight - 1),
1167 				bitmap.ColorSpace(), 0);
1168 			if (bitmaps[i] == NULL) {
1169 				result = B_NO_MEMORY;
1170 			} else {
1171 				result = bitmaps[i]->ImportBits(bitmap.Bits(),
1172 						bitmap.BitsLength(), bitmap.BytesPerRow(),
1173 						bitmap.ColorSpace(), sourceRect.LeftTop(),
1174 						BPoint(0, 0), targetWidth, targetHeight);
1175 				if (result != B_OK) {
1176 					delete bitmaps[i];
1177 					bitmaps[i] = NULL;
1178 				}
1179 			}
1180 		}
1181 
1182 		if (result != B_OK) {
1183 			for (int32 j = 0; j < i; j++)
1184 				delete bitmaps[j];
1185 			free(bitmaps);
1186 			return result;
1187 		}
1188 	}
1189 
1190 	return B_OK;
1191 }
1192