2 * Copyright 2001-2007, Haiku Inc.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
8 * Marcus Overhagen (marcus@overhagen.de)
11 /** PicturePlayer is used to play picture data. */
13 #include <PicturePlayer.h>
18 #include <AffineTransform.h>
19 #include <PictureProtocol.h>
23 using BPrivate::PicturePlayer
;
26 typedef void (*fnc
)(void*);
27 typedef void (*fnc_BPoint
)(void*, BPoint
);
28 typedef void (*fnc_BPointBPoint
)(void*, BPoint
, BPoint
);
29 typedef void (*fnc_BRect
)(void*, BRect
);
30 typedef void (*fnc_BRectBPoint
)(void*, BRect
, BPoint
);
31 typedef void (*fnc_PBPoint
)(void*, const BPoint
*);
32 typedef void (*fnc_i
)(void*, int32
);
33 typedef void (*fnc_iPBPointb
)(void*, int32
, const BPoint
*, bool);
34 typedef void (*fnc_iPBPoint
)(void*, int32
, const BPoint
*);
35 typedef void (*fnc_Pc
)(void*, const char*);
36 typedef void (*fnc_Pcff
)(void*, const char*, float, float);
37 typedef void (*fnc_BPointBPointff
)(void*, BPoint
, BPoint
, float, float);
38 typedef void (*fnc_s
)(void*, int16
);
39 typedef void (*fnc_ssf
)(void*, int16
, int16
, float);
40 typedef void (*fnc_f
)(void*, float);
41 typedef void (*fnc_Color
)(void*, rgb_color
);
42 typedef void (*fnc_Pattern
)(void*, pattern
);
43 typedef void (*fnc_ss
)(void *, int16
, int16
);
44 typedef void (*fnc_PBRecti
)(void*, const BRect
*, uint32
);
45 typedef void (*fnc_DrawPixels
)(void *, BRect
, BRect
, int32
, int32
, int32
,
46 int32
, int32
, const void *);
47 typedef void (*fnc_DrawPicture
)(void *, BPoint
, int32
);
48 typedef void (*fnc_BShape
)(void*, BShape
*);
49 typedef void (*fnc_BAffineTransform
)(void*, BAffineTransform
);
60 PictureOpToString(int op
)
62 #define RETURN_STRING(x) case x: return #x
65 RETURN_STRING(B_PIC_MOVE_PEN_BY
);
66 RETURN_STRING(B_PIC_STROKE_LINE
);
67 RETURN_STRING(B_PIC_STROKE_RECT
);
68 RETURN_STRING(B_PIC_FILL_RECT
);
69 RETURN_STRING(B_PIC_STROKE_ROUND_RECT
);
70 RETURN_STRING(B_PIC_FILL_ROUND_RECT
);
71 RETURN_STRING(B_PIC_STROKE_BEZIER
);
72 RETURN_STRING(B_PIC_FILL_BEZIER
);
73 RETURN_STRING(B_PIC_STROKE_POLYGON
);
74 RETURN_STRING(B_PIC_FILL_POLYGON
);
75 RETURN_STRING(B_PIC_STROKE_SHAPE
);
76 RETURN_STRING(B_PIC_FILL_SHAPE
);
77 RETURN_STRING(B_PIC_DRAW_STRING
);
78 RETURN_STRING(B_PIC_DRAW_PIXELS
);
79 RETURN_STRING(B_PIC_DRAW_PICTURE
);
80 RETURN_STRING(B_PIC_STROKE_ARC
);
81 RETURN_STRING(B_PIC_FILL_ARC
);
82 RETURN_STRING(B_PIC_STROKE_ELLIPSE
);
83 RETURN_STRING(B_PIC_FILL_ELLIPSE
);
85 RETURN_STRING(B_PIC_ENTER_STATE_CHANGE
);
86 RETURN_STRING(B_PIC_SET_CLIPPING_RECTS
);
87 RETURN_STRING(B_PIC_CLIP_TO_PICTURE
);
88 RETURN_STRING(B_PIC_PUSH_STATE
);
89 RETURN_STRING(B_PIC_POP_STATE
);
90 RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS
);
92 RETURN_STRING(B_PIC_SET_ORIGIN
);
93 RETURN_STRING(B_PIC_SET_PEN_LOCATION
);
94 RETURN_STRING(B_PIC_SET_DRAWING_MODE
);
95 RETURN_STRING(B_PIC_SET_LINE_MODE
);
96 RETURN_STRING(B_PIC_SET_PEN_SIZE
);
97 RETURN_STRING(B_PIC_SET_SCALE
);
98 RETURN_STRING(B_PIC_SET_TRANSFORM
);
99 RETURN_STRING(B_PIC_SET_FORE_COLOR
);
100 RETURN_STRING(B_PIC_SET_BACK_COLOR
);
101 RETURN_STRING(B_PIC_SET_STIPLE_PATTERN
);
102 RETURN_STRING(B_PIC_ENTER_FONT_STATE
);
103 RETURN_STRING(B_PIC_SET_BLENDING_MODE
);
104 RETURN_STRING(B_PIC_SET_FONT_FAMILY
);
105 RETURN_STRING(B_PIC_SET_FONT_STYLE
);
106 RETURN_STRING(B_PIC_SET_FONT_SPACING
);
107 RETURN_STRING(B_PIC_SET_FONT_ENCODING
);
108 RETURN_STRING(B_PIC_SET_FONT_FLAGS
);
109 RETURN_STRING(B_PIC_SET_FONT_SIZE
);
110 RETURN_STRING(B_PIC_SET_FONT_ROTATE
);
111 RETURN_STRING(B_PIC_SET_FONT_SHEAR
);
112 RETURN_STRING(B_PIC_SET_FONT_BPP
);
113 RETURN_STRING(B_PIC_SET_FONT_FACE
);
114 default: return "Unknown op";
121 PicturePlayer::PicturePlayer(const void *data
, size_t size
, BList
*pictures
)
129 PicturePlayer::~PicturePlayer()
135 PicturePlayer::Play(void **callBackTable
, int32 tableEntries
, void *userData
)
137 // We don't check if the functions in the table are NULL, but we
138 // check the tableEntries to see if the table is big enough.
139 // If an application supplies the wrong size or an invalid pointer,
140 // it's its own fault.
142 FILE *file
= fopen("/var/log/PicturePlayer.log", "a");
143 fprintf(file
, "Start rendering BPicture...\n");
144 bigtime_t startTime
= system_time();
147 // If the caller supplied a function table smaller than needed,
148 // we use our dummy table, and copy the supported ops from the supplied one.
149 void **functionTable
= callBackTable
;
150 void *dummyTable
[kOpsTableSize
] = {
151 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
152 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
153 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
154 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
155 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
156 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
157 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
158 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
159 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
160 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
161 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
,
162 (void *)nop
, (void *)nop
, (void *)nop
, (void *)nop
165 if ((uint32
)tableEntries
< kOpsTableSize
) {
167 fprintf(file
, "PicturePlayer: A smaller than needed function table was supplied.\n");
169 functionTable
= dummyTable
;
170 memcpy(functionTable
, callBackTable
, tableEntries
* sizeof(void *));
173 const char *data
= reinterpret_cast<const char *>(fData
);
176 int32 fontStateBlockSize
= -1;
177 int32 stateBlockSize
= -1;
179 while ((pos
+ 6) <= fSize
) {
180 int16 op
= *reinterpret_cast<const int16
*>(data
);
181 int32 size
= *reinterpret_cast<const int32
*>(data
+ 2);
185 if (pos
+ size
> fSize
)
186 debugger("PicturePlayer::Play: buffer overrun\n");
189 bigtime_t startOpTime
= system_time();
190 fprintf(file
, "Op %s ", PictureOpToString(op
));
193 case B_PIC_MOVE_PEN_BY
:
195 ((fnc_BPoint
)functionTable
[1])(userData
,
196 *reinterpret_cast<const BPoint
*>(data
)); /* where */
200 case B_PIC_STROKE_LINE
:
202 ((fnc_BPointBPoint
)functionTable
[2])(userData
,
203 *reinterpret_cast<const BPoint
*>(data
), /* start */
204 *reinterpret_cast<const BPoint
*>(data
+ sizeof(BPoint
))); /* end */
208 case B_PIC_STROKE_RECT
:
210 ((fnc_BRect
)functionTable
[3])(userData
,
211 *reinterpret_cast<const BRect
*>(data
)); /* rect */
215 case B_PIC_FILL_RECT
:
217 ((fnc_BRect
)functionTable
[4])(userData
,
218 *reinterpret_cast<const BRect
*>(data
)); /* rect */
222 case B_PIC_STROKE_ROUND_RECT
:
224 ((fnc_BRectBPoint
)functionTable
[5])(userData
,
225 *reinterpret_cast<const BRect
*>(data
), /* rect */
226 *reinterpret_cast<const BPoint
*>(data
+ sizeof(BRect
))); /* radii */
230 case B_PIC_FILL_ROUND_RECT
:
232 ((fnc_BRectBPoint
)functionTable
[6])(userData
,
233 *reinterpret_cast<const BRect
*>(data
), /* rect */
234 *reinterpret_cast<const BPoint
*>(data
+ sizeof(BRect
))); /* radii */
238 case B_PIC_STROKE_BEZIER
:
240 ((fnc_PBPoint
)functionTable
[7])(userData
,
241 reinterpret_cast<const BPoint
*>(data
));
245 case B_PIC_FILL_BEZIER
:
247 ((fnc_PBPoint
)functionTable
[8])(userData
,
248 reinterpret_cast<const BPoint
*>(data
));
252 case B_PIC_STROKE_ARC
:
254 ((fnc_BPointBPointff
)functionTable
[9])(userData
,
255 *reinterpret_cast<const BPoint
*>(data
), /* center */
256 *reinterpret_cast<const BPoint
*>(data
+ sizeof(BPoint
)), /* radii */
257 *reinterpret_cast<const float *>(data
+ 2 * sizeof(BPoint
)), /* startTheta */
258 *reinterpret_cast<const float *>(data
+ 2 * sizeof(BPoint
) + sizeof(float))); /* arcTheta */
264 ((fnc_BPointBPointff
)functionTable
[10])(userData
,
265 *reinterpret_cast<const BPoint
*>(data
), /* center */
266 *reinterpret_cast<const BPoint
*>(data
+ sizeof(BPoint
)), /* radii */
267 *reinterpret_cast<const float *>(data
+ 2 * sizeof(BPoint
)), /* startTheta */
268 *reinterpret_cast<const float *>(data
+ 2 * sizeof(BPoint
) + sizeof(float))); /* arcTheta */
272 case B_PIC_STROKE_ELLIPSE
:
274 const BRect
*rect
= reinterpret_cast<const BRect
*>(data
);
275 BPoint
radii((rect
->Width() + 1) / 2.0f
, (rect
->Height() + 1) / 2.0f
);
276 BPoint center
= rect
->LeftTop() + radii
;
277 ((fnc_BPointBPoint
)functionTable
[11])(userData
, center
, radii
);
281 case B_PIC_FILL_ELLIPSE
:
283 const BRect
*rect
= reinterpret_cast<const BRect
*>(data
);
284 BPoint
radii((rect
->Width() + 1) / 2.0f
, (rect
->Height() + 1) / 2.0f
);
285 BPoint center
= rect
->LeftTop() + radii
;
286 ((fnc_BPointBPoint
)functionTable
[12])(userData
, center
, radii
);
290 case B_PIC_STROKE_POLYGON
:
292 int32 numPoints
= *reinterpret_cast<const int32
*>(data
);
293 ((fnc_iPBPointb
)functionTable
[13])(userData
,
295 reinterpret_cast<const BPoint
*>(data
+ sizeof(int32
)), /* points */
296 *reinterpret_cast<const uint8
*>(data
+ sizeof(int32
) + numPoints
* sizeof(BPoint
))); /* is-closed */
300 case B_PIC_FILL_POLYGON
:
302 ((fnc_iPBPoint
)functionTable
[14])(userData
,
303 *reinterpret_cast<const int32
*>(data
), /* numPoints */
304 reinterpret_cast<const BPoint
*>(data
+ sizeof(int32
))); /* points */
308 case B_PIC_STROKE_SHAPE
:
309 case B_PIC_FILL_SHAPE
:
311 const bool stroke
= (op
== B_PIC_STROKE_SHAPE
);
312 int32 opCount
= *reinterpret_cast<const int32
*>(data
);
313 int32 ptCount
= *reinterpret_cast<const int32
*>(data
+ sizeof(int32
));
314 const uint32
*opList
= reinterpret_cast<const uint32
*>(data
+ 2 * sizeof(int32
));
315 const BPoint
*ptList
= reinterpret_cast<const BPoint
*>(data
+ 2 * sizeof(int32
) + opCount
* sizeof(uint32
));
317 // TODO: remove BShape data copying
319 shape
.SetData(opCount
, ptCount
, opList
, ptList
);
321 const int32 tableIndex
= stroke
? 15 : 16;
322 ((fnc_BShape
)functionTable
[tableIndex
])(userData
, &shape
);
326 case B_PIC_DRAW_STRING
:
328 ((fnc_Pcff
)functionTable
[17])(userData
,
329 reinterpret_cast<const char *>(data
+ 2 * sizeof(float)), /* string */
330 *reinterpret_cast<const float *>(data
), /* escapement.space */
331 *reinterpret_cast<const float *>(data
+ sizeof(float))); /* escapement.nonspace */
335 case B_PIC_DRAW_PIXELS
:
337 ((fnc_DrawPixels
)functionTable
[18])(userData
,
338 *reinterpret_cast<const BRect
*>(data
), /* src */
339 *reinterpret_cast<const BRect
*>(data
+ 1 * sizeof(BRect
)), /* dst */
340 *reinterpret_cast<const int32
*>(data
+ 2 * sizeof(BRect
)), /* width */
341 *reinterpret_cast<const int32
*>(data
+ 2 * sizeof(BRect
) + 1 * sizeof(int32
)), /* height */
342 *reinterpret_cast<const int32
*>(data
+ 2 * sizeof(BRect
) + 2 * sizeof(int32
)), /* bytesPerRow */
343 *reinterpret_cast<const int32
*>(data
+ 2 * sizeof(BRect
) + 3 * sizeof(int32
)), /* pixelFormat */
344 *reinterpret_cast<const int32
*>(data
+ 2 * sizeof(BRect
) + 4 * sizeof(int32
)), /* flags */
345 reinterpret_cast<const void *>(data
+ 2 * sizeof(BRect
) + 5 * sizeof(int32
))); /* data */
349 case B_PIC_DRAW_PICTURE
:
351 ((fnc_DrawPicture
)functionTable
[19])(userData
,
352 *reinterpret_cast<const BPoint
*>(data
),
353 *reinterpret_cast<const int32
*>(data
+ sizeof(BPoint
)));
357 case B_PIC_SET_CLIPPING_RECTS
:
359 // TODO: Not sure if it's compatible with R5's BPicture version
360 const uint32 numRects
= *reinterpret_cast<const uint32
*>(data
);
361 const BRect
*rects
= reinterpret_cast<const BRect
*>(data
+ sizeof(uint32
));
362 ((fnc_PBRecti
)functionTable
[20])(userData
, rects
, numRects
);
367 case B_PIC_CLEAR_CLIPPING_RECTS
:
369 ((fnc_PBRecti
)functionTable
[20])(userData
, NULL
, 0);
373 case B_PIC_CLIP_TO_PICTURE
:
379 case B_PIC_PUSH_STATE
:
381 ((fnc
)functionTable
[22])(userData
);
385 case B_PIC_POP_STATE
:
387 ((fnc
)functionTable
[23])(userData
);
391 case B_PIC_ENTER_STATE_CHANGE
:
393 ((fnc
)functionTable
[24])(userData
);
394 stateBlockSize
= size
;
398 case B_PIC_ENTER_FONT_STATE
:
400 ((fnc
)functionTable
[26])(userData
);
401 fontStateBlockSize
= size
;
405 case B_PIC_SET_ORIGIN
:
407 ((fnc_BPoint
)functionTable
[28])(userData
,
408 *reinterpret_cast<const BPoint
*>(data
)); /* origin */
412 case B_PIC_SET_PEN_LOCATION
:
414 ((fnc_BPoint
)functionTable
[29])(userData
,
415 *reinterpret_cast<const BPoint
*>(data
)); /* location */
419 case B_PIC_SET_DRAWING_MODE
:
421 ((fnc_s
)functionTable
[30])(userData
,
422 *reinterpret_cast<const int16
*>(data
)); /* mode */
426 case B_PIC_SET_LINE_MODE
:
428 ((fnc_ssf
)functionTable
[31])(userData
,
429 *reinterpret_cast<const int16
*>(data
), /* cap-mode */
430 *reinterpret_cast<const int16
*>(data
+ 1 * sizeof(int16
)), /* join-mode */
431 *reinterpret_cast<const float *>(data
+ 2 * sizeof(int16
))); /* miter-limit */
435 case B_PIC_SET_PEN_SIZE
:
437 ((fnc_f
)functionTable
[32])(userData
,
438 *reinterpret_cast<const float *>(data
)); /* size */
442 case B_PIC_SET_FORE_COLOR
:
444 ((fnc_Color
)functionTable
[33])(userData
,
445 *reinterpret_cast<const rgb_color
*>(data
)); /* color */
449 case B_PIC_SET_BACK_COLOR
:
451 ((fnc_Color
)functionTable
[34])(userData
,
452 *reinterpret_cast<const rgb_color
*>(data
)); /* color */
456 case B_PIC_SET_STIPLE_PATTERN
:
458 ((fnc_Pattern
)functionTable
[35])(userData
,
459 *reinterpret_cast<const pattern
*>(data
)); /* pattern */
463 case B_PIC_SET_SCALE
:
465 ((fnc_f
)functionTable
[36])(userData
,
466 *reinterpret_cast<const float *>(data
)); /* scale */
470 case B_PIC_SET_FONT_FAMILY
:
472 ((fnc_Pc
)functionTable
[37])(userData
,
473 reinterpret_cast<const char *>(data
)); /* string */
477 case B_PIC_SET_FONT_STYLE
:
479 ((fnc_Pc
)functionTable
[38])(userData
,
480 reinterpret_cast<const char *>(data
)); /* string */
484 case B_PIC_SET_FONT_SPACING
:
486 ((fnc_i
)functionTable
[39])(userData
,
487 *reinterpret_cast<const int32
*>(data
)); /* spacing */
491 case B_PIC_SET_FONT_SIZE
:
493 ((fnc_f
)functionTable
[40])(userData
,
494 *reinterpret_cast<const float *>(data
)); /* size */
498 case B_PIC_SET_FONT_ROTATE
:
500 ((fnc_f
)functionTable
[41])(userData
,
501 *reinterpret_cast<const float *>(data
)); /* rotation */
505 case B_PIC_SET_FONT_ENCODING
:
507 ((fnc_i
)functionTable
[42])(userData
,
508 *reinterpret_cast<const int32
*>(data
)); /* encoding */
512 case B_PIC_SET_FONT_FLAGS
:
514 ((fnc_i
)functionTable
[43])(userData
,
515 *reinterpret_cast<const int32
*>(data
)); /* flags */
519 case B_PIC_SET_FONT_SHEAR
:
521 ((fnc_f
)functionTable
[44])(userData
,
522 *reinterpret_cast<const float *>(data
)); /* shear */
526 case B_PIC_SET_FONT_FACE
:
528 ((fnc_i
)functionTable
[46])(userData
,
529 *reinterpret_cast<const int32
*>(data
)); /* flags */
533 case B_PIC_SET_BLENDING_MODE
:
535 ((fnc_ss
)functionTable
[47])(userData
,
536 *reinterpret_cast<const int16
*>(data
), /* alphaSrcMode */
537 *reinterpret_cast<const int16
*>(data
+ sizeof(int16
))); /* alphaFncMode */
541 case B_PIC_SET_TRANSFORM
:
543 ((fnc_BAffineTransform
)functionTable
[48])(userData
,
544 *reinterpret_cast<const BAffineTransform
*>(data
));
552 // Skip the already handled block unless it's one of these two,
553 // since they can contain other nested ops.
554 if (op
!= B_PIC_ENTER_STATE_CHANGE
&& op
!= B_PIC_ENTER_FONT_STATE
) {
557 if (stateBlockSize
> 0)
558 stateBlockSize
-= size
+ 6;
559 if (fontStateBlockSize
> 0)
560 fontStateBlockSize
-= size
+ 6;
563 // call the exit_state_change hook if needed
564 if (stateBlockSize
== 0) {
565 ((fnc
)functionTable
[25])(userData
);
569 // call the exit_font_state hook if needed
570 if (fontStateBlockSize
== 0) {
571 ((fnc
)functionTable
[27])(userData
);
572 fontStateBlockSize
= -1;
577 fprintf(file
, "executed in %" B_PRId64
" usecs\n", system_time()
581 // TODO: what if too much was read, should we return B_ERROR?
585 fprintf(file
, "Done! %" B_PRId32
" ops, rendering completed in %"
586 B_PRId64
" usecs.\n", numOps
, system_time() - startTime
);