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