1/*
2 * Copyright 2001-2019, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Marc Flerackers (mflerackers@androme.be)
7 *		Stefano Ceccherini (stefano.ceccherini@gmail.com)
8 *		Marcus Overhagen <marcus@overhagen.de>
9 *		Julian Harnath <julian.harnath@rwth-aachen.de>
10 *		Stephan A��mus <superstippi@gmx.de>
11 */
12
13#include "ServerPicture.h"
14
15#include <new>
16#include <stdio.h>
17#include <stack>
18
19#include "AlphaMask.h"
20#include "DrawingEngine.h"
21#include "DrawState.h"
22#include "GlobalFontManager.h"
23#include "Layer.h"
24#include "ServerApp.h"
25#include "ServerBitmap.h"
26#include "ServerFont.h"
27#include "ServerTokenSpace.h"
28#include "View.h"
29#include "Window.h"
30
31#include <LinkReceiver.h>
32#include <OffsetFile.h>
33#include <ObjectListPrivate.h>
34#include <PicturePlayer.h>
35#include <PictureProtocol.h>
36#include <PortLink.h>
37#include <ServerProtocol.h>
38#include <ShapePrivate.h>
39#include <StackOrHeapArray.h>
40
41#include <Bitmap.h>
42#include <Debug.h>
43#include <List.h>
44#include <Shape.h>
45
46
47using std::stack;
48
49
50class ShapePainter : public BShapeIterator {
51public:
52	ShapePainter(Canvas* canvas, BGradient* gradient);
53	virtual ~ShapePainter();
54
55	status_t Iterate(const BShape* shape);
56
57	virtual status_t IterateMoveTo(BPoint* point);
58	virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts);
59	virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts);
60	virtual status_t IterateClose();
61	virtual status_t IterateArcTo(float& rx, float& ry,
62		float& angle, bool largeArc, bool counterClockWise, BPoint& point);
63
64	void Draw(BRect frame, bool filled);
65
66private:
67	Canvas*	fCanvas;
68	BGradient* fGradient;
69	stack<uint32>	fOpStack;
70	stack<BPoint>	fPtStack;
71};
72
73
74ShapePainter::ShapePainter(Canvas* canvas, BGradient* gradient)
75	:
76	fCanvas(canvas),
77	fGradient(gradient)
78{
79}
80
81
82ShapePainter::~ShapePainter()
83{
84}
85
86
87status_t
88ShapePainter::Iterate(const BShape* shape)
89{
90	// this class doesn't modify the shape data
91	return BShapeIterator::Iterate(const_cast<BShape*>(shape));
92}
93
94
95status_t
96ShapePainter::IterateMoveTo(BPoint* point)
97{
98	try {
99		fOpStack.push(OP_MOVETO);
100		fPtStack.push(*point);
101	} catch (std::bad_alloc&) {
102		return B_NO_MEMORY;
103	}
104
105	return B_OK;
106}
107
108
109status_t
110ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts)
111{
112	try {
113		fOpStack.push(OP_LINETO | lineCount);
114		for (int32 i = 0; i < lineCount; i++)
115			fPtStack.push(linePts[i]);
116	} catch (std::bad_alloc&) {
117		return B_NO_MEMORY;
118	}
119
120	return B_OK;
121}
122
123
124status_t
125ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts)
126{
127	bezierCount *= 3;
128	try {
129		fOpStack.push(OP_BEZIERTO | bezierCount);
130		for (int32 i = 0; i < bezierCount; i++)
131			fPtStack.push(bezierPts[i]);
132	} catch (std::bad_alloc&) {
133		return B_NO_MEMORY;
134	}
135
136	return B_OK;
137}
138
139
140status_t
141ShapePainter::IterateArcTo(float& rx, float& ry,
142	float& angle, bool largeArc, bool counterClockWise, BPoint& point)
143{
144	uint32 op;
145	if (largeArc) {
146		if (counterClockWise)
147			op = OP_LARGE_ARC_TO_CCW;
148		else
149			op = OP_LARGE_ARC_TO_CW;
150	} else {
151		if (counterClockWise)
152			op = OP_SMALL_ARC_TO_CCW;
153		else
154			op = OP_SMALL_ARC_TO_CW;
155	}
156
157	try {
158		fOpStack.push(op | 3);
159		fPtStack.push(BPoint(rx, ry));
160		fPtStack.push(BPoint(angle, 0));
161		fPtStack.push(point);
162	} catch (std::bad_alloc&) {
163		return B_NO_MEMORY;
164	}
165
166	return B_OK;
167}
168
169
170status_t
171ShapePainter::IterateClose()
172{
173	try {
174		fOpStack.push(OP_CLOSE);
175	} catch (std::bad_alloc&) {
176		return B_NO_MEMORY;
177	}
178
179	return B_OK;
180}
181
182
183void
184ShapePainter::Draw(BRect frame, bool filled)
185{
186	// We're going to draw the currently iterated shape.
187	// TODO: This can be more efficient by skipping the conversion.
188	int32 opCount = fOpStack.size();
189	int32 ptCount = fPtStack.size();
190
191	if (opCount > 0 && ptCount > 0) {
192		int32 i;
193		uint32* opList = new(std::nothrow) uint32[opCount];
194		if (opList == NULL)
195			return;
196
197		BPoint* ptList = new(std::nothrow) BPoint[ptCount];
198		if (ptList == NULL) {
199			delete[] opList;
200			return;
201		}
202
203		for (i = opCount - 1; i >= 0; i--) {
204			opList[i] = fOpStack.top();
205			fOpStack.pop();
206		}
207
208		for (i = ptCount - 1; i >= 0; i--) {
209			ptList[i] = fPtStack.top();
210			fPtStack.pop();
211		}
212
213		// this might seem a bit weird, but under R5, the shapes
214		// are always offset by the current pen location
215		BPoint screenOffset = fCanvas->CurrentState()->PenLocation();
216		frame.OffsetBy(screenOffset);
217
218		const SimpleTransform transform = fCanvas->PenToScreenTransform();
219		transform.Apply(&screenOffset);
220		transform.Apply(&frame);
221
222		/* stroked gradients are not yet supported */
223		if (fGradient != NULL && filled) {
224			fCanvas->GetDrawingEngine()->FillShape(frame, opCount, opList,
225				ptCount, ptList, *fGradient, screenOffset, fCanvas->Scale());
226		} else {
227			fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList,
228				ptCount, ptList, filled, screenOffset, fCanvas->Scale());
229		}
230
231		delete[] opList;
232		delete[] ptList;
233	}
234}
235
236
237// #pragma mark - drawing functions
238
239
240static void
241get_polygon_frame(const BPoint* points, uint32 numPoints, BRect* _frame)
242{
243	ASSERT(numPoints > 0);
244
245	float left = points->x;
246	float top = points->y;
247	float right = left;
248	float bottom = top;
249
250	points++;
251	numPoints--;
252
253	while (numPoints--) {
254		if (points->x < left)
255			left = points->x;
256		if (points->x > right)
257			right = points->x;
258		if (points->y < top)
259			top = points->y;
260		if (points->y > bottom)
261			bottom = points->y;
262		points++;
263	}
264
265	_frame->Set(left, top, right, bottom);
266}
267
268
269static void
270move_pen_by(void* _canvas, const BPoint& delta)
271{
272	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
273	canvas->CurrentState()->SetPenLocation(
274		canvas->CurrentState()->PenLocation() + delta);
275}
276
277
278static void
279stroke_line(void* _canvas, const BPoint& _start, const BPoint& _end)
280{
281	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
282	BPoint start = _start;
283	BPoint end = _end;
284
285	const SimpleTransform transform = canvas->PenToScreenTransform();
286	transform.Apply(&start);
287	transform.Apply(&end);
288	canvas->GetDrawingEngine()->StrokeLine(start, end);
289
290	canvas->CurrentState()->SetPenLocation(_end);
291	// the DrawingEngine/Painter does not need to be updated, since this
292	// effects only the view->screen coord conversion, which is handled
293	// by the view only
294}
295
296
297static void
298draw_rect(void* _canvas, const BRect& _rect, bool fill)
299{
300	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
301	BRect rect = _rect;
302
303	canvas->PenToScreenTransform().Apply(&rect);
304	if (fill)
305		canvas->GetDrawingEngine()->FillRect(rect);
306	else
307		canvas->GetDrawingEngine()->StrokeRect(rect);
308}
309
310
311static void
312draw_round_rect(void* _canvas, const BRect& _rect, const BPoint& radii,
313	bool fill)
314{
315	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
316	BRect rect = _rect;
317
318	canvas->PenToScreenTransform().Apply(&rect);
319	float scale = canvas->CurrentState()->CombinedScale();
320	canvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale,
321		radii.y * scale, fill);
322}
323
324
325static void
326draw_bezier(void* _canvas, size_t numPoints, const BPoint viewPoints[],
327	bool fill)
328{
329	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
330
331	const size_t kSupportedPoints = 4;
332	if (numPoints != kSupportedPoints)
333		return;
334
335	BPoint points[kSupportedPoints];
336	canvas->PenToScreenTransform().Apply(points, viewPoints, kSupportedPoints);
337	canvas->GetDrawingEngine()->DrawBezier(points, fill);
338}
339
340
341static void
342draw_arc(void* _canvas, const BPoint& center, const BPoint& radii,
343	float startTheta, float arcTheta, bool fill)
344{
345	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
346
347	BRect rect(center.x - radii.x, center.y - radii.y,
348		center.x + radii.x - 1, center.y + radii.y - 1);
349	canvas->PenToScreenTransform().Apply(&rect);
350	canvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill);
351}
352
353
354static void
355draw_ellipse(void* _canvas, const BRect& _rect, bool fill)
356{
357	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
358
359	BRect rect = _rect;
360	canvas->PenToScreenTransform().Apply(&rect);
361	canvas->GetDrawingEngine()->DrawEllipse(rect, fill);
362}
363
364
365static void
366draw_polygon(void* _canvas, size_t numPoints, const BPoint viewPoints[],
367	bool isClosed, bool fill)
368{
369	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
370
371	if (numPoints == 0)
372		return;
373
374	BStackOrHeapArray<BPoint, 200> points(numPoints);
375	if (!points.IsValid())
376		return;
377
378	canvas->PenToScreenTransform().Apply(points, viewPoints, numPoints);
379
380	BRect polyFrame;
381	get_polygon_frame(points, numPoints, &polyFrame);
382
383	canvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
384		fill, isClosed && numPoints > 2);
385}
386
387
388static void
389draw_shape(void* _canvas, const BShape& shape, bool fill)
390{
391	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
392	ShapePainter drawShape(canvas, NULL);
393
394	drawShape.Iterate(&shape);
395	drawShape.Draw(shape.Bounds(), fill);
396}
397
398
399static void
400draw_rect_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
401{
402	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
403	BRect rect = _rect;
404
405	const SimpleTransform transform =
406		canvas->PenToScreenTransform();
407	transform.Apply(&rect);
408	transform.Apply(&gradient);
409
410	canvas->GetDrawingEngine()->FillRect(rect, gradient);
411}
412
413
414static void
415draw_round_rect_gradient(void* _canvas, const BRect& _rect, const BPoint& radii, BGradient& gradient,
416	bool fill)
417{
418	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
419	BRect rect = _rect;
420
421	const SimpleTransform transform =
422		canvas->PenToScreenTransform();
423	transform.Apply(&rect);
424	transform.Apply(&gradient);
425	float scale = canvas->CurrentState()->CombinedScale();
426	canvas->GetDrawingEngine()->FillRoundRect(rect, radii.x * scale,
427		radii.y * scale, gradient);
428}
429
430
431static void
432draw_bezier_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[], BGradient& gradient,
433	bool fill)
434{
435	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
436
437	const size_t kSupportedPoints = 4;
438	if (numPoints != kSupportedPoints)
439		return;
440
441	BPoint points[kSupportedPoints];
442	const SimpleTransform transform =
443		canvas->PenToScreenTransform();
444	transform.Apply(points, viewPoints, kSupportedPoints);
445	transform.Apply(&gradient);
446	canvas->GetDrawingEngine()->FillBezier(points, gradient);
447}
448
449
450static void
451draw_arc_gradient(void* _canvas, const BPoint& center, const BPoint& radii,
452	float startTheta, float arcTheta, BGradient& gradient, bool fill)
453{
454	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
455
456	BRect rect(center.x - radii.x, center.y - radii.y,
457		center.x + radii.x - 1, center.y + radii.y - 1);
458	const SimpleTransform transform =
459		canvas->PenToScreenTransform();
460	transform.Apply(&rect);
461	transform.Apply(&gradient);
462	canvas->GetDrawingEngine()->FillArc(rect, startTheta, arcTheta, gradient);
463}
464
465
466static void
467draw_ellipse_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
468{
469	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
470	BRect rect = _rect;
471
472	const SimpleTransform transform =
473		canvas->PenToScreenTransform();
474	transform.Apply(&rect);
475	transform.Apply(&gradient);
476	canvas->GetDrawingEngine()->FillEllipse(rect, gradient);
477}
478
479
480static void
481draw_polygon_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[],
482	bool isClosed, BGradient& gradient, bool fill)
483{
484	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
485
486	if (numPoints == 0)
487		return;
488
489	BStackOrHeapArray<BPoint, 200> points(numPoints);
490	if (!points.IsValid())
491		return;
492
493	const SimpleTransform transform =
494		canvas->PenToScreenTransform();
495	transform.Apply(points, viewPoints, numPoints);
496	transform.Apply(&gradient);
497
498	BRect polyFrame;
499	get_polygon_frame(points, numPoints, &polyFrame);
500
501	canvas->GetDrawingEngine()->FillPolygon(points, numPoints, polyFrame,
502		gradient, isClosed && numPoints > 2);
503}
504
505
506static void
507draw_shape_gradient(void* _canvas, const BShape& shape, BGradient& gradient, bool fill)
508{
509	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
510	ShapePainter drawShape(canvas, &gradient);
511
512	drawShape.Iterate(&shape);
513	drawShape.Draw(shape.Bounds(), fill);
514}
515
516
517static void
518draw_string(void* _canvas, const char* string, size_t length, float deltaSpace,
519	float deltaNonSpace)
520{
521	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
522
523	// NOTE: the picture data was recorded with a "set pen location"
524	// command inserted before the "draw string" command, so we can
525	// use PenLocation()
526	BPoint location = canvas->CurrentState()->PenLocation();
527
528	escapement_delta delta = { deltaSpace, deltaNonSpace };
529	canvas->PenToScreenTransform().Apply(&location);
530	location = canvas->GetDrawingEngine()->DrawString(string, length,
531		location, &delta);
532
533	canvas->PenToScreenTransform().Apply(&location);
534	canvas->CurrentState()->SetPenLocation(location);
535	// the DrawingEngine/Painter does not need to be updated, since this
536	// effects only the view->screen coord conversion, which is handled
537	// by the view only
538}
539
540
541static void
542draw_string_locations(void* _canvas, const char* string, size_t length,
543	const BPoint* _locations, size_t locationsCount)
544{
545	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
546	BStackOrHeapArray<BPoint, 200> locations(locationsCount);
547	if (!locations.IsValid())
548		return;
549
550	const SimpleTransform transform = canvas->PenToScreenTransform();
551	for (size_t i = 0; i < locationsCount; i++) {
552		locations[i] = _locations[i];
553		transform.Apply(&locations[i]);
554	}
555
556	BPoint location = canvas->GetDrawingEngine()->DrawString(string, length,
557		locations);
558
559	canvas->PenToScreenTransform().Apply(&location);
560	canvas->CurrentState()->SetPenLocation(location);
561	// the DrawingEngine/Painter does not need to be updated, since this
562	// effects only the view->screen coord conversion, which is handled
563	// by the view only
564}
565
566
567static void
568draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width,
569	uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
570	const void* data, size_t length)
571{
572	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
573
574	UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1),
575		(color_space)pixelFormat, 0, bytesPerRow);
576
577	if (!bitmap.IsValid())
578		return;
579
580	memcpy(bitmap.Bits(), data, std::min(height * bytesPerRow, length));
581
582	BRect dest = _dest;
583	canvas->PenToScreenTransform().Apply(&dest);
584	canvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options);
585}
586
587
588static void
589draw_picture(void* _canvas, const BPoint& where, int32 token)
590{
591	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
592
593	BReference<ServerPicture> picture(canvas->GetPicture(token), true);
594	if (picture != NULL) {
595		canvas->PushState();
596		canvas->SetDrawingOrigin(where);
597
598		canvas->PushState();
599		picture->Play(canvas);
600		canvas->PopState();
601
602		canvas->PopState();
603	}
604}
605
606
607static void
608set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[])
609{
610	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
611
612	if (numRects == 0)
613		canvas->SetUserClipping(NULL);
614	else {
615		// TODO: This might be too slow, we should copy the rects
616		// directly to BRegion's internal data
617		BRegion region;
618		for (uint32 c = 0; c < numRects; c++)
619			region.Include(rects[c]);
620		canvas->SetUserClipping(&region);
621	}
622	canvas->UpdateCurrentDrawingRegion();
623}
624
625
626static void
627clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where,
628	bool clipToInverse)
629{
630	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
631
632	BReference<ServerPicture> picture(canvas->GetPicture(pictureToken), true);
633	if (picture == NULL)
634		return;
635	BReference<AlphaMask> mask(new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(),
636		picture, *canvas->CurrentState(), where, clipToInverse), true);
637	canvas->SetAlphaMask(mask);
638	canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
639		canvas->Bounds());
640	canvas->ResyncDrawState();
641}
642
643
644static void
645push_state(void* _canvas)
646{
647	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
648	canvas->PushState();
649}
650
651
652static void
653pop_state(void* _canvas)
654{
655	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
656	canvas->PopState();
657
658	BPoint p(0, 0);
659	canvas->PenToScreenTransform().Apply(&p);
660	canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(),
661		(int32)p.x, (int32)p.y);
662}
663
664
665// TODO: Be smart and actually take advantage of these methods:
666// only apply state changes when they are called
667static void
668enter_state_change(void* _canvas)
669{
670}
671
672
673static void
674exit_state_change(void* _canvas)
675{
676	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
677	canvas->ResyncDrawState();
678}
679
680
681static void
682enter_font_state(void* _canvas)
683{
684}
685
686
687static void
688exit_font_state(void* _canvas)
689{
690	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
691	canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font());
692}
693
694
695static void
696set_origin(void* _canvas, const BPoint& pt)
697{
698	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
699	canvas->CurrentState()->SetOrigin(pt);
700}
701
702
703static void
704set_pen_location(void* _canvas, const BPoint& pt)
705{
706	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
707	canvas->CurrentState()->SetPenLocation(pt);
708	// the DrawingEngine/Painter does not need to be updated, since this
709	// effects only the view->screen coord conversion, which is handled
710	// by the view only
711}
712
713
714static void
715set_drawing_mode(void* _canvas, drawing_mode mode)
716{
717	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
718	if (canvas->CurrentState()->SetDrawingMode(mode))
719		canvas->GetDrawingEngine()->SetDrawingMode(mode);
720}
721
722
723static void
724set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode,
725	float miterLimit)
726{
727	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
728	DrawState* state = canvas->CurrentState();
729	state->SetLineCapMode(capMode);
730	state->SetLineJoinMode(joinMode);
731	state->SetMiterLimit(miterLimit);
732	canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
733}
734
735
736static void
737set_pen_size(void* _canvas, float size)
738{
739	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
740	canvas->CurrentState()->SetPenSize(size);
741	canvas->GetDrawingEngine()->SetPenSize(
742		canvas->CurrentState()->PenSize());
743		// DrawState::PenSize() returns the scaled pen size, so we
744		// need to use that value to set the drawing engine pen size.
745}
746
747
748static void
749set_fore_color(void* _canvas, const rgb_color& color)
750{
751	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
752	canvas->CurrentState()->SetHighColor(color);
753	canvas->GetDrawingEngine()->SetHighColor(color);
754}
755
756
757static void
758set_back_color(void* _canvas, const rgb_color& color)
759{
760	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
761	canvas->CurrentState()->SetLowColor(color);
762	canvas->GetDrawingEngine()->SetLowColor(color);
763}
764
765
766static void
767set_stipple_pattern(void* _canvas, const pattern& pattern)
768{
769	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
770	canvas->CurrentState()->SetPattern(Pattern(pattern));
771	canvas->GetDrawingEngine()->SetPattern(pattern);
772}
773
774
775static void
776set_scale(void* _canvas, float scale)
777{
778	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
779	canvas->CurrentState()->SetScale(scale);
780	canvas->ResyncDrawState();
781
782	// Update the drawing engine draw state, since some stuff
783	// (for example the pen size) needs to be recalculated.
784}
785
786
787static void
788set_font_family(void* _canvas, const char* _family, size_t length)
789{
790	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
791	BString family(_family, length);
792
793	FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
794	ServerFont font;
795	font.SetStyle(fontStyle);
796	canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
797}
798
799
800static void
801set_font_style(void* _canvas, const char* _style, size_t length)
802{
803	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
804	BString style(_style, length);
805
806	ServerFont font(canvas->CurrentState()->Font());
807
808	FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
809
810	font.SetStyle(fontStyle);
811	canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
812}
813
814
815static void
816set_font_spacing(void* _canvas, uint8 spacing)
817{
818	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
819	ServerFont font;
820	font.SetSpacing(spacing);
821	canvas->CurrentState()->SetFont(font, B_FONT_SPACING);
822}
823
824
825static void
826set_font_size(void* _canvas, float size)
827{
828	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
829	ServerFont font;
830	font.SetSize(size);
831	canvas->CurrentState()->SetFont(font, B_FONT_SIZE);
832}
833
834
835static void
836set_font_rotation(void* _canvas, float rotation)
837{
838	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
839	ServerFont font;
840	font.SetRotation(rotation);
841	canvas->CurrentState()->SetFont(font, B_FONT_ROTATION);
842}
843
844
845static void
846set_font_encoding(void* _canvas, uint8 encoding)
847{
848	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
849	ServerFont font;
850	font.SetEncoding(encoding);
851	canvas->CurrentState()->SetFont(font, B_FONT_ENCODING);
852}
853
854
855static void
856set_font_flags(void* _canvas, uint32 flags)
857{
858	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
859	ServerFont font;
860	font.SetFlags(flags);
861	canvas->CurrentState()->SetFont(font, B_FONT_FLAGS);
862}
863
864
865static void
866set_font_shear(void* _canvas, float shear)
867{
868	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
869	ServerFont font;
870	font.SetShear(shear);
871	canvas->CurrentState()->SetFont(font, B_FONT_SHEAR);
872}
873
874
875static void
876set_font_face(void* _canvas, uint16 face)
877{
878	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
879	ServerFont font;
880	font.SetFace(face);
881	canvas->CurrentState()->SetFont(font, B_FONT_FACE);
882}
883
884
885static void
886set_blending_mode(void* _canvas, source_alpha alphaSrcMode,
887	alpha_function alphaFncMode)
888{
889	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
890	canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
891}
892
893
894static void
895set_fill_rule(void* _canvas, int32 fillRule)
896{
897	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
898	canvas->CurrentState()->SetFillRule(fillRule);
899	canvas->GetDrawingEngine()->SetFillRule(fillRule);
900}
901
902
903static void
904set_transform(void* _canvas, const BAffineTransform& transform)
905{
906	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
907
908	BPoint leftTop(0, 0);
909	canvas->PenToScreenTransform().Apply(&leftTop);
910
911	canvas->CurrentState()->SetTransform(transform);
912	canvas->GetDrawingEngine()->SetTransform(
913		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
914}
915
916
917static void
918translate_by(void* _canvas, double x, double y)
919{
920	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
921
922	BPoint leftTop(0, 0);
923	canvas->PenToScreenTransform().Apply(&leftTop);
924
925	BAffineTransform transform = canvas->CurrentState()->Transform();
926	transform.PreTranslateBy(x, y);
927	canvas->CurrentState()->SetTransform(transform);
928	canvas->GetDrawingEngine()->SetTransform(
929		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
930}
931
932
933static void
934scale_by(void* _canvas, double x, double y)
935{
936	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
937
938	BPoint leftTop(0, 0);
939	canvas->PenToScreenTransform().Apply(&leftTop);
940
941	BAffineTransform transform = canvas->CurrentState()->Transform();
942	transform.PreScaleBy(x, y);
943	canvas->CurrentState()->SetTransform(transform);
944	canvas->GetDrawingEngine()->SetTransform(
945		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
946}
947
948
949static void
950rotate_by(void* _canvas, double angleRadians)
951{
952	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
953
954	BPoint leftTop(0, 0);
955	canvas->PenToScreenTransform().Apply(&leftTop);
956
957	BAffineTransform transform = canvas->CurrentState()->Transform();
958	transform.PreRotateBy(angleRadians);
959	canvas->CurrentState()->SetTransform(transform);
960	canvas->GetDrawingEngine()->SetTransform(
961		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
962}
963
964
965static void
966blend_layer(void* _canvas, Layer* layer)
967{
968	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
969	canvas->BlendLayer(layer);
970}
971
972
973static void
974clip_to_rect(void* _canvas, const BRect& rect, bool inverse)
975{
976	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
977	bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse);
978	if (needDrawStateUpdate) {
979		canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
980			canvas->Bounds());
981		canvas->ResyncDrawState();
982	}
983	canvas->UpdateCurrentDrawingRegion();
984}
985
986
987static void
988clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[],
989	int32 ptCount, const BPoint ptList[], bool inverse)
990{
991	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
992	shape_data shapeData;
993
994	// TODO: avoid copies
995	shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32));
996	memcpy(shapeData.opList, opList, opCount * sizeof(uint32));
997	shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint));
998	memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint));
999
1000	shapeData.opCount = opCount;
1001	shapeData.opSize = opCount * sizeof(uint32);
1002	shapeData.ptCount = ptCount;
1003	shapeData.ptSize = ptCount * sizeof(BPoint);
1004
1005	canvas->ClipToShape(&shapeData, inverse);
1006	canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
1007		canvas->Bounds());
1008	canvas->ResyncDrawState();
1009
1010	free(shapeData.opList);
1011	free(shapeData.ptList);
1012}
1013
1014
1015static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = {
1016	move_pen_by,
1017	stroke_line,
1018	draw_rect,
1019	draw_round_rect,
1020	draw_bezier,
1021	draw_arc,
1022	draw_ellipse,
1023	draw_polygon,
1024	draw_shape,
1025	draw_string,
1026	draw_pixels,
1027	draw_picture,
1028	set_clipping_rects,
1029	clip_to_picture,
1030	push_state,
1031	pop_state,
1032	enter_state_change,
1033	exit_state_change,
1034	enter_font_state,
1035	exit_font_state,
1036	set_origin,
1037	set_pen_location,
1038	set_drawing_mode,
1039	set_line_mode,
1040	set_pen_size,
1041	set_fore_color,
1042	set_back_color,
1043	set_stipple_pattern,
1044	set_scale,
1045	set_font_family,
1046	set_font_style,
1047	set_font_spacing,
1048	set_font_size,
1049	set_font_rotation,
1050	set_font_encoding,
1051	set_font_flags,
1052	set_font_shear,
1053	set_font_face,
1054	set_blending_mode,
1055	set_transform,
1056	translate_by,
1057	scale_by,
1058	rotate_by,
1059	blend_layer,
1060	clip_to_rect,
1061	clip_to_shape,
1062	draw_string_locations,
1063	draw_rect_gradient,
1064	draw_round_rect_gradient,
1065	draw_bezier_gradient,
1066	draw_arc_gradient,
1067	draw_ellipse_gradient,
1068	draw_polygon_gradient,
1069	draw_shape_gradient,
1070	set_fill_rule
1071};
1072
1073
1074// #pragma mark - ServerPicture
1075
1076
1077ServerPicture::ServerPicture()
1078	:
1079	fFile(NULL),
1080	fOwner(NULL)
1081{
1082	fToken = gTokenSpace.NewToken(kPictureToken, this);
1083	fData.SetTo(new(std::nothrow) BMallocIO());
1084
1085	PictureDataWriter::SetTo(fData.Get());
1086}
1087
1088
1089ServerPicture::ServerPicture(const ServerPicture& picture)
1090	:
1091	fFile(NULL),
1092	fData(NULL),
1093	fOwner(NULL)
1094{
1095	fToken = gTokenSpace.NewToken(kPictureToken, this);
1096
1097	BMallocIO* mallocIO = new(std::nothrow) BMallocIO();
1098	if (mallocIO == NULL)
1099		return;
1100
1101	fData.SetTo(mallocIO);
1102
1103	const off_t size = picture.DataLength();
1104	if (mallocIO->SetSize(size) < B_OK)
1105		return;
1106
1107	picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()),
1108		size);
1109
1110	PictureDataWriter::SetTo(fData.Get());
1111}
1112
1113
1114ServerPicture::ServerPicture(const char* fileName, int32 offset)
1115	:
1116	fFile(NULL),
1117	fData(NULL),
1118	fOwner(NULL)
1119{
1120	fToken = gTokenSpace.NewToken(kPictureToken, this);
1121
1122	fFile.SetTo(new(std::nothrow) BFile(fileName, B_READ_WRITE));
1123	if (!fFile.IsSet())
1124		return;
1125
1126	BPrivate::Storage::OffsetFile* offsetFile
1127		= new(std::nothrow) BPrivate::Storage::OffsetFile(fFile.Get(), offset);
1128	if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) {
1129		delete offsetFile;
1130		return;
1131	}
1132
1133	fData.SetTo(offsetFile);
1134
1135	PictureDataWriter::SetTo(fData.Get());
1136}
1137
1138
1139ServerPicture::~ServerPicture()
1140{
1141	ASSERT(fOwner == NULL);
1142
1143	gTokenSpace.RemoveToken(fToken);
1144
1145	if (fPictures.IsSet()) {
1146		for (int32 i = fPictures->CountItems(); i-- > 0;) {
1147			ServerPicture* picture = fPictures->ItemAt(i);
1148			picture->SetOwner(NULL);
1149			picture->ReleaseReference();
1150		}
1151	}
1152
1153	if (fPushed != NULL)
1154		fPushed->SetOwner(NULL);
1155}
1156
1157
1158bool
1159ServerPicture::SetOwner(ServerApp* owner)
1160{
1161	if (owner == fOwner)
1162		return true;
1163
1164	// Acquire an extra reference, since calling RemovePicture()
1165	// May remove the last reference and then we will self-destruct right then.
1166	// Setting fOwner to NULL would access free'd memory. If owner is another
1167	// ServerApp, it's expected to already have a reference of course.
1168	BReference<ServerPicture> _(this);
1169
1170	if (fOwner != NULL)
1171		fOwner->RemovePicture(this);
1172
1173	fOwner = NULL;
1174	if (owner == NULL)
1175		return true;
1176
1177	if (!owner->AddPicture(this))
1178		return false;
1179
1180	fOwner = owner;
1181	return true;
1182}
1183
1184
1185void
1186ServerPicture::EnterStateChange()
1187{
1188	BeginOp(B_PIC_ENTER_STATE_CHANGE);
1189}
1190
1191
1192void
1193ServerPicture::ExitStateChange()
1194{
1195	EndOp();
1196}
1197
1198
1199void
1200ServerPicture::SyncState(Canvas* canvas)
1201{
1202	// TODO: Finish this
1203	EnterStateChange();
1204
1205	WriteSetOrigin(canvas->CurrentState()->Origin());
1206	WriteSetPenLocation(canvas->CurrentState()->PenLocation());
1207	WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize());
1208	WriteSetScale(canvas->CurrentState()->Scale());
1209	WriteSetLineMode(canvas->CurrentState()->LineCapMode(),
1210		canvas->CurrentState()->LineJoinMode(),
1211		canvas->CurrentState()->MiterLimit());
1212	//WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8());
1213	WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode());
1214
1215	WriteSetHighColor(canvas->CurrentState()->HighColor());
1216	WriteSetLowColor(canvas->CurrentState()->LowColor());
1217
1218	ExitStateChange();
1219}
1220
1221
1222void
1223ServerPicture::WriteFontState(const ServerFont& font, uint16 mask)
1224{
1225	BeginOp(B_PIC_ENTER_FONT_STATE);
1226
1227	if (mask & B_FONT_FAMILY_AND_STYLE) {
1228		WriteSetFontFamily(font.Family());
1229		WriteSetFontStyle(font.Style());
1230	}
1231
1232	if (mask & B_FONT_SIZE) {
1233		WriteSetFontSize(font.Size());
1234	}
1235
1236	if (mask & B_FONT_SHEAR) {
1237		WriteSetFontShear(font.Shear());
1238	}
1239
1240	if (mask & B_FONT_ROTATION) {
1241		WriteSetFontRotation(font.Rotation());
1242	}
1243
1244	if (mask & B_FONT_FALSE_BOLD_WIDTH) {
1245		// TODO: Implement
1246//		WriteSetFalseBoldWidth(font.FalseBoldWidth());
1247	}
1248
1249	if (mask & B_FONT_SPACING) {
1250		WriteSetFontSpacing(font.Spacing());
1251	}
1252
1253	if (mask & B_FONT_ENCODING) {
1254		WriteSetFontEncoding(font.Encoding());
1255	}
1256
1257	if (mask & B_FONT_FACE) {
1258		WriteSetFontFace(font.Face());
1259	}
1260
1261	if (mask & B_FONT_FLAGS) {
1262		WriteSetFontFlags(font.Flags());
1263	}
1264
1265	EndOp();
1266}
1267
1268
1269void
1270ServerPicture::Play(Canvas* target)
1271{
1272	// TODO: for now: then change PicturePlayer
1273	// to accept a BPositionIO object
1274	BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData.Get());
1275	if (mallocIO == NULL)
1276		return;
1277
1278	BPrivate::PicturePlayer player(mallocIO->Buffer(),
1279		mallocIO->BufferLength(), PictureList::Private(fPictures.Get()).AsBList());
1280	player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks),
1281		target);
1282}
1283
1284
1285/*!	Acquires a reference to the pushed picture.
1286*/
1287void
1288ServerPicture::PushPicture(ServerPicture* picture)
1289{
1290	if (fPushed != NULL)
1291		debugger("already pushed a picture");
1292
1293	fPushed.SetTo(picture, false);
1294}
1295
1296
1297/*!	Returns a reference with the popped picture.
1298*/
1299ServerPicture*
1300ServerPicture::PopPicture()
1301{
1302	return fPushed.Detach();
1303}
1304
1305
1306void
1307ServerPicture::AppendPicture(ServerPicture* picture)
1308{
1309	// A pushed picture is the same as an appended one
1310	PushPicture(picture);
1311}
1312
1313
1314bool
1315ServerPicture::NestPicture(ServerPicture* picture)
1316{
1317	if (!fPictures.IsSet())
1318		fPictures.SetTo(new(std::nothrow) PictureList);
1319
1320	if (!fPictures.IsSet() || !fPictures->AddItem(picture))
1321		return false;
1322
1323	picture->AcquireReference();
1324	return true;
1325}
1326
1327
1328off_t
1329ServerPicture::DataLength() const
1330{
1331	if (!fData.IsSet())
1332		return 0;
1333	off_t size;
1334	fData->GetSize(&size);
1335	return size;
1336}
1337
1338
1339status_t
1340ServerPicture::ImportData(BPrivate::LinkReceiver& link)
1341{
1342	int32 size = 0;
1343	link.Read<int32>(&size);
1344
1345	off_t oldPosition = fData->Position();
1346	fData->Seek(0, SEEK_SET);
1347
1348	status_t status = B_NO_MEMORY;
1349	char* buffer = new(std::nothrow) char[size];
1350	if (buffer) {
1351		status = B_OK;
1352		ssize_t read = link.Read(buffer, size);
1353		if (read < B_OK || fData->Write(buffer, size) < B_OK)
1354			status = B_ERROR;
1355		delete [] buffer;
1356	}
1357
1358	fData->Seek(oldPosition, SEEK_SET);
1359	return status;
1360}
1361
1362
1363status_t
1364ServerPicture::ExportData(BPrivate::PortLink& link)
1365{
1366	link.StartMessage(B_OK);
1367
1368	off_t oldPosition = fData->Position();
1369	fData->Seek(0, SEEK_SET);
1370
1371	int32 subPicturesCount = 0;
1372	if (fPictures.IsSet())
1373		subPicturesCount = fPictures->CountItems();
1374	link.Attach<int32>(subPicturesCount);
1375	if (subPicturesCount > 0) {
1376		for (int32 i = 0; i < subPicturesCount; i++) {
1377			ServerPicture* subPicture = fPictures->ItemAt(i);
1378			link.Attach<int32>(subPicture->Token());
1379		}
1380	}
1381
1382	off_t size = 0;
1383	fData->GetSize(&size);
1384	link.Attach<int32>((int32)size);
1385
1386	status_t status = B_NO_MEMORY;
1387	char* buffer = new(std::nothrow) char[size];
1388	if (buffer) {
1389		status = B_OK;
1390		ssize_t read = fData->Read(buffer, size);
1391		if (read < B_OK || link.Attach(buffer, read) < B_OK)
1392			status = B_ERROR;
1393		delete [] buffer;
1394	}
1395
1396	if (status != B_OK) {
1397		link.CancelMessage();
1398		link.StartMessage(B_ERROR);
1399	}
1400
1401	fData->Seek(oldPosition, SEEK_SET);
1402	return status;
1403}
1404