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