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