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