xref: /haiku/src/servers/app/ServerPicture.cpp (revision a5061ecec55353a5f394759473f1fd6df04890da)
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 	BReference<ServerPicture> picture(canvas->GetPicture(token), true);
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 	}
604 }
605 
606 
607 static void
608 set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[])
609 {
610 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
611 
612 	if (numRects == 0)
613 		canvas->SetUserClipping(NULL);
614 	else {
615 		// TODO: This might be too slow, we should copy the rects
616 		// directly to BRegion's internal data
617 		BRegion region;
618 		for (uint32 c = 0; c < numRects; c++)
619 			region.Include(rects[c]);
620 		canvas->SetUserClipping(&region);
621 	}
622 	canvas->UpdateCurrentDrawingRegion();
623 }
624 
625 
626 static void
627 clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where,
628 	bool clipToInverse)
629 {
630 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
631 
632 	BReference<ServerPicture> picture(canvas->GetPicture(pictureToken), true);
633 	if (picture == NULL)
634 		return;
635 	BReference<AlphaMask> mask(new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(),
636 		picture, *canvas->CurrentState(), where, clipToInverse), true);
637 	canvas->SetAlphaMask(mask);
638 	canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
639 		canvas->Bounds());
640 	canvas->ResyncDrawState();
641 }
642 
643 
644 static void
645 push_state(void* _canvas)
646 {
647 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
648 	canvas->PushState();
649 }
650 
651 
652 static void
653 pop_state(void* _canvas)
654 {
655 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
656 	canvas->PopState();
657 
658 	BPoint p(0, 0);
659 	canvas->PenToScreenTransform().Apply(&p);
660 	canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(),
661 		(int32)p.x, (int32)p.y);
662 }
663 
664 
665 // TODO: Be smart and actually take advantage of these methods:
666 // only apply state changes when they are called
667 static void
668 enter_state_change(void* _canvas)
669 {
670 }
671 
672 
673 static void
674 exit_state_change(void* _canvas)
675 {
676 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
677 	canvas->ResyncDrawState();
678 }
679 
680 
681 static void
682 enter_font_state(void* _canvas)
683 {
684 }
685 
686 
687 static void
688 exit_font_state(void* _canvas)
689 {
690 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
691 	canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font());
692 }
693 
694 
695 static void
696 set_origin(void* _canvas, const BPoint& pt)
697 {
698 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
699 	canvas->CurrentState()->SetOrigin(pt);
700 }
701 
702 
703 static void
704 set_pen_location(void* _canvas, const BPoint& pt)
705 {
706 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
707 	canvas->CurrentState()->SetPenLocation(pt);
708 	// the DrawingEngine/Painter does not need to be updated, since this
709 	// effects only the view->screen coord conversion, which is handled
710 	// by the view only
711 }
712 
713 
714 static void
715 set_drawing_mode(void* _canvas, drawing_mode mode)
716 {
717 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
718 	if (canvas->CurrentState()->SetDrawingMode(mode))
719 		canvas->GetDrawingEngine()->SetDrawingMode(mode);
720 }
721 
722 
723 static void
724 set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode,
725 	float miterLimit)
726 {
727 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
728 	DrawState* state = canvas->CurrentState();
729 	state->SetLineCapMode(capMode);
730 	state->SetLineJoinMode(joinMode);
731 	state->SetMiterLimit(miterLimit);
732 	canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
733 }
734 
735 
736 static void
737 set_pen_size(void* _canvas, float size)
738 {
739 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
740 	canvas->CurrentState()->SetPenSize(size);
741 	canvas->GetDrawingEngine()->SetPenSize(
742 		canvas->CurrentState()->PenSize());
743 		// DrawState::PenSize() returns the scaled pen size, so we
744 		// need to use that value to set the drawing engine pen size.
745 }
746 
747 
748 static void
749 set_fore_color(void* _canvas, const rgb_color& color)
750 {
751 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
752 	canvas->CurrentState()->SetHighColor(color);
753 	canvas->GetDrawingEngine()->SetHighColor(color);
754 }
755 
756 
757 static void
758 set_back_color(void* _canvas, const rgb_color& color)
759 {
760 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
761 	canvas->CurrentState()->SetLowColor(color);
762 	canvas->GetDrawingEngine()->SetLowColor(color);
763 }
764 
765 
766 static void
767 set_stipple_pattern(void* _canvas, const pattern& pattern)
768 {
769 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
770 	canvas->CurrentState()->SetPattern(Pattern(pattern));
771 	canvas->GetDrawingEngine()->SetPattern(pattern);
772 }
773 
774 
775 static void
776 set_scale(void* _canvas, float scale)
777 {
778 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
779 	canvas->CurrentState()->SetScale(scale);
780 	canvas->ResyncDrawState();
781 
782 	// Update the drawing engine draw state, since some stuff
783 	// (for example the pen size) needs to be recalculated.
784 }
785 
786 
787 static void
788 set_font_family(void* _canvas, const char* _family, size_t length)
789 {
790 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
791 	BString family(_family, length);
792 
793 	FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
794 	ServerFont font;
795 	font.SetStyle(fontStyle);
796 	canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
797 }
798 
799 
800 static void
801 set_font_style(void* _canvas, const char* _style, size_t length)
802 {
803 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
804 	BString style(_style, length);
805 
806 	ServerFont font(canvas->CurrentState()->Font());
807 
808 	FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
809 
810 	font.SetStyle(fontStyle);
811 	canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
812 }
813 
814 
815 static void
816 set_font_spacing(void* _canvas, uint8 spacing)
817 {
818 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
819 	ServerFont font;
820 	font.SetSpacing(spacing);
821 	canvas->CurrentState()->SetFont(font, B_FONT_SPACING);
822 }
823 
824 
825 static void
826 set_font_size(void* _canvas, float size)
827 {
828 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
829 	ServerFont font;
830 	font.SetSize(size);
831 	canvas->CurrentState()->SetFont(font, B_FONT_SIZE);
832 }
833 
834 
835 static void
836 set_font_rotation(void* _canvas, float rotation)
837 {
838 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
839 	ServerFont font;
840 	font.SetRotation(rotation);
841 	canvas->CurrentState()->SetFont(font, B_FONT_ROTATION);
842 }
843 
844 
845 static void
846 set_font_encoding(void* _canvas, uint8 encoding)
847 {
848 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
849 	ServerFont font;
850 	font.SetEncoding(encoding);
851 	canvas->CurrentState()->SetFont(font, B_FONT_ENCODING);
852 }
853 
854 
855 static void
856 set_font_flags(void* _canvas, uint32 flags)
857 {
858 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
859 	ServerFont font;
860 	font.SetFlags(flags);
861 	canvas->CurrentState()->SetFont(font, B_FONT_FLAGS);
862 }
863 
864 
865 static void
866 set_font_shear(void* _canvas, float shear)
867 {
868 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
869 	ServerFont font;
870 	font.SetShear(shear);
871 	canvas->CurrentState()->SetFont(font, B_FONT_SHEAR);
872 }
873 
874 
875 static void
876 set_font_face(void* _canvas, uint16 face)
877 {
878 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
879 	ServerFont font;
880 	font.SetFace(face);
881 	canvas->CurrentState()->SetFont(font, B_FONT_FACE);
882 }
883 
884 
885 static void
886 set_blending_mode(void* _canvas, source_alpha alphaSrcMode,
887 	alpha_function alphaFncMode)
888 {
889 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
890 	canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
891 }
892 
893 
894 static void
895 set_fill_rule(void* _canvas, int32 fillRule)
896 {
897 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
898 	canvas->CurrentState()->SetFillRule(fillRule);
899 	canvas->GetDrawingEngine()->SetFillRule(fillRule);
900 }
901 
902 
903 static void
904 set_transform(void* _canvas, const BAffineTransform& transform)
905 {
906 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
907 
908 	BPoint leftTop(0, 0);
909 	canvas->PenToScreenTransform().Apply(&leftTop);
910 
911 	canvas->CurrentState()->SetTransform(transform);
912 	canvas->GetDrawingEngine()->SetTransform(
913 		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
914 }
915 
916 
917 static void
918 translate_by(void* _canvas, double x, double y)
919 {
920 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
921 
922 	BPoint leftTop(0, 0);
923 	canvas->PenToScreenTransform().Apply(&leftTop);
924 
925 	BAffineTransform transform = canvas->CurrentState()->Transform();
926 	transform.PreTranslateBy(x, y);
927 	canvas->CurrentState()->SetTransform(transform);
928 	canvas->GetDrawingEngine()->SetTransform(
929 		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
930 }
931 
932 
933 static void
934 scale_by(void* _canvas, double x, double y)
935 {
936 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
937 
938 	BPoint leftTop(0, 0);
939 	canvas->PenToScreenTransform().Apply(&leftTop);
940 
941 	BAffineTransform transform = canvas->CurrentState()->Transform();
942 	transform.PreScaleBy(x, y);
943 	canvas->CurrentState()->SetTransform(transform);
944 	canvas->GetDrawingEngine()->SetTransform(
945 		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
946 }
947 
948 
949 static void
950 rotate_by(void* _canvas, double angleRadians)
951 {
952 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
953 
954 	BPoint leftTop(0, 0);
955 	canvas->PenToScreenTransform().Apply(&leftTop);
956 
957 	BAffineTransform transform = canvas->CurrentState()->Transform();
958 	transform.PreRotateBy(angleRadians);
959 	canvas->CurrentState()->SetTransform(transform);
960 	canvas->GetDrawingEngine()->SetTransform(
961 		canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
962 }
963 
964 
965 static void
966 blend_layer(void* _canvas, Layer* layer)
967 {
968 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
969 	canvas->BlendLayer(layer);
970 }
971 
972 
973 static void
974 clip_to_rect(void* _canvas, const BRect& rect, bool inverse)
975 {
976 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
977 	bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse);
978 	if (needDrawStateUpdate) {
979 		canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
980 			canvas->Bounds());
981 		canvas->ResyncDrawState();
982 	}
983 	canvas->UpdateCurrentDrawingRegion();
984 }
985 
986 
987 static void
988 clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[],
989 	int32 ptCount, const BPoint ptList[], bool inverse)
990 {
991 	Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
992 	shape_data shapeData;
993 
994 	// TODO: avoid copies
995 	shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32));
996 	memcpy(shapeData.opList, opList, opCount * sizeof(uint32));
997 	shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint));
998 	memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint));
999 
1000 	shapeData.opCount = opCount;
1001 	shapeData.opSize = opCount * sizeof(uint32);
1002 	shapeData.ptCount = ptCount;
1003 	shapeData.ptSize = ptCount * sizeof(BPoint);
1004 
1005 	canvas->ClipToShape(&shapeData, inverse);
1006 	canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
1007 		canvas->Bounds());
1008 	canvas->ResyncDrawState();
1009 
1010 	free(shapeData.opList);
1011 	free(shapeData.ptList);
1012 }
1013 
1014 
1015 static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = {
1016 	move_pen_by,
1017 	stroke_line,
1018 	draw_rect,
1019 	draw_round_rect,
1020 	draw_bezier,
1021 	draw_arc,
1022 	draw_ellipse,
1023 	draw_polygon,
1024 	draw_shape,
1025 	draw_string,
1026 	draw_pixels,
1027 	draw_picture,
1028 	set_clipping_rects,
1029 	clip_to_picture,
1030 	push_state,
1031 	pop_state,
1032 	enter_state_change,
1033 	exit_state_change,
1034 	enter_font_state,
1035 	exit_font_state,
1036 	set_origin,
1037 	set_pen_location,
1038 	set_drawing_mode,
1039 	set_line_mode,
1040 	set_pen_size,
1041 	set_fore_color,
1042 	set_back_color,
1043 	set_stipple_pattern,
1044 	set_scale,
1045 	set_font_family,
1046 	set_font_style,
1047 	set_font_spacing,
1048 	set_font_size,
1049 	set_font_rotation,
1050 	set_font_encoding,
1051 	set_font_flags,
1052 	set_font_shear,
1053 	set_font_face,
1054 	set_blending_mode,
1055 	set_transform,
1056 	translate_by,
1057 	scale_by,
1058 	rotate_by,
1059 	blend_layer,
1060 	clip_to_rect,
1061 	clip_to_shape,
1062 	draw_string_locations,
1063 	draw_rect_gradient,
1064 	draw_round_rect_gradient,
1065 	draw_bezier_gradient,
1066 	draw_arc_gradient,
1067 	draw_ellipse_gradient,
1068 	draw_polygon_gradient,
1069 	draw_shape_gradient,
1070 	set_fill_rule
1071 };
1072 
1073 
1074 // #pragma mark - ServerPicture
1075 
1076 
1077 ServerPicture::ServerPicture()
1078 	:
1079 	fFile(NULL),
1080 	fOwner(NULL)
1081 {
1082 	fToken = gTokenSpace.NewToken(kPictureToken, this);
1083 	fData.SetTo(new(std::nothrow) BMallocIO());
1084 
1085 	PictureDataWriter::SetTo(fData.Get());
1086 }
1087 
1088 
1089 ServerPicture::ServerPicture(const ServerPicture& picture)
1090 	:
1091 	fFile(NULL),
1092 	fData(NULL),
1093 	fOwner(NULL)
1094 {
1095 	fToken = gTokenSpace.NewToken(kPictureToken, this);
1096 
1097 	BMallocIO* mallocIO = new(std::nothrow) BMallocIO();
1098 	if (mallocIO == NULL)
1099 		return;
1100 
1101 	fData.SetTo(mallocIO);
1102 
1103 	const off_t size = picture.DataLength();
1104 	if (mallocIO->SetSize(size) < B_OK)
1105 		return;
1106 
1107 	picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()),
1108 		size);
1109 
1110 	PictureDataWriter::SetTo(fData.Get());
1111 }
1112 
1113 
1114 ServerPicture::ServerPicture(const char* fileName, int32 offset)
1115 	:
1116 	fFile(NULL),
1117 	fData(NULL),
1118 	fOwner(NULL)
1119 {
1120 	fToken = gTokenSpace.NewToken(kPictureToken, this);
1121 
1122 	fFile.SetTo(new(std::nothrow) BFile(fileName, B_READ_WRITE));
1123 	if (!fFile.IsSet())
1124 		return;
1125 
1126 	BPrivate::Storage::OffsetFile* offsetFile
1127 		= new(std::nothrow) BPrivate::Storage::OffsetFile(fFile.Get(), offset);
1128 	if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) {
1129 		delete offsetFile;
1130 		return;
1131 	}
1132 
1133 	fData.SetTo(offsetFile);
1134 
1135 	PictureDataWriter::SetTo(fData.Get());
1136 }
1137 
1138 
1139 ServerPicture::~ServerPicture()
1140 {
1141 	ASSERT(fOwner == NULL);
1142 
1143 	gTokenSpace.RemoveToken(fToken);
1144 
1145 	if (fPictures.IsSet()) {
1146 		for (int32 i = fPictures->CountItems(); i-- > 0;) {
1147 			ServerPicture* picture = fPictures->ItemAt(i);
1148 			picture->SetOwner(NULL);
1149 			picture->ReleaseReference();
1150 		}
1151 	}
1152 
1153 	if (fPushed != NULL)
1154 		fPushed->SetOwner(NULL);
1155 }
1156 
1157 
1158 bool
1159 ServerPicture::SetOwner(ServerApp* owner)
1160 {
1161 	if (owner == fOwner)
1162 		return true;
1163 
1164 	// Acquire an extra reference, since calling RemovePicture()
1165 	// May remove the last reference and then we will self-destruct right then.
1166 	// Setting fOwner to NULL would access free'd memory. If owner is another
1167 	// ServerApp, it's expected to already have a reference of course.
1168 	BReference<ServerPicture> _(this);
1169 
1170 	if (fOwner != NULL)
1171 		fOwner->RemovePicture(this);
1172 
1173 	fOwner = NULL;
1174 	if (owner == NULL)
1175 		return true;
1176 
1177 	if (!owner->AddPicture(this))
1178 		return false;
1179 
1180 	fOwner = owner;
1181 	return true;
1182 }
1183 
1184 
1185 void
1186 ServerPicture::EnterStateChange()
1187 {
1188 	BeginOp(B_PIC_ENTER_STATE_CHANGE);
1189 }
1190 
1191 
1192 void
1193 ServerPicture::ExitStateChange()
1194 {
1195 	EndOp();
1196 }
1197 
1198 
1199 void
1200 ServerPicture::SyncState(Canvas* canvas)
1201 {
1202 	// TODO: Finish this
1203 	EnterStateChange();
1204 
1205 	WriteSetOrigin(canvas->CurrentState()->Origin());
1206 	WriteSetPenLocation(canvas->CurrentState()->PenLocation());
1207 	WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize());
1208 	WriteSetScale(canvas->CurrentState()->Scale());
1209 	WriteSetLineMode(canvas->CurrentState()->LineCapMode(),
1210 		canvas->CurrentState()->LineJoinMode(),
1211 		canvas->CurrentState()->MiterLimit());
1212 	//WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8());
1213 	WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode());
1214 
1215 	WriteSetHighColor(canvas->CurrentState()->HighColor());
1216 	WriteSetLowColor(canvas->CurrentState()->LowColor());
1217 
1218 	ExitStateChange();
1219 }
1220 
1221 
1222 void
1223 ServerPicture::WriteFontState(const ServerFont& font, uint16 mask)
1224 {
1225 	BeginOp(B_PIC_ENTER_FONT_STATE);
1226 
1227 	if (mask & B_FONT_FAMILY_AND_STYLE) {
1228 		WriteSetFontFamily(font.Family());
1229 		WriteSetFontStyle(font.Style());
1230 	}
1231 
1232 	if (mask & B_FONT_SIZE) {
1233 		WriteSetFontSize(font.Size());
1234 	}
1235 
1236 	if (mask & B_FONT_SHEAR) {
1237 		WriteSetFontShear(font.Shear());
1238 	}
1239 
1240 	if (mask & B_FONT_ROTATION) {
1241 		WriteSetFontRotation(font.Rotation());
1242 	}
1243 
1244 	if (mask & B_FONT_FALSE_BOLD_WIDTH) {
1245 		// TODO: Implement
1246 //		WriteSetFalseBoldWidth(font.FalseBoldWidth());
1247 	}
1248 
1249 	if (mask & B_FONT_SPACING) {
1250 		WriteSetFontSpacing(font.Spacing());
1251 	}
1252 
1253 	if (mask & B_FONT_ENCODING) {
1254 		WriteSetFontEncoding(font.Encoding());
1255 	}
1256 
1257 	if (mask & B_FONT_FACE) {
1258 		WriteSetFontFace(font.Face());
1259 	}
1260 
1261 	if (mask & B_FONT_FLAGS) {
1262 		WriteSetFontFlags(font.Flags());
1263 	}
1264 
1265 	EndOp();
1266 }
1267 
1268 
1269 void
1270 ServerPicture::Play(Canvas* target)
1271 {
1272 	// TODO: for now: then change PicturePlayer
1273 	// to accept a BPositionIO object
1274 	BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData.Get());
1275 	if (mallocIO == NULL)
1276 		return;
1277 
1278 	BPrivate::PicturePlayer player(mallocIO->Buffer(),
1279 		mallocIO->BufferLength(), PictureList::Private(fPictures.Get()).AsBList());
1280 	player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks),
1281 		target);
1282 }
1283 
1284 
1285 /*!	Acquires a reference to the pushed picture.
1286 */
1287 void
1288 ServerPicture::PushPicture(ServerPicture* picture)
1289 {
1290 	if (fPushed != NULL)
1291 		debugger("already pushed a picture");
1292 
1293 	fPushed.SetTo(picture, false);
1294 }
1295 
1296 
1297 /*!	Returns a reference with the popped picture.
1298 */
1299 ServerPicture*
1300 ServerPicture::PopPicture()
1301 {
1302 	return fPushed.Detach();
1303 }
1304 
1305 
1306 void
1307 ServerPicture::AppendPicture(ServerPicture* picture)
1308 {
1309 	// A pushed picture is the same as an appended one
1310 	PushPicture(picture);
1311 }
1312 
1313 
1314 bool
1315 ServerPicture::NestPicture(ServerPicture* picture)
1316 {
1317 	if (!fPictures.IsSet())
1318 		fPictures.SetTo(new(std::nothrow) PictureList);
1319 
1320 	if (!fPictures.IsSet() || !fPictures->AddItem(picture))
1321 		return false;
1322 
1323 	picture->AcquireReference();
1324 	return true;
1325 }
1326 
1327 
1328 off_t
1329 ServerPicture::DataLength() const
1330 {
1331 	if (!fData.IsSet())
1332 		return 0;
1333 	off_t size;
1334 	fData->GetSize(&size);
1335 	return size;
1336 }
1337 
1338 
1339 status_t
1340 ServerPicture::ImportData(BPrivate::LinkReceiver& link)
1341 {
1342 	int32 size = 0;
1343 	link.Read<int32>(&size);
1344 
1345 	off_t oldPosition = fData->Position();
1346 	fData->Seek(0, SEEK_SET);
1347 
1348 	status_t status = B_NO_MEMORY;
1349 	char* buffer = new(std::nothrow) char[size];
1350 	if (buffer) {
1351 		status = B_OK;
1352 		ssize_t read = link.Read(buffer, size);
1353 		if (read < B_OK || fData->Write(buffer, size) < B_OK)
1354 			status = B_ERROR;
1355 		delete [] buffer;
1356 	}
1357 
1358 	fData->Seek(oldPosition, SEEK_SET);
1359 	return status;
1360 }
1361 
1362 
1363 status_t
1364 ServerPicture::ExportData(BPrivate::PortLink& link)
1365 {
1366 	link.StartMessage(B_OK);
1367 
1368 	off_t oldPosition = fData->Position();
1369 	fData->Seek(0, SEEK_SET);
1370 
1371 	int32 subPicturesCount = 0;
1372 	if (fPictures.IsSet())
1373 		subPicturesCount = fPictures->CountItems();
1374 	link.Attach<int32>(subPicturesCount);
1375 	if (subPicturesCount > 0) {
1376 		for (int32 i = 0; i < subPicturesCount; i++) {
1377 			ServerPicture* subPicture = fPictures->ItemAt(i);
1378 			link.Attach<int32>(subPicture->Token());
1379 		}
1380 	}
1381 
1382 	off_t size = 0;
1383 	fData->GetSize(&size);
1384 	link.Attach<int32>((int32)size);
1385 
1386 	status_t status = B_NO_MEMORY;
1387 	char* buffer = new(std::nothrow) char[size];
1388 	if (buffer) {
1389 		status = B_OK;
1390 		ssize_t read = fData->Read(buffer, size);
1391 		if (read < B_OK || link.Attach(buffer, read) < B_OK)
1392 			status = B_ERROR;
1393 		delete [] buffer;
1394 	}
1395 
1396 	if (status != B_OK) {
1397 		link.CancelMessage();
1398 		link.StartMessage(B_ERROR);
1399 	}
1400 
1401 	fData->Seek(oldPosition, SEEK_SET);
1402 	return status;
1403 }
1404