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