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