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