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_DEFINESHAPE4:
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_DEFINESCALINGGRID: //pseudodefine
110 case ST_DEFINEBUTTON:
111 case ST_DEFINEBUTTON2:
112 case ST_DEFINEBUTTONCXFORM: //pseudodefine
113 case ST_DEFINEBUTTONSOUND: //pseudodefine
114 case ST_CSMTEXTSETTINGS: //pseudodefine
118 case ST_DEFINEFONTINFO: //pseudodefine
119 case ST_DEFINEFONTINFO2: //pseudodefine
120 case ST_DEFINEFONTALIGNZONES: //pseudodefine
124 case ST_DEFINESPRITE:
126 case ST_DEFINEVIDEOSTREAM:
127 case ST_GLYPHNAMES: //pseudodefine
128 case ST_VIDEOFRAME: //pseudodefine
129 case ST_NAMECHARACTER: //pseudodefine
130 case ST_DOINITACTION: //pseudodefine
134 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
137 swf_SetTagPos(t,oldTagPos);
142 SRECT swf_GetDefineBBox(TAG * t)
147 memset(&b1, 0, sizeof(b1));
149 oldTagPos = swf_GetTagPos(t);
154 switch (swf_GetTagID(t))
155 { case ST_DEFINESHAPE:
156 case ST_DEFINESHAPE2:
157 case ST_DEFINESHAPE3:
158 case ST_DEFINEEDITTEXT:
161 case ST_DEFINEVIDEOSTREAM:
165 case ST_DEFINEMORPHSHAPE:
169 swf_ExpandRect2(&b1, &b2);
171 case ST_DEFINEBITSLOSSLESS:
172 case ST_DEFINEBITSLOSSLESS2:
174 case ST_DEFINEBITSJPEG2:
175 case ST_DEFINEBITSJPEG3:
180 swf_SetTagPos(t,oldTagPos);
185 U16 swf_GetPlaceID(TAG * t)
190 oldTagPos = swf_GetTagPos(t);
193 switch (swf_GetTagID(t))
194 { case ST_PLACEOBJECT:
195 case ST_REMOVEOBJECT:
196 case ST_FREECHARACTER:
201 case ST_PLACEOBJECT2:
202 { U8 flags = swf_GetU8(t);
203 U16 d = swf_GetU16(t);
204 id = (flags&PF_CHAR)?swf_GetU16(t):id;
206 case ST_PLACEOBJECT3:
207 { U8 flags = swf_GetU8(t);
208 U8 flags2 = swf_GetU8(t);
209 U16 d = swf_GetU16(t);
210 id = (flags&PF_CHAR)?swf_GetU16(t):id;
215 swf_SetTagPos(t,oldTagPos);
220 static int swf_definingtagids[] =
235 ST_DEFINEBITSLOSSLESS,
236 ST_DEFINEBITSLOSSLESS2,
242 ST_DEFINEVIDEOSTREAM,
246 // tags which may be used inside a sprite definition
247 static int swf_spritetagids[] =
264 /* tags which add content or information to a character with a given ID */
265 static int swf_pseudodefiningtagids[] =
269 ST_DEFINEFONTALIGNZONES,
270 ST_DEFINEBUTTONCXFORM,
271 ST_DEFINEBUTTONSOUND,
272 ST_DEFINESCALINGGRID,
281 U8 swf_isAllowedSpriteTag(TAG * tag)
285 while(swf_spritetagids[t]>=0)
287 if(swf_spritetagids[t] == id)
294 U8 swf_isDefiningTag(TAG * tag)
298 while(swf_definingtagids[t]>=0)
300 if(swf_definingtagids[t] == id)
307 U8 swf_isPseudoDefiningTag(TAG * tag)
311 while(swf_pseudodefiningtagids[t]>=0)
313 if(swf_pseudodefiningtagids[t] == id)
320 int swf_GetDepth(TAG * t)
324 oldTagPos = swf_GetTagPos(t);
327 switch (swf_GetTagID(t))
328 { case ST_PLACEOBJECT:
329 case ST_REMOVEOBJECT:
331 depth = swf_GetU16(t);
333 case ST_REMOVEOBJECT2:
334 depth = swf_GetU16(t);
336 case ST_PLACEOBJECT2:
337 { U8 flags = swf_GetU8(t);
338 depth = swf_GetU16(t);
340 case ST_PLACEOBJECT3:
341 { U8 flags = swf_GetU8(t);
342 U8 flags2 = swf_GetU8(t);
343 depth = swf_GetU16(t);
347 depth = swf_GetU16(t);
350 swf_SetTagPos(t,oldTagPos);
354 void swf_SetDepth(TAG * t, U16 depth)
356 switch (swf_GetTagID(t))
357 { case ST_PLACEOBJECT:
358 case ST_REMOVEOBJECT:
359 PUT16(t->data, depth);
361 case ST_REMOVEOBJECT2:
362 PUT16(t->data, depth);
364 case ST_PLACEOBJECT2:
365 PUT16(&t->data[1], depth);
368 PUT16(t->data, depth);
371 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
375 char* swf_GetName(TAG * t)
381 oldTagPos = swf_GetTagPos(t);
383 switch(swf_GetTagID(t))
386 name = &t->data[swf_GetTagPos(t)];
388 case ST_PLACEOBJECT3:
389 case ST_PLACEOBJECT2: {
390 U8 flags = swf_GetU8(t);
391 if(t->id == ST_PLACEOBJECT3)
393 swf_GetU16(t); //depth;
397 swf_GetMatrix(t, &m);
399 swf_GetCXForm(t, &c, 1);
402 if(flags&PF_CLIPDEPTH)
405 swf_ResetReadBits(t);
406 name = &t->data[swf_GetTagPos(t)];
411 swf_SetTagPos(t,oldTagPos);
415 /* used in enumerateUsedIDs */
416 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
426 gradient2->num = swf_GetU8(tag);
427 for(t=0;t<gradient1->num;t++)
432 gradient1->ratios[s] = swf_GetU8(tag);
433 swf_GetRGBA(tag, &gradient1->rgba[s]);
434 gradient2->ratios[s] = swf_GetU8(tag);
435 swf_GetRGBA(tag, &gradient2->rgba[s]);
439 #define DEBUG_ENUMERATE if(0)
440 //#define DEBUG_ENUMERATE
442 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
446 count = swf_GetU8(tag);
447 if(count == 0xff && num>1) // defineshape2,3,4 only
448 count = swf_GetU16(tag);
450 DEBUG_ENUMERATE printf("%d fill styles\n", count);
455 type = swf_GetU8(tag); //type
456 DEBUG_ENUMERATE printf("fill style %d) %02x (tagpos=%d)\n", t, type, tag->pos);
459 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
461 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
463 else if(type == 0x10 || type == 0x12 || type == 0x13)
465 swf_ResetReadBits(tag);
467 swf_GetMatrix(tag, &m);
468 DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m);
470 swf_GetMatrix(tag, NULL);
471 swf_ResetReadBits(tag);
473 swf_GetMorphGradient(tag, NULL, NULL);
475 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
478 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
480 swf_ResetReadBits(tag);
482 if(tag->data[tag->pos] != 0xff ||
483 tag->data[tag->pos+1] != 0xff)
484 (callback)(tag, tag->pos, callback_data);
487 swf_ResetReadBits(tag);
488 swf_GetMatrix(tag, NULL);
490 swf_GetMatrix(tag, NULL);
493 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02x\n",type, tag->id);
496 swf_ResetReadBits(tag);
497 count = swf_GetU8(tag); // line style array
499 count = swf_GetU16(tag);
500 DEBUG_ENUMERATE printf("%d line styles\n", count);
505 width = swf_GetU16(tag);
509 {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);}
511 {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);}
512 DEBUG_ENUMERATE printf("line style %d: %02x%02x%02x%02x \n", t, color.r,color.g,color.b,color.a);
516 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
519 swf_ResetReadBits(tag);
523 case ST_DEFINEBUTTONSOUND: {
525 callback(tag, tag->pos + base, callback_data);
528 callback(tag, tag->pos + base, callback_data);
529 swf_GetU16(tag); //sound id
530 flags = swf_GetU8(tag);
532 swf_GetU32(tag); // in point
534 swf_GetU32(tag); // out points
536 swf_GetU16(tag); // loop count
539 int npoints = swf_GetU8(tag);
541 for(s=0;s<npoints;s++)
550 case ST_DEFINEBUTTONCXFORM:
551 callback(tag, tag->pos + base, callback_data); //button id
554 case ST_EXPORTASSETS: {
555 int num = swf_GetU16(tag);
558 callback(tag, tag->pos + base, callback_data); //button id
559 swf_GetU16(tag); //id
560 while(swf_GetU8(tag)); //name
564 case ST_IMPORTASSETS:
565 case ST_IMPORTASSETS2: {
566 swf_GetString(tag); //count
567 swf_GetU8(tag); //reserved
568 swf_GetU8(tag); //reserved
569 int num = swf_GetU16(tag); //url
572 callback(tag, tag->pos + base, callback_data); //button id
573 swf_GetU16(tag); //id
574 while(swf_GetU8(tag)); //name
578 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
579 case ST_NAMECHARACTER:
580 case ST_GENERATORTEXT:
581 callback(tag, tag->pos + base, callback_data);
584 callback(tag, tag->pos + base, callback_data);
586 case ST_PLACEOBJECT2:
587 // only if placeflaghascharacter
588 if(!(tag->data[0]&2))
590 callback(tag, 3 + base, callback_data);
592 case ST_PLACEOBJECT3:
593 // only if placeflaghascharacter
594 if(!(tag->data[0]&2))
596 callback(tag, 4 + base, callback_data);
598 case ST_REMOVEOBJECT:
599 callback(tag, tag->pos + base, callback_data);
602 callback(tag, tag->pos + base, callback_data);
604 case ST_DEFINESPRITE: {
606 break; // sprite is expanded
608 swf_GetU16(tag); // id
609 swf_GetU16(tag); // framenum
612 U16 flags = swf_GetU16(tag);
615 TAG *tag2 = swf_InsertTag(NULL, id);
618 len = swf_GetU32(tag);
621 tag2->len = tag2->memsize = len;
622 tag2->data = rfx_alloc(len);
623 memcpy(tag2->data, &tag->data[tag->pos], len);
624 /* I never saw recursive sprites, but they are (theoretically)
625 possible, so better add base here again */
626 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
628 swf_GetBlock(tag, NULL, len);
632 case ST_DEFINEBUTTON2: // has some font ids in the button records
635 case ST_DEFINEBUTTON: {
636 swf_GetU16(tag); //button id
640 swf_GetU8(tag); //flag
641 offset = swf_GetU16(tag); //offset
646 if(!swf_GetU8(tag)) //flags
648 callback(tag, tag->pos + base, callback_data);
649 swf_GetU16(tag); //char
650 swf_GetU16(tag); //layer
651 swf_ResetReadBits(tag);
652 swf_GetMatrix(tag, NULL);
654 swf_ResetReadBits(tag);
655 swf_GetCXForm(tag, NULL, 1);
661 case ST_DEFINEEDITTEXT: {
663 swf_GetU16(tag); //id
664 swf_GetRect(tag, NULL); //bounding box
665 swf_ResetReadBits(tag);
666 flags1 = swf_GetU8(tag);
667 flags2 = swf_GetU8(tag);
669 callback(tag, tag->pos + base, callback_data);
674 case ST_DEFINETEXT: {
675 int glyphbits, advancebits;
677 id = swf_GetU16(tag); //id
678 swf_GetRect(tag, NULL); //bounding box
679 swf_ResetReadBits(tag);
680 swf_GetMatrix(tag, NULL); //matrix
681 swf_ResetReadBits(tag);
682 glyphbits = swf_GetU8(tag); //glyphbits
683 advancebits = swf_GetU8(tag); //advancebits
687 swf_ResetReadBits(tag);
688 flags = swf_GetBits(tag, 8);
691 swf_ResetReadBits(tag);
692 if(flags & 8) { // hasfont
693 callback(tag, tag->pos + base, callback_data);
694 id = swf_GetU16(tag);
696 if(flags & 4) { // hascolor
697 if(num==1) swf_GetRGB(tag, NULL);
698 else swf_GetRGBA(tag, NULL);
700 if(flags & 2) { //has x offset
701 swf_ResetReadBits(tag);
704 if(flags & 1) { //has y offset
705 swf_ResetReadBits(tag);
708 if(flags & 8) { //has height
709 swf_ResetReadBits(tag);
713 flags = swf_GetBits(tag, 8);
715 swf_ResetReadBits(tag);
716 for(t=0;t<flags;t++) {
717 swf_GetBits(tag, glyphbits);
718 swf_GetBits(tag, advancebits);
723 case ST_DEFINEFONTALIGNZONES:
724 case ST_DEFINESCALINGGRID:
726 case ST_CSMTEXTSETTINGS:
727 case ST_DEFINEFONTINFO:
728 case ST_DEFINEFONTINFO2:
730 callback(tag, tag->pos + base, callback_data);
732 case ST_DEFINEVIDEOSTREAM:
735 case ST_DOINITACTION:
736 callback(tag, tag->pos + base, callback_data);
739 case ST_DEFINEMORPHSHAPE2:
740 case ST_DEFINESHAPE4:
742 case ST_DEFINEMORPHSHAPE:
743 case ST_DEFINESHAPE3:
745 case ST_DEFINESHAPE2:
747 case ST_DEFINESHAPE: {
753 if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) {
758 id = swf_GetU16(tag); // id;
760 swf_GetRect(tag, &r); // shape bounds
762 swf_ResetReadBits(tag);
763 swf_GetRect(tag, NULL); // shape bounds2
765 swf_GetRect(tag, NULL); // edge bounds1
768 swf_GetRect(tag, NULL); // edge bounds
769 swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
772 swf_GetU32(tag); //offset to endedges
775 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
776 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);
778 DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos);
779 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
780 DEBUG_ENUMERATE printf("-------\n");
781 while(--numshapes>=0) /* morph shapes define two shapes */
783 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
784 fillbits = swf_GetBits(tag, 4);
785 linebits = swf_GetBits(tag, 4);
786 DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits);
787 swf_ResetReadBits(tag);
790 flags = swf_GetBits(tag, 1);
791 if(!flags) { //style change
792 flags = swf_GetBits(tag, 5);
796 int n = swf_GetBits(tag, 5);
798 x = swf_GetBits(tag, n); //x
799 y = swf_GetBits(tag, n); //y
800 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
802 if(flags&2) { //fill0
804 fill0 = swf_GetBits(tag, fillbits);
805 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
807 if(flags&4) { //fill1
809 fill1 = swf_GetBits(tag, fillbits);
810 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
812 if(flags&8) { //linestyle
814 line = swf_GetBits(tag, linebits);
815 DEBUG_ENUMERATE printf("linestyle %d\n",line);
818 DEBUG_ENUMERATE printf("more fillstyles\n");
819 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
820 fillbits = swf_GetBits(tag, 4);
821 linebits = swf_GetBits(tag, 4);
824 flags = swf_GetBits(tag, 1);
825 if(flags) { //straight edge
826 int n = swf_GetBits(tag, 4) + 2;
827 if(swf_GetBits(tag, 1)) { //line flag
829 x = swf_GetSBits(tag, n); //delta x
830 y = swf_GetSBits(tag, n); //delta y
831 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
833 int v=swf_GetBits(tag, 1);
835 d = swf_GetSBits(tag, n); //vert/horz
836 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
838 } else { //curved edge
839 int n = swf_GetBits(tag, 4) + 2;
841 x1 = swf_GetSBits(tag, n);
842 y1 = swf_GetSBits(tag, n);
843 x2 = swf_GetSBits(tag, n);
844 y2 = swf_GetSBits(tag, n);
845 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
857 void callbackCount(TAG * t,int pos, void*ptr)
860 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
863 void callbackFillin(TAG * t,int pos, void*ptr)
867 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
870 int swf_GetNumUsedIDs(TAG * t)
873 enumerateUsedIDs(t, 0, callbackCount, &num);
877 void swf_GetUsedIDs(TAG * t, int * positions)
879 int * ptr = positions;
880 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
883 void swf_Relocate (SWF*swf, char*bitmap)
887 memset(slaveids, -1, sizeof(slaveids));
895 if(swf_isDefiningTag(tag))
900 id = swf_GetDefineID(tag); //own id
902 if(!bitmap[id]) { //free
907 for (t=1;t<65536;t++)
917 slaveids[id] = newid;
919 swf_SetDefineID(tag, newid);
922 num = swf_GetNumUsedIDs(tag);
924 ptr = rfx_alloc(sizeof(int)*num);
925 swf_GetUsedIDs(tag, ptr);
928 int id = GET16(&tag->data[ptr[t]]);
930 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
931 swf_TagGetName(tag));
935 PUT16(&tag->data[ptr[t]], id);
943 void swf_Relocate2(SWF*swf, int*id2id)
948 if(swf_isDefiningTag(tag)) {
949 int id = swf_GetDefineID(tag);
952 swf_SetDefineID(tag, id);
955 int num = swf_GetNumUsedIDs(tag);
959 ptr = rfx_alloc(sizeof(int)*num);
960 swf_GetUsedIDs(tag, ptr);
962 int id = GET16(&tag->data[ptr[t]]);
965 PUT16(&tag->data[ptr[t]], id);
972 void swf_RelocateDepth(SWF*swf, char*bitmap)
977 for(nr=65535;nr>=0;nr--) {
981 // now nr is the highest used depth. So we start
982 // assigning depths at nr+1
988 /* TODO * clip depths
991 if(tag->id == ST_PLACEOBJECT2) {
993 swf_GetPlaceObject(tag, &obj);
995 int newdepth = obj.clipdepth+nr;
997 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1000 obj.clipdepth = newdepth;
1001 swf_ResetTag(tag, ST_PLACEOBJECT2);
1002 swf_SetPlaceObject(tag, &obj);
1004 swf_PlaceObjectFree(&obj);
1007 depth = swf_GetDepth(tag);
1009 int newdepth = depth+nr;
1010 if(newdepth>65535) {
1011 fprintf(stderr, "Couldn't relocate depths: too large values\n");
1014 swf_SetDepth(tag, newdepth);
1020 U8 swf_isShapeTag(TAG*tag)
1022 if(tag->id == ST_DEFINESHAPE ||
1023 tag->id == ST_DEFINESHAPE2 ||
1024 tag->id == ST_DEFINESHAPE3 ||
1025 tag->id == ST_DEFINESHAPE4)
1030 U8 swf_isPlaceTag(TAG*tag)
1032 if(tag->id == ST_PLACEOBJECT ||
1033 tag->id == ST_PLACEOBJECT2 ||
1034 tag->id == ST_PLACEOBJECT3)
1038 U8 swf_isTextTag(TAG*tag)
1040 if(tag->id == ST_DEFINETEXT ||
1041 tag->id == ST_DEFINETEXT2)
1046 U8 swf_isFontTag(TAG*tag)
1048 if(tag->id == ST_DEFINEFONT ||
1049 tag->id == ST_DEFINEFONT2 ||
1050 tag->id == ST_DEFINEFONTINFO)
1055 U8 swf_isImageTag(TAG*tag)
1057 if(tag->id == ST_DEFINEBITSJPEG ||
1058 tag->id == ST_DEFINEBITSJPEG2 ||
1059 tag->id == ST_DEFINEBITSJPEG3 ||
1060 tag->id == ST_DEFINEBITSLOSSLESS ||
1061 tag->id == ST_DEFINEBITSLOSSLESS2)
1066 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1068 TAG*tag=0,*lasttag=0;
1070 char depthmap[65536];
1072 memset(bitmap, 0, sizeof(bitmap));
1073 memset(depthmap, 0, sizeof(depthmap));
1074 memset(&swf1, 0, sizeof(swf1));
1075 memset(&swf2, 0, sizeof(swf2));
1077 swf1.firstTag = list1;
1079 swf2.firstTag = list2;
1084 if(!swf_isDefiningTag(tag)) {
1085 int id = swf_GetDefineID(tag);
1088 if(tag->id == ST_PLACEOBJECT ||
1089 tag->id == ST_PLACEOBJECT2) {
1090 int depth = swf_GetDepth(tag);
1091 depthmap[depth] = 1;
1093 if(tag->id == ST_REMOVEOBJECT ||
1094 tag->id == ST_REMOVEOBJECT2) {
1095 int depth = swf_GetDepth(tag);
1096 depthmap[depth] = 0;
1101 swf_Relocate(&swf2, bitmap);
1102 swf_RelocateDepth(&swf2, depthmap);
1103 lasttag->next = swf2.firstTag;
1104 swf2.firstTag->prev = lasttag;
1106 return swf1.firstTag;
1109 static int tagHash(TAG*tag)
1112 unsigned int a = 0x6b973e5a;
1113 /* start at pos 2, as 0 and 1 are the id */
1114 for(t=2;t<tag->len;t++) {
1117 a += tag->data[t]*0xefbc35a5*b*(t+1);
1119 return a&0x7fffffff; //always return positive number
1122 void swf_Optimize(SWF*swf)
1124 const int hash_size = 131072;
1125 char* dontremap = rfx_calloc(sizeof(char)*65536);
1126 U16* remap = rfx_alloc(sizeof(U16)*65536);
1127 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1128 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1131 for(t=0;t<65536;t++) {
1137 tag = swf->firstTag;
1139 /* make sure we don't remap to this tag,
1140 as it might have different "helper tags"
1141 FIXME: a better way would be to compare
1142 the helper tags, too.
1144 if(swf_isPseudoDefiningTag(tag) &&
1145 tag->id != ST_NAMECHARACTER) {
1146 dontremap[swf_GetDefineID(tag)] = 1;
1150 tag = swf->firstTag;
1152 TAG*next = tag->next;
1155 int num = swf_GetNumUsedIDs(tag);
1156 int*positions = rfx_alloc(sizeof(int)*num);
1158 swf_GetUsedIDs(tag, positions);
1159 for(t=0;t<num;t++) {
1160 int id = GET16(&tag->data[positions[t]]);
1162 PUT16(&tag->data[positions[t]], id);
1164 rfx_free(positions);
1166 /* now look for previous tags with the same
1168 if(swf_isDefiningTag(tag)) {
1170 int id = swf_GetDefineID(tag);
1171 int hash = tagHash(tag);
1174 while((tag2 = hashmap[hash%hash_size])) {
1175 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1176 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1184 while(hashmap[hash%hash_size]) hash++;
1185 hashmap[hash%hash_size] = tag;
1187 /* we found two identical tags- remap one
1189 remap[id] = swf_GetDefineID(tag2);
1191 if(tag == swf->firstTag)
1192 swf->firstTag = next;
1194 } else if(swf_isPseudoDefiningTag(tag)) {
1195 int id = swf_GetDefineID(tag);
1197 /* if this tag was remapped, we don't
1198 need the helper tag anymore. Discard
1201 if(tag == swf->firstTag)
1202 swf->firstTag = next;
1209 rfx_free(dontremap);
1215 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1219 swf_SetTagPos(tag,0);
1221 switch (swf_GetTagID(tag))
1223 case ST_DEFINESHAPE:
1224 case ST_DEFINESHAPE2:
1225 case ST_DEFINESHAPE3:
1226 case ST_DEFINEEDITTEXT:
1228 case ST_DEFINETEXT2:
1229 case ST_DEFINEVIDEOSTREAM: {
1230 U32 after_bbox_offset = 0, len;
1232 id = swf_GetU16(tag);
1233 swf_GetRect(tag, &b1);
1234 swf_ResetReadBits(tag);
1235 after_bbox_offset = tag->pos;
1236 len = tag->len - after_bbox_offset;
1238 memcpy(data, &tag->data[after_bbox_offset], len);
1241 swf_SetRect(tag, &newbbox);
1242 swf_SetBlock(tag, data, len);
1244 tag->pos = tag->readBit = 0;
1248 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1252 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1254 TAG*t=swf->firstTag;
1256 color.r = color.b = color.g = 0;
1259 if(t->id == ST_SETBACKGROUNDCOLOR) {
1260 swf_SetTagPos(t, 0);
1261 color.r = swf_GetU8(t);
1262 color.g = swf_GetU8(t);
1263 color.b = swf_GetU8(t);