xref: /haiku/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp (revision 2e4991285be2010b88879e1754262efeb1fe3e46)
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(), xOffset, yOffset);
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 	int32 xOffset, int32 yOffset)
275 {
276 	// TODO: take offset into account
277 
278 	if (fState.Transform() == transform)
279 		return;
280 
281 	fState.SetTransform(transform);
282 
283 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
284 	message.Start(RP_SET_TRANSFORM);
285 	message.Add(fToken);
286 	message.AddTransform(transform);
287 }
288 
289 
290 // #pragma mark -
291 
292 
293 BRect
294 RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const
295 {
296 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
297 	message.Start(RP_COPY_RECT_NO_CLIPPING);
298 	message.Add(xOffset);
299 	message.Add(yOffset);
300 	message.Add(rect);
301 	return rect.OffsetBySelf(xOffset, yOffset);
302 }
303 
304 
305 void
306 RemoteDrawingEngine::InvertRect(BRect rect)
307 {
308 	if (!fClippingRegion.Intersects(rect))
309 		return;
310 
311 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
312 	message.Start(RP_INVERT_RECT);
313 	message.Add(fToken);
314 	message.Add(rect);
315 }
316 
317 
318 void
319 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
320 	const BRect& _viewRect, uint32 options)
321 {
322 	BRect bitmapRect = _bitmapRect;
323 	BRect viewRect = _viewRect;
324 	double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1);
325 	double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1);
326 
327 	// constrain rect to passed bitmap bounds
328 	// and transfer the changes to the viewRect with the right scale
329 	BRect actualBitmapRect = bitmap->Bounds();
330 	if (bitmapRect.left < actualBitmapRect.left) {
331 		float diff = actualBitmapRect.left - bitmapRect.left;
332 		viewRect.left += diff / xScale;
333 		bitmapRect.left = actualBitmapRect.left;
334 	}
335 	if (bitmapRect.top < actualBitmapRect.top) {
336 		float diff = actualBitmapRect.top - bitmapRect.top;
337 		viewRect.top += diff / yScale;
338 		bitmapRect.top = actualBitmapRect.top;
339 	}
340 	if (bitmapRect.right > actualBitmapRect.right) {
341 		float diff = bitmapRect.right - actualBitmapRect.right;
342 		viewRect.right -= diff / xScale;
343 		bitmapRect.right = actualBitmapRect.right;
344 	}
345 	if (bitmapRect.bottom > actualBitmapRect.bottom) {
346 		float diff = bitmapRect.bottom - actualBitmapRect.bottom;
347 		viewRect.bottom -= diff / yScale;
348 		bitmapRect.bottom = actualBitmapRect.bottom;
349 	}
350 
351 	BRegion clippedRegion(viewRect);
352 	clippedRegion.IntersectWith(&fClippingRegion);
353 
354 	int32 rectCount = clippedRegion.CountRects();
355 	if (rectCount == 0)
356 		return;
357 
358 	if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != viewRect)
359 		|| viewRect.Width() < bitmapRect.Width()
360 		|| viewRect.Height() < bitmapRect.Height()) {
361 		UtilityBitmap** bitmaps;
362 		if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, viewRect,
363 				xScale, yScale, clippedRegion, bitmaps) != B_OK) {
364 			return;
365 		}
366 
367 		RemoteMessage message(NULL, fHWInterface->SendBuffer());
368 		message.Start(RP_DRAW_BITMAP_RECTS);
369 		message.Add(fToken);
370 		message.Add(options);
371 		message.Add(bitmap->ColorSpace());
372 		message.Add(bitmap->Flags());
373 		message.Add(rectCount);
374 
375 		for (int32 i = 0; i < rectCount; i++) {
376 			message.Add(clippedRegion.RectAt(i));
377 			message.AddBitmap(*bitmaps[i], true);
378 			delete bitmaps[i];
379 		}
380 
381 		free(bitmaps);
382 		return;
383 	}
384 
385 	// TODO: we may want to cache/checksum bitmaps
386 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
387 	message.Start(RP_DRAW_BITMAP);
388 	message.Add(fToken);
389 	message.Add(bitmapRect);
390 	message.Add(viewRect);
391 	message.Add(options);
392 	message.AddBitmap(*bitmap);
393 }
394 
395 
396 void
397 RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span,
398 	bool filled)
399 {
400 	BRect bounds = rect;
401 	if (!filled)
402 		bounds.InsetBy(fExtendWidth, fExtendWidth);
403 
404 	if (!fClippingRegion.Intersects(bounds))
405 		return;
406 
407 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
408 	message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC);
409 	message.Add(fToken);
410 	message.Add(rect);
411 	message.Add(angle);
412 	message.Add(span);
413 }
414 
415 void
416 RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span,
417 	const BGradient& gradient)
418 {
419 	if (!fClippingRegion.Intersects(rect))
420 		return;
421 
422 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
423 	message.Start(RP_FILL_ARC_GRADIENT);
424 	message.Add(fToken);
425 	message.Add(rect);
426 	message.Add(angle);
427 	message.Add(span);
428 	message.AddGradient(gradient);
429 }
430 
431 
432 void
433 RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled)
434 {
435 	BRect bounds = _BuildBounds(points, 4);
436 	if (!filled)
437 		bounds.InsetBy(fExtendWidth, fExtendWidth);
438 
439 	if (!fClippingRegion.Intersects(bounds))
440 		return;
441 
442 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
443 	message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER);
444 	message.Add(fToken);
445 	message.AddList(points, 4);
446 }
447 
448 
449 void
450 RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient)
451 {
452 	BRect bounds = _BuildBounds(points, 4);
453 	if (!fClippingRegion.Intersects(bounds))
454 		return;
455 
456 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
457 	message.Start(RP_FILL_BEZIER_GRADIENT);
458 	message.Add(fToken);
459 	message.AddList(points, 4);
460 	message.AddGradient(gradient);
461 }
462 
463 
464 void
465 RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled)
466 {
467 	BRect bounds = rect;
468 	if (!filled)
469 		bounds.InsetBy(fExtendWidth, fExtendWidth);
470 
471 	if (!fClippingRegion.Intersects(bounds))
472 		return;
473 
474 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
475 	message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE);
476 	message.Add(fToken);
477 	message.Add(rect);
478 }
479 
480 
481 void
482 RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient)
483 {
484 	if (!fClippingRegion.Intersects(rect))
485 		return;
486 
487 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
488 	message.Start(RP_FILL_ELLIPSE_GRADIENT);
489 	message.Add(fToken);
490 	message.Add(rect);
491 	message.AddGradient(gradient);
492 }
493 
494 
495 void
496 RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints,
497 	BRect bounds, bool filled, bool closed)
498 {
499 	BRect clipBounds = bounds;
500 	if (!filled)
501 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
502 
503 	if (!fClippingRegion.Intersects(clipBounds))
504 		return;
505 
506 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
507 	message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON);
508 	message.Add(fToken);
509 	message.Add(bounds);
510 	message.Add(closed);
511 	message.Add(numPoints);
512 	for (int32 i = 0; i < numPoints; i++)
513 		message.Add(pointList[i]);
514 }
515 
516 
517 void
518 RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints,
519 	BRect bounds, const BGradient& gradient, bool closed)
520 {
521 	if (!fClippingRegion.Intersects(bounds))
522 		return;
523 
524 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
525 	message.Start(RP_FILL_POLYGON_GRADIENT);
526 	message.Add(fToken);
527 	message.Add(bounds);
528 	message.Add(closed);
529 	message.Add(numPoints);
530 	for (int32 i = 0; i < numPoints; i++)
531 		message.Add(pointList[i]);
532 	message.AddGradient(gradient);
533 }
534 
535 
536 // #pragma mark - rgb_color versions
537 
538 
539 void
540 RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color)
541 {
542 	BRect bounds(point, point);
543 	bounds.InsetBy(fExtendWidth, fExtendWidth);
544 
545 	if (!fClippingRegion.Intersects(bounds))
546 		return;
547 
548 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
549 	message.Start(RP_STROKE_POINT_COLOR);
550 	message.Add(fToken);
551 	message.Add(point);
552 	message.Add(color);
553 }
554 
555 
556 void
557 RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
558 	const rgb_color& color)
559 {
560 	BPoint points[2] = { start, end };
561 	BRect bounds = _BuildBounds(points, 2);
562 
563 	if (!fClippingRegion.Intersects(bounds))
564 		return;
565 
566 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
567 	message.Start(RP_STROKE_LINE_1PX_COLOR);
568 	message.Add(fToken);
569 	message.AddList(points, 2);
570 	message.Add(color);
571 }
572 
573 
574 void
575 RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color)
576 {
577 	BRect bounds = rect;
578 	bounds.InsetBy(fExtendWidth, fExtendWidth);
579 
580 	if (!fClippingRegion.Intersects(bounds))
581 		return;
582 
583 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
584 	message.Start(RP_STROKE_RECT_1PX_COLOR);
585 	message.Add(fToken);
586 	message.Add(rect);
587 	message.Add(color);
588 }
589 
590 
591 void
592 RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color)
593 {
594 	if (!fClippingRegion.Intersects(rect))
595 		return;
596 
597 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
598 	message.Start(RP_FILL_RECT_COLOR);
599 	message.Add(fToken);
600 	message.Add(rect);
601 	message.Add(color);
602 }
603 
604 
605 void
606 RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color)
607 {
608 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
609 	message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING);
610 	message.AddRegion(region);
611 	message.Add(color);
612 }
613 
614 
615 // #pragma mark - DrawState versions
616 
617 
618 void
619 RemoteDrawingEngine::StrokeRect(BRect rect)
620 {
621 	BRect bounds = rect;
622 	bounds.InsetBy(fExtendWidth, fExtendWidth);
623 
624 	if (!fClippingRegion.Intersects(bounds))
625 		return;
626 
627 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
628 	message.Start(RP_STROKE_RECT);
629 	message.Add(fToken);
630 	message.Add(rect);
631 }
632 
633 
634 void
635 RemoteDrawingEngine::FillRect(BRect rect)
636 {
637 	if (!fClippingRegion.Intersects(rect))
638 		return;
639 
640 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
641 	message.Start(RP_FILL_RECT);
642 	message.Add(fToken);
643 	message.Add(rect);
644 }
645 
646 
647 void
648 RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient)
649 {
650 	if (!fClippingRegion.Intersects(rect))
651 		return;
652 
653 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
654 	message.Start(RP_FILL_RECT_GRADIENT);
655 	message.Add(fToken);
656 	message.Add(rect);
657 	message.AddGradient(gradient);
658 }
659 
660 
661 void
662 RemoteDrawingEngine::FillRegion(BRegion& region)
663 {
664 	BRegion clippedRegion = region;
665 	clippedRegion.IntersectWith(&fClippingRegion);
666 	if (clippedRegion.CountRects() == 0)
667 		return;
668 
669 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
670 	message.Start(RP_FILL_REGION);
671 	message.Add(fToken);
672 	message.AddRegion(clippedRegion.CountRects() < region.CountRects()
673 		? clippedRegion : region);
674 }
675 
676 
677 void
678 RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient)
679 {
680 	BRegion clippedRegion = region;
681 	clippedRegion.IntersectWith(&fClippingRegion);
682 	if (clippedRegion.CountRects() == 0)
683 		return;
684 
685 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
686 	message.Start(RP_FILL_REGION_GRADIENT);
687 	message.Add(fToken);
688 	message.AddRegion(clippedRegion.CountRects() < region.CountRects()
689 		? clippedRegion : region);
690 	message.AddGradient(gradient);
691 }
692 
693 
694 void
695 RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius,
696 	bool filled)
697 {
698 	BRect bounds = rect;
699 	if (!filled)
700 		bounds.InsetBy(fExtendWidth, fExtendWidth);
701 
702 	if (!fClippingRegion.Intersects(bounds))
703 		return;
704 
705 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
706 	message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT);
707 	message.Add(fToken);
708 	message.Add(rect);
709 	message.Add(xRadius);
710 	message.Add(yRadius);
711 }
712 
713 
714 void
715 RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
716 	const BGradient& gradient)
717 {
718 	if (!fClippingRegion.Intersects(rect))
719 		return;
720 
721 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
722 	message.Start(RP_FILL_ROUND_RECT_GRADIENT);
723 	message.Add(fToken);
724 	message.Add(rect);
725 	message.Add(xRadius);
726 	message.Add(yRadius);
727 	message.AddGradient(gradient);
728 }
729 
730 
731 void
732 RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
733 	const uint32* opList, int32 pointCount, const BPoint* pointList,
734 	bool filled, const BPoint& viewToScreenOffset, float viewScale)
735 {
736 	BRect clipBounds = bounds;
737 	if (!filled)
738 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
739 
740 	if (!fClippingRegion.Intersects(clipBounds))
741 		return;
742 
743 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
744 	message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE);
745 	message.Add(fToken);
746 	message.Add(bounds);
747 	message.Add(opCount);
748 	message.AddList(opList, opCount);
749 	message.Add(pointCount);
750 	message.AddList(pointList, pointCount);
751 	message.Add(viewToScreenOffset);
752 	message.Add(viewScale);
753 }
754 
755 
756 void
757 RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
758 	const uint32* opList, int32 pointCount, const BPoint* pointList,
759 	const BGradient& gradient, const BPoint& viewToScreenOffset,
760 	float viewScale)
761 {
762 	if (!fClippingRegion.Intersects(bounds))
763 		return;
764 
765 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
766 	message.Start(RP_FILL_SHAPE_GRADIENT);
767 	message.Add(fToken);
768 	message.Add(bounds);
769 	message.Add(opCount);
770 	message.AddList(opList, opCount);
771 	message.Add(pointCount);
772 	message.AddList(pointList, pointCount);
773 	message.Add(viewToScreenOffset);
774 	message.Add(viewScale);
775 	message.AddGradient(gradient);
776 }
777 
778 
779 void
780 RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds,
781 	bool filled)
782 {
783 	BRect clipBounds = bounds;
784 	if (!filled)
785 		clipBounds.InsetBy(fExtendWidth, fExtendWidth);
786 
787 	if (!fClippingRegion.Intersects(clipBounds))
788 		return;
789 
790 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
791 	message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE);
792 	message.Add(fToken);
793 	message.AddList(points, 3);
794 	message.Add(bounds);
795 }
796 
797 
798 void
799 RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds,
800 	const BGradient& gradient)
801 {
802 	if (!fClippingRegion.Intersects(bounds))
803 		return;
804 
805 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
806 	message.Start(RP_FILL_TRIANGLE_GRADIENT);
807 	message.Add(fToken);
808 	message.AddList(points, 3);
809 	message.Add(bounds);
810 	message.AddGradient(gradient);
811 }
812 
813 
814 void
815 RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
816 {
817 	BPoint points[2] = { start, end };
818 	BRect bounds = _BuildBounds(points, 2);
819 
820 	if (!fClippingRegion.Intersects(bounds))
821 		return;
822 
823 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
824 	message.Start(RP_STROKE_LINE);
825 	message.Add(fToken);
826 	message.AddList(points, 2);
827 }
828 
829 
830 void
831 RemoteDrawingEngine::StrokeLineArray(int32 numLines,
832 	const ViewLineArrayInfo *lineData)
833 {
834 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
835 	message.Start(RP_STROKE_LINE_ARRAY);
836 	message.Add(fToken);
837 	message.Add(numLines);
838 	for (int32 i = 0; i < numLines; i++)
839 		message.AddArrayLine(lineData[i]);
840 }
841 
842 
843 // #pragma mark - string functions
844 
845 
846 BPoint
847 RemoteDrawingEngine::DrawString(const char* string, int32 length,
848 	const BPoint& point, escapement_delta* delta)
849 {
850 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
851 
852 	message.Start(RP_DRAW_STRING);
853 	message.Add(fToken);
854 	message.Add(point);
855 	message.AddString(string, length);
856 	message.Add(delta != NULL);
857 	if (delta != NULL)
858 		message.AddList(delta, length);
859 
860 	status_t result = _AddCallback();
861 	if (message.Flush() != B_OK)
862 		return point;
863 
864 	if (result != B_OK)
865 		return point;
866 
867 	do {
868 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
869 			1 * 1000 * 1000);
870 	} while (result == B_INTERRUPTED);
871 
872 	if (result != B_OK)
873 		return point;
874 
875 	return fDrawStringResult;
876 }
877 
878 
879 BPoint
880 RemoteDrawingEngine::DrawString(const char* string, int32 length,
881 	const BPoint* offsets)
882 {
883 	// Guaranteed to have at least one point.
884 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
885 
886 	message.Start(RP_DRAW_STRING_WITH_OFFSETS);
887 	message.Add(fToken);
888 	message.AddString(string, length);
889 	message.AddList(offsets, UTF8CountChars(string, length));
890 
891 	status_t result = _AddCallback();
892 	if (message.Flush() != B_OK)
893 		return offsets[0];
894 
895 	if (result != B_OK)
896 		return offsets[0];
897 
898 	do {
899 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
900 			1 * 1000 * 1000);
901 	} while (result == B_INTERRUPTED);
902 
903 	if (result != B_OK)
904 		return offsets[0];
905 
906 	return fDrawStringResult;
907 }
908 
909 
910 float
911 RemoteDrawingEngine::StringWidth(const char* string, int32 length,
912 	escapement_delta* delta)
913 {
914 	// TODO: Decide if really needed.
915 
916 	while (true) {
917 		if (_AddCallback() != B_OK)
918 			break;
919 
920 		RemoteMessage message(NULL, fHWInterface->SendBuffer());
921 
922 		message.Start(RP_STRING_WIDTH);
923 		message.Add(fToken);
924 		message.AddString(string, length);
925 			// TODO: Support escapement delta.
926 
927 		if (message.Flush() != B_OK)
928 			break;
929 
930 		status_t result;
931 		do {
932 			result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
933 				1 * 1000 * 1000);
934 		} while (result == B_INTERRUPTED);
935 
936 		if (result != B_OK)
937 			break;
938 
939 		return fStringWidthResult;
940 	}
941 
942 	// Fall back to local calculation.
943 	return fState.Font().StringWidth(string, length, delta);
944 }
945 
946 
947 // #pragma mark -
948 
949 
950 status_t
951 RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
952 	BRect bounds)
953 {
954 	if (_AddCallback() != B_OK)
955 		return B_UNSUPPORTED;
956 
957 	RemoteMessage message(NULL, fHWInterface->SendBuffer());
958 
959 	message.Start(RP_READ_BITMAP);
960 	message.Add(fToken);
961 	message.Add(bounds);
962 	message.Add(drawCursor);
963 	if (message.Flush() != B_OK)
964 		return B_UNSUPPORTED;
965 
966 	status_t result;
967 	do {
968 		result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
969 			10 * 1000 * 1000);
970 	} while (result == B_INTERRUPTED);
971 
972 	if (result != B_OK)
973 		return result;
974 
975 	BBitmap* read = fReadBitmapResult;
976 	if (read == NULL)
977 		return B_UNSUPPORTED;
978 
979 	result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
980 		read->BytesPerRow(), read->ColorSpace());
981 	delete read;
982 	return result;
983 }
984 
985 
986 // #pragma mark -
987 
988 
989 status_t
990 RemoteDrawingEngine::_AddCallback()
991 {
992 	if (fCallbackAdded)
993 		return B_OK;
994 
995 	if (fResultNotify < 0)
996 		fResultNotify = create_sem(0, "drawing engine result");
997 	if (fResultNotify < 0)
998 		return fResultNotify;
999 
1000 	status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
1001 		this);
1002 
1003 	fCallbackAdded = result == B_OK;
1004 	return result;
1005 }
1006 
1007 
1008 bool
1009 RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
1010 {
1011 	RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
1012 
1013 	switch (message.Code()) {
1014 		case RP_DRAW_STRING_RESULT:
1015 		{
1016 			status_t result = message.Read(engine->fDrawStringResult);
1017 			if (result != B_OK) {
1018 				TRACE_ERROR("failed to read draw string result: %s\n",
1019 					strerror(result));
1020 				return false;
1021 			}
1022 
1023 			break;
1024 		}
1025 
1026 		case RP_STRING_WIDTH_RESULT:
1027 		{
1028 			status_t result = message.Read(engine->fStringWidthResult);
1029 			if (result != B_OK) {
1030 				TRACE_ERROR("failed to read string width result: %s\n",
1031 					strerror(result));
1032 				return false;
1033 			}
1034 
1035 			break;
1036 		}
1037 
1038 		case RP_READ_BITMAP_RESULT:
1039 		{
1040 			status_t result = message.ReadBitmap(&engine->fReadBitmapResult);
1041 			if (result != B_OK) {
1042 				TRACE_ERROR("failed to read bitmap of read bitmap result: %s\n",
1043 					strerror(result));
1044 				return false;
1045 			}
1046 
1047 			break;
1048 		}
1049 
1050 		default:
1051 			return false;
1052 	}
1053 
1054 	release_sem(engine->fResultNotify);
1055 	return true;
1056 }
1057 
1058 
1059 BRect
1060 RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
1061 {
1062 	BRect bounds(1000000, 1000000, 0, 0);
1063 	for (int32 i = 0; i < pointCount; i++) {
1064 		bounds.left = min_c(bounds.left, points[i].x);
1065 		bounds.top = min_c(bounds.top, points[i].y);
1066 		bounds.right = max_c(bounds.right, points[i].x);
1067 		bounds.bottom = max_c(bounds.bottom, points[i].y);
1068 	}
1069 
1070 	return bounds;
1071 }
1072 
1073 
1074 status_t
1075 RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 options,
1076 	const BRect& bitmapRect, const BRect& viewRect, double xScale,
1077 	double yScale, BRegion& region, UtilityBitmap**& bitmaps)
1078 {
1079 	int32 rectCount = region.CountRects();
1080 	bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
1081 	if (bitmaps == NULL)
1082 		return B_NO_MEMORY;
1083 
1084 	for (int32 i = 0; i < rectCount; i++) {
1085 		BRect sourceRect = region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
1086 		int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
1087 		int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
1088 
1089 		if (xScale != 1.0) {
1090 			sourceRect.left = (int32)(sourceRect.left * xScale + 0.5);
1091 			sourceRect.right = (int32)(sourceRect.right * xScale + 0.5);
1092 			if (xScale < 1.0)
1093 				targetWidth = (int32)(sourceRect.Width() + 1.5);
1094 		}
1095 
1096 		if (yScale != 1.0) {
1097 			sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
1098 			sourceRect.bottom = (int32)(sourceRect.bottom * yScale + 0.5);
1099 			if (yScale < 1.0)
1100 				targetHeight = (int32)(sourceRect.Height() + 1.5);
1101 		}
1102 
1103 		sourceRect.OffsetBy(bitmapRect.LeftTop());
1104 			// sourceRect is now the part of the bitmap we want copied
1105 
1106 		status_t result = B_OK;
1107 		if ((xScale > 1.0 || yScale > 1.0)
1108 			&& (targetWidth * targetHeight < (int32)(sourceRect.Width() + 1.5)
1109 				* (int32)(sourceRect.Height() + 1.5))) {
1110 			// the target bitmap is smaller than the source, scale it locally
1111 			// and send over the smaller version to avoid sending any extra data
1112 			if (fBitmapDrawingEngine == NULL) {
1113 				fBitmapDrawingEngine
1114 					= new(std::nothrow) BitmapDrawingEngine(B_RGBA32);
1115 				if (fBitmapDrawingEngine == NULL)
1116 					result = B_NO_MEMORY;
1117 			}
1118 
1119 			if (result == B_OK) {
1120 				result = fBitmapDrawingEngine->SetSize(targetWidth,
1121 					targetHeight);
1122 			}
1123 
1124 			if (result == B_OK) {
1125 				fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1126 
1127 				switch (bitmap.ColorSpace()) {
1128 					case B_RGBA32:
1129 					case B_RGBA32_BIG:
1130 					case B_RGBA15:
1131 					case B_RGBA15_BIG:
1132 						break;
1133 
1134 					default:
1135 					{
1136 						// we need to clear the background if there may be
1137 						// transparency through transparent magic (we use
1138 						// B_OP_COPY when we draw alpha enabled bitmaps, so we
1139 						// don't need to clear there)
1140 						// TODO: this is not actually correct, as we're going to
1141 						// loose the transparency with the conversion to the
1142 						// original non-alpha colorspace happening in
1143 						// ExportToBitmap
1144 						rgb_color background = { 0, 0, 0, 0 };
1145 						fBitmapDrawingEngine->FillRect(
1146 							BRect(0, 0, targetWidth - 1, targetHeight -1),
1147 							background);
1148 						fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1149 						break;
1150 					}
1151 				}
1152 
1153 				fBitmapDrawingEngine->DrawBitmap(&bitmap, sourceRect,
1154 					BRect(0, 0, targetWidth - 1, targetHeight - 1), options);
1155 				bitmaps[i] = fBitmapDrawingEngine->ExportToBitmap(targetWidth,
1156 					targetHeight, bitmap.ColorSpace());
1157 				if (bitmaps[i] == NULL)
1158 					result = B_NO_MEMORY;
1159 			}
1160 		} else {
1161 			// source is smaller or equal target, extract the relevant rects
1162 			// directly without any scaling and conversion
1163 			targetWidth = (int32)(sourceRect.Width() + 1.5);
1164 			targetHeight = (int32)(sourceRect.Height() + 1.5);
1165 
1166 			bitmaps[i] = new(std::nothrow) UtilityBitmap(
1167 				BRect(0, 0, targetWidth - 1, targetHeight - 1),
1168 				bitmap.ColorSpace(), 0);
1169 			if (bitmaps[i] == NULL) {
1170 				result = B_NO_MEMORY;
1171 			} else {
1172 				result = bitmaps[i]->ImportBits(bitmap.Bits(),
1173 						bitmap.BitsLength(), bitmap.BytesPerRow(),
1174 						bitmap.ColorSpace(), sourceRect.LeftTop(),
1175 						BPoint(0, 0), targetWidth, targetHeight);
1176 				if (result != B_OK) {
1177 					delete bitmaps[i];
1178 					bitmaps[i] = NULL;
1179 				}
1180 			}
1181 		}
1182 
1183 		if (result != B_OK) {
1184 			for (int32 j = 0; j < i; j++)
1185 				delete bitmaps[j];
1186 			free(bitmaps);
1187 			return result;
1188 		}
1189 	}
1190 
1191 	return B_OK;
1192 }
1193