xref: /haiku/src/servers/app/ServerPicture.cpp (revision 020cbad9d40235a2c50a81a42d69912a5ff8fbc4)
1 /*
2  * Copyright 2001-2007, 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 "ViewLayer.h"
19 #include "WindowLayer.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(ViewLayer *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(ViewLayer *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(ViewLayer *view, BPoint delta)
181 {
182 	view->CurrentState()->SetPenLocation(view->CurrentState()->PenLocation() + delta);
183 }
184 
185 
186 static void
187 stroke_line(ViewLayer *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(ViewLayer *view, BRect rect)
204 {
205 	view->ConvertToScreenForDrawing(&rect);
206 	view->Window()->GetDrawingEngine()->StrokeRect(rect);
207 }
208 
209 
210 static void
211 fill_rect(ViewLayer *view, BRect rect)
212 {
213 	view->ConvertToScreenForDrawing(&rect);
214 	view->Window()->GetDrawingEngine()->FillRect(rect);
215 }
216 
217 
218 static void
219 stroke_round_rect(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *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(ViewLayer *view, int32 numPoints, const BPoint *viewPoints, bool isClosed)
300 {
301 	if (numPoints <= 0) {
302 		return;
303 	} else if (numPoints <= 200) {
304 		// fast path: no malloc/free, also avoid constructor/destructor calls
305 		char data[200 * sizeof(BPoint)];
306 		BPoint *points = (BPoint *)data;
307 
308 		view->ConvertToScreenForDrawing(points, viewPoints, numPoints);
309 
310 		BRect polyFrame;
311 		get_polygon_frame(points, numPoints, &polyFrame);
312 
313 		view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
314 			false, isClosed && numPoints > 2);
315 	} else {
316 		 // avoid constructor/destructor calls by using malloc instead of new []
317 		BPoint *points = (BPoint *)malloc(numPoints * sizeof(BPoint));
318 		if (!points)
319 			return;
320 
321 		view->ConvertToScreenForDrawing(points, viewPoints, numPoints);
322 
323 		BRect polyFrame;
324 		get_polygon_frame(points, numPoints, &polyFrame);
325 
326 		view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
327 			false, isClosed && numPoints > 2);
328 		free(points);
329 	}
330 }
331 
332 
333 static void
334 fill_polygon(ViewLayer *view, int32 numPoints, const BPoint *viewPoints)
335 {
336 	if (numPoints <= 0) {
337 		return;
338 	} else if (numPoints <= 200) {
339 		// fast path: no malloc/free, also avoid constructor/destructor calls
340 		char data[200 * sizeof(BPoint)];
341 		BPoint *points = (BPoint *)data;
342 
343 		view->ConvertToScreenForDrawing(points, viewPoints, numPoints);
344 
345 		BRect polyFrame;
346 		get_polygon_frame(points, numPoints, &polyFrame);
347 
348 		view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
349 			true, true);
350 	} else {
351 		 // avoid constructor/destructor calls by using malloc instead of new []
352 		BPoint *points = (BPoint *)malloc(numPoints * sizeof(BPoint));
353 		if (!points)
354 			return;
355 
356 		view->ConvertToScreenForDrawing(points, viewPoints, numPoints);
357 
358 		BRect polyFrame;
359 		get_polygon_frame(points, numPoints, &polyFrame);
360 
361 		view->Window()->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
362 			true, true);
363 		free(points);
364 	}
365 }
366 
367 
368 static void
369 stroke_shape(ViewLayer *view, const BShape *shape)
370 {
371 	ShapePainter drawShape;
372 
373 	drawShape.Iterate(shape);
374 	drawShape.Draw(view, shape->Bounds(), false);
375 }
376 
377 
378 static void
379 fill_shape(ViewLayer *view, const BShape *shape)
380 {
381 	ShapePainter drawShape;
382 
383 	drawShape.Iterate(shape);
384 	drawShape.Draw(view, shape->Bounds(), true);
385 }
386 
387 
388 static void
389 draw_string(ViewLayer *view, const char *string, float deltaSpace,
390 	float deltaNonSpace)
391 {
392 	// NOTE: the picture data was recorded with a "set pen location" command
393 	// inserted before the "draw string" command, so we can use PenLocation()
394 	BPoint location = view->CurrentState()->PenLocation();
395 
396 	escapement_delta delta = {deltaSpace, deltaNonSpace };
397 	view->ConvertToScreenForDrawing(&location);
398 	view->Window()->GetDrawingEngine()->DrawString(string, strlen(string),
399 		location, &delta);
400 
401 	view->ConvertFromScreenForDrawing(&location);
402 	view->CurrentState()->SetPenLocation(location);
403 	// the DrawingEngine/Painter does not need to be updated, since this
404 	// effects only the view->screen coord conversion, which is handled
405 	// by the view only
406 }
407 
408 
409 static void
410 draw_pixels(ViewLayer *view, BRect src, BRect dest, int32 width, int32 height,
411 				 int32 bytesPerRow, int32 pixelFormat, int32 flags, const void *data)
412 {
413 	UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1), (color_space)pixelFormat, flags, bytesPerRow);
414 
415 	if (!bitmap.IsValid())
416 		return;
417 
418 	memcpy(bitmap.Bits(), data, height * bytesPerRow);
419 
420 	view->ConvertToScreenForDrawing(&dest);
421 
422 	view->Window()->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest);
423 }
424 
425 
426 static void
427 draw_picture(ViewLayer *view, BPoint where, int32 token)
428 {
429 	ServerPicture *picture = view->Window()->ServerWindow()->App()->FindPicture(token);
430 	if (picture != NULL) {
431 		view->CurrentState()->SetOrigin(where);
432 		picture->Play(view);
433 	}
434 }
435 
436 
437 static void
438 set_clipping_rects(ViewLayer *view, const BRect *rects, uint32 numRects)
439 {
440 	// TODO: This might be too slow, we should copy the rects
441 	// directly to BRegion's internal data
442 	BRegion region;
443 	for (uint32 c = 0; c < numRects; c++)
444 		region.Include(rects[c]);
445 	view->SetUserClipping(&region);
446 }
447 
448 
449 static void
450 clip_to_picture(ViewLayer *view, BPicture *picture, BPoint pt,
451 				   bool clip_to_inverse_picture)
452 {
453 	printf("ClipToPicture(picture, BPoint(%.2f, %.2f), %s)\n", pt.x, pt.y,
454 		clip_to_inverse_picture ? "inverse" : "");
455 }
456 
457 
458 static void
459 push_state(ViewLayer *view)
460 {
461 	view->PushState();
462 }
463 
464 
465 static void
466 pop_state(ViewLayer *view)
467 {
468 	view->PopState();
469 
470 	BPoint p(0, 0);
471 	view->ConvertToScreenForDrawing(&p);
472 	view->Window()->GetDrawingEngine()->SetDrawState(
473 		view->CurrentState(), p.x, p.y);
474 }
475 
476 
477 // TODO: Be smart and actually take advantage of these methods:
478 // only apply state changes when they are called
479 static void
480 enter_state_change(ViewLayer *view)
481 {
482 }
483 
484 
485 static void
486 exit_state_change(ViewLayer *view)
487 {
488 	view->Window()->ServerWindow()->ResyncDrawState();
489 }
490 
491 
492 static void
493 enter_font_state(ViewLayer *view)
494 {
495 }
496 
497 
498 static void
499 exit_font_state(ViewLayer *view)
500 {
501 	view->Window()->GetDrawingEngine()->SetFont(view->CurrentState()->Font());
502 }
503 
504 
505 static void
506 set_origin(ViewLayer *view, BPoint pt)
507 {
508 	view->CurrentState()->SetOrigin(pt);
509 }
510 
511 
512 static void
513 set_pen_location(ViewLayer *view, BPoint pt)
514 {
515 	view->CurrentState()->SetPenLocation(pt);
516 	// the DrawingEngine/Painter does not need to be updated, since this
517 	// effects only the view->screen coord conversion, which is handled
518 	// by the view only
519 }
520 
521 
522 static void
523 set_drawing_mode(ViewLayer *view, drawing_mode mode)
524 {
525 	view->CurrentState()->SetDrawingMode(mode);
526 	view->Window()->GetDrawingEngine()->SetDrawingMode(mode);
527 }
528 
529 
530 static void
531 set_line_mode(ViewLayer *view, cap_mode capMode, join_mode joinMode, float miterLimit)
532 {
533 	DrawState *state = view->CurrentState();
534 	state->SetLineCapMode(capMode);
535 	state->SetLineJoinMode(joinMode);
536 	state->SetMiterLimit(miterLimit);
537 	view->Window()->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
538 }
539 
540 
541 static void
542 set_pen_size(ViewLayer *view, float size)
543 {
544 	view->CurrentState()->SetPenSize(size);
545 	view->Window()->GetDrawingEngine()->SetPenSize(view->CurrentState()->PenSize());
546 		// DrawState::PenSize() returns the scaled pen size, so we need to
547 		// use that value to set the drawing engine pen size.
548 }
549 
550 
551 static void
552 set_fore_color(ViewLayer *view, rgb_color color)
553 {
554 	view->CurrentState()->SetHighColor(color);
555 	view->Window()->GetDrawingEngine()->SetHighColor(color);
556 }
557 
558 
559 static void
560 set_back_color(ViewLayer *view, rgb_color color)
561 {
562 	view->CurrentState()->SetLowColor(color);
563 	view->Window()->GetDrawingEngine()->SetLowColor(color);
564 }
565 
566 
567 static void
568 set_stipple_pattern(ViewLayer *view, pattern p)
569 {
570 	view->CurrentState()->SetPattern(Pattern(p));
571 	view->Window()->GetDrawingEngine()->SetPattern(p);
572 }
573 
574 
575 static void
576 set_scale(ViewLayer *view, float scale)
577 {
578 	view->CurrentState()->SetScale(scale);
579 	view->Window()->ServerWindow()->ResyncDrawState();
580 
581 	// Update the drawing engine draw state, since some stuff (for example
582 	// the pen size) needs to be recalculated.
583 }
584 
585 
586 static void
587 set_font_family(ViewLayer *view, const char *family)
588 {
589 	// TODO: Implement
590 	// Can we have a ServerFont::SetFamily() which accepts a string ?
591 }
592 
593 
594 static void
595 set_font_style(ViewLayer *view, const char *style)
596 {
597 	// TODO: Implement
598 	// Can we have a ServerFont::SetStyle() which accepts a string ?
599 }
600 
601 
602 static void
603 set_font_spacing(ViewLayer *view, int32 spacing)
604 {
605 	ServerFont font;
606 	font.SetSpacing(spacing);
607 	view->CurrentState()->SetFont(font, B_FONT_SPACING);
608 }
609 
610 
611 static void
612 set_font_size(ViewLayer *view, float size)
613 {
614 	ServerFont font;
615 	font.SetSize(size);
616 	view->CurrentState()->SetFont(font, B_FONT_SIZE);
617 }
618 
619 
620 static void
621 set_font_rotate(ViewLayer *view, float rotation)
622 {
623 	ServerFont font;
624 	font.SetRotation(rotation);
625 	view->CurrentState()->SetFont(font, B_FONT_ROTATION);
626 }
627 
628 
629 static void
630 set_font_encoding(ViewLayer *view, int32 encoding)
631 {
632 	ServerFont font;
633 	font.SetEncoding(encoding);
634 	view->CurrentState()->SetFont(font, B_FONT_ENCODING);
635 }
636 
637 
638 static void
639 set_font_flags(ViewLayer *view, int32 flags)
640 {
641 	ServerFont font;
642 	font.SetFlags(flags);
643 	view->CurrentState()->SetFont(font, B_FONT_FLAGS);
644 }
645 
646 
647 static void
648 set_font_shear(ViewLayer *view, float shear)
649 {
650 	ServerFont font;
651 	font.SetShear(shear);
652 	view->CurrentState()->SetFont(font, B_FONT_SHEAR);
653 }
654 
655 
656 static void
657 set_font_face(ViewLayer *view, int32 face)
658 {
659 	ServerFont font;
660 	font.SetFace(face);
661 	view->CurrentState()->SetFont(font, B_FONT_FACE);
662 }
663 
664 
665 static void
666 set_blending_mode(ViewLayer *view, int16 alphaSrcMode, int16 alphaFncMode)
667 {
668 	view->CurrentState()->SetBlendingMode((source_alpha)alphaSrcMode, (alpha_function)alphaFncMode);
669 }
670 
671 
672 static void
673 reserved()
674 {
675 }
676 
677 
678 const static void *kTableEntries[] = {
679 	(const void *)nop,
680 	(const void *)move_pen_by,
681 	(const void *)stroke_line,
682 	(const void *)stroke_rect,
683 	(const void *)fill_rect,
684 	(const void *)stroke_round_rect,
685 	(const void *)fill_round_rect,
686 	(const void *)stroke_bezier,
687 	(const void *)fill_bezier,
688 	(const void *)stroke_arc,
689 	(const void *)fill_arc,
690 	(const void *)stroke_ellipse,
691 	(const void *)fill_ellipse,
692 	(const void *)stroke_polygon,
693 	(const void *)fill_polygon,
694 	(const void *)stroke_shape,
695 	(const void *)fill_shape,
696 	(const void *)draw_string,
697 	(const void *)draw_pixels,
698 	(const void *)draw_picture,
699 	(const void *)set_clipping_rects,
700 	(const void *)clip_to_picture,
701 	(const void *)push_state,
702 	(const void *)pop_state,
703 	(const void *)enter_state_change,
704 	(const void *)exit_state_change,
705 	(const void *)enter_font_state,
706 	(const void *)exit_font_state,
707 	(const void *)set_origin,
708 	(const void *)set_pen_location,
709 	(const void *)set_drawing_mode,
710 	(const void *)set_line_mode,
711 	(const void *)set_pen_size,
712 	(const void *)set_fore_color,
713 	(const void *)set_back_color,
714 	(const void *)set_stipple_pattern,
715 	(const void *)set_scale,
716 	(const void *)set_font_family,
717 	(const void *)set_font_style,
718 	(const void *)set_font_spacing,
719 	(const void *)set_font_size,
720 	(const void *)set_font_rotate,
721 	(const void *)set_font_encoding,
722 	(const void *)set_font_flags,
723 	(const void *)set_font_shear,
724 	(const void *)reserved,		// TODO: Marc Flerackers calls this "set_font_bpp". Investigate
725 	(const void *)set_font_face,
726 	(const void *)set_blending_mode
727 };
728 
729 
730 // ServerPicture
731 ServerPicture::ServerPicture()
732 	:
733 	PictureDataWriter(),
734 	fData(NULL),
735 	fPictures(NULL),
736 	fUsurped(NULL)
737 {
738 	fToken = gTokenSpace.NewToken(kPictureToken, this);
739 	fData = new (std::nothrow) BMallocIO();
740 
741 	PictureDataWriter::SetTo(fData);
742 }
743 
744 
745 ServerPicture::ServerPicture(const ServerPicture &picture)
746 	:
747 	PictureDataWriter(),
748 	fData(NULL),
749 	fPictures(NULL),
750 	fUsurped(NULL)
751 {
752 	BMallocIO *mallocIO = new (std::nothrow) BMallocIO();
753 	if (mallocIO == NULL)
754 		return;
755 
756 	fData = mallocIO;
757 
758 	const off_t size = picture.DataLength();
759 	if (mallocIO->SetSize(size) < B_OK)
760 		return;
761 
762 	fToken = gTokenSpace.NewToken(kPictureToken, this);
763 
764 	picture.fData->ReadAt(0, const_cast<void *>(mallocIO->Buffer()), size);
765 
766 	PictureDataWriter::SetTo(fData);
767 }
768 
769 
770 ServerPicture::ServerPicture(const char *fileName, const int32 &offset)
771 	:
772 	PictureDataWriter(),
773 	fData(NULL),
774 	fPictures(NULL),
775 	fUsurped(NULL)
776 {
777 	BPrivate::Storage::OffsetFile *file =
778 		new BPrivate::Storage::OffsetFile(new BFile(fileName, B_READ_WRITE), (off_t)offset);
779 
780 	if (file == NULL || file->InitCheck() != B_OK)
781 		return;
782 
783 	fData = file;
784 	fToken = gTokenSpace.NewToken(kPictureToken, this);
785 
786 	PictureDataWriter::SetTo(fData);
787 }
788 
789 
790 ServerPicture::~ServerPicture()
791 {
792 	delete fData;
793 	gTokenSpace.RemoveToken(fToken);
794 
795 	// We only delete the subpictures list, not the subpictures themselves,
796 	// since the ServerApp keeps them in a list and will delete them on quit.
797 	delete fPictures;
798 }
799 
800 
801 void
802 ServerPicture::EnterStateChange()
803 {
804 	BeginOp(B_PIC_ENTER_STATE_CHANGE);
805 }
806 
807 
808 void
809 ServerPicture::ExitStateChange()
810 {
811 	EndOp();
812 }
813 
814 
815 void
816 ServerPicture::SyncState(ViewLayer *view)
817 {
818 	// TODO: Finish this
819 	EnterStateChange();
820 
821 	WriteSetOrigin(view->CurrentState()->Origin());
822 	WriteSetPenLocation(view->CurrentState()->PenLocation());
823 	WriteSetPenSize(view->CurrentState()->PenSize());
824 	WriteSetScale(view->CurrentState()->Scale());
825 	WriteSetLineMode(view->CurrentState()->LineCapMode(), view->CurrentState()->LineJoinMode(),
826 			view->CurrentState()->MiterLimit());
827 	//WriteSetPattern(*view->CurrentState()->GetPattern().GetInt8());
828 	WriteSetDrawingMode(view->CurrentState()->GetDrawingMode());
829 
830 	WriteSetHighColor(view->CurrentState()->HighColor());
831 	WriteSetLowColor(view->CurrentState()->LowColor());
832 
833 	ExitStateChange();
834 }
835 
836 void
837 ServerPicture::SetFontFromLink(BPrivate::LinkReceiver& link)
838 {
839 	BeginOp(B_PIC_ENTER_FONT_STATE);
840 
841 	uint16 mask;
842 	link.Read<uint16>(&mask);
843 
844 	if (mask & B_FONT_FAMILY_AND_STYLE) {
845 		uint32 fontID;
846 		link.Read<uint32>(&fontID);
847 		ServerFont font;
848 		font.SetFamilyAndStyle(fontID);
849 		WriteSetFontFamily(font.Family());
850 		WriteSetFontStyle(font.Style());
851 	}
852 
853 	if (mask & B_FONT_SIZE) {
854 		float size;
855 		link.Read<float>(&size);
856 		WriteSetFontSize(size);
857 	}
858 
859 	if (mask & B_FONT_SHEAR) {
860 		float shear;
861 		link.Read<float>(&shear);
862 		WriteSetFontShear(shear);
863 	}
864 
865 	if (mask & B_FONT_ROTATION) {
866 		float rotation;
867 		link.Read<float>(&rotation);
868 		WriteSetFontRotation(rotation);
869 	}
870 
871 	if (mask & B_FONT_FALSE_BOLD_WIDTH) {
872 		float falseBoldWidth;
873 		link.Read<float>(&falseBoldWidth);
874 		//SetFalseBoldWidth(falseBoldWidth);
875 	}
876 
877 	if (mask & B_FONT_SPACING) {
878 		uint8 spacing;
879 		link.Read<uint8>(&spacing);
880 		WriteSetFontSpacing(spacing);
881 	}
882 
883 	if (mask & B_FONT_ENCODING) {
884 		uint8 encoding;
885 		link.Read<uint8>((uint8*)&encoding);
886 		WriteSetFontEncoding(encoding);
887 	}
888 
889 	if (mask & B_FONT_FACE) {
890 		uint16 face;
891 		link.Read<uint16>(&face);
892 		WriteSetFontFace(face);
893 	}
894 
895 	if (mask & B_FONT_FLAGS) {
896 		uint32 flags;
897 		link.Read<uint32>(&flags);
898 		WriteSetFontFlags(flags);
899 	}
900 
901 	EndOp();
902 }
903 
904 
905 void
906 ServerPicture::Play(ViewLayer *view)
907 {
908 	// TODO: for now: then change PicturePlayer to accept a BPositionIO object
909 	BMallocIO *mallocIO = dynamic_cast<BMallocIO *>(fData);
910 	if (mallocIO == NULL)
911 		return;
912 
913 	BPrivate::PicturePlayer player(mallocIO->Buffer(), mallocIO->BufferLength(), fPictures);
914 	player.Play(const_cast<void **>(kTableEntries), sizeof(kTableEntries) / sizeof(void *), view);
915 }
916 
917 
918 void
919 ServerPicture::Usurp(ServerPicture *picture)
920 {
921 	fUsurped = picture;
922 }
923 
924 
925 ServerPicture *
926 ServerPicture::StepDown()
927 {
928 	ServerPicture *old = fUsurped;
929 	fUsurped = NULL;
930 	return old;
931 }
932 
933 
934 bool
935 ServerPicture::NestPicture(ServerPicture *picture)
936 {
937 	if (fPictures == NULL)
938 		fPictures = new (std::nothrow) BList;
939 
940 	if (fPictures == NULL
941 		|| !fPictures->AddItem(picture))
942 		return false;
943 
944 	return true;
945 }
946 
947 
948 off_t
949 ServerPicture::DataLength() const
950 {
951 	if (fData == NULL)
952 		return 0;
953 	off_t size;
954 	fData->GetSize(&size);
955 	return size;
956 }
957 
958 
959 #define BUFFER_SIZE 4096
960 
961 
962 status_t
963 ServerPicture::ImportData(BPrivate::LinkReceiver &link)
964 {
965 	int32 size = 0;
966 	link.Read<int32>(&size);
967 
968 	if (size >= 65536) {
969 		//TODO: Pass via an area.
970 		// Ideally the Link** api would allow to write partial messages,
971 		// so that a big picture could be written in chunks of 4096 bytes
972 		// or so
973 		return B_ERROR;
974 	}
975 
976 	off_t oldPosition = fData->Position();
977 	fData->Seek(0, SEEK_SET);
978 
979 	// TODO: Oh yeah... 65kb on the stack...
980 	char buffer[size];
981 	status_t read = link.Read(buffer, size);
982 	if (read < B_OK)
983 		return (status_t)read;
984 
985 	fData->Write(buffer, size);
986 
987 	fData->Seek(oldPosition, SEEK_SET);
988 
989 	return B_OK;
990 }
991 
992 
993 status_t
994 ServerPicture::ExportData(BPrivate::PortLink &link)
995 {
996 	link.StartMessage(B_OK);
997 
998 	off_t oldPosition = fData->Position();
999 	fData->Seek(0, SEEK_SET);
1000 
1001 	int32 subPicturesCount = 0;
1002 	if (fPictures != NULL)
1003 		subPicturesCount = fPictures->CountItems();
1004 	link.Attach<int32>(subPicturesCount);
1005 	if (subPicturesCount > 0) {
1006 		for (int32 i = 0; i < subPicturesCount; i++) {
1007 			ServerPicture *subPic = static_cast<ServerPicture *>(fPictures->ItemAtFast(i));
1008 			link.Attach<int32>(subPic->Token());
1009 		}
1010 	}
1011 
1012 	off_t size = 0;
1013 	fData->GetSize(&size);
1014 	link.Attach<int32>((int32)size);
1015 	if (size >= 65536) {
1016 		//TODO: Pass via an area
1017 		link.CancelMessage();
1018 		link.StartMessage(B_ERROR);
1019 		return B_ERROR;
1020 	}
1021 	// TODO: Oh yeah... 65kb on the stack...
1022 	char buffer[size];
1023 	ssize_t read = fData->Read(buffer, size);
1024 	if (read < B_OK)
1025 		return (status_t)read;
1026 	if (link.Attach(buffer, read) < B_OK) {
1027 		//
1028 		link.CancelMessage();
1029 		link.StartMessage(B_ERROR);
1030 	};
1031 
1032 
1033 	fData->Seek(oldPosition, SEEK_SET);
1034 
1035 	return B_OK;
1036 }
1037 
1038 
1039