1 /*
2 * Copyright 2001-2019, 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 * Julian Harnath <julian.harnath@rwth-aachen.de>
10 * Stephan Aßmus <superstippi@gmx.de>
11 */
12
13 #include "ServerPicture.h"
14
15 #include <new>
16 #include <stdio.h>
17 #include <stack>
18
19 #include "AlphaMask.h"
20 #include "DrawingEngine.h"
21 #include "DrawState.h"
22 #include "GlobalFontManager.h"
23 #include "Layer.h"
24 #include "ServerApp.h"
25 #include "ServerBitmap.h"
26 #include "ServerFont.h"
27 #include "ServerTokenSpace.h"
28 #include "View.h"
29 #include "Window.h"
30
31 #include <LinkReceiver.h>
32 #include <OffsetFile.h>
33 #include <ObjectListPrivate.h>
34 #include <PicturePlayer.h>
35 #include <PictureProtocol.h>
36 #include <PortLink.h>
37 #include <ServerProtocol.h>
38 #include <ShapePrivate.h>
39 #include <StackOrHeapArray.h>
40
41 #include <Bitmap.h>
42 #include <Debug.h>
43 #include <List.h>
44 #include <Shape.h>
45
46
47 using std::stack;
48
49
50 class ShapePainter : public BShapeIterator {
51 public:
52 ShapePainter(Canvas* canvas, BGradient* gradient);
53 virtual ~ShapePainter();
54
55 status_t Iterate(const BShape* shape);
56
57 virtual status_t IterateMoveTo(BPoint* point);
58 virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts);
59 virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts);
60 virtual status_t IterateClose();
61 virtual status_t IterateArcTo(float& rx, float& ry,
62 float& angle, bool largeArc, bool counterClockWise, BPoint& point);
63
64 void Draw(BRect frame, bool filled);
65
66 private:
67 Canvas* fCanvas;
68 BGradient* fGradient;
69 stack<uint32> fOpStack;
70 stack<BPoint> fPtStack;
71 };
72
73
ShapePainter(Canvas * canvas,BGradient * gradient)74 ShapePainter::ShapePainter(Canvas* canvas, BGradient* gradient)
75 :
76 fCanvas(canvas),
77 fGradient(gradient)
78 {
79 }
80
81
~ShapePainter()82 ShapePainter::~ShapePainter()
83 {
84 }
85
86
87 status_t
Iterate(const BShape * shape)88 ShapePainter::Iterate(const BShape* shape)
89 {
90 // this class doesn't modify the shape data
91 return BShapeIterator::Iterate(const_cast<BShape*>(shape));
92 }
93
94
95 status_t
IterateMoveTo(BPoint * point)96 ShapePainter::IterateMoveTo(BPoint* point)
97 {
98 try {
99 fOpStack.push(OP_MOVETO);
100 fPtStack.push(*point);
101 } catch (std::bad_alloc&) {
102 return B_NO_MEMORY;
103 }
104
105 return B_OK;
106 }
107
108
109 status_t
IterateLineTo(int32 lineCount,BPoint * linePts)110 ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts)
111 {
112 try {
113 fOpStack.push(OP_LINETO | lineCount);
114 for (int32 i = 0; i < lineCount; i++)
115 fPtStack.push(linePts[i]);
116 } catch (std::bad_alloc&) {
117 return B_NO_MEMORY;
118 }
119
120 return B_OK;
121 }
122
123
124 status_t
IterateBezierTo(int32 bezierCount,BPoint * bezierPts)125 ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts)
126 {
127 bezierCount *= 3;
128 try {
129 fOpStack.push(OP_BEZIERTO | bezierCount);
130 for (int32 i = 0; i < bezierCount; i++)
131 fPtStack.push(bezierPts[i]);
132 } catch (std::bad_alloc&) {
133 return B_NO_MEMORY;
134 }
135
136 return B_OK;
137 }
138
139
140 status_t
IterateArcTo(float & rx,float & ry,float & angle,bool largeArc,bool counterClockWise,BPoint & point)141 ShapePainter::IterateArcTo(float& rx, float& ry,
142 float& angle, bool largeArc, bool counterClockWise, BPoint& point)
143 {
144 uint32 op;
145 if (largeArc) {
146 if (counterClockWise)
147 op = OP_LARGE_ARC_TO_CCW;
148 else
149 op = OP_LARGE_ARC_TO_CW;
150 } else {
151 if (counterClockWise)
152 op = OP_SMALL_ARC_TO_CCW;
153 else
154 op = OP_SMALL_ARC_TO_CW;
155 }
156
157 try {
158 fOpStack.push(op | 3);
159 fPtStack.push(BPoint(rx, ry));
160 fPtStack.push(BPoint(angle, 0));
161 fPtStack.push(point);
162 } catch (std::bad_alloc&) {
163 return B_NO_MEMORY;
164 }
165
166 return B_OK;
167 }
168
169
170 status_t
IterateClose()171 ShapePainter::IterateClose()
172 {
173 try {
174 fOpStack.push(OP_CLOSE);
175 } catch (std::bad_alloc&) {
176 return B_NO_MEMORY;
177 }
178
179 return B_OK;
180 }
181
182
183 void
Draw(BRect frame,bool filled)184 ShapePainter::Draw(BRect frame, bool filled)
185 {
186 // We're going to draw the currently iterated shape.
187 // TODO: This can be more efficient by skipping the conversion.
188 int32 opCount = fOpStack.size();
189 int32 ptCount = fPtStack.size();
190
191 if (opCount > 0 && ptCount > 0) {
192 int32 i;
193 uint32* opList = new(std::nothrow) uint32[opCount];
194 if (opList == NULL)
195 return;
196
197 BPoint* ptList = new(std::nothrow) BPoint[ptCount];
198 if (ptList == NULL) {
199 delete[] opList;
200 return;
201 }
202
203 for (i = opCount - 1; i >= 0; i--) {
204 opList[i] = fOpStack.top();
205 fOpStack.pop();
206 }
207
208 for (i = ptCount - 1; i >= 0; i--) {
209 ptList[i] = fPtStack.top();
210 fPtStack.pop();
211 }
212
213 // this might seem a bit weird, but under R5, the shapes
214 // are always offset by the current pen location
215 BPoint screenOffset = fCanvas->CurrentState()->PenLocation();
216 frame.OffsetBy(screenOffset);
217
218 const SimpleTransform transform = fCanvas->PenToScreenTransform();
219 transform.Apply(&screenOffset);
220 transform.Apply(&frame);
221
222 /* stroked gradients are not yet supported */
223 if (fGradient != NULL && filled) {
224 fCanvas->GetDrawingEngine()->FillShape(frame, opCount, opList,
225 ptCount, ptList, *fGradient, screenOffset, fCanvas->Scale());
226 } else {
227 fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList,
228 ptCount, ptList, filled, screenOffset, fCanvas->Scale());
229 }
230
231 delete[] opList;
232 delete[] ptList;
233 }
234 }
235
236
237 // #pragma mark - drawing functions
238
239
240 static void
get_polygon_frame(const BPoint * points,uint32 numPoints,BRect * _frame)241 get_polygon_frame(const BPoint* points, uint32 numPoints, BRect* _frame)
242 {
243 ASSERT(numPoints > 0);
244
245 float left = points->x;
246 float top = points->y;
247 float right = left;
248 float bottom = top;
249
250 points++;
251 numPoints--;
252
253 while (numPoints--) {
254 if (points->x < left)
255 left = points->x;
256 if (points->x > right)
257 right = points->x;
258 if (points->y < top)
259 top = points->y;
260 if (points->y > bottom)
261 bottom = points->y;
262 points++;
263 }
264
265 _frame->Set(left, top, right, bottom);
266 }
267
268
269 static void
move_pen_by(void * _canvas,const BPoint & delta)270 move_pen_by(void* _canvas, const BPoint& delta)
271 {
272 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
273 canvas->CurrentState()->SetPenLocation(
274 canvas->CurrentState()->PenLocation() + delta);
275 }
276
277
278 static void
stroke_line(void * _canvas,const BPoint & _start,const BPoint & _end)279 stroke_line(void* _canvas, const BPoint& _start, const BPoint& _end)
280 {
281 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
282 BPoint start = _start;
283 BPoint end = _end;
284
285 const SimpleTransform transform = canvas->PenToScreenTransform();
286 transform.Apply(&start);
287 transform.Apply(&end);
288 canvas->GetDrawingEngine()->StrokeLine(start, end);
289
290 canvas->CurrentState()->SetPenLocation(_end);
291 // the DrawingEngine/Painter does not need to be updated, since this
292 // effects only the view->screen coord conversion, which is handled
293 // by the view only
294 }
295
296
297 static void
draw_rect(void * _canvas,const BRect & _rect,bool fill)298 draw_rect(void* _canvas, const BRect& _rect, bool fill)
299 {
300 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
301 BRect rect = _rect;
302
303 canvas->PenToScreenTransform().Apply(&rect);
304 if (fill)
305 canvas->GetDrawingEngine()->FillRect(rect);
306 else
307 canvas->GetDrawingEngine()->StrokeRect(rect);
308 }
309
310
311 static void
draw_round_rect(void * _canvas,const BRect & _rect,const BPoint & radii,bool fill)312 draw_round_rect(void* _canvas, const BRect& _rect, const BPoint& radii,
313 bool fill)
314 {
315 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
316 BRect rect = _rect;
317
318 canvas->PenToScreenTransform().Apply(&rect);
319 float scale = canvas->CurrentState()->CombinedScale();
320 canvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale,
321 radii.y * scale, fill);
322 }
323
324
325 static void
draw_bezier(void * _canvas,size_t numPoints,const BPoint viewPoints[],bool fill)326 draw_bezier(void* _canvas, size_t numPoints, const BPoint viewPoints[],
327 bool fill)
328 {
329 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
330
331 const size_t kSupportedPoints = 4;
332 if (numPoints != kSupportedPoints)
333 return;
334
335 BPoint points[kSupportedPoints];
336 canvas->PenToScreenTransform().Apply(points, viewPoints, kSupportedPoints);
337 canvas->GetDrawingEngine()->DrawBezier(points, fill);
338 }
339
340
341 static void
draw_arc(void * _canvas,const BPoint & center,const BPoint & radii,float startTheta,float arcTheta,bool fill)342 draw_arc(void* _canvas, const BPoint& center, const BPoint& radii,
343 float startTheta, float arcTheta, bool fill)
344 {
345 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
346
347 BRect rect(center.x - radii.x, center.y - radii.y,
348 center.x + radii.x - 1, center.y + radii.y - 1);
349 canvas->PenToScreenTransform().Apply(&rect);
350 canvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill);
351 }
352
353
354 static void
draw_ellipse(void * _canvas,const BRect & _rect,bool fill)355 draw_ellipse(void* _canvas, const BRect& _rect, bool fill)
356 {
357 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
358
359 BRect rect = _rect;
360 canvas->PenToScreenTransform().Apply(&rect);
361 canvas->GetDrawingEngine()->DrawEllipse(rect, fill);
362 }
363
364
365 static void
draw_polygon(void * _canvas,size_t numPoints,const BPoint viewPoints[],bool isClosed,bool fill)366 draw_polygon(void* _canvas, size_t numPoints, const BPoint viewPoints[],
367 bool isClosed, bool fill)
368 {
369 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
370
371 if (numPoints == 0)
372 return;
373
374 BStackOrHeapArray<BPoint, 200> points(numPoints);
375 if (!points.IsValid())
376 return;
377
378 canvas->PenToScreenTransform().Apply(points, viewPoints, numPoints);
379
380 BRect polyFrame;
381 get_polygon_frame(points, numPoints, &polyFrame);
382
383 canvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
384 fill, isClosed && numPoints > 2);
385 }
386
387
388 static void
draw_shape(void * _canvas,const BShape & shape,bool fill)389 draw_shape(void* _canvas, const BShape& shape, bool fill)
390 {
391 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
392 ShapePainter drawShape(canvas, NULL);
393
394 drawShape.Iterate(&shape);
395 drawShape.Draw(shape.Bounds(), fill);
396 }
397
398
399 static void
draw_rect_gradient(void * _canvas,const BRect & _rect,BGradient & gradient,bool fill)400 draw_rect_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
401 {
402 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
403 BRect rect = _rect;
404
405 const SimpleTransform transform =
406 canvas->PenToScreenTransform();
407 transform.Apply(&rect);
408 transform.Apply(&gradient);
409
410 canvas->GetDrawingEngine()->FillRect(rect, gradient);
411 }
412
413
414 static void
draw_round_rect_gradient(void * _canvas,const BRect & _rect,const BPoint & radii,BGradient & gradient,bool fill)415 draw_round_rect_gradient(void* _canvas, const BRect& _rect, const BPoint& radii, BGradient& gradient,
416 bool fill)
417 {
418 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
419 BRect rect = _rect;
420
421 const SimpleTransform transform =
422 canvas->PenToScreenTransform();
423 transform.Apply(&rect);
424 transform.Apply(&gradient);
425 float scale = canvas->CurrentState()->CombinedScale();
426 canvas->GetDrawingEngine()->FillRoundRect(rect, radii.x * scale,
427 radii.y * scale, gradient);
428 }
429
430
431 static void
draw_bezier_gradient(void * _canvas,size_t numPoints,const BPoint viewPoints[],BGradient & gradient,bool fill)432 draw_bezier_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[], BGradient& gradient,
433 bool fill)
434 {
435 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
436
437 const size_t kSupportedPoints = 4;
438 if (numPoints != kSupportedPoints)
439 return;
440
441 BPoint points[kSupportedPoints];
442 const SimpleTransform transform =
443 canvas->PenToScreenTransform();
444 transform.Apply(points, viewPoints, kSupportedPoints);
445 transform.Apply(&gradient);
446 canvas->GetDrawingEngine()->FillBezier(points, gradient);
447 }
448
449
450 static void
draw_arc_gradient(void * _canvas,const BPoint & center,const BPoint & radii,float startTheta,float arcTheta,BGradient & gradient,bool fill)451 draw_arc_gradient(void* _canvas, const BPoint& center, const BPoint& radii,
452 float startTheta, float arcTheta, BGradient& gradient, bool fill)
453 {
454 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
455
456 BRect rect(center.x - radii.x, center.y - radii.y,
457 center.x + radii.x - 1, center.y + radii.y - 1);
458 const SimpleTransform transform =
459 canvas->PenToScreenTransform();
460 transform.Apply(&rect);
461 transform.Apply(&gradient);
462 canvas->GetDrawingEngine()->FillArc(rect, startTheta, arcTheta, gradient);
463 }
464
465
466 static void
draw_ellipse_gradient(void * _canvas,const BRect & _rect,BGradient & gradient,bool fill)467 draw_ellipse_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
468 {
469 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
470 BRect rect = _rect;
471
472 const SimpleTransform transform =
473 canvas->PenToScreenTransform();
474 transform.Apply(&rect);
475 transform.Apply(&gradient);
476 canvas->GetDrawingEngine()->FillEllipse(rect, gradient);
477 }
478
479
480 static void
draw_polygon_gradient(void * _canvas,size_t numPoints,const BPoint viewPoints[],bool isClosed,BGradient & gradient,bool fill)481 draw_polygon_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[],
482 bool isClosed, BGradient& gradient, bool fill)
483 {
484 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
485
486 if (numPoints == 0)
487 return;
488
489 BStackOrHeapArray<BPoint, 200> points(numPoints);
490 if (!points.IsValid())
491 return;
492
493 const SimpleTransform transform =
494 canvas->PenToScreenTransform();
495 transform.Apply(points, viewPoints, numPoints);
496 transform.Apply(&gradient);
497
498 BRect polyFrame;
499 get_polygon_frame(points, numPoints, &polyFrame);
500
501 canvas->GetDrawingEngine()->FillPolygon(points, numPoints, polyFrame,
502 gradient, isClosed && numPoints > 2);
503 }
504
505
506 static void
draw_shape_gradient(void * _canvas,const BShape & shape,BGradient & gradient,bool fill)507 draw_shape_gradient(void* _canvas, const BShape& shape, BGradient& gradient, bool fill)
508 {
509 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
510 ShapePainter drawShape(canvas, &gradient);
511
512 drawShape.Iterate(&shape);
513 drawShape.Draw(shape.Bounds(), fill);
514 }
515
516
517 static void
draw_string(void * _canvas,const char * string,size_t length,float deltaSpace,float deltaNonSpace)518 draw_string(void* _canvas, const char* string, size_t length, float deltaSpace,
519 float deltaNonSpace)
520 {
521 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
522
523 // NOTE: the picture data was recorded with a "set pen location"
524 // command inserted before the "draw string" command, so we can
525 // use PenLocation()
526 BPoint location = canvas->CurrentState()->PenLocation();
527
528 escapement_delta delta = { deltaSpace, deltaNonSpace };
529 canvas->PenToScreenTransform().Apply(&location);
530 location = canvas->GetDrawingEngine()->DrawString(string, length,
531 location, &delta);
532
533 canvas->PenToScreenTransform().Apply(&location);
534 canvas->CurrentState()->SetPenLocation(location);
535 // the DrawingEngine/Painter does not need to be updated, since this
536 // effects only the view->screen coord conversion, which is handled
537 // by the view only
538 }
539
540
541 static void
draw_string_locations(void * _canvas,const char * string,size_t length,const BPoint * _locations,size_t locationsCount)542 draw_string_locations(void* _canvas, const char* string, size_t length,
543 const BPoint* _locations, size_t locationsCount)
544 {
545 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
546 BStackOrHeapArray<BPoint, 200> locations(locationsCount);
547 if (!locations.IsValid())
548 return;
549
550 const SimpleTransform transform = canvas->PenToScreenTransform();
551 for (size_t i = 0; i < locationsCount; i++) {
552 locations[i] = _locations[i];
553 transform.Apply(&locations[i]);
554 }
555
556 BPoint location = canvas->GetDrawingEngine()->DrawString(string, length,
557 locations);
558
559 canvas->PenToScreenTransform().Apply(&location);
560 canvas->CurrentState()->SetPenLocation(location);
561 // the DrawingEngine/Painter does not need to be updated, since this
562 // effects only the view->screen coord conversion, which is handled
563 // by the view only
564 }
565
566
567 static void
draw_pixels(void * _canvas,const BRect & src,const BRect & _dest,uint32 width,uint32 height,size_t bytesPerRow,color_space pixelFormat,uint32 options,const void * data,size_t length)568 draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width,
569 uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
570 const void* data, size_t length)
571 {
572 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
573
574 UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1),
575 (color_space)pixelFormat, 0, bytesPerRow);
576
577 if (!bitmap.IsValid())
578 return;
579
580 memcpy(bitmap.Bits(), data, std::min(height * bytesPerRow, length));
581
582 BRect dest = _dest;
583 canvas->PenToScreenTransform().Apply(&dest);
584 canvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options);
585 }
586
587
588 static void
draw_picture(void * _canvas,const BPoint & where,int32 token)589 draw_picture(void* _canvas, const BPoint& where, int32 token)
590 {
591 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
592
593 BReference<ServerPicture> picture(canvas->GetPicture(token), true);
594 if (picture != NULL) {
595 canvas->PushState();
596 canvas->SetDrawingOrigin(where);
597
598 canvas->PushState();
599 picture->Play(canvas);
600 canvas->PopState();
601
602 canvas->PopState();
603 }
604 }
605
606
607 static void
set_clipping_rects(void * _canvas,size_t numRects,const BRect rects[])608 set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[])
609 {
610 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
611
612 if (numRects == 0)
613 canvas->SetUserClipping(NULL);
614 else {
615 // TODO: This might be too slow, we should copy the rects
616 // directly to BRegion's internal data
617 BRegion region;
618 for (uint32 c = 0; c < numRects; c++)
619 region.Include(rects[c]);
620 canvas->SetUserClipping(®ion);
621 }
622 canvas->UpdateCurrentDrawingRegion();
623 }
624
625
626 static void
clip_to_picture(void * _canvas,int32 pictureToken,const BPoint & where,bool clipToInverse)627 clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where,
628 bool clipToInverse)
629 {
630 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
631
632 BReference<ServerPicture> picture(canvas->GetPicture(pictureToken), true);
633 if (picture == NULL)
634 return;
635 BReference<AlphaMask> mask(new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(),
636 picture, *canvas->CurrentState(), where, clipToInverse), true);
637 canvas->SetAlphaMask(mask);
638 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
639 canvas->Bounds());
640 canvas->ResyncDrawState();
641 }
642
643
644 static void
push_state(void * _canvas)645 push_state(void* _canvas)
646 {
647 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
648 canvas->PushState();
649 }
650
651
652 static void
pop_state(void * _canvas)653 pop_state(void* _canvas)
654 {
655 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
656 canvas->PopState();
657
658 BPoint p(0, 0);
659 canvas->PenToScreenTransform().Apply(&p);
660 canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(),
661 (int32)p.x, (int32)p.y);
662 }
663
664
665 // TODO: Be smart and actually take advantage of these methods:
666 // only apply state changes when they are called
667 static void
enter_state_change(void * _canvas)668 enter_state_change(void* _canvas)
669 {
670 }
671
672
673 static void
exit_state_change(void * _canvas)674 exit_state_change(void* _canvas)
675 {
676 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
677 canvas->ResyncDrawState();
678 }
679
680
681 static void
enter_font_state(void * _canvas)682 enter_font_state(void* _canvas)
683 {
684 }
685
686
687 static void
exit_font_state(void * _canvas)688 exit_font_state(void* _canvas)
689 {
690 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
691 canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font());
692 }
693
694
695 static void
set_origin(void * _canvas,const BPoint & pt)696 set_origin(void* _canvas, const BPoint& pt)
697 {
698 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
699 canvas->CurrentState()->SetOrigin(pt);
700 }
701
702
703 static void
set_pen_location(void * _canvas,const BPoint & pt)704 set_pen_location(void* _canvas, const BPoint& pt)
705 {
706 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
707 canvas->CurrentState()->SetPenLocation(pt);
708 // the DrawingEngine/Painter does not need to be updated, since this
709 // effects only the view->screen coord conversion, which is handled
710 // by the view only
711 }
712
713
714 static void
set_drawing_mode(void * _canvas,drawing_mode mode)715 set_drawing_mode(void* _canvas, drawing_mode mode)
716 {
717 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
718 if (canvas->CurrentState()->SetDrawingMode(mode))
719 canvas->GetDrawingEngine()->SetDrawingMode(mode);
720 }
721
722
723 static void
set_line_mode(void * _canvas,cap_mode capMode,join_mode joinMode,float miterLimit)724 set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode,
725 float miterLimit)
726 {
727 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
728 DrawState* state = canvas->CurrentState();
729 state->SetLineCapMode(capMode);
730 state->SetLineJoinMode(joinMode);
731 state->SetMiterLimit(miterLimit);
732 canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
733 }
734
735
736 static void
set_pen_size(void * _canvas,float size)737 set_pen_size(void* _canvas, float size)
738 {
739 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
740 canvas->CurrentState()->SetPenSize(size);
741 canvas->GetDrawingEngine()->SetPenSize(
742 canvas->CurrentState()->PenSize());
743 // DrawState::PenSize() returns the scaled pen size, so we
744 // need to use that value to set the drawing engine pen size.
745 }
746
747
748 static void
set_fore_color(void * _canvas,const rgb_color & color)749 set_fore_color(void* _canvas, const rgb_color& color)
750 {
751 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
752 canvas->CurrentState()->SetHighColor(color);
753 canvas->GetDrawingEngine()->SetHighColor(color);
754 }
755
756
757 static void
set_back_color(void * _canvas,const rgb_color & color)758 set_back_color(void* _canvas, const rgb_color& color)
759 {
760 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
761 canvas->CurrentState()->SetLowColor(color);
762 canvas->GetDrawingEngine()->SetLowColor(color);
763 }
764
765
766 static void
set_stipple_pattern(void * _canvas,const pattern & pattern)767 set_stipple_pattern(void* _canvas, const pattern& pattern)
768 {
769 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
770 canvas->CurrentState()->SetPattern(Pattern(pattern));
771 canvas->GetDrawingEngine()->SetPattern(pattern);
772 }
773
774
775 static void
set_scale(void * _canvas,float scale)776 set_scale(void* _canvas, float scale)
777 {
778 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
779 canvas->CurrentState()->SetScale(scale);
780 canvas->ResyncDrawState();
781
782 // Update the drawing engine draw state, since some stuff
783 // (for example the pen size) needs to be recalculated.
784 }
785
786
787 static void
set_font_family(void * _canvas,const char * _family,size_t length)788 set_font_family(void* _canvas, const char* _family, size_t length)
789 {
790 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
791 BString family(_family, length);
792
793 gFontManager->Lock();
794 FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
795 ServerFont font;
796 font.SetStyle(fontStyle);
797 gFontManager->Unlock();
798 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
799 }
800
801
802 static void
set_font_style(void * _canvas,const char * _style,size_t length)803 set_font_style(void* _canvas, const char* _style, size_t length)
804 {
805 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
806 BString style(_style, length);
807
808 ServerFont font(canvas->CurrentState()->Font());
809
810 gFontManager->Lock();
811 FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
812
813 font.SetStyle(fontStyle);
814 gFontManager->Unlock();
815 canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
816 }
817
818
819 static void
set_font_spacing(void * _canvas,uint8 spacing)820 set_font_spacing(void* _canvas, uint8 spacing)
821 {
822 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
823 ServerFont font;
824 font.SetSpacing(spacing);
825 canvas->CurrentState()->SetFont(font, B_FONT_SPACING);
826 }
827
828
829 static void
set_font_size(void * _canvas,float size)830 set_font_size(void* _canvas, float size)
831 {
832 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
833 ServerFont font;
834 font.SetSize(size);
835 canvas->CurrentState()->SetFont(font, B_FONT_SIZE);
836 }
837
838
839 static void
set_font_rotation(void * _canvas,float rotation)840 set_font_rotation(void* _canvas, float rotation)
841 {
842 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
843 ServerFont font;
844 font.SetRotation(rotation);
845 canvas->CurrentState()->SetFont(font, B_FONT_ROTATION);
846 }
847
848
849 static void
set_font_encoding(void * _canvas,uint8 encoding)850 set_font_encoding(void* _canvas, uint8 encoding)
851 {
852 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
853 ServerFont font;
854 font.SetEncoding(encoding);
855 canvas->CurrentState()->SetFont(font, B_FONT_ENCODING);
856 }
857
858
859 static void
set_font_flags(void * _canvas,uint32 flags)860 set_font_flags(void* _canvas, uint32 flags)
861 {
862 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
863 ServerFont font;
864 font.SetFlags(flags);
865 canvas->CurrentState()->SetFont(font, B_FONT_FLAGS);
866 }
867
868
869 static void
set_font_shear(void * _canvas,float shear)870 set_font_shear(void* _canvas, float shear)
871 {
872 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
873 ServerFont font;
874 font.SetShear(shear);
875 canvas->CurrentState()->SetFont(font, B_FONT_SHEAR);
876 }
877
878
879 static void
set_font_face(void * _canvas,uint16 face)880 set_font_face(void* _canvas, uint16 face)
881 {
882 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
883 ServerFont font;
884 font.SetFace(face);
885 canvas->CurrentState()->SetFont(font, B_FONT_FACE);
886 }
887
888
889 static void
set_blending_mode(void * _canvas,source_alpha alphaSrcMode,alpha_function alphaFncMode)890 set_blending_mode(void* _canvas, source_alpha alphaSrcMode,
891 alpha_function alphaFncMode)
892 {
893 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
894 canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
895 }
896
897
898 static void
set_fill_rule(void * _canvas,int32 fillRule)899 set_fill_rule(void* _canvas, int32 fillRule)
900 {
901 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
902 canvas->CurrentState()->SetFillRule(fillRule);
903 canvas->GetDrawingEngine()->SetFillRule(fillRule);
904 }
905
906
907 static void
set_transform(void * _canvas,const BAffineTransform & transform)908 set_transform(void* _canvas, const BAffineTransform& transform)
909 {
910 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
911
912 BPoint leftTop(0, 0);
913 canvas->PenToScreenTransform().Apply(&leftTop);
914
915 canvas->CurrentState()->SetTransform(transform);
916 canvas->GetDrawingEngine()->SetTransform(
917 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
918 }
919
920
921 static void
translate_by(void * _canvas,double x,double y)922 translate_by(void* _canvas, double x, double y)
923 {
924 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
925
926 BPoint leftTop(0, 0);
927 canvas->PenToScreenTransform().Apply(&leftTop);
928
929 BAffineTransform transform = canvas->CurrentState()->Transform();
930 transform.PreTranslateBy(x, y);
931 canvas->CurrentState()->SetTransform(transform);
932 canvas->GetDrawingEngine()->SetTransform(
933 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
934 }
935
936
937 static void
scale_by(void * _canvas,double x,double y)938 scale_by(void* _canvas, double x, double y)
939 {
940 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
941
942 BPoint leftTop(0, 0);
943 canvas->PenToScreenTransform().Apply(&leftTop);
944
945 BAffineTransform transform = canvas->CurrentState()->Transform();
946 transform.PreScaleBy(x, y);
947 canvas->CurrentState()->SetTransform(transform);
948 canvas->GetDrawingEngine()->SetTransform(
949 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
950 }
951
952
953 static void
rotate_by(void * _canvas,double angleRadians)954 rotate_by(void* _canvas, double angleRadians)
955 {
956 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
957
958 BPoint leftTop(0, 0);
959 canvas->PenToScreenTransform().Apply(&leftTop);
960
961 BAffineTransform transform = canvas->CurrentState()->Transform();
962 transform.PreRotateBy(angleRadians);
963 canvas->CurrentState()->SetTransform(transform);
964 canvas->GetDrawingEngine()->SetTransform(
965 canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
966 }
967
968
969 static void
blend_layer(void * _canvas,Layer * layer)970 blend_layer(void* _canvas, Layer* layer)
971 {
972 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
973 canvas->BlendLayer(layer);
974 }
975
976
977 static void
clip_to_rect(void * _canvas,const BRect & rect,bool inverse)978 clip_to_rect(void* _canvas, const BRect& rect, bool inverse)
979 {
980 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
981 bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse);
982 if (needDrawStateUpdate) {
983 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
984 canvas->Bounds());
985 canvas->ResyncDrawState();
986 }
987 canvas->UpdateCurrentDrawingRegion();
988 }
989
990
991 static void
clip_to_shape(void * _canvas,int32 opCount,const uint32 opList[],int32 ptCount,const BPoint ptList[],bool inverse)992 clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[],
993 int32 ptCount, const BPoint ptList[], bool inverse)
994 {
995 Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
996 shape_data shapeData;
997
998 // TODO: avoid copies
999 shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32));
1000 memcpy(shapeData.opList, opList, opCount * sizeof(uint32));
1001 shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint));
1002 memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint));
1003
1004 shapeData.opCount = opCount;
1005 shapeData.opSize = opCount * sizeof(uint32);
1006 shapeData.ptCount = ptCount;
1007 shapeData.ptSize = ptCount * sizeof(BPoint);
1008
1009 canvas->ClipToShape(&shapeData, inverse);
1010 canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
1011 canvas->Bounds());
1012 canvas->ResyncDrawState();
1013
1014 free(shapeData.opList);
1015 free(shapeData.ptList);
1016 }
1017
1018
1019 static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = {
1020 move_pen_by,
1021 stroke_line,
1022 draw_rect,
1023 draw_round_rect,
1024 draw_bezier,
1025 draw_arc,
1026 draw_ellipse,
1027 draw_polygon,
1028 draw_shape,
1029 draw_string,
1030 draw_pixels,
1031 draw_picture,
1032 set_clipping_rects,
1033 clip_to_picture,
1034 push_state,
1035 pop_state,
1036 enter_state_change,
1037 exit_state_change,
1038 enter_font_state,
1039 exit_font_state,
1040 set_origin,
1041 set_pen_location,
1042 set_drawing_mode,
1043 set_line_mode,
1044 set_pen_size,
1045 set_fore_color,
1046 set_back_color,
1047 set_stipple_pattern,
1048 set_scale,
1049 set_font_family,
1050 set_font_style,
1051 set_font_spacing,
1052 set_font_size,
1053 set_font_rotation,
1054 set_font_encoding,
1055 set_font_flags,
1056 set_font_shear,
1057 set_font_face,
1058 set_blending_mode,
1059 set_transform,
1060 translate_by,
1061 scale_by,
1062 rotate_by,
1063 blend_layer,
1064 clip_to_rect,
1065 clip_to_shape,
1066 draw_string_locations,
1067 draw_rect_gradient,
1068 draw_round_rect_gradient,
1069 draw_bezier_gradient,
1070 draw_arc_gradient,
1071 draw_ellipse_gradient,
1072 draw_polygon_gradient,
1073 draw_shape_gradient,
1074 set_fill_rule
1075 };
1076
1077
1078 // #pragma mark - ServerPicture
1079
1080
ServerPicture()1081 ServerPicture::ServerPicture()
1082 :
1083 fFile(NULL),
1084 fOwner(NULL)
1085 {
1086 fToken = gTokenSpace.NewToken(kPictureToken, this);
1087 fData.SetTo(new(std::nothrow) BMallocIO());
1088
1089 PictureDataWriter::SetTo(fData.Get());
1090 }
1091
1092
ServerPicture(const ServerPicture & picture)1093 ServerPicture::ServerPicture(const ServerPicture& picture)
1094 :
1095 fFile(NULL),
1096 fData(NULL),
1097 fOwner(NULL)
1098 {
1099 fToken = gTokenSpace.NewToken(kPictureToken, this);
1100
1101 BMallocIO* mallocIO = new(std::nothrow) BMallocIO();
1102 if (mallocIO == NULL)
1103 return;
1104
1105 fData.SetTo(mallocIO);
1106
1107 const off_t size = picture.DataLength();
1108 if (mallocIO->SetSize(size) < B_OK)
1109 return;
1110
1111 picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()),
1112 size);
1113
1114 PictureDataWriter::SetTo(fData.Get());
1115 }
1116
1117
ServerPicture(const char * fileName,int32 offset)1118 ServerPicture::ServerPicture(const char* fileName, int32 offset)
1119 :
1120 fFile(NULL),
1121 fData(NULL),
1122 fOwner(NULL)
1123 {
1124 fToken = gTokenSpace.NewToken(kPictureToken, this);
1125
1126 fFile.SetTo(new(std::nothrow) BFile(fileName, B_READ_WRITE));
1127 if (!fFile.IsSet())
1128 return;
1129
1130 BPrivate::Storage::OffsetFile* offsetFile
1131 = new(std::nothrow) BPrivate::Storage::OffsetFile(fFile.Get(), offset);
1132 if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) {
1133 delete offsetFile;
1134 return;
1135 }
1136
1137 fData.SetTo(offsetFile);
1138
1139 PictureDataWriter::SetTo(fData.Get());
1140 }
1141
1142
~ServerPicture()1143 ServerPicture::~ServerPicture()
1144 {
1145 ASSERT(fOwner == NULL);
1146
1147 gTokenSpace.RemoveToken(fToken);
1148
1149 if (fPictures.IsSet()) {
1150 for (int32 i = fPictures->CountItems(); i-- > 0;) {
1151 ServerPicture* picture = fPictures->ItemAt(i);
1152 picture->SetOwner(NULL);
1153 picture->ReleaseReference();
1154 }
1155 }
1156
1157 if (fPushed != NULL)
1158 fPushed->SetOwner(NULL);
1159 }
1160
1161
1162 bool
SetOwner(ServerApp * owner)1163 ServerPicture::SetOwner(ServerApp* owner)
1164 {
1165 if (owner == fOwner)
1166 return true;
1167
1168 // Acquire an extra reference, since calling RemovePicture()
1169 // May remove the last reference and then we will self-destruct right then.
1170 // Setting fOwner to NULL would access free'd memory. If owner is another
1171 // ServerApp, it's expected to already have a reference of course.
1172 BReference<ServerPicture> _(this);
1173
1174 if (fOwner != NULL)
1175 fOwner->RemovePicture(this);
1176
1177 fOwner = NULL;
1178 if (owner == NULL)
1179 return true;
1180
1181 if (!owner->AddPicture(this))
1182 return false;
1183
1184 fOwner = owner;
1185 return true;
1186 }
1187
1188
1189 void
EnterStateChange()1190 ServerPicture::EnterStateChange()
1191 {
1192 BeginOp(B_PIC_ENTER_STATE_CHANGE);
1193 }
1194
1195
1196 void
ExitStateChange()1197 ServerPicture::ExitStateChange()
1198 {
1199 EndOp();
1200 }
1201
1202
1203 void
SyncState(Canvas * canvas)1204 ServerPicture::SyncState(Canvas* canvas)
1205 {
1206 // TODO: Finish this
1207 EnterStateChange();
1208
1209 WriteSetOrigin(canvas->CurrentState()->Origin());
1210 WriteSetPenLocation(canvas->CurrentState()->PenLocation());
1211 WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize());
1212 WriteSetScale(canvas->CurrentState()->Scale());
1213 WriteSetLineMode(canvas->CurrentState()->LineCapMode(),
1214 canvas->CurrentState()->LineJoinMode(),
1215 canvas->CurrentState()->MiterLimit());
1216 //WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8());
1217 WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode());
1218
1219 WriteSetHighColor(canvas->CurrentState()->HighColor());
1220 WriteSetLowColor(canvas->CurrentState()->LowColor());
1221
1222 ExitStateChange();
1223 }
1224
1225
1226 void
WriteFontState(const ServerFont & font,uint16 mask)1227 ServerPicture::WriteFontState(const ServerFont& font, uint16 mask)
1228 {
1229 BeginOp(B_PIC_ENTER_FONT_STATE);
1230
1231 if (mask & B_FONT_FAMILY_AND_STYLE) {
1232 WriteSetFontFamily(font.Family());
1233 WriteSetFontStyle(font.Style());
1234 }
1235
1236 if (mask & B_FONT_SIZE) {
1237 WriteSetFontSize(font.Size());
1238 }
1239
1240 if (mask & B_FONT_SHEAR) {
1241 WriteSetFontShear(font.Shear());
1242 }
1243
1244 if (mask & B_FONT_ROTATION) {
1245 WriteSetFontRotation(font.Rotation());
1246 }
1247
1248 if (mask & B_FONT_FALSE_BOLD_WIDTH) {
1249 // TODO: Implement
1250 // WriteSetFalseBoldWidth(font.FalseBoldWidth());
1251 }
1252
1253 if (mask & B_FONT_SPACING) {
1254 WriteSetFontSpacing(font.Spacing());
1255 }
1256
1257 if (mask & B_FONT_ENCODING) {
1258 WriteSetFontEncoding(font.Encoding());
1259 }
1260
1261 if (mask & B_FONT_FACE) {
1262 WriteSetFontFace(font.Face());
1263 }
1264
1265 if (mask & B_FONT_FLAGS) {
1266 WriteSetFontFlags(font.Flags());
1267 }
1268
1269 EndOp();
1270 }
1271
1272
1273 void
Play(Canvas * target)1274 ServerPicture::Play(Canvas* target)
1275 {
1276 // TODO: for now: then change PicturePlayer
1277 // to accept a BPositionIO object
1278 BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData.Get());
1279 if (mallocIO == NULL)
1280 return;
1281
1282 BPrivate::PicturePlayer player(mallocIO->Buffer(),
1283 mallocIO->BufferLength(), PictureList::Private(fPictures.Get()).AsBList());
1284 player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks),
1285 target);
1286 }
1287
1288
1289 /*! Acquires a reference to the pushed picture.
1290 */
1291 void
PushPicture(ServerPicture * picture)1292 ServerPicture::PushPicture(ServerPicture* picture)
1293 {
1294 if (fPushed != NULL)
1295 debugger("already pushed a picture");
1296
1297 fPushed.SetTo(picture, false);
1298 }
1299
1300
1301 /*! Returns a reference with the popped picture.
1302 */
1303 ServerPicture*
PopPicture()1304 ServerPicture::PopPicture()
1305 {
1306 return fPushed.Detach();
1307 }
1308
1309
1310 void
AppendPicture(ServerPicture * picture)1311 ServerPicture::AppendPicture(ServerPicture* picture)
1312 {
1313 // A pushed picture is the same as an appended one
1314 PushPicture(picture);
1315 }
1316
1317
1318 bool
NestPicture(ServerPicture * picture)1319 ServerPicture::NestPicture(ServerPicture* picture)
1320 {
1321 if (!fPictures.IsSet())
1322 fPictures.SetTo(new(std::nothrow) PictureList);
1323
1324 if (!fPictures.IsSet() || !fPictures->AddItem(picture))
1325 return false;
1326
1327 picture->AcquireReference();
1328 return true;
1329 }
1330
1331
1332 off_t
DataLength() const1333 ServerPicture::DataLength() const
1334 {
1335 if (!fData.IsSet())
1336 return 0;
1337 off_t size;
1338 fData->GetSize(&size);
1339 return size;
1340 }
1341
1342
1343 status_t
ImportData(BPrivate::LinkReceiver & link)1344 ServerPicture::ImportData(BPrivate::LinkReceiver& link)
1345 {
1346 int32 size = 0;
1347 link.Read<int32>(&size);
1348
1349 off_t oldPosition = fData->Position();
1350 fData->Seek(0, SEEK_SET);
1351
1352 status_t status = B_NO_MEMORY;
1353 char* buffer = new(std::nothrow) char[size];
1354 if (buffer) {
1355 status = B_OK;
1356 ssize_t read = link.Read(buffer, size);
1357 if (read < B_OK || fData->Write(buffer, size) < B_OK)
1358 status = B_ERROR;
1359 delete [] buffer;
1360 }
1361
1362 fData->Seek(oldPosition, SEEK_SET);
1363 return status;
1364 }
1365
1366
1367 status_t
ExportData(BPrivate::PortLink & link)1368 ServerPicture::ExportData(BPrivate::PortLink& link)
1369 {
1370 link.StartMessage(B_OK);
1371
1372 off_t oldPosition = fData->Position();
1373 fData->Seek(0, SEEK_SET);
1374
1375 int32 subPicturesCount = 0;
1376 if (fPictures.IsSet())
1377 subPicturesCount = fPictures->CountItems();
1378 link.Attach<int32>(subPicturesCount);
1379 if (subPicturesCount > 0) {
1380 for (int32 i = 0; i < subPicturesCount; i++) {
1381 ServerPicture* subPicture = fPictures->ItemAt(i);
1382 link.Attach<int32>(subPicture->Token());
1383 }
1384 }
1385
1386 off_t size = 0;
1387 fData->GetSize(&size);
1388 link.Attach<int32>((int32)size);
1389
1390 status_t status = B_NO_MEMORY;
1391 char* buffer = new(std::nothrow) char[size];
1392 if (buffer) {
1393 status = B_OK;
1394 ssize_t read = fData->Read(buffer, size);
1395 if (read < B_OK || link.Attach(buffer, read) < B_OK)
1396 status = B_ERROR;
1397 delete [] buffer;
1398 }
1399
1400 if (status != B_OK) {
1401 link.CancelMessage();
1402 link.StartMessage(B_ERROR);
1403 }
1404
1405 fData->Seek(oldPosition, SEEK_SET);
1406 return status;
1407 }
1408