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