3 functions for rendering swf content
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2004 Mederra Oy <http://www.mederra.fi>
9 Copyright (c) 2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31 typedef struct _renderpoint
42 enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
57 // texture- & gradientfill;
63 typedef struct _renderline
65 TAG*points; //incremented in 128 byte steps
67 U32 pending_clipdepth;
70 typedef struct _bitmap {
78 typedef struct _renderbuf_internal
94 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
96 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
97 if(x >= i->width2 || y >= i->height2 || y<0) return;
99 if(y<i->ymin) i->ymin = y;
100 if(y>i->ymax) i->ymax = y;
103 swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
106 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
107 problem appears to often */
110 #define INT(x) ((int)((x)+16)-16)
112 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
114 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
116 double ny1, ny2, stepx;
118 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
119 printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
121 assert(p->shapeline);
147 ny1 = INT(y1) + 1.0 + CUT;
150 ny2 = INT(y2) - 1.0 + CUT;
157 x1 = x1 + (ny1-y1)*stepx;
158 x2 = x2 + (ny2-y2)*stepx;
167 float xx = (float)(startx + posx);
168 add_pixel(buf, xx ,posy, p);
174 #define PI 3.14159265358979
175 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
177 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
190 /* Make sure the line is always at least one pixel wide */
192 /* That's what Macromedia's Player does at least at zoom level >= 1. */
195 /* That's what Macromedia's Player seems to do at zoom level 0. */
196 /* TODO: needs testing */
201 sd = (double)dx*(double)dx+(double)dy*(double)dy;
223 add_line(buf, x1+vx, y1+vy, xx, yy, p);
226 for(t=1;t<segments;t++) {
227 double s = sin(t*PI/segments);
228 double c = cos(t*PI/segments);
229 xx = (x2 + vx*c - vy*s);
230 yy = (y2 + vx*s + vy*c);
231 add_line(buf, lastx, lasty, xx, yy, p);
238 add_line(buf, lastx, lasty, xx, yy, p);
243 add_line(buf, lastx, lasty, xx, yy, p);
246 for(t=1;t<segments;t++) {
247 double s = sin(t*PI/segments);
248 double c = cos(t*PI/segments);
249 xx = (x1 - vx*c + vy*s);
250 yy = (y1 - vx*s - vy*c);
251 add_line(buf, lastx, lasty, xx, yy, p);
255 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
258 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
263 d = swf_TurnPoint(p, m);
268 static int compare_renderpoints(const void * _a, const void * _b)
270 renderpoint_t*a = (renderpoint_t*)_a;
271 renderpoint_t*b = (renderpoint_t*)_b;
272 if(a->x < b->x) return -1;
273 if(a->x > b->x) return 1;
277 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
279 renderbuf_internal*i;
281 memset(buf, 0, sizeof(RENDERBUF));
282 buf->width = width*multiply;
283 buf->height = height*multiply;
286 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
287 i = (renderbuf_internal*)buf->internal;
288 i->antialize = !!antialize;
289 i->multiply = antialize?multiply*2:multiply;
290 i->height2 = antialize?2*buf->height:buf->height;
291 i->width2 = antialize?2*buf->width:buf->width;
292 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
293 for(y=0;y<i->height2;y++) {
294 memset(&i->lines[y], 0, sizeof(renderline_t));
295 i->lines[y].points = swf_InsertTag(0, 0);
298 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
299 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
301 i->ymin = 0x7fffffff;
302 i->ymax = -0x80000000;
304 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
306 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
308 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
311 int xstep=width*65536/i->width2;
312 int ystep=height*65536/i->height2;
313 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
314 RGBA*src = &img[(yy>>16) * width];
315 RGBA*line = &i->img[y * i->width2];
316 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
317 line[x] = src[xx>>16];
321 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
323 swf_Render_SetBackground(buf, &color, 1, 1);
325 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
327 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
329 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
333 bm->data = rfx_alloc(width*height*4);
334 memcpy(bm->data, img, width*height*4);
336 bm->next = i->bitmaps;
339 void swf_Render_ClearCanvas(RENDERBUF*dest)
341 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
343 for(y=0;y<i->height2;y++) {
344 swf_ClearTag(i->lines[y].points);
346 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
347 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
349 void swf_Render_Delete(RENDERBUF*dest)
351 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
353 bitmap_t*b = i->bitmaps;
359 /* delete line buffers */
360 for(y=0;y<i->height2;y++) {
361 swf_DeleteTag(i->lines[y].points);
362 i->lines[y].points = 0;
367 bitmap_t*next = b->next;
368 free(b->data);b->data=0;
373 rfx_free(i->lines); i->lines = 0;
374 rfx_free(dest->internal); dest->internal = 0;
377 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
379 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
381 s->numfillstyles = shape->numlinestyles;
382 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
383 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
384 for(t=0;t<shape->numlinestyles;t++) {
385 s->lines[t].fillstyle0 = t+1;
386 s->fillstyles[t].type = FILL_SOLID;
387 s->fillstyles[t].color = shape->linestyles[t].color;
392 void swf_Process(RENDERBUF*dest, U32 clipdepth);
394 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
396 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
406 memset(&p, 0, sizeof(renderpoint_t));
407 memset(&lp, 0, sizeof(renderpoint_t));
409 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
410 p.depth = _depth << 16;
412 mat.tx -= dest->posx*20;
413 mat.ty -= dest->posy*20;
415 s2 = swf_Shape2Clone(shape);
417 if(shape->numfillstyles) {
420 /* multiply fillstyles matrices with placement matrix-
421 important for texture and gradient fill */
422 for(t=0;t<s2->numfillstyles;t++) {
424 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
425 nm.sx *= i->multiply;
426 nm.sy *= i->multiply;
427 nm.r0 *= i->multiply;
428 nm.r1 *= i->multiply;
429 nm.tx *= i->multiply;
430 nm.ty *= i->multiply;
431 s2->fillstyles[t].m = nm;
435 if(shape->numlinestyles) {
436 lshape = linestyle2fillstyle(shape);
438 lp.depth = (_depth << 16)+1;
443 int x1,y1,x2,y2,x3,y3;
445 if(line->type == moveTo) {
446 } else if(line->type == lineTo) {
447 transform_point(&mat, x, y, &x1, &y1);
448 transform_point(&mat, line->x, line->y, &x3, &y3);
450 if(line->linestyle && ! clipdepth) {
451 lp.shapeline = &lshape->lines[line->linestyle-1];
452 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
455 if(line->fillstyle0 || line->fillstyle1) {
456 assert(shape->numfillstyles);
458 add_line(dest, x1, y1, x3, y3, &p);
460 } else if(line->type == splineTo) {
461 int c,t,parts,qparts;
464 transform_point(&mat, x, y, &x1, &y1);
465 transform_point(&mat, line->sx, line->sy, &x2, &y2);
466 transform_point(&mat, line->x, line->y, &x3, &y3);
468 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
472 parts = (int)(sqrt(c)/3);
473 if(!parts) parts = 1;
475 for(t=1;t<=parts;t++) {
476 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
477 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
479 if(line->linestyle && ! clipdepth) {
480 lp.shapeline = &lshape->lines[line->linestyle-1];
481 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
484 if(line->fillstyle0 || line->fillstyle1) {
485 assert(shape->numfillstyles);
487 add_line(dest, xx, yy, nx, ny, &p);
499 swf_Process(dest, clipdepth);
502 swf_Shape2Free(s2);rfx_free(s2);s2=0;
505 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
510 static RGBA color_red = {255,255,0,0};
511 static RGBA color_white = {255,255,255,255};
513 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
525 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
530 int ainv = 255-col.a;
531 col.r = (col.r*col.a)>>8;
532 col.g = (col.g*col.a)>>8;
533 col.b = (col.b*col.a)>>8;
537 line[x].r = ((line[x].r*ainv)>>8)+col.r;
538 line[x].g = ((line[x].g*ainv)>>8)+col.g;
539 line[x].b = ((line[x].b*ainv)>>8)+col.b;
554 static void fill_bitmap(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clipbitmap, U32 depth)
557 double m11=m->sx/65536.0, m21=m->r1/65536.0;
558 double m12=m->r0/65536.0, m22=m->sy/65536.0;
559 double rx = m->tx/20.0;
560 double ry = m->ty/20.0;
561 double det = m11*m22 - m12*m21;
562 if(fabs(det) < 0.0005) {
563 /* x direction equals y direction- the image is invisible */
568 if(!b->width || !b->height) {
569 fill_solid(line, z, y, x1, x2, color_red, depth);
576 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
577 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
582 if(xx>=b->width) xx = b->width-1;
584 if(yy>=b->height) yy = b->height-1;
590 col = b->data[yy*b->width+xx];
593 line[x].r = ((line[x].r*ainv)>>8)+col.r;
594 line[x].g = ((line[x].g*ainv)>>8)+col.g;
595 line[x].b = ((line[x].b*ainv)>>8)+col.b;
603 typedef struct _layer {
615 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
617 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
620 layer_t*l = fillstate->layers;
622 if(x1>=x2) //zero width? nothing to do.
627 /* not filled. TODO: we should never add those in the first place */
629 printf("(not filled)");
630 } else if(l->fillid > l->p->s->numfillstyles) {
631 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
632 } else if(clipdepth) {
633 /* filled region- not used for clipping */
638 printf("(%d -> %d style %d)", x1, x2, l->fillid);
640 f = &l->p->s->fillstyles[l->fillid-1];
642 if(f->type == FILL_SOLID) {
643 /* plain color fill */
644 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
645 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
646 /* TODO: optimize (do this in add_pixel()?) */
647 bitmap_t* b = i->bitmaps;
648 while(b && b->id != f->id_bitmap) {
652 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
653 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
655 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth);
658 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
663 if(clip && clipdepth) {
664 fill_clip(line, zline, y, x1, x2, clipdepth);
668 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
670 layer_t*last=0,*l = state->layers;
671 while(l && l->p->depth < depth) {
676 if(l && l->p->depth == depth)
681 static void delete_layer(state_t*state, layer_t*todel)
683 layer_t*before=todel->prev;
684 layer_t*next = todel->next;
687 state->layers = next;
693 before->next->prev = before;
696 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
699 toadd->next = state->layers;
703 toadd->next = before->next;
704 toadd->prev = before;
705 before->next = toadd;
708 toadd->next->prev = toadd;
710 static void free_layers(state_t* state)
712 layer_t*l = state->layers;
714 layer_t*next = l->next;
720 static void change_state(int y, state_t* state, renderpoint_t*p)
722 layer_t*before=0, *self=0, *after=0;
725 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
728 search_layer(state, p->depth, &before, &self, &after);
732 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
734 if(DEBUG&2) printf("<D>");
736 delete_layer(state, self);
738 /*both fill0 and fill1 are set- exchange the two, updating the layer */
739 if(self->fillid == p->shapeline->fillstyle0) {
740 self->fillid = p->shapeline->fillstyle1;
742 if(DEBUG&2) printf("<X>");
743 } else if(self->fillid == p->shapeline->fillstyle1) {
744 self->fillid = p->shapeline->fillstyle0;
746 if(DEBUG&2) printf("<X>");
748 /* buggy shape. keep everything as-is. */
749 if(DEBUG&2) printf("<!>");
750 //fprintf(stderr, "<line %d: bad swap>\n", y);
756 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
757 /* this is a hack- a better way would be to make sure that
758 we always get (0,32), (32, 33), (33, 0) in the right order if
759 they happen to fall on the same pixel.
760 (not: (0,32), (33, 0), (32, 33))
762 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
766 n = rfx_calloc(sizeof(layer_t));
768 if(DEBUG&2) printf("<+>");
770 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
773 add_layer(state, before, n);
777 void swf_Process(RENDERBUF*dest, U32 clipdepth)
779 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
782 if(i->ymax < i->ymin) {
783 /* shape is empty. return.
784 only, if it's a clipshape, remember the clipdepth */
786 for(y=0;y<i->height2;y++) {
787 if(clipdepth > i->lines[y].pending_clipdepth)
788 i->lines[y].pending_clipdepth = clipdepth;
791 return; //nothing (else) to do
795 /* lines outside the clip shape are not filled
796 immediately, only the highest clipdepth so far is
797 stored there. They will be clipfilled once there's
798 actually something about to happen in that line */
799 for(y=0;y<i->ymin;y++) {
800 if(clipdepth > i->lines[y].pending_clipdepth)
801 i->lines[y].pending_clipdepth = clipdepth;
803 for(y=i->ymax+1;y<i->height2;y++) {
804 if(clipdepth > i->lines[y].pending_clipdepth)
805 i->lines[y].pending_clipdepth = clipdepth;
809 for(y=i->ymin;y<=i->ymax;y++) {
811 TAG*tag = i->lines[y].points;
812 int num = i->lines[y].num;
813 renderpoint_t*points = (renderpoint_t*)tag->data;
814 RGBA*line = &i->img[i->width2*y];
815 int*zline = &i->zbuf[i->width2*y];
818 memset(&fillstate, 0, sizeof(state_t));
819 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
821 if(i->lines[y].pending_clipdepth && !clipdepth) {
822 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
823 i->lines[y].pending_clipdepth=0;
827 renderpoint_t*p = &points[n];
828 renderpoint_t*next= n<num-1?&points[n+1]:0;
830 int endx = next?next->x:i->width2;
839 /* for clipping, the inverse is filled */
840 fill_clip(line, zline, y, lastx, startx, clipdepth);
842 change_state(y, &fillstate, p);
844 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
845 /* if(y == 0 && startx == 232 && endx == 418) {
846 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
848 renderpoint_t*p = &points[n];
849 printf("x=%f depth=%08x\n", p->x, p->depth);
854 if(endx == i->width2)
858 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
860 free_layers(&fillstate);
863 swf_ClearTag(i->lines[y].points);
865 i->ymin = 0x7fffffff;
866 i->ymax = -0x80000000;
869 RGBA* swf_Render(RENDERBUF*dest)
871 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
872 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
876 for(y=0;y<i->height2;y++) {
878 RGBA*line = &i->img[y*i->width2];
881 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
888 RGBA* p = &img[(y/2)*dest->width];
889 for(x=0;x<dest->width;x++) {
890 RGBA*p1 = &line1[x*2];
891 RGBA*p2 = &line1[x*2+1];
892 RGBA*p3 = &line2[x*2];
893 RGBA*p4 = &line2[x*2+1];
894 p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
895 p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
896 p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
897 p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
911 enum {none_type, shape_type, image_type, text_type, font_type} type;
918 int compare_placements(const void *v1, const void *v2)
920 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
921 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
922 if(p1->depth != p2->depth)
923 return (int)p1->depth - (int)p2->depth;
926 return 1; // do the clip first
930 /* if(!p1->clipdepth) {
932 // !p1->clipdepth && !p2->clipdepth
933 return (int)p1->depth - (int)p2->depth;
935 // !p1->clipdepth && p2->clipdepth
936 if(p1->depth != p2->clipdepth)
937 return (int)p1->depth - (int)p2->clipdepth;
939 return 1; // do the clip first
943 // p1->clipdepth && !p2->clipdepth
944 if(p1->clipdepth != p2->depth)
945 return (int)p1->clipdepth - (int)p2->depth;
947 return -1;// do the clip first
949 if(p1->clipdepth != p2->clipdepth)
950 return (int)p1->clipdepth - (int)p2->clipdepth;
952 return (int)p1->depth - (int)p2->depth;
957 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
963 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
964 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
969 if(tag->id == ST_PLACEOBJECT ||
970 tag->id == ST_PLACEOBJECT2) {
975 SWFPLACEOBJECT* placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
978 /* set background color */
979 RGBA color = swf_GetSWFBackgroundColor(swf);
980 swf_Render_SetBackgroundColor(buf, color);
982 /* parse definitions */
985 if(swf_isDefiningTag(tag)) {
986 int id = swf_GetDefineID(tag);
987 idtable[id].tag = tag;
988 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
989 *idtable[id].bbox = swf_GetDefineBBox(tag);
991 if(swf_isShapeTag(tag)) {
992 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
993 swf_ParseDefineShape(tag, shape);
994 idtable[id].type = shape_type;
995 idtable[id].obj.shape = shape;
996 } else if(swf_isImageTag(tag)) {
998 RGBA*data = swf_ExtractImage(tag, &width, &height);
999 idtable[id].type = image_type;
1000 swf_Render_AddImage(buf, id, data, width, height);
1002 } else if(tag->id == ST_DEFINEFONT ||
1003 tag->id == ST_DEFINEFONT2) {
1004 //swf_FontExtract(swf,id,&idtable[id].font);
1005 idtable[id].obj.font = 0;
1006 } else if(tag->id == ST_DEFINEFONTINFO ||
1007 tag->id == ST_DEFINEFONTINFO2) {
1008 idtable[id].type = font_type;
1009 } else if(tag->id == ST_DEFINETEXT ||
1010 tag->id == ST_DEFINETEXT2) {
1011 idtable[id].type = text_type;
1013 } else if(tag->id == ST_PLACEOBJECT ||
1014 tag->id == ST_PLACEOBJECT2) {
1016 swf_GetPlaceObject(tag, &p);
1017 /* TODO: add move and deletion */
1018 placements[numplacements++] = p;
1019 swf_PlaceObjectFree(&p); //dirty! but it only removes items we don't need
1024 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1026 for(t=0;t<numplacements;t++) {
1027 SWFPLACEOBJECT*p = &placements[t];
1030 if(!idtable[id].tag) {
1031 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1035 if(idtable[id].type == shape_type) {
1036 SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1037 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1038 } else if(idtable[id].type == text_type) {
1041 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1045 /* free id and depth tables again */
1046 for(t=0;t<65536;t++) {
1047 if(idtable[t].bbox) {
1048 free(idtable[t].bbox);
1051 if(idtable[t].type == shape_type) {
1052 SHAPE2* shape = idtable[t].obj.shape;
1054 swf_Shape2Free(shape); // FIXME
1055 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;