vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / PicturePlayer.cpp
blob4cbc85fd3bb8eaed621fa655110df0f5e2604dc1
1 /*
2 * Copyright 2001-2007, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
8 * Marcus Overhagen (marcus@overhagen.de)
9 */
11 /** PicturePlayer is used to play picture data. */
13 #include <PicturePlayer.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include <AffineTransform.h>
20 #include <PictureProtocol.h>
21 #include <Shape.h>
24 using BPrivate::PicturePlayer;
27 struct adapter_context {
28 void* user_data;
29 void** function_table;
33 static void
34 nop()
39 static void
40 move_pen_by(void* _context, const BPoint& delta)
42 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
43 ((void (*)(void*, BPoint))context->function_table[1])(context->user_data,
44 delta);
48 static void
49 stroke_line(void* _context, const BPoint& start, const BPoint& end)
51 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
52 ((void (*)(void*, BPoint, BPoint))context->function_table[2])(
53 context->user_data, start, end);
57 static void
58 draw_rect(void* _context, const BRect& rect, bool fill)
60 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
61 ((void (*)(void*, BRect))context->function_table[fill ? 4 : 3])(
62 context->user_data, rect);
66 static void
67 draw_round_rect(void* _context, const BRect& rect, const BPoint& radii,
68 bool fill)
70 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
71 ((void (*)(void*, BRect, BPoint))context->function_table[fill ? 6 : 5])(
72 context->user_data, rect, radii);
76 static void
77 draw_bezier(void* _context, size_t numPoints, const BPoint _points[], bool fill)
79 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
80 if (numPoints != 4)
81 return;
83 BPoint points[4] = { _points[0], _points[1], _points[2], _points[3] };
84 ((void (*)(void*, BPoint*))context->function_table[fill ? 8 : 7])(
85 context->user_data, points);
89 static void
90 draw_arc(void* _context, const BPoint& center, const BPoint& radii,
91 float startTheta, float arcTheta, bool fill)
93 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
94 ((void (*)(void*, BPoint, BPoint, float, float))
95 context->function_table[fill ? 10 : 9])(context->user_data, center,
96 radii, startTheta, arcTheta);
100 static void
101 draw_ellipse(void* _context, const BRect& rect, bool fill)
103 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
104 BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f);
105 BPoint center = rect.LeftTop() + radii;
106 ((void (*)(void*, BPoint, BPoint))
107 context->function_table[fill ? 12 : 11])(context->user_data, center,
108 radii);
112 static void
113 draw_polygon(void* _context, size_t numPoints, const BPoint _points[],
114 bool isClosed, bool fill)
116 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
118 // This is rather ugly but works for such a trivial class.
119 const size_t kMaxStackCount = 200;
120 char stackData[kMaxStackCount * sizeof(BPoint)];
121 BPoint* points = (BPoint*)stackData;
122 if (numPoints > kMaxStackCount) {
123 points = (BPoint*)malloc(numPoints * sizeof(BPoint));
124 if (points == NULL)
125 return;
128 memcpy(points, _points, numPoints * sizeof(BPoint));
130 ((void (*)(void*, int32, BPoint*, bool))
131 context->function_table[fill ? 14 : 13])(context->user_data, numPoints,
132 points, isClosed);
134 if (numPoints > kMaxStackCount)
135 free(points);
139 static void
140 draw_shape(void* _context, const BShape& shape, bool fill)
142 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
143 ((void (*)(void*, BShape))context->function_table[fill ? 16 : 15])(
144 context->user_data, shape);
148 static void
149 draw_string(void* _context, const char* _string, size_t length,
150 float deltaSpace, float deltaNonSpace)
152 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
153 char* string = strndup(_string, length);
155 ((void (*)(void*, char*, float, float))
156 context->function_table[17])(context->user_data, string, deltaSpace,
157 deltaNonSpace);
159 free(string);
163 static void
164 draw_pixels(void* _context, const BRect& src, const BRect& dest, uint32 width,
165 uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
166 const void* _data, size_t length)
168 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
169 void* data = malloc(length);
170 if (data == NULL)
171 return;
173 memcpy(data, _data, length);
175 ((void (*)(void*, BRect, BRect, int32, int32, int32, int32, int32, void*))
176 context->function_table[18])(context->user_data, src, dest, width,
177 height, bytesPerRow, pixelFormat, options, data);
179 free(data);
183 static void
184 draw_picture(void* _context, const BPoint& where, int32 token)
186 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
187 ((void (*)(void*, BPoint, int32))context->function_table[19])(
188 context->user_data, where, token);
192 static void
193 set_clipping_rects(void* _context, size_t numRects, const BRect _rects[])
195 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
197 // This is rather ugly but works for such a trivial class.
198 const size_t kMaxStackCount = 100;
199 char stackData[kMaxStackCount * sizeof(BRect)];
200 BRect* rects = (BRect*)stackData;
201 if (numRects > kMaxStackCount) {
202 rects = (BRect*)malloc(numRects * sizeof(BRect));
203 if (rects == NULL)
204 return;
207 memcpy(rects, _rects, numRects * sizeof(BRect));
209 ((void (*)(void*, BRect*, uint32))context->function_table[20])(
210 context->user_data, rects, numRects);
212 if (numRects > kMaxStackCount)
213 free(rects);
217 static void
218 clip_to_picture(void* _context, int32 token, const BPoint& origin,
219 bool clipToInverse)
221 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
222 ((void (*)(void*, int32, BPoint, bool))context->function_table[21])(
223 context->user_data, token, origin, clipToInverse);
227 static void
228 push_state(void* _context)
230 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
231 ((void (*)(void*))context->function_table[22])(context->user_data);
235 static void
236 pop_state(void* _context)
238 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
239 ((void (*)(void*))context->function_table[23])(context->user_data);
243 static void
244 enter_state_change(void* _context)
246 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
247 ((void (*)(void*))context->function_table[24])(context->user_data);
251 static void
252 exit_state_change(void* _context)
254 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
255 ((void (*)(void*))context->function_table[25])(context->user_data);
259 static void
260 enter_font_state(void* _context)
262 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
263 ((void (*)(void*))context->function_table[26])(context->user_data);
267 static void
268 exit_font_state(void* _context)
270 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
271 ((void (*)(void*))context->function_table[27])(context->user_data);
275 static void
276 set_origin(void* _context, const BPoint& origin)
278 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
279 ((void (*)(void*, BPoint))context->function_table[28])(context->user_data,
280 origin);
284 static void
285 set_pen_location(void* _context, const BPoint& penLocation)
287 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
288 ((void (*)(void*, BPoint))context->function_table[29])(context->user_data,
289 penLocation);
293 static void
294 set_drawing_mode(void* _context, drawing_mode mode)
296 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
297 ((void (*)(void*, drawing_mode))context->function_table[30])(
298 context->user_data, mode);
302 static void
303 set_line_mode(void* _context, cap_mode capMode, join_mode joinMode,
304 float miterLimit)
306 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
307 ((void (*)(void*, cap_mode, join_mode, float))context->function_table[31])(
308 context->user_data, capMode, joinMode, miterLimit);
312 static void
313 set_pen_size(void* _context, float size)
315 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
316 ((void (*)(void*, float))context->function_table[32])(context->user_data,
317 size);
321 static void
322 set_fore_color(void* _context, const rgb_color& color)
324 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
325 ((void (*)(void*, rgb_color))context->function_table[33])(
326 context->user_data, color);
330 static void
331 set_back_color(void* _context, const rgb_color& color)
333 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
334 ((void (*)(void*, rgb_color))context->function_table[34])(
335 context->user_data, color);
339 static void
340 set_stipple_pattern(void* _context, const pattern& stipplePattern)
342 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
343 ((void (*)(void*, pattern))context->function_table[35])(context->user_data,
344 stipplePattern);
348 static void
349 set_scale(void* _context, float scale)
351 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
352 ((void (*)(void*, float))context->function_table[36])(context->user_data,
353 scale);
357 static void
358 set_font_family(void* _context, const char* _family, size_t length)
360 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
361 char* family = strndup(_family, length);
363 ((void (*)(void*, char*))context->function_table[37])(context->user_data,
364 family);
366 free(family);
370 static void
371 set_font_style(void* _context, const char* _style, size_t length)
373 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
374 char* style = strndup(_style, length);
376 ((void (*)(void*, char*))context->function_table[38])(context->user_data,
377 style);
379 free(style);
383 static void
384 set_font_spacing(void* _context, uint8 spacing)
386 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
387 ((void (*)(void*, int32))context->function_table[39])(context->user_data,
388 spacing);
392 static void
393 set_font_size(void* _context, float size)
395 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
396 ((void (*)(void*, float))context->function_table[40])(context->user_data,
397 size);
401 static void
402 set_font_rotation(void* _context, float rotation)
404 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
405 ((void (*)(void*, float))context->function_table[41])(context->user_data,
406 rotation);
410 static void
411 set_font_encoding(void* _context, uint8 encoding)
413 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
414 ((void (*)(void*, int32))context->function_table[42])(context->user_data,
415 encoding);
419 static void
420 set_font_flags(void* _context, uint32 flags)
422 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
423 ((void (*)(void*, int32))context->function_table[43])(context->user_data,
424 flags);
428 static void
429 set_font_shear(void* _context, float shear)
431 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
432 ((void (*)(void*, float))context->function_table[44])(context->user_data,
433 shear);
437 static void
438 set_font_face(void* _context, uint16 face)
440 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
441 ((void (*)(void*, int32))context->function_table[46])(context->user_data,
442 face);
446 static void
447 set_blending_mode(void* _context, source_alpha alphaSrcMode,
448 alpha_function alphaFncMode)
450 adapter_context* context = reinterpret_cast<adapter_context*>(_context);
451 ((void (*)(void*, source_alpha, alpha_function))
452 context->function_table[47])(context->user_data, alphaSrcMode,
453 alphaFncMode);
457 #if DEBUG > 1
458 static const char *
459 PictureOpToString(int op)
461 #define RETURN_STRING(x) case x: return #x
463 switch(op) {
464 RETURN_STRING(B_PIC_MOVE_PEN_BY);
465 RETURN_STRING(B_PIC_STROKE_LINE);
466 RETURN_STRING(B_PIC_STROKE_RECT);
467 RETURN_STRING(B_PIC_FILL_RECT);
468 RETURN_STRING(B_PIC_STROKE_ROUND_RECT);
469 RETURN_STRING(B_PIC_FILL_ROUND_RECT);
470 RETURN_STRING(B_PIC_STROKE_BEZIER);
471 RETURN_STRING(B_PIC_FILL_BEZIER);
472 RETURN_STRING(B_PIC_STROKE_POLYGON);
473 RETURN_STRING(B_PIC_FILL_POLYGON);
474 RETURN_STRING(B_PIC_STROKE_SHAPE);
475 RETURN_STRING(B_PIC_FILL_SHAPE);
476 RETURN_STRING(B_PIC_DRAW_STRING);
477 RETURN_STRING(B_PIC_DRAW_PIXELS);
478 RETURN_STRING(B_PIC_DRAW_PICTURE);
479 RETURN_STRING(B_PIC_STROKE_ARC);
480 RETURN_STRING(B_PIC_FILL_ARC);
481 RETURN_STRING(B_PIC_STROKE_ELLIPSE);
482 RETURN_STRING(B_PIC_FILL_ELLIPSE);
484 RETURN_STRING(B_PIC_ENTER_STATE_CHANGE);
485 RETURN_STRING(B_PIC_SET_CLIPPING_RECTS);
486 RETURN_STRING(B_PIC_CLIP_TO_PICTURE);
487 RETURN_STRING(B_PIC_PUSH_STATE);
488 RETURN_STRING(B_PIC_POP_STATE);
489 RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS);
491 RETURN_STRING(B_PIC_SET_ORIGIN);
492 RETURN_STRING(B_PIC_SET_PEN_LOCATION);
493 RETURN_STRING(B_PIC_SET_DRAWING_MODE);
494 RETURN_STRING(B_PIC_SET_LINE_MODE);
495 RETURN_STRING(B_PIC_SET_PEN_SIZE);
496 RETURN_STRING(B_PIC_SET_SCALE);
497 RETURN_STRING(B_PIC_SET_TRANSFORM);
498 RETURN_STRING(B_PIC_SET_FORE_COLOR);
499 RETURN_STRING(B_PIC_SET_BACK_COLOR);
500 RETURN_STRING(B_PIC_SET_STIPLE_PATTERN);
501 RETURN_STRING(B_PIC_ENTER_FONT_STATE);
502 RETURN_STRING(B_PIC_SET_BLENDING_MODE);
503 RETURN_STRING(B_PIC_SET_FONT_FAMILY);
504 RETURN_STRING(B_PIC_SET_FONT_STYLE);
505 RETURN_STRING(B_PIC_SET_FONT_SPACING);
506 RETURN_STRING(B_PIC_SET_FONT_ENCODING);
507 RETURN_STRING(B_PIC_SET_FONT_FLAGS);
508 RETURN_STRING(B_PIC_SET_FONT_SIZE);
509 RETURN_STRING(B_PIC_SET_FONT_ROTATE);
510 RETURN_STRING(B_PIC_SET_FONT_SHEAR);
511 RETURN_STRING(B_PIC_SET_FONT_BPP);
512 RETURN_STRING(B_PIC_SET_FONT_FACE);
513 default: return "Unknown op";
515 #undef RETURN_STRING
517 #endif
520 PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures)
521 : fData(data),
522 fSize(size),
523 fPictures(pictures)
528 PicturePlayer::~PicturePlayer()
533 status_t
534 PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData)
536 const BPrivate::picture_player_callbacks kAdapterCallbacks = {
537 move_pen_by,
538 stroke_line,
539 draw_rect,
540 draw_round_rect,
541 draw_bezier,
542 draw_arc,
543 draw_ellipse,
544 draw_polygon,
545 draw_shape,
546 draw_string,
547 draw_pixels,
548 draw_picture,
549 set_clipping_rects,
550 clip_to_picture,
551 push_state,
552 pop_state,
553 enter_state_change,
554 exit_state_change,
555 enter_font_state,
556 exit_font_state,
557 set_origin,
558 set_pen_location,
559 set_drawing_mode,
560 set_line_mode,
561 set_pen_size,
562 set_fore_color,
563 set_back_color,
564 set_stipple_pattern,
565 set_scale,
566 set_font_family,
567 set_font_style,
568 set_font_spacing,
569 set_font_size,
570 set_font_rotation,
571 set_font_encoding,
572 set_font_flags,
573 set_font_shear,
574 set_font_face,
575 set_blending_mode
578 // We don't check if the functions in the table are NULL, but we
579 // check the tableEntries to see if the table is big enough.
580 // If an application supplies the wrong size or an invalid pointer,
581 // it's its own fault.
583 // If the caller supplied a function table smaller than needed,
584 // we use our dummy table, and copy the supported ops from the supplied one.
585 void *dummyTable[kOpsTableSize];
587 adapter_context adapterContext;
588 adapterContext.user_data = userData;
589 adapterContext.function_table = callBackTable;
591 if ((size_t)tableEntries < kOpsTableSize) {
592 memcpy(dummyTable, callBackTable, tableEntries * sizeof(void*));
593 for (size_t i = (size_t)tableEntries; i < kOpsTableSize; i++)
594 dummyTable[i] = (void*)nop;
596 adapterContext.function_table = dummyTable;
599 return _Play(kAdapterCallbacks, &adapterContext, fData, fSize, 0);
603 status_t
604 PicturePlayer::Play(const picture_player_callbacks& callbacks,
605 size_t callbacksSize, void* userData)
607 return _Play(callbacks, userData, fData, fSize, 0);
611 class DataReader {
612 public:
613 DataReader(const void* buffer, size_t length)
615 fBuffer((const uint8*)buffer),
616 fRemaining(length)
620 size_t
621 Remaining() const
623 return fRemaining;
626 template<typename T>
627 bool
628 Get(const T*& typed, size_t count = 1)
630 if (fRemaining < sizeof(T) * count)
631 return false;
633 typed = reinterpret_cast<const T *>(fBuffer);
634 fRemaining -= sizeof(T) * count;
635 fBuffer += sizeof(T) * count;
636 return true;
639 template<typename T>
640 bool
641 GetRemaining(const T*& buffer, size_t& size)
643 if (fRemaining == 0)
644 return false;
646 buffer = reinterpret_cast<const T*>(fBuffer);
647 size = fRemaining;
648 fRemaining = 0;
649 return true;
652 private:
653 const uint8* fBuffer;
654 size_t fRemaining;
658 struct picture_data_entry_header {
659 uint16 op;
660 uint32 size;
661 } _PACKED;
664 status_t
665 PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData,
666 const void* buffer, size_t length, uint16 parentOp)
668 #if DEBUG
669 printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : "");
670 bigtime_t startTime = system_time();
671 int32 numOps = 0;
672 #endif
674 DataReader pictureReader(buffer, length);
676 while (pictureReader.Remaining() > 0) {
677 const picture_data_entry_header* header;
678 const uint8* opData = NULL;
679 if (!pictureReader.Get(header)
680 || !pictureReader.Get(opData, header->size)) {
681 return B_BAD_DATA;
684 DataReader reader(opData, header->size);
686 // Disallow ops that don't fit the parent.
687 switch (parentOp) {
688 case 0:
689 // No parent op, no restrictions.
690 break;
692 case B_PIC_ENTER_STATE_CHANGE:
693 if (header->op <= B_PIC_ENTER_STATE_CHANGE
694 || header->op > B_PIC_SET_TRANSFORM) {
695 return B_BAD_DATA;
697 break;
699 case B_PIC_ENTER_FONT_STATE:
700 if (header->op < B_PIC_SET_FONT_FAMILY
701 || header->op > B_PIC_SET_FONT_FACE) {
702 return B_BAD_DATA;
704 break;
706 default:
707 return B_BAD_DATA;
710 #if DEBUG > 1
711 bigtime_t startOpTime = system_time();
712 printf("Op %s ", PictureOpToString(header->op));
713 #endif
714 switch (header->op) {
715 case B_PIC_MOVE_PEN_BY:
717 const BPoint* where;
718 if (callbacks.move_pen_by == NULL || !reader.Get(where))
719 break;
721 callbacks.move_pen_by(userData, *where);
722 break;
725 case B_PIC_STROKE_LINE:
727 const BPoint* start;
728 const BPoint* end;
729 if (callbacks.stroke_line == NULL || !reader.Get(start)
730 || !reader.Get(end)) {
731 break;
734 callbacks.stroke_line(userData, *start, *end);
735 break;
738 case B_PIC_STROKE_RECT:
739 case B_PIC_FILL_RECT:
741 const BRect* rect;
742 if (callbacks.draw_rect == NULL || !reader.Get(rect))
743 break;
745 callbacks.draw_rect(userData, *rect,
746 header->op == B_PIC_FILL_RECT);
747 break;
750 case B_PIC_STROKE_ROUND_RECT:
751 case B_PIC_FILL_ROUND_RECT:
753 const BRect* rect;
754 const BPoint* radii;
755 if (callbacks.draw_round_rect == NULL || !reader.Get(rect)
756 || !reader.Get(radii)) {
757 break;
760 callbacks.draw_round_rect(userData, *rect, *radii,
761 header->op == B_PIC_FILL_ROUND_RECT);
762 break;
765 case B_PIC_STROKE_BEZIER:
766 case B_PIC_FILL_BEZIER:
768 const size_t kNumControlPoints = 4;
769 const BPoint* controlPoints;
770 if (callbacks.draw_bezier == NULL
771 || !reader.Get(controlPoints, kNumControlPoints)) {
772 break;
775 callbacks.draw_bezier(userData, kNumControlPoints,
776 controlPoints, header->op == B_PIC_FILL_BEZIER);
777 break;
780 case B_PIC_STROKE_ARC:
781 case B_PIC_FILL_ARC:
783 const BPoint* center;
784 const BPoint* radii;
785 const float* startTheta;
786 const float* arcTheta;
787 if (callbacks.draw_arc == NULL || !reader.Get(center)
788 || !reader.Get(radii) || !reader.Get(startTheta)
789 || !reader.Get(arcTheta)) {
790 break;
793 callbacks.draw_arc(userData, *center, *radii, *startTheta,
794 *arcTheta, header->op == B_PIC_FILL_ARC);
795 break;
798 case B_PIC_STROKE_ELLIPSE:
799 case B_PIC_FILL_ELLIPSE:
801 const BRect* rect;
802 if (callbacks.draw_ellipse == NULL || !reader.Get(rect))
803 break;
805 callbacks.draw_ellipse(userData, *rect,
806 header->op == B_PIC_FILL_ELLIPSE);
807 break;
810 case B_PIC_STROKE_POLYGON:
811 case B_PIC_FILL_POLYGON:
813 const uint32* numPoints;
814 const BPoint* points;
815 if (callbacks.draw_polygon == NULL || !reader.Get(numPoints)
816 || !reader.Get(points, *numPoints)) {
817 break;
820 bool isClosed = true;
821 const bool* closedPointer;
822 if (header->op != B_PIC_FILL_POLYGON) {
823 if (!reader.Get(closedPointer))
824 break;
826 isClosed = *closedPointer;
829 callbacks.draw_polygon(userData, *numPoints, points, isClosed,
830 header->op == B_PIC_FILL_POLYGON);
831 break;
834 case B_PIC_STROKE_SHAPE:
835 case B_PIC_FILL_SHAPE:
837 const uint32* opCount;
838 const uint32* pointCount;
839 const uint32* opList;
840 const BPoint* pointList;
841 if (callbacks.draw_shape == NULL || !reader.Get(opCount)
842 || !reader.Get(pointCount) || !reader.Get(opList, *opCount)
843 || !reader.Get(pointList, *pointCount)) {
844 break;
847 // TODO: remove BShape data copying
848 BShape shape;
849 shape.SetData(*opCount, *pointCount, opList, pointList);
851 callbacks.draw_shape(userData, shape,
852 header->op == B_PIC_FILL_SHAPE);
853 break;
856 case B_PIC_DRAW_STRING:
858 const float* escapementSpace;
859 const float* escapementNonSpace;
860 const char* string;
861 size_t length;
862 if (callbacks.draw_string == NULL
863 || !reader.Get(escapementSpace)
864 || !reader.Get(escapementNonSpace)
865 || !reader.GetRemaining(string, length)) {
866 break;
869 callbacks.draw_string(userData, string, length,
870 *escapementSpace, *escapementNonSpace);
871 break;
874 case B_PIC_DRAW_PIXELS:
876 const BRect* sourceRect;
877 const BRect* destinationRect;
878 const uint32* width;
879 const uint32* height;
880 const uint32* bytesPerRow;
881 const uint32* colorSpace;
882 const uint32* flags;
883 const void* data;
884 size_t length;
885 if (callbacks.draw_pixels == NULL || !reader.Get(sourceRect)
886 || !reader.Get(destinationRect) || !reader.Get(width)
887 || !reader.Get(height) || !reader.Get(bytesPerRow)
888 || !reader.Get(colorSpace) || !reader.Get(flags)
889 || !reader.GetRemaining(data, length)) {
890 break;
893 callbacks.draw_pixels(userData, *sourceRect, *destinationRect,
894 *width, *height, *bytesPerRow, (color_space)*colorSpace,
895 *flags, data, length);
896 break;
899 case B_PIC_DRAW_PICTURE:
901 const BPoint* where;
902 const int32* token;
903 if (callbacks.draw_picture == NULL || !reader.Get(where)
904 || !reader.Get(token)) {
905 break;
908 callbacks.draw_picture(userData, *where, *token);
909 break;
912 case B_PIC_SET_CLIPPING_RECTS:
914 const uint32* numRects;
915 const BRect* rects;
916 if (callbacks.set_clipping_rects == NULL
917 || !reader.Get(numRects) || !reader.Get(rects, *numRects)) {
918 break;
921 callbacks.set_clipping_rects(userData, *numRects, rects);
922 break;
925 case B_PIC_CLEAR_CLIPPING_RECTS:
927 if (callbacks.set_clipping_rects == NULL)
928 break;
930 callbacks.set_clipping_rects(userData, 0, NULL);
931 break;
934 case B_PIC_CLIP_TO_PICTURE:
936 const int32* token;
937 const BPoint* where;
938 const bool* inverse;
939 if (callbacks.clip_to_picture == NULL || !reader.Get(token)
940 || !reader.Get(where) || !reader.Get(inverse))
941 break;
943 callbacks.clip_to_picture(userData, *token, *where, *inverse);
944 break;
947 case B_PIC_PUSH_STATE:
949 if (callbacks.push_state == NULL)
950 break;
952 callbacks.push_state(userData);
953 break;
956 case B_PIC_POP_STATE:
958 if (callbacks.pop_state == NULL)
959 break;
961 callbacks.pop_state(userData);
962 break;
965 case B_PIC_ENTER_STATE_CHANGE:
966 case B_PIC_ENTER_FONT_STATE:
968 const void* data;
969 size_t length;
970 if (!reader.GetRemaining(data, length))
971 break;
973 if (header->op == B_PIC_ENTER_STATE_CHANGE) {
974 if (callbacks.enter_state_change != NULL)
975 callbacks.enter_state_change(userData);
976 } else if (callbacks.enter_font_state != NULL)
977 callbacks.enter_font_state(userData);
979 status_t result = _Play(callbacks, userData, data, length,
980 header->op);
981 if (result != B_OK)
982 return result;
984 if (header->op == B_PIC_ENTER_STATE_CHANGE) {
985 if (callbacks.exit_state_change != NULL)
986 callbacks.exit_state_change(userData);
987 } else if (callbacks.exit_font_state != NULL)
988 callbacks.exit_font_state(userData);
990 break;
993 case B_PIC_SET_ORIGIN:
995 const BPoint* origin;
996 if (callbacks.set_origin == NULL || !reader.Get(origin))
997 break;
999 callbacks.set_origin(userData, *origin);
1000 break;
1003 case B_PIC_SET_PEN_LOCATION:
1005 const BPoint* location;
1006 if (callbacks.set_pen_location == NULL || !reader.Get(location))
1007 break;
1009 callbacks.set_pen_location(userData, *location);
1010 break;
1013 case B_PIC_SET_DRAWING_MODE:
1015 const uint16* mode;
1016 if (callbacks.set_drawing_mode == NULL || !reader.Get(mode))
1017 break;
1019 callbacks.set_drawing_mode(userData, (drawing_mode)*mode);
1020 break;
1023 case B_PIC_SET_LINE_MODE:
1025 const uint16* capMode;
1026 const uint16* joinMode;
1027 const float* miterLimit;
1028 if (callbacks.set_line_mode == NULL || !reader.Get(capMode)
1029 || !reader.Get(joinMode) || !reader.Get(miterLimit)) {
1030 break;
1033 callbacks.set_line_mode(userData, (cap_mode)*capMode,
1034 (join_mode)*joinMode, *miterLimit);
1035 break;
1038 case B_PIC_SET_PEN_SIZE:
1040 const float* penSize;
1041 if (callbacks.set_pen_size == NULL || !reader.Get(penSize))
1042 break;
1044 callbacks.set_pen_size(userData, *penSize);
1045 break;
1048 case B_PIC_SET_FORE_COLOR:
1050 const rgb_color* color;
1051 if (callbacks.set_fore_color == NULL || !reader.Get(color))
1052 break;
1054 callbacks.set_fore_color(userData, *color);
1055 break;
1058 case B_PIC_SET_BACK_COLOR:
1060 const rgb_color* color;
1061 if (callbacks.set_back_color == NULL || !reader.Get(color))
1062 break;
1064 callbacks.set_back_color(userData, *color);
1065 break;
1068 case B_PIC_SET_STIPLE_PATTERN:
1070 const pattern* stipplePattern;
1071 if (callbacks.set_stipple_pattern == NULL
1072 || !reader.Get(stipplePattern)) {
1073 break;
1076 callbacks.set_stipple_pattern(userData, *stipplePattern);
1077 break;
1080 case B_PIC_SET_SCALE:
1082 const float* scale;
1083 if (callbacks.set_scale == NULL || !reader.Get(scale))
1084 break;
1086 callbacks.set_scale(userData, *scale);
1087 break;
1090 case B_PIC_SET_FONT_FAMILY:
1092 const char* family;
1093 size_t length;
1094 if (callbacks.set_font_family == NULL
1095 || !reader.GetRemaining(family, length)) {
1096 break;
1099 callbacks.set_font_family(userData, family, length);
1100 break;
1103 case B_PIC_SET_FONT_STYLE:
1105 const char* style;
1106 size_t length;
1107 if (callbacks.set_font_style == NULL
1108 || !reader.GetRemaining(style, length)) {
1109 break;
1112 callbacks.set_font_style(userData, style, length);
1113 break;
1116 case B_PIC_SET_FONT_SPACING:
1118 const uint32* spacing;
1119 if (callbacks.set_font_spacing == NULL || !reader.Get(spacing))
1120 break;
1122 callbacks.set_font_spacing(userData, *spacing);
1123 break;
1126 case B_PIC_SET_FONT_SIZE:
1128 const float* size;
1129 if (callbacks.set_font_size == NULL || !reader.Get(size))
1130 break;
1132 callbacks.set_font_size(userData, *size);
1133 break;
1136 case B_PIC_SET_FONT_ROTATE:
1138 const float* rotation;
1139 if (callbacks.set_font_rotation == NULL
1140 || !reader.Get(rotation)) {
1141 break;
1144 callbacks.set_font_rotation(userData, *rotation);
1145 break;
1148 case B_PIC_SET_FONT_ENCODING:
1150 const uint32* encoding;
1151 if (callbacks.set_font_encoding == NULL
1152 || !reader.Get(encoding)) {
1153 break;
1156 callbacks.set_font_encoding(userData, *encoding);
1157 break;
1160 case B_PIC_SET_FONT_FLAGS:
1162 const uint32* flags;
1163 if (callbacks.set_font_flags == NULL || !reader.Get(flags))
1164 break;
1166 callbacks.set_font_flags(userData, *flags);
1167 break;
1170 case B_PIC_SET_FONT_SHEAR:
1172 const float* shear;
1173 if (callbacks.set_font_shear == NULL || !reader.Get(shear))
1174 break;
1176 callbacks.set_font_shear(userData, *shear);
1177 break;
1180 case B_PIC_SET_FONT_FACE:
1182 const uint32* face;
1183 if (callbacks.set_font_face == NULL || !reader.Get(face))
1184 break;
1186 callbacks.set_font_face(userData, *face);
1187 break;
1190 case B_PIC_SET_BLENDING_MODE:
1192 const uint16* alphaSourceMode;
1193 const uint16* alphaFunctionMode;
1194 if (callbacks.set_blending_mode == NULL
1195 || !reader.Get(alphaSourceMode)
1196 || !reader.Get(alphaFunctionMode)) {
1197 break;
1200 callbacks.set_blending_mode(userData,
1201 (source_alpha)*alphaSourceMode,
1202 (alpha_function)*alphaFunctionMode);
1203 break;
1206 case B_PIC_SET_TRANSFORM:
1208 const BAffineTransform* transform;
1209 if (callbacks.set_transform == NULL || !reader.Get(transform))
1210 break;
1212 callbacks.set_transform(userData, *transform);
1213 break;
1216 case B_PIC_AFFINE_TRANSLATE:
1218 const double* x;
1219 const double* y;
1220 if (callbacks.translate_by == NULL || !reader.Get(x)
1221 || !reader.Get(y)) {
1222 break;
1225 callbacks.translate_by(userData, *x, *y);
1226 break;
1229 case B_PIC_AFFINE_SCALE:
1231 const double* x;
1232 const double* y;
1233 if (callbacks.scale_by == NULL || !reader.Get(x)
1234 || !reader.Get(y)) {
1235 break;
1238 callbacks.scale_by(userData, *x, *y);
1239 break;
1242 case B_PIC_AFFINE_ROTATE:
1244 const double* angleRadians;
1245 if (callbacks.rotate_by == NULL || !reader.Get(angleRadians))
1246 break;
1248 callbacks.rotate_by(userData, *angleRadians);
1249 break;
1252 case B_PIC_BLEND_LAYER:
1254 Layer* const* layer;
1255 if (callbacks.blend_layer == NULL || !reader.Get<Layer*>(layer))
1256 break;
1258 callbacks.blend_layer(userData, *layer);
1259 break;
1262 case B_PIC_CLIP_TO_RECT:
1264 const bool* inverse;
1265 const BRect* rect;
1267 if (callbacks.clip_to_rect == NULL || !reader.Get(inverse)
1268 || !reader.Get(rect)) {
1269 break;
1272 callbacks.clip_to_rect(userData, *rect, *inverse);
1273 break;
1276 case B_PIC_CLIP_TO_SHAPE:
1278 const bool* inverse;
1279 const uint32* opCount;
1280 const uint32* pointCount;
1281 const uint32* opList;
1282 const BPoint* pointList;
1283 if (callbacks.clip_to_shape == NULL || !reader.Get(inverse)
1284 || !reader.Get(opCount) || !reader.Get(pointCount)
1285 || !reader.Get(opList, *opCount)
1286 || !reader.Get(pointList, *pointCount)) {
1287 break;
1290 callbacks.clip_to_shape(userData, *opCount, opList,
1291 *pointCount, pointList, *inverse);
1292 break;
1295 default:
1296 break;
1299 #if DEBUG
1300 numOps++;
1301 #if DEBUG > 1
1302 printf("executed in %" B_PRId64 " usecs\n", system_time()
1303 - startOpTime);
1304 #endif
1305 #endif
1308 #if DEBUG
1309 printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64
1310 " usecs.\n", numOps, system_time() - startTime);
1311 #endif
1312 return B_OK;