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