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