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