194ec72eb4b54591460f27c9585288ba1e5ac418
[swftools.git] / lib / modules / swftext.c
1 /* swftext.c
2
3    Text and font routines
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9    Copyright (c) 2003,2004 Matthias Kramm
10
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.
15
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.
20
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 */
24
25 #include "../rfxswf.h"
26
27 U32 readUTF8char(U8 ** text)
28 {
29     U32 c = 0;
30     if (!(*(*text) & 0x80))
31         return *((*text)++);
32
33     /* 0000 0080-0000 07FF   110xxxxx 10xxxxxx */
34     if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
35         c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
36         (*text) += 2;
37         return c;
38     }
39     /* 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx */
40     if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
41         c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
42         (*text) += 3;
43         return c;
44     }
45     /* 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
46     if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
47         && (*text)[3]) {
48         c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
49         (*text) += 4;
50         return c;
51     }
52     /* 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
53     if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
54         && (*text)[3]
55         && (*text)[4]) {
56         c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
57         (*text) += 5;
58         return c;
59     }
60     /* 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx */
61     if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
62         && (*text)[3]
63         && (*text)[4] && (*text)[5]) {
64         c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
65             ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
66         (*text) += 6;
67         return c;
68     }
69     return *((*text)++);
70 }
71
72 #define TF_TEXTCONTROL  0x80
73 #define TF_HASFONT      0x08
74 #define TF_HASCOLOR     0x04
75 #define TF_HASYOFFSET   0x02
76 #define TF_HASXOFFSET   0x01
77
78 #define FF_WIDECODES    0x01
79 #define FF_BOLD         0x02
80 #define FF_ITALIC       0x04
81 #define FF_ANSI         0x08
82 #define FF_SHIFTJIS     0x10
83 #define FF_UNICODE      0x20
84
85 #define FF2_BOLD         0x01
86 #define FF2_ITALIC       0x02
87 #define FF2_WIDECODES    0x04
88 #define FF2_WIDEOFFSETS  0x08
89 #define FF2_ANSI         0x10
90 #define FF2_UNICODE      0x20
91 #define FF2_SHIFTJIS     0x40
92 #define FF2_LAYOUT       0x80
93
94 int swf_FontIsItalic(SWFFONT * f)
95 {
96     return f->style & FONT_STYLE_ITALIC;
97 }
98
99 int swf_FontIsBold(SWFFONT * f)
100 {
101     return f->style & FONT_STYLE_BOLD;
102 }
103
104 static const int WRITEFONTID = 0x4e46;  // font id for WriteFont and ReadFont
105
106 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
107 {
108     int n;
109     TAG *t;
110     if (!swf)
111         return -1;
112     t = swf->firstTag;
113     n = 0;
114
115     while (t) {
116         if (swf_isFontTag(t)) {
117             n++;
118             if (FontCallback) {
119                 U16 id;
120                 int l;
121                 U8 s[257];
122                 s[0] = 0;
123                 swf_SetTagPos(t, 0);
124
125                 id = swf_GetU16(t);
126                 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
127                     swf_GetU16(t);
128                     l = swf_GetU8(t);
129                     swf_GetBlock(t, s, l);
130                     s[l] = 0;
131                 }
132
133                 (FontCallback) (self, id, s);
134             }
135         }
136         t = swf_NextTag(t);
137     }
138     return n;
139 }
140
141 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
142 {
143     U16 fid;
144     swf_SetTagPos(t, 0);
145
146     fid = swf_GetU16(t);
147     if ((!id) || (id == fid)) {
148         U16 of;
149         int n, i;
150
151         id = fid;
152         f->version = 1;
153         f->id = fid;
154
155         of = swf_GetU16(t);
156         n = of / 2;
157         f->numchars = n;
158         f->glyph = (SWFGLYPH*)rfx_calloc(sizeof(SWFGLYPH) * n);
159
160         for (i = 1; i < n; i++)
161             swf_GetU16(t);
162         for (i = 0; i < n; i++)
163             swf_GetSimpleShape(t, &f->glyph[i].shape);
164     }
165     return id;
166 }
167
168 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
169 {
170     U16 fid;
171     U16 maxcode;
172     U8 flags;
173     swf_SetTagPos(t, 0);
174
175     fid = swf_GetU16(t);
176     if (fid == id) {
177         U8 l = swf_GetU8(t);
178         int i;
179
180         if (f->version > 1) {
181             /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
182                too. However, they only add little information to what's already
183                inside the DefineFont2 tag */
184             return id;
185         }
186
187         if (f->name)
188             rfx_free(f->name);
189
190         f->name = (U8 *) rfx_alloc(l + 1);
191         swf_GetBlock(t, f->name, l);
192         f->name[l] = 0;
193
194         flags = swf_GetU8(t);
195         if (flags & 2)
196             f->style |= FONT_STYLE_BOLD;
197         if (flags & 4)
198             f->style |= FONT_STYLE_ITALIC;
199         if (flags & 8)
200             f->encoding |= FONT_ENCODING_ANSI;
201         if (flags & 16)
202             f->encoding |= FONT_ENCODING_SHIFTJIS;
203         if (flags & 32)
204             f->encoding |= FONT_ENCODING_UNICODE;
205
206         if (t->id == ST_DEFINEFONTINFO2) {
207             f->language = swf_GetU8(t);
208         }
209
210         f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
211         maxcode = 0;
212         for (i = 0; i < f->numchars; i++) {
213             f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
214             if (f->glyph2ascii[i] > maxcode)
215                 maxcode = f->glyph2ascii[i];
216         }
217         maxcode++;
218         if (maxcode < 256)
219             maxcode = 256;
220         f->maxascii = maxcode;
221         f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
222         memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
223
224         for (i = 0; i < f->numchars; i++)
225             f->ascii2glyph[f->glyph2ascii[i]] = i;
226     }
227     return id;
228 }
229
230 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
231 {
232     U16 fid;
233     swf_SetTagPos(tag, 0);
234
235     fid = swf_GetU16(tag);
236
237     if (fid == id) {
238         int num = swf_GetU16(tag);
239         int t;
240         f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
241         for (t = 0; t < num; t++) {
242             f->glyphnames[t] = strdup(swf_GetString(tag));
243         }
244     }
245     return id;
246 }
247
248
249 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
250 {
251     int t, glyphcount;
252     int maxcode;
253     int fid;
254     U32 offset_start;
255     U32 *offset;
256     U8 flags1, langcode, namelen;
257     swf_SetTagPos(tag, 0);
258     font->version = 2;
259     fid = swf_GetU16(tag);
260     if (id && id != fid)
261         return id;
262     font->id = fid;
263     flags1 = swf_GetU8(tag);
264     langcode = swf_GetU8(tag);  //reserved flags
265
266     if (flags1 & 1)
267         font->style |= FONT_STYLE_BOLD;
268     if (flags1 & 2)
269         font->style |= FONT_STYLE_ITALIC;
270     if (flags1 & 16)
271         font->encoding |= FONT_ENCODING_ANSI;
272     if (flags1 & 32)
273         font->encoding |= FONT_ENCODING_UNICODE;
274     if (flags1 & 64)
275         font->encoding |= FONT_ENCODING_SHIFTJIS;
276
277     namelen = swf_GetU8(tag);
278     font->name = (U8 *) rfx_alloc(namelen + 1);
279     font->name[namelen] = 0;
280     swf_GetBlock(tag, font->name, namelen);
281     font->version = 2;
282     glyphcount = swf_GetU16(tag);
283     font->numchars = glyphcount;
284
285     font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
286     font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
287
288     offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
289     offset_start = tag->pos;
290
291     if (flags1 & 8) {           // wide offsets
292         for (t = 0; t < glyphcount; t++)
293             offset[t] = swf_GetU32(tag);        //offset[t]
294
295         if (glyphcount)         /* this _if_ is not in the specs */
296             offset[glyphcount] = swf_GetU32(tag);       // fontcodeoffset
297         else
298             offset[glyphcount] = tag->pos;
299     } else {
300         for (t = 0; t < glyphcount; t++)
301             offset[t] = swf_GetU16(tag);        //offset[t]
302
303         if (glyphcount)         /* this _if_ is not in the specs */
304             offset[glyphcount] = swf_GetU16(tag);       // fontcodeoffset
305         else
306             offset[glyphcount] = tag->pos;
307     }
308     for (t = 0; t < glyphcount; t++) {
309         swf_SetTagPos(tag, offset[t]+offset_start);
310         swf_GetSimpleShape(tag, &(font->glyph[t].shape));
311     }
312
313     if(glyphcount)
314         swf_SetTagPos(tag, offset[glyphcount]+offset_start);
315
316     free(offset);
317
318     maxcode = 0;
319     for (t = 0; t < glyphcount; t++) {
320         int code;
321         if (flags1 & 4)         // wide codes (always on for definefont3)
322             code = swf_GetU16(tag);
323         else
324             code = swf_GetU8(tag);
325         font->glyph2ascii[t] = code;
326         if (code > maxcode)
327             maxcode = code;
328     }
329     maxcode++;
330     if (maxcode < 256)
331         maxcode = 256;
332     font->maxascii = maxcode;
333     font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
334     memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
335     for (t = 0; t < glyphcount; t++) {
336         font->ascii2glyph[font->glyph2ascii[t]] = t;
337     }
338
339     if (flags1 & 128) {         // has layout
340         U16 kerningcount;
341         font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
342         font->layout->ascent = swf_GetU16(tag);
343         font->layout->descent = swf_GetU16(tag);
344         font->layout->leading = swf_GetU16(tag);
345         for (t = 0; t < glyphcount; t++) {
346             S16 advance = swf_GetS16(tag);
347             font->glyph[t].advance = advance;
348         }
349         font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
350         for (t = 0; t < glyphcount; t++) {
351             swf_ResetReadBits(tag);
352             swf_GetRect(tag, &font->layout->bounds[t]);
353         }
354
355         kerningcount = swf_GetU16(tag);
356         font->layout->kerningcount = kerningcount;
357
358         font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
359         if (kerningcount) {
360             font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
361             for (t = 0; t < kerningcount; t++) {
362                 if (flags1 & 4) {       // wide codes
363                     font->layout->kerning[t].char1 = swf_GetU16(tag);
364                     font->layout->kerning[t].char2 = swf_GetU16(tag);
365                 } else {
366                     font->layout->kerning[t].char1 = swf_GetU8(tag);
367                     font->layout->kerning[t].char2 = swf_GetU8(tag);
368                 }
369                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
370             }
371         }
372     }
373     return font->id;
374 }
375
376 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
377 {
378     U16 fid;
379     swf_SetTagPos(tag, 0);
380     fid = swf_GetU16(tag);
381     
382     if (fid == id) {
383         font->alignzone_flags = swf_GetU8(tag);
384         font->alignzones = rfx_calloc(sizeof(ALIGNZONE)*font->numchars);
385         int i=0;
386         while(tag->pos < tag->len) {
387             if(i>=font->numchars)
388                 break;
389             int nr = swf_GetU8(tag); // should be 2
390             if(nr!=1 && nr!=2) {
391                 fprintf(stderr, "rfxswf: Can't parse alignzone tags with %d zones", nr);
392                 break;
393             }
394             U16 x = swf_GetU16(tag);
395             U16 y = swf_GetU16(tag);
396             U16 dx = (nr==2)?swf_GetU16(tag):0xffff;
397             U16 dy = (nr==2)?swf_GetU16(tag):0xffff;
398             U8 xy = swf_GetU8(tag);
399
400 #ifdef DEBUG_RFXSWF
401             if((!(xy&1) && (x!=0 || (dx!=0 && dx!=0xffff))) ||
402                (!(xy&2) && (y!=0 || (dy!=0 && dy!=0xffff)))) {
403                 fprintf(stderr, "Warning: weird combination of alignzone bits and values (%d x:%04x-%04x y:%04x-%04x)\n", xy,
404                         x,dx,y,dy);
405             }
406 #endif
407             if(!(xy&1)) {
408                 x = 0xffff;
409                 dx = 0xffff;
410             } else if(!(xy&2)) {
411                 y = 0xffff;
412                 dy = 0xffff;
413             }
414             font->alignzones[i].x = x;
415             font->alignzones[i].y = y;
416             font->alignzones[i].dx = dx;
417             font->alignzones[i].dy = dy;
418             i++;
419         }
420     }
421     return id;
422 }
423
424
425 #define FEDTJ_PRINT  0x01
426 #define FEDTJ_MODIFY 0x02
427 #define FEDTJ_CALLBACK 0x04
428
429 static int
430 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
431                                    void (*callback) (void *self,
432                                                      int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
433 {
434     U16 cid;
435     SRECT r;
436     MATRIX m;
437     U8 gbits, abits;
438     int fid = -1;
439     RGBA color;
440     int x = 0, y = 0;
441     int fontsize = 0;
442
443     memset(&color, 0, sizeof(color));
444
445     swf_SetTagPos(t, 0);
446
447     cid = swf_GetU16(t);
448     swf_GetRect(t, &r);
449     swf_GetMatrix(t, &m);
450     gbits = swf_GetU8(t);
451     abits = swf_GetU8(t);
452
453     while (1) {
454         int flags, num;
455         flags = swf_GetU8(t);
456         if (!flags)
457             break;
458
459         if (flags & TF_TEXTCONTROL) {
460             if (flags & TF_HASFONT)
461                 fid = swf_GetU16(t);
462             if (flags & TF_HASCOLOR) {
463                 color.r = swf_GetU8(t); // rgb
464                 color.g = swf_GetU8(t);
465                 color.b = swf_GetU8(t);
466                 if (swf_GetTagID(t) == ST_DEFINETEXT2)
467                     color.a = swf_GetU8(t);
468                 else
469                     color.a = 255;
470             }
471             if (flags & TF_HASXOFFSET)
472                 x = swf_GetS16(t);
473             if (flags & TF_HASYOFFSET)
474                 y = swf_GetS16(t);
475             if (flags & TF_HASFONT)
476                 fontsize = swf_GetU16(t);
477         }
478
479         num = swf_GetU8(t);
480         if (!num)
481             break;
482
483         {
484             int i;
485             int buf[256];
486             int advance[256];
487             int xpos = 0;
488             for (i = 0; i < num; i++) {
489                 int glyph;
490                 int adv = 0;
491                 advance[i] = xpos;
492                 glyph = swf_GetBits(t, gbits);
493                 adv = swf_GetBits(t, abits);
494                 xpos += adv;
495
496                 if (id == fid) {
497                     if (jobs & FEDTJ_PRINT) {
498                         int code = f->glyph2ascii[glyph];
499                         printf("%lc", code);
500                     }
501                     if (jobs & FEDTJ_MODIFY)
502                         f->glyph[glyph].advance = adv * 20;     //?
503                 }
504
505                 buf[i] = glyph;
506             }
507             if ((id == fid) && (jobs & FEDTJ_PRINT))
508                 printf("\n");
509             if (jobs & FEDTJ_CALLBACK)
510                 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
511             x += xpos;
512         }
513     }
514
515     return id;
516 }
517
518 int swf_ParseDefineText(TAG * tag,
519                     void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
520 {
521     return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
522 }
523
524 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
525 {
526     return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
527 }
528
529 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
530 {
531     TAG *t;
532     SWFFONT *f;
533
534     if ((!swf) || (!font))
535         return -1;
536
537     f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
538
539     t = swf->firstTag;
540
541     while (t) {
542         int nid = 0;
543         switch (swf_GetTagID(t)) {
544         case ST_DEFINEFONT:
545             nid = swf_FontExtract_DefineFont(id, f, t);
546             break;
547
548         case ST_DEFINEFONT2:
549         case ST_DEFINEFONT3:
550             nid = swf_FontExtract_DefineFont2(id, f, t);
551             break;
552
553         case ST_DEFINEFONTALIGNZONES:
554             nid = swf_FontExtract_DefineFontAlignZones(id, f, t);
555             break;
556
557         case ST_DEFINEFONTINFO:
558         case ST_DEFINEFONTINFO2:
559             nid = swf_FontExtract_DefineFontInfo(id, f, t);
560             break;
561
562         case ST_DEFINETEXT:
563         case ST_DEFINETEXT2:
564             nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
565             break;
566
567         case ST_GLYPHNAMES:
568             nid = swf_FontExtract_GlyphNames(id, f, t);
569             break;
570         }
571         if (nid > 0)
572             id = nid;
573         t = swf_NextTag(t);
574     }
575     if (f->id != id) {
576         rfx_free(f);
577         f = 0;
578     }
579     font[0] = f;
580     return 0;
581 }
582
583 int swf_FontSetID(SWFFONT * f, U16 id)
584 {
585     if (!f)
586         return -1;
587     f->id = id;
588     return 0;
589 }
590
591 void swf_LayoutFree(SWFLAYOUT * l)
592 {
593     if (l) {
594         if (l->kerning)
595             rfx_free(l->kerning);
596         l->kerning = NULL;
597         if (l->bounds)
598             rfx_free(l->bounds);
599         l->bounds = NULL;
600     }
601     rfx_free(l);
602 }
603
604
605 static void font_freeglyphnames(SWFFONT*f)
606 {
607     if (f->glyphnames)
608     {
609         int t;
610         for (t = 0; t < f->numchars; t++)
611         {
612             if (f->glyphnames[t])
613             {
614                 rfx_free(f->glyphnames[t]);
615                 f->glyphnames[t] = 0;
616             }
617         }
618         rfx_free(f->glyphnames);
619         f->glyphnames = 0;
620         }
621 }
622 static void font_freeusage(SWFFONT*f)
623 {
624     if (f->use) {
625         if(f->use->chars) {
626             rfx_free(f->use->chars);f->use->chars = 0;
627         }
628         rfx_free(f->use); f->use = 0;
629     }
630 }
631 static void font_freelayout(SWFFONT*f)
632 {
633     if (f->layout) {
634         swf_LayoutFree(f->layout);
635         f->layout = 0;
636     }
637 }
638 static void font_freename(SWFFONT*f)
639 {
640     if (f->name) {
641         rfx_free(f->name);
642         f->name = 0;
643     }
644 }
645
646 int swf_FontReduce_old(SWFFONT * f)
647 {
648     int i, j;
649     int max_unicode = 0;
650     if ((!f) || (!f->use) || f->use->is_reduced)
651         return -1;
652
653     j = 0;
654
655     for (i = 0; i < f->numchars; i++) {
656         if (f->glyph[i].shape && f->use->chars[i]) {
657             f->glyph2ascii[j] = f->glyph2ascii[i];
658             f->glyph[j] = f->glyph[i];
659             f->use->chars[i] = j;
660             j++;
661         } else {
662             f->glyph2ascii[i] = 0;
663             if(f->glyph[i].shape) {
664                 swf_ShapeFree(f->glyph[i].shape);
665                 f->glyph[i].shape = 0;
666                 f->glyph[i].advance = 0;
667             }
668             f->use->chars[i] = -1;
669             j++; //TODO: remove
670         }
671     }
672     for (i = 0; i < f->maxascii; i++) {
673         if(f->use->chars[f->ascii2glyph[i]]<0) {
674             f->ascii2glyph[i] = -1;
675         } else {
676             f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
677             max_unicode = i;
678         }
679     }
680     f->maxascii = max_unicode;
681     f->use->is_reduced = 1;
682     f->numchars = j;
683     font_freelayout(f);
684     font_freeglyphnames(f);
685     font_freename(f);
686     return j;
687 }
688
689 int swf_FontReduce_swfc(SWFFONT * f)
690 {
691     int i, j;
692     int max_unicode = 0;
693     if ((!f) || (!f->use) || f->use->is_reduced)
694         return -1;
695
696     font_freeglyphnames(f);
697
698     j = 0;
699     for (i = 0; i < f->numchars; i++) {
700         if (f->glyph[i].shape && f->use->chars[i]) {
701             f->glyph2ascii[j] = f->glyph2ascii[i];
702             if (f->layout)
703                 f->layout->bounds[j] = f->layout->bounds[i];
704             f->glyph[j] = f->glyph[i];
705             f->use->chars[i] = j;
706             j++;
707         } else {
708             f->glyph2ascii[i] = 0;
709             if(f->glyph[i].shape) {
710                 swf_ShapeFree(f->glyph[i].shape);
711                 f->glyph[i].shape = 0;
712                 f->glyph[i].advance = 0;
713             }
714             f->use->chars[i] = -1;
715         }
716     }
717     f->use->used_glyphs = j;
718     for (i = 0; i < f->maxascii; i++) {
719         if(f->ascii2glyph[i] > -1) {
720             if (f->use->chars[f->ascii2glyph[i]]<0) {
721                 f->use->chars[f->ascii2glyph[i]] = 0;
722                 f->ascii2glyph[i] = -1;
723             } else {
724                 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
725                 f->use->chars[f->ascii2glyph[i]] = 1;
726                 max_unicode = i + 1;
727             }
728         }
729     }
730     f->maxascii = max_unicode;
731     f->use->is_reduced = 1;
732     f->numchars = j;
733     font_freename(f);
734     return j;
735 }
736
737 int swf_FontReduce(SWFFONT * f)
738 {
739     int i;
740     int max_unicode = 0;
741     int max_glyph = 0;
742     if ((!f) || (!f->use) || f->use->is_reduced)
743         return -1;
744
745     font_freelayout(f);
746     font_freeglyphnames(f);
747
748     f->use->used_glyphs= 0;
749     for (i = 0; i < f->numchars; i++) {
750         if(!f->use->chars[i]) {
751             if(f->glyph2ascii) {
752                 f->glyph2ascii[i] = 0;
753             }
754             if(f->glyph[i].shape) {
755                 swf_ShapeFree(f->glyph[i].shape);
756                 f->glyph[i].shape = 0;
757                 f->glyph[i].advance = 0;
758             }
759 //          f->use->used_glyphs++;
760         } else {
761             f->use->used_glyphs++;
762             max_glyph = i+1;
763         }
764     }
765     for (i = 0; i < f->maxascii; i++) {
766         if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
767             if(f->ascii2glyph) {
768                 f->ascii2glyph[i] = -1;
769             }
770         } else {
771             max_unicode = i+1;
772         }
773     }
774     f->maxascii = max_unicode;
775     f->numchars = max_glyph;
776     font_freename(f);
777     return 0;
778 }
779
780 void swf_FontSort(SWFFONT * font)
781 {
782     int i, j;
783     int *newplace;
784     int *newpos;
785     if (!font)
786         return;
787
788     newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
789
790     for (i = 0; i < font->numchars; i++) {
791         newplace[i] = i;
792     }
793     for (i = 0; i < font->numchars; i++)
794         for (j = 0; j < i; j++) {
795             if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
796                 int n1, n2;
797                 char *c1, *c2;
798                 SWFGLYPH g1, g2;
799                 SRECT r1, r2;
800                 n1 = newplace[i];
801                 n2 = newplace[j];
802                 newplace[j] = n1;
803                 newplace[i] = n2;
804                 n1 = font->glyph2ascii[i];
805                 n2 = font->glyph2ascii[j];
806                 font->glyph2ascii[j] = n1;
807                 font->glyph2ascii[i] = n2;
808                 g1 = font->glyph[i];
809                 g2 = font->glyph[j];
810                 font->glyph[j] = g1;
811                 font->glyph[i] = g2;
812                 if (font->glyphnames) {
813                     c1 = font->glyphnames[i];
814                     c2 = font->glyphnames[j];
815                     font->glyphnames[j] = c1;
816                     font->glyphnames[i] = c2;
817                 }
818                 if (font->layout) {
819                     r1 = font->layout->bounds[i];
820                     r2 = font->layout->bounds[j];
821                     font->layout->bounds[j] = r1;
822                     font->layout->bounds[i] = r2;
823                 }
824             }
825         }
826     newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
827     for (i = 0; i < font->numchars; i++) {
828         newpos[newplace[i]] = i;
829     }
830     for (i = 0; i < font->maxascii; i++) {
831         if (font->ascii2glyph[i] >= 0)
832             font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
833     }
834
835     rfx_free(newpos);
836     rfx_free(newplace);
837 }
838
839 void swf_FontPrepareForEditText(SWFFONT * font)
840 {
841     if (!font->layout)
842         swf_FontCreateLayout(font);
843     swf_FontSort(font);
844 }
845
846 int swf_FontInitUsage(SWFFONT * f)
847 {
848     if (!f)
849         return -1;
850     if(f->use) {
851         fprintf(stderr, "Usage initialized twice");
852         return -1;
853     }
854     f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
855     f->use->is_reduced = 0;
856     f->use->smallest_size = 0xffff;
857     f->use->used_glyphs = 0;
858     f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
859     f->use->glyphs_specified = 0;
860     return 0;
861 }
862
863 void swf_FontClearUsage(SWFFONT * f)
864 {
865     if (!f || !f->use)
866         return;
867     rfx_free(f->use->chars); f->use->chars = 0;
868     rfx_free(f->use); f->use = 0;
869 }
870
871 int swf_FontUse(SWFFONT * f, U8 * s)
872 {
873     if( (!s))
874         return -1;
875     while (*s) {
876         if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
877             swf_FontUseGlyph(f, f->ascii2glyph[*s], /*FIXME*/0xffff);
878         s++;
879     }
880     return 0;
881 }
882
883 int swf_FontUseUTF8(SWFFONT * f, U8 * s, U16 size)
884 {
885     if( (!s))
886         return -1;
887     int ascii;
888     while (*s)
889     {
890         ascii = readUTF8char(&s);
891         if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
892             swf_FontUseGlyph(f, f->ascii2glyph[ascii], size);
893     }
894     return 0;
895 }
896
897 int swf_FontUseAll(SWFFONT* f)
898 {
899     int i;
900
901     if (!f->use)
902         swf_FontInitUsage(f);
903     for (i = 0; i < f->numchars; i++)
904         f->use->chars[i] = 1;
905     f->use->used_glyphs = f->numchars;
906     return 0;
907 }
908
909 int swf_FontUseGlyph(SWFFONT * f, int glyph, U16 size)
910 {
911     if (!f->use)
912         swf_FontInitUsage(f);
913     if(glyph < 0 || glyph >= f->numchars)
914         return -1;
915     if(!f->use->chars[glyph])
916         f->use->used_glyphs++;
917     f->use->chars[glyph] = 1;
918     if(size && size < f->use->smallest_size)
919         f->use->smallest_size = size;
920     return 0;
921 }
922
923 int swf_FontSetDefine(TAG * t, SWFFONT * f)
924 {
925     U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
926     int p, i, j;
927
928     if ((!t) || (!f))
929         return -1;
930     swf_ResetWriteBits(t);
931     swf_SetU16(t, f->id);
932
933     p = 0;
934     j = 0;
935     for (i = 0; i < f->numchars; i++)
936         if (f->glyph[i].shape) {
937             ofs[j++] = p;
938             p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
939         }
940
941     for (i = 0; i < j; i++)
942         swf_SetU16(t, ofs[i] + j * 2);
943     if (!j) {
944         fprintf(stderr, "rfxswf: warning: Font is empty\n");
945         swf_SetU16(t, 0);
946     }
947
948     for (i = 0; i < f->numchars; i++)
949         if (f->glyph[i].shape)
950             swf_SetSimpleShape(t, f->glyph[i].shape);
951
952     swf_ResetWriteBits(t);
953     rfx_free(ofs);
954     return 0;
955 }
956
957 static inline int fontSize(SWFFONT * font)
958 {
959     int t;
960     int size = 0;
961     for (t = 0; t < font->numchars; t++) {
962         int l = 0;
963         if(font->glyph[t].shape)
964             l = (font->glyph[t].shape->bitlen + 7) / 8;
965         else
966             l = 8;
967         size += l + 1;
968     }
969     return size + (font->numchars + 1) * 2;
970 }
971
972 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
973 {
974     U8 flags = 0;
975     int t;
976     int pos;
977     swf_SetU16(tag, f->id);
978
979     if (f->layout) flags |= 128;                // haslayout
980     if (f->numchars > 256)
981         flags |= 4;             // widecodes
982     if (f->style & FONT_STYLE_BOLD)
983         flags |= 1;             // bold
984     if (f->style & FONT_STYLE_ITALIC)
985         flags |= 2;             // italic
986     if (f->maxascii >= 256)
987         flags |= 4;             //wide codecs
988     if (fontSize(f) > 65535)
989         flags |= 8;             //wide offsets
990     flags |= 8 | 4;             //FIXME: the above check doesn't work
991
992     if (f->encoding & FONT_ENCODING_ANSI)
993         flags |= 16;            // ansi
994     if (f->encoding & FONT_ENCODING_UNICODE)
995         flags |= 32;            // unicode
996     if (f->encoding & FONT_ENCODING_SHIFTJIS)
997         flags |= 64;            // shiftjis
998
999     swf_SetU8(tag, flags);
1000     swf_SetU8(tag, 0);          //reserved flags
1001     if (f->name) {
1002         /* font name */
1003         swf_SetU8(tag, strlen((const char*)f->name)+1);
1004         swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1005     } else {
1006         /* font name (="") */
1007         swf_SetU8(tag, 1);
1008         swf_SetU8(tag, 0);
1009     }
1010     /* number of glyphs */
1011     swf_SetU16(tag, f->numchars);
1012     /* font offset table */
1013     pos = tag->len;
1014     for (t = 0; t <= f->numchars; t++) {
1015         if (flags & 8)
1016             swf_SetU32(tag, /* fontoffset */ 0);        /*placeholder */
1017         else
1018             swf_SetU16(tag, /* fontoffset */ 0);        /*placeholder */
1019     }
1020
1021     for (t = 0; t <= f->numchars; t++) {
1022         if (flags & 8) {
1023             tag->data[pos + t * 4] = (tag->len - pos);
1024             tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1025             tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1026             tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1027         } else {
1028             if (tag->len - pos > 65535) {
1029                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1030                 exit(1);
1031             }
1032             tag->data[pos + t * 2] = (tag->len - pos);
1033             tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1034         }
1035         if (t < f->numchars) {
1036             if(f->glyph[t].shape) {
1037                 swf_SetSimpleShape(tag, f->glyph[t].shape);
1038             } else {
1039                 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1040             }
1041         }
1042     }
1043
1044
1045     /* font code table */
1046     for (t = 0; t < f->numchars; t++) {
1047         if (flags & 4) {                /* wide codes */
1048             if(f->glyph2ascii[t]) {
1049                 swf_SetU16(tag, f->glyph2ascii[t]);
1050             } else {
1051                 swf_SetU16(tag, 0);
1052             }
1053         } else {
1054             if(f->glyph2ascii[t]) {
1055                 swf_SetU8(tag, f->glyph2ascii[t]);
1056             } else {
1057                 swf_SetU8(tag, 0);
1058             }
1059         }
1060     }
1061
1062     if (f->layout) {
1063         swf_SetU16(tag, f->layout->ascent);
1064         swf_SetU16(tag, f->layout->descent);
1065         swf_SetU16(tag, f->layout->leading);
1066         for (t = 0; t < f->numchars; t++)
1067             swf_SetU16(tag, f->glyph[t].advance);
1068         for (t = 0; t < f->numchars; t++) {
1069             swf_ResetWriteBits(tag);
1070             swf_SetRect(tag, &f->layout->bounds[t]);
1071         }
1072         swf_SetU16(tag, f->layout->kerningcount);
1073         for (t = 0; t < f->layout->kerningcount; t++) {
1074             if (flags & 4) {    /* wide codes */
1075                 swf_SetU16(tag, f->layout->kerning[t].char1);
1076                 swf_SetU16(tag, f->layout->kerning[t].char2);
1077             } else {
1078                 swf_SetU8(tag, f->layout->kerning[t].char1);
1079                 swf_SetU8(tag, f->layout->kerning[t].char2);
1080             }
1081             swf_SetU16(tag, f->layout->kerning[t].adjustment);
1082         }
1083     }
1084     return 0;
1085 }
1086
1087 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1088 {
1089     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1090     f->layout->ascent = ascent;
1091     f->layout->descent = descent;
1092     f->layout->leading = leading;
1093     f->layout->kerningcount = 0;
1094     f->layout->kerning = 0;
1095     f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1096 }
1097
1098 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1099 {
1100     int l, i;
1101     U8 wide = 0;
1102     U8 flags = 0;
1103     if ((!t) || (!f))
1104         return -1;
1105     swf_ResetWriteBits(t);
1106     swf_SetU16(t, f->id);
1107     l = f->name ? strlen((const char *)f->name) : 0;
1108     if (l > 255)
1109         l = 255;
1110     swf_SetU8(t, l);
1111     if (l)
1112         swf_SetBlock(t, f->name, l);
1113     if (f->numchars >= 256)
1114         wide = 1;
1115
1116     if (f->style & FONT_STYLE_BOLD)
1117         flags |= 2;
1118     if (f->style & FONT_STYLE_ITALIC)
1119         flags |= 4;
1120     if (f->style & FONT_ENCODING_ANSI)
1121         flags |= 8;
1122     if (f->style & FONT_ENCODING_SHIFTJIS)
1123         flags |= 16;
1124     if (f->style & FONT_ENCODING_UNICODE)
1125         flags |= 32;
1126
1127     swf_SetU8(t, (flags & 0xfe) | wide);
1128
1129     for (i = 0; i < f->numchars; i++) {
1130         if (f->glyph[i].shape) {
1131             int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1132             wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1133         }
1134     }
1135
1136     return 0;
1137 }
1138
1139 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1140 {
1141     int id = swf_GetTagID(t);
1142     if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1143         swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1144     else
1145         return -1;
1146     return 0;
1147 }
1148
1149 void swf_FontFree(SWFFONT * f)
1150 {
1151     int i;
1152     if (!f)
1153         return;
1154
1155     if (f->glyph)
1156     {
1157         for (i = 0; i < f->numchars; i++)
1158             if (f->glyph[i].shape)
1159             {
1160                 swf_ShapeFree(f->glyph[i].shape);
1161                 f->glyph[i].shape = NULL;
1162             }
1163             rfx_free(f->glyph);
1164             f->glyph = NULL;
1165     }
1166     if (f->ascii2glyph)
1167     {
1168         rfx_free(f->ascii2glyph);
1169         f->ascii2glyph = NULL;
1170     }
1171     if (f->glyph2ascii)
1172     {
1173         rfx_free(f->glyph2ascii);
1174         f->glyph2ascii = NULL;
1175     }
1176     font_freename(f);
1177     font_freelayout(f);
1178     font_freeglyphnames(f);
1179     font_freeusage(f);
1180
1181     rfx_free(f);
1182 }
1183
1184 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1185 {
1186     U8 flags;
1187     if (!t)
1188         return -1;
1189
1190     flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1191         | (y ? TF_HASYOFFSET : 0);
1192
1193     swf_SetU8(t, flags);
1194     if (font)
1195         swf_SetU16(t, font->id);
1196     if (color) {
1197         if (swf_GetTagID(t) == ST_DEFINETEXT2)
1198             swf_SetRGBA(t, color);
1199         else
1200             swf_SetRGB(t, color);
1201     }
1202     if (x) {
1203         if(x != SET_TO_ZERO) {
1204             if(x>32767 || x<-32768)
1205                 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1206             swf_SetS16(t, x);
1207         } else {
1208             swf_SetS16(t, 0);
1209         }
1210     }
1211     if (y) {
1212         if(y != SET_TO_ZERO) {
1213             if(y>32767 || y<-32768)
1214                 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1215             swf_SetS16(t, y);
1216         } else {
1217             swf_SetS16(t, 0);
1218         }
1219     }
1220     if (font)
1221         swf_SetU16(t, size);
1222
1223     return 0;
1224 }
1225
1226 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1227 {
1228     U16 g, a;
1229     char utf8 = 0;
1230     if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1231         return -1;
1232     g = a = 0;
1233
1234     if (!strcmp(encoding, "UTF8"))
1235         utf8 = 1;
1236     else if (!strcmp(encoding, "iso-8859-1"))
1237         utf8 = 0;
1238     else
1239         fprintf(stderr, "Unknown encoding: %s", encoding);
1240
1241     while (*s) {
1242         int glyph = -1, c;
1243
1244         if (!utf8)
1245             c = *s++;
1246         else
1247             c = readUTF8char(&s);
1248
1249         if (c < font->maxascii)
1250             glyph = font->ascii2glyph[c];
1251         if (glyph >= 0) {
1252             g = swf_CountUBits(glyph, g);
1253             a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1254         }
1255     }
1256
1257     if (gbits)
1258         gbits[0] = (U8) g;
1259     if (abits)
1260         abits[0] = (U8) a;
1261     return 0;
1262 }
1263
1264 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1265 {
1266     int l = 0, pos;
1267     char utf8 = 0;
1268
1269     if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1270         return -1;
1271
1272     if (!strcmp(encoding, "UTF8"))
1273         utf8 = 1;
1274     else if (!strcmp(encoding, "iso-8859-1"))
1275         utf8 = 0;
1276     else
1277         fprintf(stderr, "Unknown encoding: %s", encoding);
1278
1279     pos = t->len;
1280     swf_SetU8(t, l);            //placeholder
1281
1282     while (*s) {
1283         int g = -1, c;
1284
1285         if (!utf8)
1286             c = *s++;
1287         else
1288             c = readUTF8char(&s);
1289
1290         if (c < font->maxascii)
1291             g = font->ascii2glyph[c];
1292         if (g >= 0) {
1293             swf_SetBits(t, g, gbits);
1294             swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1295             l++;
1296             /* We split into 127 characters per text field.
1297                We could do 255, by the (formerly wrong) flash specification,
1298                but some SWF parsing code out there still assumes that char blocks
1299                are at max 127 characters, and it would save only a few bits.
1300             */
1301             if (l == 0x7f)
1302                 break;
1303         }
1304     }
1305
1306     PUT8(&t->data[pos], l);
1307
1308     swf_ResetWriteBits(t);
1309     return 0;
1310 }
1311
1312 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1313 {
1314     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1315 }
1316
1317 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1318 {
1319     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1320 }
1321
1322 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1323 {
1324     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1325 }
1326
1327 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1328 {
1329     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1330 }
1331
1332 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1333 {
1334     U32 res = 0;
1335
1336     if (font && s) {
1337         while (s[0]) {
1338             int g = -1;
1339             if (*s < font->maxascii)
1340                 g = font->ascii2glyph[*s];
1341             if (g >= 0)
1342                 res += font->glyph[g].advance / 20;
1343             s++;
1344         }
1345         if (scale)
1346             res = (res * scale) / 100;
1347     }
1348     return res;
1349 }
1350
1351 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1352 {
1353     int xpos = 0;
1354     int ypos = 0;
1355     SRECT r;
1356     swf_GetRect(0, &r);
1357     while (*s) {
1358         int c = readUTF8char(&s);
1359         if(c==13 || c==10) {
1360             if(s[0] == 10) {
1361                 s++;
1362             }
1363             xpos=0;
1364             ypos+=font->layout->leading;
1365             continue;
1366         }
1367         if (c < font->maxascii) {
1368             int g = font->ascii2glyph[c];
1369             if (g >= 0) {
1370                 SRECT rn = font->layout->bounds[g];
1371                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1372                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1373                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1374                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1375                 swf_ExpandRect2(&r, &rn);
1376                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1377             }
1378         }
1379     }
1380     return r;
1381 }
1382
1383
1384 SWFFONT *swf_ReadFont(const char *filename)
1385 {
1386     int f;
1387     SWF swf;
1388     if (!filename)
1389         return 0;
1390     f = open(filename, O_RDONLY|O_BINARY);
1391
1392     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1393         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1394         close(f);
1395         return 0;
1396     } else {
1397         SWFFONT *font;
1398         close(f);
1399         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1400             return 0;
1401         swf_FreeTags(&swf);
1402         return font;
1403     }
1404 }
1405
1406 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, const char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, const char *variable)
1407 {
1408     swf_SetRect(tag, &r);
1409     swf_ResetWriteBits(tag);
1410
1411     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1412     if (text)
1413         flags |= ET_HASTEXT;
1414     if (color)
1415         flags |= ET_HASTEXTCOLOR;
1416     if (maxlength)
1417         flags |= ET_HASMAXLENGTH;
1418     if (font)
1419         flags |= ET_HASFONT;
1420     if (layout)
1421         flags |= ET_HASLAYOUT;
1422
1423     swf_SetBits(tag, flags, 16);
1424
1425     if (flags & ET_HASFONT) {
1426         swf_SetU16(tag, font);  //font
1427         swf_SetU16(tag, height);        //fontheight
1428     }
1429     if (flags & ET_HASTEXTCOLOR) {
1430         swf_SetRGBA(tag, color);
1431     }
1432     if (flags & ET_HASMAXLENGTH) {
1433         swf_SetU16(tag, maxlength);     //maxlength
1434     }
1435     if (flags & ET_HASLAYOUT) {
1436         swf_SetU8(tag, layout->align);  //align
1437         swf_SetU16(tag, layout->leftmargin);    //left margin
1438         swf_SetU16(tag, layout->rightmargin);   //right margin
1439         swf_SetU16(tag, layout->indent);        //indent
1440         swf_SetU16(tag, layout->leading);       //leading
1441     }
1442     swf_SetString(tag, variable);
1443     if (flags & ET_HASTEXT)
1444         swf_SetString(tag, text);
1445 }
1446
1447 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1448 {
1449     SRECT r;
1450     U8 gbits, abits;
1451     U8 *utext = (U8 *) strdup(text);
1452     U8 *upos = utext;
1453     int x = 0, y = 0;
1454     int pos = 0;
1455     int ystep = 0;
1456     if (font->layout) {
1457         r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1458         ystep = font->layout->leading;
1459     } else {
1460         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1461         /* Hm, without layout information, we can't compute a bounding
1462            box. We could call swf_FontCreateLayout to create a layout,
1463            but the caller probably doesn't want us to mess up his font
1464            structure.
1465          */
1466         r.xmin = r.ymin = 0;
1467         r.xmax = r.ymax = 1024 * 20;
1468         ystep = 100;
1469     }
1470
1471     swf_SetRect(tag, &r);
1472
1473     /* The text matrix is pretty boring, as it doesn't apply to
1474        individual characters, but rather whole text objects (or
1475        at least whole char records- haven't tested).
1476        So it can't do anything which we can't already do with
1477        the placeobject tag we use for placing the text on the scene.
1478      */
1479     swf_SetMatrix(tag, 0);
1480
1481     swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1482     swf_SetU8(tag, gbits);
1483     swf_SetU8(tag, abits);
1484
1485     while(*upos) {
1486         U8*next = upos;
1487         int count = 0;
1488
1489         swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y);      //scale
1490         x = 0;
1491
1492         while(*next && *next!=13 && *next!=10 && count<127) {
1493             readUTF8char(&next);
1494             count++;
1495         }
1496         if(next[0] == 13 || next[0] == 10) {
1497             x = SET_TO_ZERO;
1498             y += ystep;
1499         }
1500
1501         if(next[0] == 13 && next[1] == 10)
1502             next++;
1503
1504         if(next[0] == 13 || next[0] == 10) {
1505             *next = 0;
1506             next++;
1507         }
1508
1509         /* now set the text params- notice that a font size of
1510            1024 (or 1024*20 for definefont3) means that the glyphs will 
1511            be displayed exactly as they would be in/with a defineshape.
1512            This is not documented in the specs.
1513          */
1514
1515         /* set the actual text- notice that we just pass our scale
1516            parameter over, as TextSetCharRecord calculates with
1517            percent, too */
1518         swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1519
1520         upos= next;
1521     }
1522     free(utext);
1523
1524     swf_SetU8(tag, 0);
1525     return r;
1526 }
1527
1528 void swf_FontCreateLayout(SWFFONT * f)
1529 {
1530     S16 leading = 0;
1531     int t;
1532     if (f->layout)
1533         return;
1534     if (!f->numchars)
1535         return;
1536
1537     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1538     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1539     f->layout->ascent = 0;
1540     f->layout->descent = 0;
1541
1542     for (t = 0; t < f->numchars; t++) {
1543         SHAPE2 *shape2;
1544         SRECT bbox;
1545         int width;
1546         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1547         if (!shape2) {
1548             fprintf(stderr, "Shape parse error\n");
1549             exit(1);
1550         }
1551         bbox = swf_GetShapeBoundingBox(shape2);
1552         swf_Shape2Free(shape2);
1553         f->layout->bounds[t] = bbox;
1554
1555         width = (bbox.xmax);
1556
1557         /* The following is a heuristic- it may be that extractfont_DefineText
1558            has already found out some widths for individual characters (from the way
1559            they are used)- we now have to guess whether that width might be possible,
1560            which is the case if it isn't either much too big or much too small */
1561         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1562             f->glyph[t].advance = width;
1563
1564         if (-bbox.ymin > f->layout->ascent)
1565             f->layout->ascent = -bbox.ymin;
1566         if (bbox.ymax > f->layout->descent)
1567             f->layout->descent = bbox.ymax;
1568     }
1569 }
1570
1571 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1572 {
1573     U8 *s = (U8 *) text;
1574     int advance = 0;
1575     while (*s) {
1576         SHAPE *shape;
1577         SHAPE2 *shape2;
1578         SHAPELINE *l;
1579         U32 c = readUTF8char(&s);
1580         int g = font->ascii2glyph[c];
1581         shape = font->glyph[g].shape;
1582         if (((int) g) < 0) {
1583             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1584             continue;
1585         }
1586         shape2 = swf_ShapeToShape2(shape);
1587         l = shape2->lines;
1588         while (l) {
1589             if (l->type == moveTo) {
1590                 FPOINT to;
1591                 to.x = l->x * size / 100.0 / 20.0 + advance;
1592                 to.y = l->y * size / 100.0 / 20.0;
1593                 draw->moveTo(draw, &to);
1594             } else if (l->type == lineTo) {
1595                 FPOINT to;
1596                 to.x = l->x * size / 100.0 / 20.0 + advance;
1597                 to.y = l->y * size / 100.0 / 20.0;
1598                 draw->lineTo(draw, &to);
1599             } else if (l->type == splineTo) {
1600                 FPOINT mid, to;
1601                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1602                 mid.y = l->sy * size / 100.0 / 20.0;
1603                 to.x = l->x * size / 100.0 / 20.0 + advance;
1604                 to.y = l->y * size / 100.0 / 20.0;
1605                 draw->splineTo(draw, &mid, &to);
1606             }
1607             l = l->next;
1608         }
1609         swf_Shape2Free(shape2);
1610         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1611     }
1612 }
1613
1614 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1615 {
1616     if(!font->layout) 
1617         swf_FontCreateLayout(font);
1618     
1619     SWF swf;
1620     memset(&swf, 0, sizeof(SWF));
1621     swf.fileVersion = 9;
1622     swf.frameRate = 0x4000;
1623     swf.movieSize.xmax = 200;
1624     swf.movieSize.ymax = 200;
1625     
1626     if(!font->id) font->id=1;
1627
1628     TAG *tag;
1629     swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1630     swf_FontSetDefine2(tag, font);
1631
1632     char*name = font->name?(char*)font->name:"font";
1633
1634     tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1635     swf_SetU16(tag, font->id);
1636     swf_SetString(tag, name);
1637     tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1638     swf_SetU16(tag, 1);
1639     swf_SetU16(tag, font->id);
1640     swf_SetString(tag, name);
1641     tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1642     
1643     tag = swf_InsertTag(tag, ST_END);
1644     swf_SaveSWF(&swf, filename);
1645     swf_FreeTags(&swf);
1646 }
1647
1648 void swf_WriteFont(SWFFONT * font, char *filename)
1649 {
1650     if(!font->layout)
1651         swf_FontCreateLayout(font);
1652
1653     char viewer = 1;
1654     U16 id = 1;
1655     U16 depth = 1;
1656
1657     font->id = id++;
1658     
1659     SWF swf;
1660     memset(&swf, 0, sizeof(SWF));
1661     swf.fileVersion = 8;
1662     swf.frameRate = 0x4000;
1663     swf.movieSize.xmax = 1024*20;
1664     swf.movieSize.ymax = 768*20;
1665     
1666     TAG *tag;
1667     swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1668     swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1669
1670     tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1671     swf_FontSetDefine2(tag, font);
1672
1673     if(font->glyphnames) {
1674         int c;
1675         tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1676         swf_SetU16(tag, font->id);
1677         swf_SetU16(tag, font->numchars);
1678         for (c = 0; c < font->numchars; c++) {
1679             if (font->glyphnames[c])
1680                 swf_SetString(tag, font->glyphnames[c]);
1681             else
1682                 swf_SetString(tag, "");
1683         }
1684     }
1685
1686     if(viewer)
1687     {
1688         RGBA white = {255,255,255,255};
1689         RGBA black = {255,0,0,0};
1690         RGBA gray50 = {255,128,128,128};
1691         RGBA green = {255,0,255,0};
1692         int t;
1693         SCOORD miny = SCOORD_MAX;
1694         SCOORD maxy = SCOORD_MIN;
1695         double width = 0;
1696         U16 max_advance = 0;
1697         char*flags = rfx_calloc(font->numchars);
1698         double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1699         double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1700         int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1701         for(t=0;t<font->numchars;t++) {
1702             SHAPE*s = font->glyph[t].shape;
1703             SHAPE2*s2 = swf_ShapeToShape2(s);
1704             SRECT r = swf_GetShapeBoundingBox(s2);
1705
1706             // inside a definefont3, everything is 20x the resolution:
1707             double rx1 = r.xmin / 20.0;
1708             double ry1 = r.ymin / 20.0;
1709             double rx2 = r.xmax / 20.0;
1710             double ry2 = r.ymax / 20.0;
1711             
1712             xmin[t]= rx1;
1713             xmax[t]= rx2;
1714
1715             if(ry1<miny) {miny=ry1;}
1716             if(ry2>maxy) {maxy=ry2;}
1717             swf_Shape2Free(s2);free(s2);
1718             width += font->glyph[t].advance;
1719             if(font->glyph[t].advance>max_advance)
1720                 max_advance = font->glyph[t].advance;
1721         }
1722
1723         if(miny==SCOORD_MAX) miny=maxy=0;
1724         if(miny==maxy) maxy=miny+1;
1725
1726         /* scale the font so that it's 256 pixels high */
1727         double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1728         double overlarge_factor;
1729         int fontsize;
1730         if(scale > 32767) {
1731             fontsize = 32767;
1732             overlarge_factor = scale / 32767.0;
1733         } else {
1734             fontsize = scale;
1735             overlarge_factor = 1.0;
1736         }
1737
1738         int textid = id++;
1739         int spriteid = id++;
1740         SRECT r;
1741         r.xmin = 0;
1742         r.ymin = miny*fontsize/1024;
1743         r.xmax = width*fontsize/20480;
1744         r.ymax = maxy*fontsize/1024;
1745         tag = swf_InsertTag(tag, ST_DEFINETEXT);
1746         swf_SetU16(tag, textid);
1747         swf_SetRect(tag, &r);
1748         swf_SetMatrix(tag, NULL);
1749
1750         U8 abits = 15;
1751         U8 gbits = swf_CountBits(font->numchars, 0);
1752         swf_SetU8(tag, gbits);
1753         swf_SetU8(tag, abits);
1754
1755         RGBA rgb = {255,0,0,0};
1756
1757         swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1758         ActionTAG*array = 0;
1759         double x=0;
1760         array = action_PushString(array, "xpos");
1761         for(t=0;t<font->numchars;t++) {
1762             swf_SetU8(tag, 1);
1763             int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1764             array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1765             x += width * overlarge_factor;
1766             swf_SetBits(tag, t, gbits);
1767             swf_SetBits(tag, width, abits);
1768             swf_SetU8(tag, 128);
1769         }
1770         array = action_PushInt(array, x/20);
1771         array = action_PushInt(array, font->numchars+1);
1772         array = action_InitArray(array);
1773         array = action_SetVariable(array);
1774         swf_SetU8(tag, 0);
1775
1776         if(font->layout) {
1777             tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1778             SHAPE* s;
1779             swf_ShapeNew(&s);
1780             int ls = swf_ShapeAddLineStyle(s,20,&white);
1781             int shapeid = id++;
1782             swf_SetU16(tag,shapeid);
1783             SRECT r;
1784             r.xmin = 0;
1785             r.xmax = 1024*20;
1786             r.ymin = 0;
1787             r.ymax = 256*20;
1788             swf_SetRect(tag,&r);
1789             swf_SetShapeHeader(tag,s);
1790             swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1791
1792             /* Ç and Â are good chars to test ascent/descent extend */
1793             int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1794             int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1795
1796             swf_ShapeSetMove(tag,s,0,y1);
1797             swf_ShapeSetLine(tag,s,width,0);
1798             swf_ShapeSetMove(tag,s,0,y2);
1799             swf_ShapeSetLine(tag,s,width,0);
1800
1801             swf_ShapeSetEnd(tag);
1802             swf_ShapeFree(s);
1803             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1804             swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1805         }
1806
1807         /* shapes */
1808         
1809         for(t=0;t<font->numchars;t++) {
1810             tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1811             SHAPE* s;
1812             swf_ShapeNew(&s);
1813             int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1814             int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1815             int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1816             int shapeid = id++;
1817             swf_SetU16(tag,shapeid);
1818             SRECT r;
1819             r.xmin = 0;
1820             r.xmax = 1024*20;
1821             r.ymin = 0;
1822             r.ymax = 512*20;
1823             swf_SetRect(tag,&r);
1824             swf_SetShapeHeader(tag,s);
1825             swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1826             SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1827             SHAPELINE*l = s2->lines;
1828             int lastx=0,lasty=0;
1829
1830             double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1831             double y1 = -miny*20*scale*2/20480.0;
1832             double scalex = scale*2/20480.0;
1833             double scaley = scale*2/20480.0;
1834
1835             while(l) {
1836                 int lx = (l->x)*scalex+x1;
1837                 int ly = (l->y)*scaley+y1;
1838                 int sx = (l->sx)*scalex+x1;
1839                 int sy = (l->sy)*scaley+y1;
1840                 if(l->type == moveTo) {
1841                     swf_ShapeSetMove(tag,s,lx,ly);
1842                 } else if(l->type == lineTo) {
1843                     swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1844                 } else if(l->type == splineTo) {
1845                     swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1846                 }
1847                 lastx = lx;
1848                 lasty = ly;
1849                 l = l->next;
1850             }
1851             
1852             if(font->alignzones) {
1853                 ALIGNZONE*zone = &font->alignzones[t];
1854                 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1855                 if((zone->x&zone->dx)!=0xffff) {
1856                     double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1857                     double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1858                     swf_ShapeSetMove(tag,s,x,0);
1859                     swf_ShapeSetLine(tag,s,0,1024*20);
1860                     swf_ShapeSetMove(tag,s,dx,0);
1861                     swf_ShapeSetLine(tag,s,0,1024*20);
1862                 }
1863                 if((zone->y&zone->dy)!=0xffff) {
1864                     double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1865                     double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1866                     swf_ShapeSetMove(tag,s,0,y);
1867                     swf_ShapeSetLine(tag,s,1024*20,0);
1868                     swf_ShapeSetMove(tag,s,0,dy);
1869                     swf_ShapeSetLine(tag,s,1024*20,0);
1870                 }
1871             }
1872
1873             swf_ShapeSetEnd(tag);
1874             swf_ShapeFree(s);
1875         
1876             tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1877             U16 spriteid=id++;
1878             swf_SetU16(tag, spriteid);
1879             swf_SetU16(tag, 1);
1880             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1881             swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1882             tag = swf_InsertTag(tag, ST_END);
1883             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1884             MATRIX m;
1885             swf_GetMatrix(0, &m);
1886             m.ty = 20000;
1887             char txt[80];
1888             sprintf(txt, "char%d", font->numchars-t);
1889             swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1890         }
1891         
1892         /* marker */
1893         tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1894         int shapeid=id++;
1895         RGBA blue = {0xff,0xc0,0xc0,0xff};
1896         swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1897         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1898         U16 spriteid2=id++;
1899         swf_SetU16(tag, spriteid2);
1900         swf_SetU16(tag, 1);
1901         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1902         swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1903         tag = swf_InsertTag(tag, ST_END);
1904         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1905         swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1906         
1907         /* textbar */
1908         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1909         swf_SetU16(tag, spriteid);
1910         swf_SetU16(tag, 1);
1911         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1912         MATRIX m;
1913         swf_GetMatrix(0, &m);
1914         m.sx = 65536 * overlarge_factor;
1915         m.sy = 65536 * overlarge_factor;
1916         m.tx = 0;
1917         m.ty = -miny*256*20/(maxy-miny);
1918         swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1919         tag = swf_InsertTag(tag, ST_END);
1920         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1921         swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
1922         
1923         /* marker2 */
1924         RGBA blue2 = {0x80,0x80,0xff,0x80};
1925         tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1926         int shapeid2=id++;
1927         swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
1928         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1929         U16 spriteid3=id++;
1930         swf_SetU16(tag, spriteid3);
1931         swf_SetU16(tag, 1);
1932         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1933         swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
1934         tag = swf_InsertTag(tag, ST_END);
1935         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1936         swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
1937
1938
1939 char*data = 
1940 " var mouseListener = new Object();"
1941 " var speed = 0;"
1942 " var myx = 0;"
1943 " var currentMouseOver, currentChar;"
1944 " mouseListener.onMouseDown = function() { "
1945 "     eval(\"_root.char\"+currentChar)._y = 20000;"
1946 "     currentChar = currentMouseOver;"
1947 "     var i = currentMouseOver;"
1948 "     eval(\"_root.char\"+i)._y = 256;"
1949 "     _root.marker2._yscale=256*100;"
1950 "     _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
1951 "     _root.marker2._x=xpos[i]+myx;"
1952 " };"
1953 " mouseListener.onMouseMove = function() { "
1954 "     if(_ymouse<256) {"
1955 "          speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
1956 "     } else {"
1957 "          speed = 0;"
1958 "     }; "
1959 " }; "
1960 " setInterval( function(){ "
1961 "     if(_ymouse<256) {"
1962 "         var i, x=_xmouse-_root.textbar._x;"
1963 "         for(i=xpos.length-1;i>0;i--) {"
1964 "             if(x<xpos[i-1]) break;"
1965 "         }"
1966 "         currentMouseOver = i;"
1967 "         _root.marker._yscale=256*100;"
1968 "         _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
1969 "         _root.marker._x=xpos[i]+myx;"
1970 "         _root.textbar._x += 0.05;"
1971 "     }"
1972 "     if(myx+speed>0) {"
1973 "         speed=0;"
1974 "     } else if(myx+speed<-xpos[0]+1024) {"
1975 "         speed=0;"
1976 "     }"
1977 "     myx+=speed;"
1978 "     _root.textbar._x = myx;"
1979 "     _root.marker._x += speed;"
1980 "     _root.marker2._x += speed;"
1981 " }, 20);"
1982 " Mouse.addListener(mouseListener);"
1983 ;
1984         ActionTAG* atag = swf_ActionCompile(data, 6);
1985
1986         tag = swf_InsertTag(tag, ST_DOACTION);
1987         swf_ActionSet(tag, array);
1988         swf_ActionSet(tag, atag);
1989         swf_SetU8(tag, 0);
1990         swf_ActionFree(atag);
1991
1992         tag = swf_InsertTag(tag, ST_SHOWFRAME);
1993
1994         free(flags);
1995         free(xmin);
1996         free(xmax);
1997     }
1998
1999     tag = swf_InsertTag(tag, ST_END);
2000
2001     swf.compressed = -1;
2002     swf_SaveSWF(&swf, filename);
2003     swf_FreeTags(&swf);
2004 }