3 Math and matrix functions, misc tools
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 // Matrix & Math tools for SWF files
26 #include "../rfxswf.h"
29 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
30 { S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
31 SFIXED result = (SFIXED)(a);
33 fprintf(stderr, "Warning: overflow in matrix multiplication");
36 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
37 { S64 z = zaehler<<16;
38 S64 a = z/(S64)nenner;
43 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
46 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
47 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
49 d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
50 d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
52 d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
53 d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
55 d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
56 d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
63 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
64 int x1,int y1,int x2,int y2)
71 if ((!dx)||(!dy)) return NULL; // check DIV by zero
75 m->sx = RFXSWF_QFIX(dx1,dx);
76 m->sy = RFXSWF_QFIX(dy2,dy);
77 m->r0 = RFXSWF_QFIX(dy1,dx);
78 m->r1 = RFXSWF_QFIX(dx2,dy);
83 void swf_SetDefineID(TAG * tag, U16 newid)
85 int oldlen = tag->len;
87 swf_SetU16(tag, newid); /* set defining ID */
91 U16 swf_GetDefineID(TAG * t)
96 oldTagPos = swf_GetTagPos(t);
99 switch (swf_GetTagID(t))
100 { case ST_DEFINESHAPE:
101 case ST_DEFINESHAPE2:
102 case ST_DEFINESHAPE3:
103 case ST_DEFINESHAPE4:
104 case ST_DEFINEMORPHSHAPE:
105 case ST_DEFINEMORPHSHAPE2:
106 case ST_DEFINEEDITTEXT:
108 case ST_DEFINEBITSJPEG2:
109 case ST_DEFINEBITSJPEG3:
110 case ST_DEFINEBITSLOSSLESS:
111 case ST_DEFINEBITSLOSSLESS2:
112 case ST_DEFINESCALINGGRID: //pseudodefine
113 case ST_DEFINEBUTTON:
114 case ST_DEFINEBUTTON2:
115 case ST_DEFINEBUTTONCXFORM: //pseudodefine
116 case ST_DEFINEBUTTONSOUND: //pseudodefine
117 case ST_CSMTEXTSETTINGS: //pseudodefine
121 case ST_DEFINEFONTINFO: //pseudodefine
122 case ST_DEFINEFONTINFO2: //pseudodefine
123 case ST_DEFINEFONTALIGNZONES: //pseudodefine
124 case ST_DEFINEFONTNAME: //pseudodefine
126 case ST_DEFINEBINARY:
129 case ST_DEFINESPRITE:
131 case ST_DEFINEVIDEOSTREAM:
132 case ST_GLYPHNAMES: //pseudodefine
133 case ST_VIDEOFRAME: //pseudodefine
134 case ST_NAMECHARACTER: //pseudodefine
135 case ST_DOINITACTION: //pseudodefine
139 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
142 swf_SetTagPos(t,oldTagPos);
147 SRECT swf_GetDefineBBox(TAG * t)
152 memset(&b1, 0, sizeof(b1));
154 oldTagPos = swf_GetTagPos(t);
159 switch (swf_GetTagID(t))
160 { case ST_DEFINESHAPE:
161 case ST_DEFINESHAPE2:
162 case ST_DEFINESHAPE3:
163 case ST_DEFINESHAPE4:
164 case ST_DEFINEEDITTEXT:
167 case ST_DEFINEVIDEOSTREAM:
171 case ST_DEFINEMORPHSHAPE:
175 swf_ExpandRect2(&b1, &b2);
177 case ST_DEFINEBITSLOSSLESS:
178 case ST_DEFINEBITSLOSSLESS2:
180 case ST_DEFINEBITSJPEG2:
181 case ST_DEFINEBITSJPEG3:
186 swf_SetTagPos(t,oldTagPos);
191 U16 swf_GetPlaceID(TAG * t)
196 oldTagPos = swf_GetTagPos(t);
199 switch (swf_GetTagID(t))
200 { case ST_PLACEOBJECT:
201 case ST_REMOVEOBJECT:
202 case ST_FREECHARACTER:
207 case ST_PLACEOBJECT2:
208 { U8 flags = swf_GetU8(t);
209 U16 d = swf_GetU16(t);
210 id = (flags&PF_CHAR)?swf_GetU16(t):id;
212 case ST_PLACEOBJECT3:
213 { U8 flags = swf_GetU8(t);
214 U8 flags2 = swf_GetU8(t);
215 U16 d = swf_GetU16(t);
216 id = (flags&PF_CHAR)?swf_GetU16(t):id;
221 swf_SetTagPos(t,oldTagPos);
226 static int swf_definingtagids[] =
232 ST_DEFINEMORPHSHAPE2,
242 ST_DEFINEBITSLOSSLESS,
243 ST_DEFINEBITSLOSSLESS2,
249 ST_DEFINEVIDEOSTREAM,
254 // tags which may be used inside a sprite definition
255 static int swf_spritetagids[] =
273 /* tags which add content or information to a character with a given ID */
274 static int swf_pseudodefiningtagids[] =
278 ST_DEFINEFONTALIGNZONES,
280 ST_DEFINEBUTTONCXFORM,
281 ST_DEFINEBUTTONSOUND,
282 ST_DEFINESCALINGGRID,
291 U8 swf_isAllowedSpriteTag(TAG * tag)
295 while(swf_spritetagids[t]>=0)
297 if(swf_spritetagids[t] == id)
304 U8 swf_isDefiningTag(TAG * tag)
308 while(swf_definingtagids[t]>=0)
310 if(swf_definingtagids[t] == id)
317 U8 swf_isPseudoDefiningTag(TAG * tag)
321 while(swf_pseudodefiningtagids[t]>=0)
323 if(swf_pseudodefiningtagids[t] == id)
330 int swf_GetDepth(TAG * t)
334 oldTagPos = swf_GetTagPos(t);
337 switch (swf_GetTagID(t))
338 { case ST_PLACEOBJECT:
339 case ST_REMOVEOBJECT:
341 depth = swf_GetU16(t);
343 case ST_REMOVEOBJECT2:
344 depth = swf_GetU16(t);
346 case ST_PLACEOBJECT2:
347 { U8 flags = swf_GetU8(t);
348 depth = swf_GetU16(t);
350 case ST_PLACEOBJECT3:
351 { U8 flags = swf_GetU8(t);
352 U8 flags2 = swf_GetU8(t);
353 depth = swf_GetU16(t);
357 depth = swf_GetU16(t);
360 swf_SetTagPos(t,oldTagPos);
364 void swf_SetDepth(TAG * t, U16 depth)
366 switch (swf_GetTagID(t))
367 { case ST_PLACEOBJECT:
368 case ST_REMOVEOBJECT:
369 PUT16(t->data, depth);
371 case ST_REMOVEOBJECT2:
372 PUT16(t->data, depth);
374 case ST_PLACEOBJECT2:
375 PUT16(&t->data[1], depth);
378 PUT16(t->data, depth);
381 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
385 char* swf_GetName(TAG * t)
391 oldTagPos = swf_GetTagPos(t);
393 switch(swf_GetTagID(t))
396 name = (char*)&t->data[swf_GetTagPos(t)];
398 case ST_PLACEOBJECT3:
399 case ST_PLACEOBJECT2: {
400 U8 flags = swf_GetU8(t);
401 if(t->id == ST_PLACEOBJECT3)
403 swf_GetU16(t); //depth;
407 swf_GetMatrix(t, &m);
409 swf_GetCXForm(t, &c, 1);
412 if(flags&PF_CLIPDEPTH)
415 swf_ResetReadBits(t);
416 name = (char*)&t->data[swf_GetTagPos(t)];
421 swf_SetTagPos(t,oldTagPos);
425 /* used in enumerateUsedIDs */
426 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
429 int num = swf_GetU8(tag) & 15;
430 if(gradient1) gradient1->num = num;
431 if(gradient2) gradient2->num = num;
434 gradient1->num = num;
435 gradient1->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient1->num);
436 gradient1->ratios = (U8*)rfx_calloc(sizeof(gradient1->ratios[0])*gradient1->num);
439 gradient2->num = num;
440 gradient2->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient2->num);
441 gradient2->ratios = (U8*)rfx_calloc(sizeof(gradient2->ratios[0])*gradient2->num);
448 ratio = swf_GetU8(tag);
449 swf_GetRGBA(tag, &color);
451 gradient1->ratios[t] = ratio;
452 gradient1->rgba[t] = color;
455 ratio = swf_GetU8(tag);
456 swf_GetRGBA(tag, &color);
458 gradient2->ratios[t] = ratio;
459 gradient2->rgba[t] = color;
464 #define DEBUG_ENUMERATE if(0)
465 //#define DEBUG_ENUMERATE
467 void enumerateUsedIDs_fillstyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
470 type = swf_GetU8(tag); //type
471 DEBUG_ENUMERATE printf("fill style %d) type=%02x (tagpos=%d)\n", t, type, tag->pos);
475 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
477 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
478 DEBUG_ENUMERATE printf(" %02x%02x%02x%02x\n", color.r,color.g,color.b,color.a);
480 else if(type == 0x10 || type == 0x12 || type == 0x13)
482 swf_ResetReadBits(tag);
484 swf_GetMatrix(tag, &m);
485 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
487 swf_GetMatrix(tag, &m);
488 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
490 swf_ResetReadBits(tag);
492 swf_GetMorphGradient(tag, NULL, NULL);
499 swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0);
500 DEBUG_ENUMERATE swf_DumpGradient(stdout, &g);
505 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
507 swf_ResetReadBits(tag);
508 if(tag->data[tag->pos] != 0xff ||
509 tag->data[tag->pos+1] != 0xff)
510 (callback)(tag, tag->pos, callback_data);
513 swf_ResetReadBits(tag);
514 swf_GetMatrix(tag, NULL);
516 swf_GetMatrix(tag, NULL);
519 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02d\n",type, tag->id);
523 void enumerateUsedIDs_linestyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
527 width = swf_GetU16(tag);
532 U16 flags = swf_GetU16(tag);
533 DEBUG_ENUMERATE printf("line style %d) flags: %08x\n", t, flags);
534 if((flags & 0x30) == 0x20) {
535 U16 miter = swf_GetU16(tag); // miter limit
536 DEBUG_ENUMERATE printf("line style %d) miter join: %08x\n", t, miter);
544 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
546 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
548 enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
550 DEBUG_ENUMERATE printf("line style %d) width=%.2f color=%02x%02x%02x%02x \n", t, width/20.0, color.r,color.g,color.b,color.a);
553 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
557 count = swf_GetU8(tag);
558 if(count == 0xff && num>1) // defineshape2,3,4 only
559 count = swf_GetU16(tag);
561 DEBUG_ENUMERATE printf("%d fill styles\n", count);
564 enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph);
566 swf_ResetReadBits(tag);
567 count = swf_GetU8(tag); // line style array
569 count = swf_GetU16(tag);
570 DEBUG_ENUMERATE printf("%d line styles\n", count);
573 enumerateUsedIDs_linestyle(tag, t, callback, callback_data, num, morph);
577 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
580 swf_ResetReadBits(tag);
584 case ST_DEFINEBUTTONSOUND: {
586 callback(tag, tag->pos + base, callback_data);
589 callback(tag, tag->pos + base, callback_data);
590 swf_GetU16(tag); //sound id
591 flags = swf_GetU8(tag);
593 swf_GetU32(tag); // in point
595 swf_GetU32(tag); // out points
597 swf_GetU16(tag); // loop count
600 int npoints = swf_GetU8(tag);
602 for(s=0;s<npoints;s++)
611 case ST_DEFINEBUTTONCXFORM:
612 callback(tag, tag->pos + base, callback_data); //button id
615 case ST_EXPORTASSETS: {
616 int num = swf_GetU16(tag);
619 callback(tag, tag->pos + base, callback_data); //button id
620 swf_GetU16(tag); //id
621 while(swf_GetU8(tag)); //name
625 case ST_IMPORTASSETS:
626 case ST_IMPORTASSETS2: {
627 swf_GetString(tag); //count
628 swf_GetU8(tag); //reserved
629 swf_GetU8(tag); //reserved
630 int num = swf_GetU16(tag); //url
633 callback(tag, tag->pos + base, callback_data); //button id
634 swf_GetU16(tag); //id
635 while(swf_GetU8(tag)); //name
643 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
644 case ST_NAMECHARACTER:
645 case ST_DEFINEBINARY:
646 case ST_DEFINEFONTNAME:
647 case ST_GENERATORTEXT:
648 callback(tag, tag->pos + base, callback_data);
651 callback(tag, tag->pos + base, callback_data);
653 case ST_PLACEOBJECT2:
654 // only if placeflaghascharacter
655 if(!(tag->data[0]&2))
657 callback(tag, 3 + base, callback_data);
659 case ST_PLACEOBJECT3:
660 // only if placeflaghascharacter
661 if(!(tag->data[0]&2))
663 callback(tag, 4 + base, callback_data);
665 case ST_REMOVEOBJECT:
666 callback(tag, tag->pos + base, callback_data);
669 callback(tag, tag->pos + base, callback_data);
671 case ST_DEFINESPRITE: {
673 break; // sprite is expanded
675 swf_GetU16(tag); // id
676 swf_GetU16(tag); // framenum
679 U16 flags = swf_GetU16(tag);
682 TAG *tag2 = swf_InsertTag(NULL, id);
685 len = swf_GetU32(tag);
688 tag2->len = tag2->memsize = len;
689 tag2->data = (U8*)rfx_alloc(len);
690 memcpy(tag2->data, &tag->data[tag->pos], len);
691 /* I never saw recursive sprites, but they are (theoretically)
692 possible, so better add base here again */
693 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
694 swf_DeleteTag(0, tag2);
695 swf_GetBlock(tag, NULL, len);
699 case ST_DEFINEBUTTON2: // has some font ids in the button records
702 case ST_DEFINEBUTTON: {
703 swf_GetU16(tag); //button id
707 swf_GetU8(tag); //flag
708 offset = swf_GetU16(tag); //offset
712 U8 flags = swf_GetU8(tag);
715 callback(tag, tag->pos + base, callback_data);
716 swf_GetU16(tag); //char
717 swf_GetU16(tag); //layer
718 swf_ResetReadBits(tag);
719 swf_GetMatrix(tag, NULL);
721 swf_ResetReadBits(tag);
722 swf_GetCXForm(tag, NULL, 1);
725 U8 num = swf_GetU8(tag);
728 swf_DeleteFilter(swf_GetFilter(tag));
732 U8 blendmode = swf_GetU8(tag);
738 case ST_DEFINEEDITTEXT: {
740 swf_GetU16(tag); //id
741 swf_GetRect(tag, NULL); //bounding box
742 swf_ResetReadBits(tag);
743 flags1 = swf_GetU8(tag);
744 flags2 = swf_GetU8(tag);
746 callback(tag, tag->pos + base, callback_data);
751 case ST_DEFINETEXT: {
752 int glyphbits, advancebits;
754 id = swf_GetU16(tag); //id
755 swf_GetRect(tag, NULL); //bounding box
756 swf_ResetReadBits(tag);
757 swf_GetMatrix(tag, NULL); //matrix
758 swf_ResetReadBits(tag);
759 glyphbits = swf_GetU8(tag); //glyphbits
760 advancebits = swf_GetU8(tag); //advancebits
764 swf_ResetReadBits(tag);
765 flags = swf_GetBits(tag, 8);
768 swf_ResetReadBits(tag);
769 if(flags & 8) { // hasfont
770 callback(tag, tag->pos + base, callback_data);
771 id = swf_GetU16(tag);
773 if(flags & 4) { // hascolor
774 if(num==1) swf_GetRGB(tag, NULL);
775 else swf_GetRGBA(tag, NULL);
777 if(flags & 2) { //has x offset
778 swf_ResetReadBits(tag);
781 if(flags & 1) { //has y offset
782 swf_ResetReadBits(tag);
785 if(flags & 8) { //has height
786 swf_ResetReadBits(tag);
790 flags = swf_GetBits(tag, 8);
792 swf_ResetReadBits(tag);
793 for(t=0;t<flags;t++) {
794 swf_GetBits(tag, glyphbits);
795 swf_GetBits(tag, advancebits);
800 case ST_DEFINEFONTALIGNZONES:
801 case ST_DEFINESCALINGGRID:
803 case ST_CSMTEXTSETTINGS:
804 case ST_DEFINEFONTINFO:
805 case ST_DEFINEFONTINFO2:
807 callback(tag, tag->pos + base, callback_data);
809 case ST_DEFINEVIDEOSTREAM:
812 case ST_DOINITACTION:
813 callback(tag, tag->pos + base, callback_data);
816 case ST_DEFINEMORPHSHAPE2:
817 case ST_DEFINESHAPE4:
819 case ST_DEFINEMORPHSHAPE:
820 case ST_DEFINESHAPE3:
822 case ST_DEFINESHAPE2:
824 case ST_DEFINESHAPE: {
830 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
835 id = swf_GetU16(tag); // id;
836 SRECT r={0,0,0,0},r2={0,0,0,0};
837 swf_GetRect(tag, &r); // shape bounds
839 swf_ResetReadBits(tag);
840 swf_GetRect(tag, NULL); // shape bounds2
842 swf_ResetReadBits(tag);
843 swf_GetRect(tag, NULL); // edge bounds1
847 swf_ResetReadBits(tag);
848 swf_GetRect(tag, &r2); // edge bounds
849 U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
850 DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags);
853 swf_GetU32(tag); //offset to endedges
856 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
857 DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r.xmin/20.0,r.ymin/20.0,r.xmax/20.0,r.ymax/20.0);
858 DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r2.xmin/20.0,r2.ymin/20.0,r2.xmax/20.0,r2.ymax/20.0);
860 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
861 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
862 DEBUG_ENUMERATE printf("-------\n");
863 swf_ResetReadBits(tag);
864 while(--numshapes>=0) /* morph shapes define two shapes */
866 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
867 fillbits = swf_GetBits(tag, 4);
868 linebits = swf_GetBits(tag, 4);
869 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
870 swf_ResetReadBits(tag);
874 flags = swf_GetBits(tag, 1);
875 if(!flags) { //style change
876 flags = swf_GetBits(tag, 5);
880 int n = swf_GetBits(tag, 5);
881 x = swf_GetBits(tag, n); //x
882 y = swf_GetBits(tag, n); //y
883 DEBUG_ENUMERATE printf("moveTo %.2f %.2f\n",x/20.0,y/20.0);
885 if(flags&2) { //fill0
887 fill0 = swf_GetBits(tag, fillbits);
888 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
890 if(flags&4) { //fill1
892 fill1 = swf_GetBits(tag, fillbits);
893 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
895 if(flags&8) { //linestyle
897 line = swf_GetBits(tag, linebits);
898 DEBUG_ENUMERATE printf("linestyle %d\n",line);
901 DEBUG_ENUMERATE printf("more fillstyles\n");
902 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
903 fillbits = swf_GetBits(tag, 4);
904 linebits = swf_GetBits(tag, 4);
907 flags = swf_GetBits(tag, 1);
908 if(flags) { //straight edge
909 int n = swf_GetBits(tag, 4) + 2;
910 if(swf_GetBits(tag, 1)) { //line flag
911 x += swf_GetSBits(tag, n); //delta x
912 y += swf_GetSBits(tag, n); //delta y
913 DEBUG_ENUMERATE printf("lineTo %.2f %.2f\n",x/20.0,y/20.0);
915 int v=swf_GetBits(tag, 1);
917 d = swf_GetSBits(tag, n); //vert/horz
922 DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal");
924 } else { //curved edge
925 int n = swf_GetBits(tag, 4) + 2;
927 x1 = swf_GetSBits(tag, n);
928 y1 = swf_GetSBits(tag, n);
929 x2 = swf_GetSBits(tag, n);
930 y2 = swf_GetSBits(tag, n);
931 DEBUG_ENUMERATE printf("splineTo %.2f %.2f %.2f %.2f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
943 void callbackCount(TAG * t,int pos, void*ptr)
946 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
949 void callbackFillin(TAG * t,int pos, void*ptr)
953 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
956 int swf_GetNumUsedIDs(TAG * t)
959 enumerateUsedIDs(t, 0, callbackCount, &num);
963 void swf_GetUsedIDs(TAG * t, int * positions)
965 int * ptr = positions;
966 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
969 char swf_Relocate (SWF*swf, char*bitmap)
973 memset(slaveids, -1, sizeof(slaveids));
982 if(swf_isDefiningTag(tag))
987 id = swf_GetDefineID(tag); //own id
989 if(!bitmap[id]) { //free
993 for (t=1;t<65536;t++)
1002 fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs");
1007 slaveids[id] = newid;
1009 swf_SetDefineID(tag, newid);
1012 num = swf_GetNumUsedIDs(tag);
1014 ptr = (int*)rfx_alloc(sizeof(int)*num);
1015 swf_GetUsedIDs(tag, ptr);
1017 for(t=0;t<num;t++) {
1018 int id = GET16(&tag->data[ptr[t]]);
1019 if(slaveids[id]<0) {
1020 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
1021 swf_TagGetName(tag));
1025 PUT16(&tag->data[ptr[t]], id);
1035 void swf_Relocate2(SWF*swf, int*id2id)
1038 tag = swf->firstTag;
1040 if(swf_isDefiningTag(tag)) {
1041 int id = swf_GetDefineID(tag);
1044 swf_SetDefineID(tag, id);
1047 int num = swf_GetNumUsedIDs(tag);
1051 ptr = (int*)rfx_alloc(sizeof(int)*num);
1052 swf_GetUsedIDs(tag, ptr);
1053 for(t=0;t<num;t++) {
1054 int id = GET16(&tag->data[ptr[t]]);
1057 PUT16(&tag->data[ptr[t]], id);
1064 void swf_RelocateDepth(SWF*swf, char*bitmap)
1068 tag = swf->firstTag;
1069 for(nr=65535;nr>=0;nr--) {
1073 // now nr is the highest used depth. So we start
1074 // assigning depths at nr+1
1080 /* TODO * clip depths
1083 if(tag->id == ST_PLACEOBJECT2) {
1085 swf_GetPlaceObject(tag, &obj);
1087 int newdepth = obj.clipdepth+nr;
1088 if(newdepth>65535) {
1089 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1092 obj.clipdepth = newdepth;
1093 swf_ResetTag(tag, ST_PLACEOBJECT2);
1094 swf_SetPlaceObject(tag, &obj);
1096 swf_PlaceObjectFree(&obj);
1099 depth = swf_GetDepth(tag);
1101 int newdepth = depth+nr;
1102 if(newdepth>65535) {
1103 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1106 swf_SetDepth(tag, newdepth);
1112 U8 swf_isShapeTag(TAG*tag)
1114 if(tag->id == ST_DEFINESHAPE ||
1115 tag->id == ST_DEFINESHAPE2 ||
1116 tag->id == ST_DEFINESHAPE3 ||
1117 tag->id == ST_DEFINESHAPE4)
1122 U8 swf_isPlaceTag(TAG*tag)
1124 if(tag->id == ST_PLACEOBJECT ||
1125 tag->id == ST_PLACEOBJECT2 ||
1126 tag->id == ST_PLACEOBJECT3)
1130 U8 swf_isTextTag(TAG*tag)
1132 if(tag->id == ST_DEFINETEXT ||
1133 tag->id == ST_DEFINETEXT2)
1138 U8 swf_isFontTag(TAG*tag)
1140 if(tag->id == ST_DEFINEFONT ||
1141 tag->id == ST_DEFINEFONT2 ||
1142 tag->id == ST_DEFINEFONTINFO)
1147 U8 swf_isImageTag(TAG*tag)
1149 if(tag->id == ST_DEFINEBITSJPEG ||
1150 tag->id == ST_DEFINEBITSJPEG2 ||
1151 tag->id == ST_DEFINEBITSJPEG3 ||
1152 tag->id == ST_DEFINEBITSLOSSLESS ||
1153 tag->id == ST_DEFINEBITSLOSSLESS2)
1158 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1160 TAG*tag=0,*lasttag=0;
1162 char depthmap[65536];
1164 memset(bitmap, 0, sizeof(bitmap));
1165 memset(depthmap, 0, sizeof(depthmap));
1166 memset(&swf1, 0, sizeof(swf1));
1167 memset(&swf2, 0, sizeof(swf2));
1169 swf1.firstTag = list1;
1171 swf2.firstTag = list2;
1176 if(!swf_isDefiningTag(tag)) {
1177 int id = swf_GetDefineID(tag);
1180 if(tag->id == ST_PLACEOBJECT ||
1181 tag->id == ST_PLACEOBJECT2) {
1182 int depth = swf_GetDepth(tag);
1183 depthmap[depth] = 1;
1185 if(tag->id == ST_REMOVEOBJECT ||
1186 tag->id == ST_REMOVEOBJECT2) {
1187 int depth = swf_GetDepth(tag);
1188 depthmap[depth] = 0;
1193 swf_Relocate(&swf2, bitmap);
1194 swf_RelocateDepth(&swf2, depthmap);
1195 lasttag->next = swf2.firstTag;
1196 swf2.firstTag->prev = lasttag;
1198 return swf1.firstTag;
1201 static int tagHash(TAG*tag)
1204 unsigned int a = 0x6b973e5a;
1205 /* start at pos 2, as 0 and 1 are the id */
1206 for(t=2;t<tag->len;t++) {
1209 a += tag->data[t]*0xefbc35a5*b*(t+1);
1211 return a&0x7fffffff; //always return positive number
1214 void swf_Optimize(SWF*swf)
1216 const int hash_size = 131072;
1217 char* dontremap = (char*)rfx_calloc(sizeof(char)*65536);
1218 U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536);
1219 TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536);
1220 TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size);
1223 for(t=0;t<65536;t++) {
1229 tag = swf->firstTag;
1231 /* make sure we don't remap to this tag,
1232 as it might have different "helper tags"
1233 FIXME: a better way would be to compare
1234 the helper tags, too.
1236 if(swf_isPseudoDefiningTag(tag) &&
1237 tag->id != ST_NAMECHARACTER) {
1238 dontremap[swf_GetDefineID(tag)] = 1;
1242 tag = swf->firstTag;
1244 TAG*next = tag->next;
1247 int num = swf_GetNumUsedIDs(tag);
1248 int*positions = (int*)rfx_alloc(sizeof(int)*num);
1250 swf_GetUsedIDs(tag, positions);
1251 for(t=0;t<num;t++) {
1252 int id = GET16(&tag->data[positions[t]]);
1254 PUT16(&tag->data[positions[t]], id);
1256 rfx_free(positions);
1258 /* now look for previous tags with the same
1260 if(swf_isDefiningTag(tag)) {
1262 int id = swf_GetDefineID(tag);
1263 int hash = tagHash(tag);
1266 while((tag2 = hashmap[hash%hash_size])) {
1267 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1268 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1276 while(hashmap[hash%hash_size]) hash++;
1277 hashmap[hash%hash_size] = tag;
1279 /* we found two identical tags- remap one
1281 remap[id] = swf_GetDefineID(tag2);
1282 swf_DeleteTag(swf, tag);
1284 } else if(swf_isPseudoDefiningTag(tag)) {
1285 int id = swf_GetDefineID(tag);
1287 /* if this tag was remapped, we don't
1288 need the helper tag anymore. Discard
1290 swf_DeleteTag(swf, tag);
1297 rfx_free(dontremap);
1303 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1307 swf_SetTagPos(tag,0);
1309 switch (swf_GetTagID(tag))
1311 case ST_DEFINESHAPE:
1312 case ST_DEFINESHAPE2:
1313 case ST_DEFINESHAPE3:
1314 case ST_DEFINEEDITTEXT:
1316 case ST_DEFINETEXT2:
1317 case ST_DEFINEVIDEOSTREAM: {
1318 U32 after_bbox_offset = 0, len;
1320 id = swf_GetU16(tag);
1321 swf_GetRect(tag, &b1);
1322 swf_ResetReadBits(tag);
1323 after_bbox_offset = tag->pos;
1324 len = tag->len - after_bbox_offset;
1325 data = (U8*)malloc(len);
1326 memcpy(data, &tag->data[after_bbox_offset], len);
1329 swf_SetRect(tag, &newbbox);
1330 swf_SetBlock(tag, data, len);
1332 tag->pos = tag->readBit = 0;
1336 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1340 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1342 TAG*t=swf->firstTag;
1344 color.r = color.b = color.g = 0;
1347 if(t->id == ST_SETBACKGROUNDCOLOR) {
1348 swf_SetTagPos(t, 0);
1349 color.r = swf_GetU8(t);
1350 color.g = swf_GetU8(t);
1351 color.b = swf_GetU8(t);