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)
28 { S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
29 SFIXED result = (SFIXED)(a);
31 fprintf(stderr, "Warning: overflow in matrix multiplication");
34 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
35 { S64 z = zaehler<<16;
36 S64 a = z/(S64)nenner;
41 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
44 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
45 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
47 d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
48 d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
50 d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
51 d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
53 d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
54 d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
61 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
62 int x1,int y1,int x2,int y2)
69 if ((!dx)||(!dy)) return NULL; // check DIV by zero
73 m->sx = RFXSWF_QFIX(dx1,dx);
74 m->sy = RFXSWF_QFIX(dy2,dy);
75 m->r0 = RFXSWF_QFIX(dy1,dx);
76 m->r1 = RFXSWF_QFIX(dx2,dy);
81 void swf_SetDefineID(TAG * tag, U16 newid)
83 int oldlen = tag->len;
85 swf_SetU16(tag, newid); /* set defining ID */
89 U16 swf_GetDefineID(TAG * t)
94 oldTagPos = swf_GetTagPos(t);
97 switch (swf_GetTagID(t))
98 { case ST_DEFINESHAPE:
100 case ST_DEFINESHAPE3:
101 case ST_DEFINEMORPHSHAPE:
102 case ST_DEFINEEDITTEXT:
104 case ST_DEFINEBITSJPEG2:
105 case ST_DEFINEBITSJPEG3:
106 case ST_DEFINEBITSLOSSLESS:
107 case ST_DEFINEBITSLOSSLESS2:
108 case ST_DEFINEBUTTON:
109 case ST_DEFINEBUTTON2:
110 case ST_DEFINEBUTTONCXFORM: //pseudodefine
111 case ST_DEFINEBUTTONSOUND: //pseudodefine
114 case ST_DEFINEFONTINFO: //pseudodefine
115 case ST_DEFINEFONTINFO2: //pseudodefine
119 case ST_DEFINESPRITE:
121 case ST_DEFINEVIDEOSTREAM:
122 case ST_GLYPHNAMES: //pseudodefine
123 case ST_VIDEOFRAME: //pseudodefine
124 case ST_NAMECHARACTER: //pseudodefine
125 case ST_DOINITACTION: //pseudodefine
129 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
132 swf_SetTagPos(t,oldTagPos);
137 SRECT swf_GetDefineBBox(TAG * t)
142 memset(&b1, 0, sizeof(b1));
144 oldTagPos = swf_GetTagPos(t);
149 switch (swf_GetTagID(t))
150 { case ST_DEFINESHAPE:
151 case ST_DEFINESHAPE2:
152 case ST_DEFINESHAPE3:
153 case ST_DEFINEEDITTEXT:
156 case ST_DEFINEVIDEOSTREAM:
160 case ST_DEFINEMORPHSHAPE:
164 swf_ExpandRect2(&b1, &b2);
166 case ST_DEFINEBITSLOSSLESS:
167 case ST_DEFINEBITSLOSSLESS2:
169 case ST_DEFINEBITSJPEG2:
170 case ST_DEFINEBITSJPEG3:
175 swf_SetTagPos(t,oldTagPos);
180 U16 swf_GetPlaceID(TAG * t)
185 oldTagPos = swf_GetTagPos(t);
188 switch (swf_GetTagID(t))
189 { case ST_PLACEOBJECT:
190 case ST_REMOVEOBJECT:
191 case ST_FREECHARACTER:
196 case ST_PLACEOBJECT2:
197 { U8 flags = swf_GetU8(t);
198 U16 d = swf_GetU16(t);
199 id = (flags&PF_CHAR)?swf_GetU16(t):id;
204 swf_SetTagPos(t,oldTagPos);
209 static int swf_definingtagids[] =
222 ST_DEFINEBITSLOSSLESS,
223 ST_DEFINEBITSLOSSLESS2,
229 ST_DEFINEVIDEOSTREAM,
233 // tags which may be used inside a sprite definition
234 static int swf_spritetagids[] =
239 ST_REMOVEOBJECT2, //?
250 static int swf_pseudodefiningtagids[] =
254 ST_DEFINEBUTTONCXFORM,
255 ST_DEFINEBUTTONSOUND,
263 U8 swf_isAllowedSpriteTag(TAG * tag)
267 while(swf_spritetagids[t]>=0)
269 if(swf_spritetagids[t] == id)
276 U8 swf_isDefiningTag(TAG * tag)
280 while(swf_definingtagids[t]>=0)
282 if(swf_definingtagids[t] == id)
289 U8 swf_isPseudoDefiningTag(TAG * tag)
293 while(swf_pseudodefiningtagids[t]>=0)
295 if(swf_pseudodefiningtagids[t] == id)
302 int swf_GetDepth(TAG * t)
306 oldTagPos = swf_GetTagPos(t);
309 switch (swf_GetTagID(t))
310 { case ST_PLACEOBJECT:
311 case ST_REMOVEOBJECT:
313 depth = swf_GetU16(t);
315 case ST_REMOVEOBJECT2:
316 depth = swf_GetU16(t);
318 case ST_PLACEOBJECT2:
319 { U8 flags = swf_GetU8(t);
320 depth = swf_GetU16(t);
324 depth = swf_GetU16(t);
327 swf_SetTagPos(t,oldTagPos);
331 void swf_SetDepth(TAG * t, U16 depth)
333 switch (swf_GetTagID(t))
334 { case ST_PLACEOBJECT:
335 case ST_REMOVEOBJECT:
336 PUT16(t->data, depth);
338 case ST_REMOVEOBJECT2:
339 PUT16(t->data, depth);
341 case ST_PLACEOBJECT2:
342 PUT16(&t->data[1], depth);
345 PUT16(t->data, depth);
348 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
352 char* swf_GetName(TAG * t)
358 oldTagPos = swf_GetTagPos(t);
360 switch(swf_GetTagID(t))
363 name = &t->data[swf_GetTagPos(t)];
365 case ST_PLACEOBJECT2: {
366 U8 flags = swf_GetU8(t);
367 swf_GetU16(t); //depth;
371 swf_GetMatrix(t, &m);
373 swf_GetCXForm(t, &c, 1);
376 if(flags&PF_CLIPACTION)
379 swf_ResetReadBits(t);
380 name = &t->data[swf_GetTagPos(t)];
385 swf_SetTagPos(t,oldTagPos);
389 /* used in enumerateUsedIDs */
390 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
400 gradient2->num = swf_GetU8(tag);
401 for(t=0;t<gradient1->num;t++)
406 gradient1->ratios[t] = swf_GetU8(tag);
407 swf_GetRGBA(tag, &gradient1->rgba[t]);
408 gradient2->ratios[t] = swf_GetU8(tag);
409 swf_GetRGBA(tag, &gradient2->rgba[t]);
413 #define DEBUG_ENUMERATE if(0)
415 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
419 count = swf_GetU8(tag);
420 if(count == 0xff && num>1) // defineshape2,3 only
421 count = swf_GetU16(tag);
427 swf_ResetReadBits(tag);
428 type = swf_GetU8(tag); //type
431 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
433 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
435 else if(type == 0x10 || type == 0x12)
437 swf_ResetReadBits(tag);
438 swf_GetMatrix(tag, NULL);
440 swf_GetMatrix(tag, NULL);
441 swf_ResetReadBits(tag);
443 swf_GetMorphGradient(tag, NULL, NULL);
445 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
447 else if(type == 0x40 || type == 0x41)
449 swf_ResetReadBits(tag);
451 if(tag->data[tag->pos] != 0xff ||
452 tag->data[tag->pos+1] != 0xff)
453 (callback)(tag, tag->pos, callback_data);
456 swf_ResetReadBits(tag);
457 swf_GetMatrix(tag, NULL);
459 swf_GetMatrix(tag, NULL);
462 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
465 swf_ResetReadBits(tag);
466 count = swf_GetU8(tag); // line style array
468 count = swf_GetU16(tag);
475 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
477 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
481 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
484 swf_ResetReadBits(tag);
488 case ST_DEFINEBUTTONSOUND: {
490 callback(tag, tag->pos + base, callback_data);
493 callback(tag, tag->pos + base, callback_data);
494 swf_GetU16(tag); //sound id
495 flags = swf_GetU8(tag);
497 swf_GetU32(tag); // in point
499 swf_GetU32(tag); // out points
501 swf_GetU16(tag); // loop count
504 int npoints = swf_GetU8(tag);
506 for(s=0;s<npoints;s++)
515 case ST_DEFINEBUTTONCXFORM:
516 callback(tag, tag->pos + base, callback_data); //button id
519 case ST_EXPORTASSETS: {
520 int num = swf_GetU16(tag);
523 callback(tag, tag->pos + base, callback_data); //button id
524 swf_GetU16(tag); //id
525 while(swf_GetU8(tag)); //name
529 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
530 case ST_NAMECHARACTER:
531 case ST_GENERATORTEXT:
532 callback(tag, tag->pos + base, callback_data);
535 callback(tag, tag->pos + base, callback_data);
537 case ST_PLACEOBJECT2:
538 // only if placeflaghascharacter
539 if(!(tag->data[0]&2))
541 callback(tag, 3 + base, callback_data);
543 case ST_REMOVEOBJECT:
544 callback(tag, tag->pos + base, callback_data);
547 callback(tag, tag->pos + base, callback_data);
549 case ST_DEFINESPRITE: {
551 break; // sprite is expanded
553 swf_GetU16(tag); // id
554 swf_GetU16(tag); // framenum
557 U16 flags = swf_GetU16(tag);
560 TAG *tag2 = swf_InsertTag(NULL, id);
563 len = swf_GetU32(tag);
566 tag2->len = tag2->memsize = len;
567 tag2->data = rfx_alloc(len);
568 memcpy(tag2->data, &tag->data[tag->pos], len);
569 /* I never saw recursive sprites, but they are (theoretically)
570 possible, so better add base here again */
571 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
573 swf_GetBlock(tag, NULL, len);
577 case ST_DEFINEBUTTON2: // has some font ids in the button records
580 case ST_DEFINEBUTTON: {
581 swf_GetU16(tag); //button id
585 swf_GetU8(tag); //flag
586 offset = swf_GetU16(tag); //offset
591 if(!swf_GetU8(tag)) //flags
593 callback(tag, tag->pos + base, callback_data);
594 swf_GetU16(tag); //char
595 swf_GetU16(tag); //layer
596 swf_ResetReadBits(tag);
597 swf_GetMatrix(tag, NULL);
599 swf_ResetReadBits(tag);
600 swf_GetCXForm(tag, NULL, 1);
606 case ST_DEFINEEDITTEXT: {
608 swf_GetU16(tag); //id
609 swf_GetRect(tag, NULL); //bounding box
610 swf_ResetReadBits(tag);
611 flags1 = swf_GetU8(tag);
612 flags2 = swf_GetU8(tag);
614 callback(tag, tag->pos + base, callback_data);
619 case ST_DEFINETEXT: {
620 int glyphbits, advancebits;
622 id = swf_GetU16(tag); //id
623 swf_GetRect(tag, NULL); //bounding box
624 swf_ResetReadBits(tag);
625 swf_GetMatrix(tag, NULL); //matrix
626 swf_ResetReadBits(tag);
627 glyphbits = swf_GetU8(tag); //glyphbits
628 advancebits = swf_GetU8(tag); //advancebits
632 swf_ResetReadBits(tag);
633 flags = swf_GetBits(tag, 8);
636 swf_ResetReadBits(tag);
637 if(flags & 8) { // hasfont
638 callback(tag, tag->pos + base, callback_data);
639 id = swf_GetU16(tag);
641 if(flags & 4) { // hascolor
642 if(num==1) swf_GetRGB(tag, NULL);
643 else swf_GetRGBA(tag, NULL);
645 if(flags & 2) { //has x offset
646 swf_ResetReadBits(tag);
649 if(flags & 1) { //has y offset
650 swf_ResetReadBits(tag);
653 if(flags & 8) { //has height
654 swf_ResetReadBits(tag);
658 flags = swf_GetBits(tag, 8);
660 swf_ResetReadBits(tag);
661 for(t=0;t<flags;t++) {
662 swf_GetBits(tag, glyphbits);
663 swf_GetBits(tag, advancebits);
669 case ST_DEFINEFONTINFO:
670 case ST_DEFINEFONTINFO2:
672 callback(tag, tag->pos + base, callback_data);
674 case ST_DEFINEVIDEOSTREAM:
677 case ST_DOINITACTION:
678 callback(tag, tag->pos + base, callback_data);
681 case ST_DEFINEMORPHSHAPE:
682 case ST_DEFINESHAPE3:
684 case ST_DEFINESHAPE2:
686 case ST_DEFINESHAPE: {
692 if(tag->id == ST_DEFINEMORPHSHAPE) {
697 id = swf_GetU16(tag); // id;
698 swf_GetRect(tag, NULL); // bounds
700 swf_ResetReadBits(tag);
701 swf_GetRect(tag, NULL); // bounds2
702 swf_GetU32(tag); //offset to endedges
705 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
707 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
708 DEBUG_ENUMERATE printf("-------\n");
709 while(--numshapes>=0) /* morph shapes define two shapes */
711 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
712 fillbits = swf_GetBits(tag, 4);
713 linebits = swf_GetBits(tag, 4);
714 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
715 swf_ResetReadBits(tag);
718 flags = swf_GetBits(tag, 1);
719 if(!flags) { //style change
720 flags = swf_GetBits(tag, 5);
724 int n = swf_GetBits(tag, 5);
726 x = swf_GetBits(tag, n); //x
727 y = swf_GetBits(tag, n); //y
728 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
730 if(flags&2) { //fill0
732 fill0 = swf_GetBits(tag, fillbits);
733 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
735 if(flags&4) { //fill1
737 fill1 = swf_GetBits(tag, fillbits);
738 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
740 if(flags&8) { //linestyle
742 line = swf_GetBits(tag, linebits);
743 DEBUG_ENUMERATE printf("linestyle %d\n",line);
746 DEBUG_ENUMERATE printf("more fillstyles\n");
747 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
748 fillbits = swf_GetBits(tag, 4);
749 linebits = swf_GetBits(tag, 4);
752 flags = swf_GetBits(tag, 1);
753 if(flags) { //straight edge
754 int n = swf_GetBits(tag, 4) + 2;
755 if(swf_GetBits(tag, 1)) { //line flag
757 x = swf_GetSBits(tag, n); //delta x
758 y = swf_GetSBits(tag, n); //delta y
759 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
761 int v=swf_GetBits(tag, 1);
763 d = swf_GetSBits(tag, n); //vert/horz
764 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
766 } else { //curved edge
767 int n = swf_GetBits(tag, 4) + 2;
769 x1 = swf_GetSBits(tag, n);
770 y1 = swf_GetSBits(tag, n);
771 x2 = swf_GetSBits(tag, n);
772 y2 = swf_GetSBits(tag, n);
773 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
785 void callbackCount(TAG * t,int pos, void*ptr)
788 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
791 void callbackFillin(TAG * t,int pos, void*ptr)
795 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
798 int swf_GetNumUsedIDs(TAG * t)
801 enumerateUsedIDs(t, 0, callbackCount, &num);
805 void swf_GetUsedIDs(TAG * t, int * positions)
807 int * ptr = positions;
808 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
811 void swf_Relocate (SWF*swf, char*bitmap)
815 memset(slaveids, -1, sizeof(slaveids));
823 if(swf_isDefiningTag(tag))
828 id = swf_GetDefineID(tag); //own id
830 if(!bitmap[id]) { //free
835 for (t=1;t<65536;t++)
845 slaveids[id] = newid;
847 swf_SetDefineID(tag, newid);
850 num = swf_GetNumUsedIDs(tag);
852 ptr = rfx_alloc(sizeof(int)*num);
853 swf_GetUsedIDs(tag, ptr);
856 int id = GET16(&tag->data[ptr[t]]);
858 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
859 swf_TagGetName(tag));
863 PUT16(&tag->data[ptr[t]], id);
870 void swf_RelocateDepth(SWF*swf, char*bitmap)
875 for(nr=65535;nr>=0;nr--) {
879 // now nr is the highest used depth. So we start
880 // assigning depths at nr+1
886 /* TODO * clip depths
889 if(tag->id == ST_PLACEOBJECT2) {
891 swf_GetPlaceObject(tag, &obj);
893 int newdepth = obj.clipdepth+nr;
895 fprintf(stderr, "Couldn't relocate depths: too large values\n");
898 obj.clipdepth = newdepth;
899 swf_ResetTag(tag, ST_PLACEOBJECT2);
900 swf_SetPlaceObject(tag, &obj);
902 swf_PlaceObjectFree(&obj);
905 depth = swf_GetDepth(tag);
907 int newdepth = depth+nr;
909 fprintf(stderr, "Couldn't relocate depths: too large values\n");
912 swf_SetDepth(tag, newdepth);
918 U8 swf_isShapeTag(TAG*tag)
920 if(tag->id == ST_DEFINESHAPE ||
921 tag->id == ST_DEFINESHAPE2 ||
922 tag->id == ST_DEFINESHAPE3)
927 U8 swf_isPlaceTag(TAG*tag)
929 if(tag->id == ST_PLACEOBJECT ||
930 tag->id == ST_PLACEOBJECT2)
934 U8 swf_isTextTag(TAG*tag)
936 if(tag->id == ST_DEFINETEXT ||
937 tag->id == ST_DEFINETEXT2)
942 U8 swf_isFontTag(TAG*tag)
944 if(tag->id == ST_DEFINEFONT ||
945 tag->id == ST_DEFINEFONT2 ||
946 tag->id == ST_DEFINEFONTINFO)
951 U8 swf_isImageTag(TAG*tag)
953 if(tag->id == ST_DEFINEBITSJPEG ||
954 tag->id == ST_DEFINEBITSJPEG2 ||
955 tag->id == ST_DEFINEBITSJPEG3 ||
956 tag->id == ST_DEFINEBITSLOSSLESS ||
957 tag->id == ST_DEFINEBITSLOSSLESS2)
962 TAG* swf_Concatenate (TAG*list1,TAG*list2)
964 TAG*tag=0,*lasttag=0;
966 char depthmap[65536];
968 memset(bitmap, 0, sizeof(bitmap));
969 memset(depthmap, 0, sizeof(depthmap));
970 memset(&swf1, 0, sizeof(swf1));
971 memset(&swf2, 0, sizeof(swf2));
973 swf1.firstTag = list1;
975 swf2.firstTag = list2;
980 if(!swf_isDefiningTag(tag)) {
981 int id = swf_GetDefineID(tag);
984 if(tag->id == ST_PLACEOBJECT ||
985 tag->id == ST_PLACEOBJECT2) {
986 int depth = swf_GetDepth(tag);
989 if(tag->id == ST_REMOVEOBJECT ||
990 tag->id == ST_REMOVEOBJECT2) {
991 int depth = swf_GetDepth(tag);
997 swf_Relocate(&swf2, bitmap);
998 swf_RelocateDepth(&swf2, depthmap);
999 lasttag->next = swf2.firstTag;
1000 swf2.firstTag->prev = lasttag;
1002 return swf1.firstTag;
1005 static int tagHash(TAG*tag)
1008 unsigned int a = 0x6b973e5a;
1009 /* start at pos 2, as 0 and 1 are the id */
1010 for(t=2;t<tag->len;t++) {
1013 a += tag->data[t]*0xefbc35a5*b*(t+1);
1015 return a&0x7fffffff; //always return positive number
1018 void swf_Optimize(SWF*swf)
1020 const int hash_size = 131072;
1021 char* dontremap = rfx_calloc(sizeof(char)*65536);
1022 U16* remap = rfx_alloc(sizeof(U16)*65536);
1023 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1024 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1027 for(t=0;t<65536;t++) {
1033 tag = swf->firstTag;
1035 /* make sure we don't remap to this tag,
1036 as it might have different "helper tags"
1037 FIXME: a better way would be to compare
1038 the helper tags, too.
1040 if(swf_isPseudoDefiningTag(tag) &&
1041 tag->id != ST_NAMECHARACTER) {
1042 dontremap[swf_GetDefineID(tag)] = 1;
1046 tag = swf->firstTag;
1050 TAG*next = tag->next;
1053 int num = swf_GetNumUsedIDs(tag);
1054 int*positions = rfx_alloc(sizeof(int)*num);
1056 swf_GetUsedIDs(tag, positions);
1057 for(t=0;t<num;t++) {
1058 int id = GET16(&tag->data[positions[t]]);
1060 PUT16(&tag->data[positions[t]], id);
1062 rfx_free(positions);
1065 /* now look for previous tags with the same
1067 if(swf_isDefiningTag(tag)) {
1069 int id = swf_GetDefineID(tag);
1070 int hash = tagHash(tag);
1073 while((tag2 = hashmap[hash%hash_size])) {
1074 if(tag2 != (TAG*)(-1) && tag->len == tag2->len) {
1076 /* start at pos 2, as 0 and 1 are the id */
1077 for(t=2;t<tag->len;t++) {
1078 if(tag->data[t] != tag2->data[t])
1086 /* we found two identical tags- remap one
1088 remap[id] = swf_GetDefineID(tag2);
1094 while(hashmap[hash%hash_size]) hash++;
1095 hashmap[hash%hash_size] = tag;
1098 if(tag == swf->firstTag)
1099 swf->firstTag = next;
1102 } else if(swf_isPseudoDefiningTag(tag)) {
1103 int id = swf_GetDefineID(tag);
1105 /* if this tag was remapped, we don't
1106 need the helper tag anymore. Discard
1109 if(tag == swf->firstTag)
1110 swf->firstTag = next;
1117 rfx_free(dontremap);
1123 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1127 swf_SetTagPos(tag,0);
1129 switch (swf_GetTagID(tag))
1131 case ST_DEFINESHAPE:
1132 case ST_DEFINESHAPE2:
1133 case ST_DEFINESHAPE3:
1134 case ST_DEFINEEDITTEXT:
1136 case ST_DEFINETEXT2:
1137 case ST_DEFINEVIDEOSTREAM: {
1138 U32 after_bbox_offset = 0, len;
1140 id = swf_GetU16(tag);
1141 swf_GetRect(tag, &b1);
1142 swf_ResetReadBits(tag);
1143 after_bbox_offset = tag->pos;
1144 len = tag->len - after_bbox_offset;
1146 memcpy(data, &tag->data[after_bbox_offset], len);
1149 swf_SetRect(tag, &newbbox);
1150 swf_SetBlock(tag, data, len);
1152 tag->pos = tag->readBit = 0;
1156 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1160 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1162 TAG*t=swf->firstTag;
1164 color.r = color.b = color.g = 0;
1167 if(t->id == ST_SETBACKGROUNDCOLOR) {
1168 swf_SetTagPos(t, 0);
1169 color.r = swf_GetU8(t);
1170 color.g = swf_GetU8(t);
1171 color.b = swf_GetU8(t);