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