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