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