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