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
27 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
29 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
30 SFIXED result = (SFIXED)(a);
32 fprintf(stderr, "Warning: overflow in matrix multiplication");
35 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
36 { S64 z = zaehler<<16;
37 S64 a = z/(S64)nenner;
42 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
45 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
46 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
48 d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
49 d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
51 d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
52 d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
54 d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
55 d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
62 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
63 int x1,int y1,int x2,int y2)
70 if ((!dx)||(!dy)) return NULL; // check DIV by zero
74 m->sx = RFXSWF_QFIX(dx1,dx);
75 m->sy = RFXSWF_QFIX(dy2,dy);
76 m->r0 = RFXSWF_QFIX(dy1,dx);
77 m->r1 = RFXSWF_QFIX(dx2,dy);
82 void swf_SetDefineID(TAG * tag, U16 newid)
84 int oldlen = tag->len;
86 swf_SetU16(tag, newid); /* set defining ID */
90 U16 swf_GetDefineID(TAG * t)
95 oldTagPos = swf_GetTagPos(t);
98 switch (swf_GetTagID(t))
99 { case ST_DEFINESHAPE:
100 case ST_DEFINESHAPE2:
101 case ST_DEFINESHAPE3:
102 case ST_DEFINEMORPHSHAPE:
103 case ST_DEFINEEDITTEXT:
105 case ST_DEFINEBITSJPEG2:
106 case ST_DEFINEBITSJPEG3:
107 case ST_DEFINEBITSLOSSLESS:
108 case ST_DEFINEBITSLOSSLESS2:
109 case ST_DEFINEBUTTON:
110 case ST_DEFINEBUTTON2:
111 case ST_DEFINEBUTTONCXFORM: //pseudodefine
112 case ST_DEFINEBUTTONSOUND: //pseudodefine
115 case ST_DEFINEFONTINFO: //pseudodefine
116 case ST_DEFINEFONTINFO2: //pseudodefine
120 case ST_DEFINESPRITE:
122 case ST_DEFINEVIDEOSTREAM:
123 case ST_GLYPHNAMES: //pseudodefine
124 case ST_VIDEOFRAME: //pseudodefine
125 case ST_NAMECHARACTER: //pseudodefine
126 case ST_DOINITACTION: //pseudodefine
130 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
133 swf_SetTagPos(t,oldTagPos);
138 SRECT swf_GetDefineBBox(TAG * t)
143 memset(&b1, 0, sizeof(b1));
145 oldTagPos = swf_GetTagPos(t);
150 switch (swf_GetTagID(t))
151 { case ST_DEFINESHAPE:
152 case ST_DEFINESHAPE2:
153 case ST_DEFINESHAPE3:
154 case ST_DEFINEEDITTEXT:
157 case ST_DEFINEVIDEOSTREAM:
161 case ST_DEFINEMORPHSHAPE:
165 swf_ExpandRect2(&b1, &b2);
167 case ST_DEFINEBITSLOSSLESS:
168 case ST_DEFINEBITSLOSSLESS2:
170 case ST_DEFINEBITSJPEG2:
171 case ST_DEFINEBITSJPEG3:
176 swf_SetTagPos(t,oldTagPos);
181 U16 swf_GetPlaceID(TAG * t)
186 oldTagPos = swf_GetTagPos(t);
189 switch (swf_GetTagID(t))
190 { case ST_PLACEOBJECT:
191 case ST_REMOVEOBJECT:
192 case ST_FREECHARACTER:
197 case ST_PLACEOBJECT2:
198 { U8 flags = swf_GetU8(t);
199 U16 d = swf_GetU16(t);
200 id = (flags&PF_CHAR)?swf_GetU16(t):id;
205 swf_SetTagPos(t,oldTagPos);
210 static int swf_definingtagids[] =
223 ST_DEFINEBITSLOSSLESS,
224 ST_DEFINEBITSLOSSLESS2,
230 ST_DEFINEVIDEOSTREAM,
234 // tags which may be used inside a sprite definition
235 static int swf_spritetagids[] =
240 ST_REMOVEOBJECT2, //?
251 static int swf_pseudodefiningtagids[] =
255 ST_DEFINEBUTTONCXFORM,
256 ST_DEFINEBUTTONSOUND,
264 U8 swf_isAllowedSpriteTag(TAG * tag)
268 while(swf_spritetagids[t]>=0)
270 if(swf_spritetagids[t] == id)
277 U8 swf_isDefiningTag(TAG * tag)
281 while(swf_definingtagids[t]>=0)
283 if(swf_definingtagids[t] == id)
290 U8 swf_isPseudoDefiningTag(TAG * tag)
294 while(swf_pseudodefiningtagids[t]>=0)
296 if(swf_pseudodefiningtagids[t] == id)
303 int swf_GetDepth(TAG * t)
307 oldTagPos = swf_GetTagPos(t);
310 switch (swf_GetTagID(t))
311 { case ST_PLACEOBJECT:
312 case ST_REMOVEOBJECT:
314 depth = swf_GetU16(t);
316 case ST_REMOVEOBJECT2:
317 depth = swf_GetU16(t);
319 case ST_PLACEOBJECT2:
320 { U8 flags = swf_GetU8(t);
321 depth = swf_GetU16(t);
325 depth = swf_GetU16(t);
328 swf_SetTagPos(t,oldTagPos);
332 void swf_SetDepth(TAG * t, U16 depth)
334 switch (swf_GetTagID(t))
335 { case ST_PLACEOBJECT:
336 case ST_REMOVEOBJECT:
337 PUT16(t->data, depth);
339 case ST_REMOVEOBJECT2:
340 PUT16(t->data, depth);
342 case ST_PLACEOBJECT2:
343 PUT16(&t->data[1], depth);
346 PUT16(t->data, depth);
349 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
353 char* swf_GetName(TAG * t)
359 oldTagPos = swf_GetTagPos(t);
361 switch(swf_GetTagID(t))
364 name = &t->data[swf_GetTagPos(t)];
366 case ST_PLACEOBJECT2: {
367 U8 flags = swf_GetU8(t);
368 swf_GetU16(t); //depth;
372 swf_GetMatrix(t, &m);
374 swf_GetCXForm(t, &c, 1);
377 if(flags&PF_CLIPACTION)
380 swf_ResetReadBits(t);
381 name = &t->data[swf_GetTagPos(t)];
386 swf_SetTagPos(t,oldTagPos);
390 /* used in enumerateUsedIDs */
391 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
401 gradient2->num = swf_GetU8(tag);
402 for(t=0;t<gradient1->num;t++)
407 gradient1->ratios[t] = swf_GetU8(tag);
408 swf_GetRGBA(tag, &gradient1->rgba[t]);
409 gradient2->ratios[t] = swf_GetU8(tag);
410 swf_GetRGBA(tag, &gradient2->rgba[t]);
414 #define DEBUG_ENUMERATE if(0)
416 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
420 count = swf_GetU8(tag);
421 if(count == 0xff && num>1) // defineshape2,3 only
422 count = swf_GetU16(tag);
428 swf_ResetReadBits(tag);
429 type = swf_GetU8(tag); //type
432 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
434 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
436 else if(type == 0x10 || type == 0x12)
438 swf_ResetReadBits(tag);
439 swf_GetMatrix(tag, NULL);
441 swf_GetMatrix(tag, NULL);
442 swf_ResetReadBits(tag);
444 swf_GetMorphGradient(tag, NULL, NULL);
446 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
448 else if(type == 0x40 || type == 0x41)
450 swf_ResetReadBits(tag);
452 if(tag->data[tag->pos] != 0xff ||
453 tag->data[tag->pos+1] != 0xff)
454 (callback)(tag, tag->pos, callback_data);
457 swf_ResetReadBits(tag);
458 swf_GetMatrix(tag, NULL);
460 swf_GetMatrix(tag, NULL);
463 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
466 swf_ResetReadBits(tag);
467 count = swf_GetU8(tag); // line style array
469 count = swf_GetU16(tag);
476 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
478 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
482 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
485 swf_ResetReadBits(tag);
489 case ST_DEFINEBUTTONSOUND: {
491 callback(tag, tag->pos + base, callback_data);
494 callback(tag, tag->pos + base, callback_data);
495 swf_GetU16(tag); //sound id
496 flags = swf_GetU8(tag);
498 swf_GetU32(tag); // in point
500 swf_GetU32(tag); // out points
502 swf_GetU16(tag); // loop count
505 int npoints = swf_GetU8(tag);
507 for(s=0;s<npoints;s++)
516 case ST_DEFINEBUTTONCXFORM:
517 callback(tag, tag->pos + base, callback_data); //button id
520 case ST_EXPORTASSETS: {
521 int num = swf_GetU16(tag);
524 callback(tag, tag->pos + base, callback_data); //button id
525 swf_GetU16(tag); //id
526 while(swf_GetU8(tag)); //name
530 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
531 case ST_NAMECHARACTER:
532 case ST_GENERATORTEXT:
533 callback(tag, tag->pos + base, callback_data);
536 callback(tag, tag->pos + base, callback_data);
538 case ST_PLACEOBJECT2:
539 // only if placeflaghascharacter
540 if(!(tag->data[0]&2))
542 callback(tag, 3 + base, callback_data);
544 case ST_REMOVEOBJECT:
545 callback(tag, tag->pos + base, callback_data);
548 callback(tag, tag->pos + base, callback_data);
550 case ST_DEFINESPRITE: {
552 break; // sprite is expanded
554 swf_GetU16(tag); // id
555 swf_GetU16(tag); // framenum
558 U16 flags = swf_GetU16(tag);
561 TAG *tag2 = swf_InsertTag(NULL, id);
564 len = swf_GetU32(tag);
567 tag2->len = tag2->memsize = len;
568 tag2->data = rfx_alloc(len);
569 memcpy(tag2->data, &tag->data[tag->pos], len);
570 /* I never saw recursive sprites, but they are (theoretically)
571 possible, so better add base here again */
572 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
574 swf_GetBlock(tag, NULL, len);
578 case ST_DEFINEBUTTON2: // has some font ids in the button records
581 case ST_DEFINEBUTTON: {
582 swf_GetU16(tag); //button id
586 swf_GetU8(tag); //flag
587 offset = swf_GetU16(tag); //offset
592 if(!swf_GetU8(tag)) //flags
594 callback(tag, tag->pos + base, callback_data);
595 swf_GetU16(tag); //char
596 swf_GetU16(tag); //layer
597 swf_ResetReadBits(tag);
598 swf_GetMatrix(tag, NULL);
600 swf_ResetReadBits(tag);
601 swf_GetCXForm(tag, NULL, 1);
607 case ST_DEFINEEDITTEXT: {
609 swf_GetU16(tag); //id
610 swf_GetRect(tag, NULL); //bounding box
611 swf_ResetReadBits(tag);
612 flags1 = swf_GetU8(tag);
613 flags2 = swf_GetU8(tag);
615 callback(tag, tag->pos + base, callback_data);
620 case ST_DEFINETEXT: {
621 int glyphbits, advancebits;
623 id = swf_GetU16(tag); //id
624 swf_GetRect(tag, NULL); //bounding box
625 swf_ResetReadBits(tag);
626 swf_GetMatrix(tag, NULL); //matrix
627 swf_ResetReadBits(tag);
628 glyphbits = swf_GetU8(tag); //glyphbits
629 advancebits = swf_GetU8(tag); //advancebits
633 swf_ResetReadBits(tag);
634 flags = swf_GetBits(tag, 8);
637 swf_ResetReadBits(tag);
638 if(flags & 8) { // hasfont
639 callback(tag, tag->pos + base, callback_data);
640 id = swf_GetU16(tag);
642 if(flags & 4) { // hascolor
643 if(num==1) swf_GetRGB(tag, NULL);
644 else swf_GetRGBA(tag, NULL);
646 if(flags & 2) { //has x offset
647 swf_ResetReadBits(tag);
650 if(flags & 1) { //has y offset
651 swf_ResetReadBits(tag);
654 if(flags & 8) { //has height
655 swf_ResetReadBits(tag);
659 flags = swf_GetBits(tag, 8);
661 swf_ResetReadBits(tag);
662 for(t=0;t<flags;t++) {
663 swf_GetBits(tag, glyphbits);
664 swf_GetBits(tag, advancebits);
670 case ST_DEFINEFONTINFO:
671 case ST_DEFINEFONTINFO2:
673 callback(tag, tag->pos + base, callback_data);
675 case ST_DEFINEVIDEOSTREAM:
678 case ST_DOINITACTION:
679 callback(tag, tag->pos + base, callback_data);
682 case ST_DEFINEMORPHSHAPE:
683 case ST_DEFINESHAPE3:
685 case ST_DEFINESHAPE2:
687 case ST_DEFINESHAPE: {
693 if(tag->id == ST_DEFINEMORPHSHAPE) {
698 id = swf_GetU16(tag); // id;
699 swf_GetRect(tag, NULL); // bounds
701 swf_ResetReadBits(tag);
702 swf_GetRect(tag, NULL); // bounds2
703 swf_GetU32(tag); //offset to endedges
706 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
708 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
709 DEBUG_ENUMERATE printf("-------\n");
710 while(--numshapes>=0) /* morph shapes define two shapes */
712 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
713 fillbits = swf_GetBits(tag, 4);
714 linebits = swf_GetBits(tag, 4);
715 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
716 swf_ResetReadBits(tag);
719 flags = swf_GetBits(tag, 1);
720 if(!flags) { //style change
721 flags = swf_GetBits(tag, 5);
725 int n = swf_GetBits(tag, 5);
727 x = swf_GetBits(tag, n); //x
728 y = swf_GetBits(tag, n); //y
729 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
731 if(flags&2) { //fill0
733 fill0 = swf_GetBits(tag, fillbits);
734 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
736 if(flags&4) { //fill1
738 fill1 = swf_GetBits(tag, fillbits);
739 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
741 if(flags&8) { //linestyle
743 line = swf_GetBits(tag, linebits);
744 DEBUG_ENUMERATE printf("linestyle %d\n",line);
747 DEBUG_ENUMERATE printf("more fillstyles\n");
748 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
749 fillbits = swf_GetBits(tag, 4);
750 linebits = swf_GetBits(tag, 4);
753 flags = swf_GetBits(tag, 1);
754 if(flags) { //straight edge
755 int n = swf_GetBits(tag, 4) + 2;
756 if(swf_GetBits(tag, 1)) { //line flag
758 x = swf_GetSBits(tag, n); //delta x
759 y = swf_GetSBits(tag, n); //delta y
760 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
762 int v=swf_GetBits(tag, 1);
764 d = swf_GetSBits(tag, n); //vert/horz
765 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
767 } else { //curved edge
768 int n = swf_GetBits(tag, 4) + 2;
770 x1 = swf_GetSBits(tag, n);
771 y1 = swf_GetSBits(tag, n);
772 x2 = swf_GetSBits(tag, n);
773 y2 = swf_GetSBits(tag, n);
774 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
786 void callbackCount(TAG * t,int pos, void*ptr)
789 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
792 void callbackFillin(TAG * t,int pos, void*ptr)
796 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
799 int swf_GetNumUsedIDs(TAG * t)
802 enumerateUsedIDs(t, 0, callbackCount, &num);
806 void swf_GetUsedIDs(TAG * t, int * positions)
808 int * ptr = positions;
809 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
812 void swf_Relocate (SWF*swf, char*bitmap)
816 memset(slaveids, -1, sizeof(slaveids));
824 if(swf_isDefiningTag(tag))
829 id = swf_GetDefineID(tag); //own id
831 if(!bitmap[id]) { //free
836 for (t=1;t<65536;t++)
846 slaveids[id] = newid;
848 swf_SetDefineID(tag, newid);
851 num = swf_GetNumUsedIDs(tag);
853 ptr = rfx_alloc(sizeof(int)*num);
854 swf_GetUsedIDs(tag, ptr);
857 int id = GET16(&tag->data[ptr[t]]);
859 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
860 swf_TagGetName(tag));
864 PUT16(&tag->data[ptr[t]], id);
871 void swf_RelocateDepth(SWF*swf, char*bitmap)
876 for(nr=65535;nr>=0;nr--) {
880 // now nr is the highest used depth. So we start
881 // assigning depths at nr+1
886 /* TODO * clip depths
889 int depth = swf_GetDepth(tag);
891 int newdepth = depth+nr;
893 fprintf(stderr, "Couldn't relocate depths: too large values\n");
896 swf_SetDepth(tag, newdepth);
902 U8 swf_isShapeTag(TAG*tag)
904 if(tag->id == ST_DEFINESHAPE ||
905 tag->id == ST_DEFINESHAPE2 ||
906 tag->id == ST_DEFINESHAPE3)
911 U8 swf_isPlaceTag(TAG*tag)
913 if(tag->id == ST_PLACEOBJECT ||
914 tag->id == ST_PLACEOBJECT2)
918 U8 swf_isTextTag(TAG*tag)
920 if(tag->id == ST_DEFINETEXT ||
921 tag->id == ST_DEFINETEXT2)
926 U8 swf_isFontTag(TAG*tag)
928 if(tag->id == ST_DEFINEFONT ||
929 tag->id == ST_DEFINEFONT2 ||
930 tag->id == ST_DEFINEFONTINFO)
935 U8 swf_isImageTag(TAG*tag)
937 if(tag->id == ST_DEFINEBITSJPEG ||
938 tag->id == ST_DEFINEBITSJPEG2 ||
939 tag->id == ST_DEFINEBITSJPEG3 ||
940 tag->id == ST_DEFINEBITSLOSSLESS ||
941 tag->id == ST_DEFINEBITSLOSSLESS2)
946 TAG* swf_Concatenate (TAG*list1,TAG*list2)
948 TAG*tag=0,*lasttag=0;
950 char depthmap[65536];
952 memset(bitmap, 0, sizeof(bitmap));
953 memset(depthmap, 0, sizeof(depthmap));
954 memset(&swf1, 0, sizeof(swf1));
955 memset(&swf2, 0, sizeof(swf2));
957 swf1.firstTag = list1;
959 swf2.firstTag = list2;
964 if(!swf_isDefiningTag(tag)) {
965 int id = swf_GetDefineID(tag);
968 if(tag->id == ST_PLACEOBJECT ||
969 tag->id == ST_PLACEOBJECT2) {
970 int depth = swf_GetDepth(tag);
973 if(tag->id == ST_REMOVEOBJECT ||
974 tag->id == ST_REMOVEOBJECT2) {
975 int depth = swf_GetDepth(tag);
981 swf_Relocate(&swf2, bitmap);
982 swf_RelocateDepth(&swf2, depthmap);
983 lasttag->next = swf2.firstTag;
984 swf2.firstTag->prev = lasttag;
986 return swf1.firstTag;
989 static int tagHash(TAG*tag)
992 unsigned int a = 0x6b973e5a;
993 /* start at pos 2, as 0 and 1 are the id */
994 for(t=2;t<tag->len;t++) {
997 a += tag->data[t]*0xefbc35a5*b*(t+1);
999 return a&0x7fffffff; //always return positive number
1002 void swf_Optimize(SWF*swf)
1004 const int hash_size = 131072;
1005 char* dontremap = rfx_calloc(sizeof(char)*65536);
1006 U16* remap = rfx_alloc(sizeof(U16)*65536);
1007 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1008 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1011 for(t=0;t<65536;t++) {
1017 tag = swf->firstTag;
1019 /* make sure we don't remap to this tag,
1020 as it might have different "helper tags"
1021 FIXME: a better way would be to compare
1022 the helper tags, too.
1024 if(swf_isPseudoDefiningTag(tag) &&
1025 tag->id != ST_NAMECHARACTER) {
1026 dontremap[swf_GetDefineID(tag)] = 1;
1030 tag = swf->firstTag;
1034 TAG*next = tag->next;
1037 int num = swf_GetNumUsedIDs(tag);
1038 int*positions = rfx_alloc(sizeof(int)*num);
1040 swf_GetUsedIDs(tag, positions);
1041 for(t=0;t<num;t++) {
1042 int id = GET16(&tag->data[positions[t]]);
1044 PUT16(&tag->data[positions[t]], id);
1046 rfx_free(positions);
1049 /* now look for previous tags with the same
1051 if(swf_isDefiningTag(tag)) {
1053 int id = swf_GetDefineID(tag);
1054 int hash = tagHash(tag);
1057 while((tag2 = hashmap[hash%hash_size])) {
1058 if(tag2 != (TAG*)(-1) && tag->len == tag2->len) {
1060 /* start at pos 2, as 0 and 1 are the id */
1061 for(t=2;t<tag->len;t++) {
1062 if(tag->data[t] != tag2->data[t])
1070 /* we found two identical tags- remap one
1072 remap[id] = swf_GetDefineID(tag2);
1078 while(hashmap[hash%hash_size]) hash++;
1079 hashmap[hash%hash_size] = tag;
1082 if(tag == swf->firstTag)
1083 swf->firstTag = next;
1086 } else if(swf_isPseudoDefiningTag(tag)) {
1087 int id = swf_GetDefineID(tag);
1089 /* if this tag was remapped, we don't
1090 need the helper tag anymore. Discard
1093 if(tag == swf->firstTag)
1094 swf->firstTag = next;
1101 rfx_free(dontremap);
1107 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1111 swf_SetTagPos(tag,0);
1113 switch (swf_GetTagID(tag))
1115 case ST_DEFINESHAPE:
1116 case ST_DEFINESHAPE2:
1117 case ST_DEFINESHAPE3:
1118 case ST_DEFINEEDITTEXT:
1120 case ST_DEFINETEXT2:
1121 case ST_DEFINEVIDEOSTREAM: {
1122 U32 after_bbox_offset = 0, len;
1124 id = swf_GetU16(tag);
1125 swf_GetRect(tag, &b1);
1126 swf_ResetReadBits(tag);
1127 after_bbox_offset = tag->pos;
1128 len = tag->len - after_bbox_offset;
1130 memcpy(data, &tag->data[after_bbox_offset], len);
1133 swf_SetRect(tag, &newbbox);
1134 swf_SetBlock(tag, data, len);
1136 tag->pos = tag->readBit = 0;
1140 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1144 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1146 TAG*t=swf->firstTag;
1148 color.r = color.b = color.g = 0;
1151 if(t->id == ST_SETBACKGROUNDCOLOR) {
1152 swf_SetTagPos(t, 0);
1153 color.r = swf_GetU8(t);
1154 color.g = swf_GetU8(t);
1155 color.b = swf_GetU8(t);