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