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