added fontalign polygon detector
[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->used_glyphs = 0;
857     f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
858     f->use->glyphs_specified = 0;
859     return 0;
860 }
861
862 void swf_FontClearUsage(SWFFONT * f)
863 {
864     if (!f || !f->use)
865         return;
866     rfx_free(f->use->chars); f->use->chars = 0;
867     rfx_free(f->use); f->use = 0;
868 }
869
870 int swf_FontUse(SWFFONT * f, U8 * s)
871 {
872     if( (!s))
873         return -1;
874     while (*s) {
875         if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
876             swf_FontUseGlyph(f, f->ascii2glyph[*s]);
877         s++;
878     }
879     return 0;
880 }
881
882 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
883 {
884     if( (!s))
885         return -1;
886     int ascii;
887     while (*s)
888     {
889         ascii = readUTF8char(&s);
890         if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
891             swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
892     }
893     return 0;
894 }
895
896 int swf_FontUseAll(SWFFONT* f)
897 {
898     int i;
899
900     if (!f->use)
901         swf_FontInitUsage(f);
902     for (i = 0; i < f->numchars; i++)
903         f->use->chars[i] = 1;
904     f->use->used_glyphs = f->numchars;
905     return 0;
906 }
907
908 int swf_FontUseGlyph(SWFFONT * f, int glyph)
909 {
910     if (!f->use)
911         swf_FontInitUsage(f);
912     if(glyph < 0 || glyph >= f->numchars)
913         return -1;
914     if(!f->use->chars[glyph])
915         f->use->used_glyphs++;
916     f->use->chars[glyph] = 1;
917     return 0;
918 }
919
920 int swf_FontSetDefine(TAG * t, SWFFONT * f)
921 {
922     U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
923     int p, i, j;
924
925     if ((!t) || (!f))
926         return -1;
927     swf_ResetWriteBits(t);
928     swf_SetU16(t, f->id);
929
930     p = 0;
931     j = 0;
932     for (i = 0; i < f->numchars; i++)
933         if (f->glyph[i].shape) {
934             ofs[j++] = p;
935             p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
936         }
937
938     for (i = 0; i < j; i++)
939         swf_SetU16(t, ofs[i] + j * 2);
940     if (!j) {
941         fprintf(stderr, "rfxswf: warning: Font is empty\n");
942         swf_SetU16(t, 0);
943     }
944
945     for (i = 0; i < f->numchars; i++)
946         if (f->glyph[i].shape)
947             swf_SetSimpleShape(t, f->glyph[i].shape);
948
949     swf_ResetWriteBits(t);
950     rfx_free(ofs);
951     return 0;
952 }
953
954 static inline int fontSize(SWFFONT * font)
955 {
956     int t;
957     int size = 0;
958     for (t = 0; t < font->numchars; t++) {
959         int l = 0;
960         if(font->glyph[t].shape)
961             l = (font->glyph[t].shape->bitlen + 7) / 8;
962         else
963             l = 8;
964         size += l + 1;
965     }
966     return size + (font->numchars + 1) * 2;
967 }
968
969 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
970 {
971     U8 flags = 0;
972     int t;
973     int pos;
974     swf_SetU16(tag, f->id);
975
976     if (f->layout) flags |= 128;                // haslayout
977     if (f->numchars > 256)
978         flags |= 4;             // widecodes
979     if (f->style & FONT_STYLE_BOLD)
980         flags |= 1;             // bold
981     if (f->style & FONT_STYLE_ITALIC)
982         flags |= 2;             // italic
983     if (f->maxascii >= 256)
984         flags |= 4;             //wide codecs
985     if (fontSize(f) > 65535)
986         flags |= 8;             //wide offsets
987     flags |= 8 | 4;             //FIXME: the above check doesn't work
988
989     if (f->encoding & FONT_ENCODING_ANSI)
990         flags |= 16;            // ansi
991     if (f->encoding & FONT_ENCODING_UNICODE)
992         flags |= 32;            // unicode
993     if (f->encoding & FONT_ENCODING_SHIFTJIS)
994         flags |= 64;            // shiftjis
995
996     swf_SetU8(tag, flags);
997     swf_SetU8(tag, 0);          //reserved flags
998     if (f->name) {
999         /* font name */
1000         swf_SetU8(tag, strlen((const char*)f->name)+1);
1001         swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
1002     } else {
1003         /* font name (="") */
1004         swf_SetU8(tag, 1);
1005         swf_SetU8(tag, 0);
1006     }
1007     /* number of glyphs */
1008     swf_SetU16(tag, f->numchars);
1009     /* font offset table */
1010     pos = tag->len;
1011     for (t = 0; t <= f->numchars; t++) {
1012         if (flags & 8)
1013             swf_SetU32(tag, /* fontoffset */ 0);        /*placeholder */
1014         else
1015             swf_SetU16(tag, /* fontoffset */ 0);        /*placeholder */
1016     }
1017
1018     for (t = 0; t <= f->numchars; t++) {
1019         if (flags & 8) {
1020             tag->data[pos + t * 4] = (tag->len - pos);
1021             tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
1022             tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
1023             tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
1024         } else {
1025             if (tag->len - pos > 65535) {
1026                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
1027                 exit(1);
1028             }
1029             tag->data[pos + t * 2] = (tag->len - pos);
1030             tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
1031         }
1032         if (t < f->numchars) {
1033             if(f->glyph[t].shape) {
1034                 swf_SetSimpleShape(tag, f->glyph[t].shape);
1035             } else {
1036                 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
1037             }
1038         }
1039     }
1040
1041
1042     /* font code table */
1043     for (t = 0; t < f->numchars; t++) {
1044         if (flags & 4) {                /* wide codes */
1045             if(f->glyph2ascii[t]) {
1046                 swf_SetU16(tag, f->glyph2ascii[t]);
1047             } else {
1048                 swf_SetU16(tag, 0);
1049             }
1050         } else {
1051             if(f->glyph2ascii[t]) {
1052                 swf_SetU8(tag, f->glyph2ascii[t]);
1053             } else {
1054                 swf_SetU8(tag, 0);
1055             }
1056         }
1057     }
1058
1059     if (f->layout) {
1060         swf_SetU16(tag, f->layout->ascent);
1061         swf_SetU16(tag, f->layout->descent);
1062         swf_SetU16(tag, f->layout->leading);
1063         for (t = 0; t < f->numchars; t++)
1064             swf_SetU16(tag, f->glyph[t].advance);
1065         for (t = 0; t < f->numchars; t++) {
1066             swf_ResetWriteBits(tag);
1067             swf_SetRect(tag, &f->layout->bounds[t]);
1068         }
1069         swf_SetU16(tag, f->layout->kerningcount);
1070         for (t = 0; t < f->layout->kerningcount; t++) {
1071             if (flags & 4) {    /* wide codes */
1072                 swf_SetU16(tag, f->layout->kerning[t].char1);
1073                 swf_SetU16(tag, f->layout->kerning[t].char2);
1074             } else {
1075                 swf_SetU8(tag, f->layout->kerning[t].char1);
1076                 swf_SetU8(tag, f->layout->kerning[t].char2);
1077             }
1078             swf_SetU16(tag, f->layout->kerning[t].adjustment);
1079         }
1080     }
1081     return 0;
1082 }
1083
1084 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1085 {
1086     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1087     f->layout->ascent = ascent;
1088     f->layout->descent = descent;
1089     f->layout->leading = leading;
1090     f->layout->kerningcount = 0;
1091     f->layout->kerning = 0;
1092     f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1093 }
1094
1095 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1096 {
1097     int l, i;
1098     U8 wide = 0;
1099     U8 flags = 0;
1100     if ((!t) || (!f))
1101         return -1;
1102     swf_ResetWriteBits(t);
1103     swf_SetU16(t, f->id);
1104     l = f->name ? strlen((const char *)f->name) : 0;
1105     if (l > 255)
1106         l = 255;
1107     swf_SetU8(t, l);
1108     if (l)
1109         swf_SetBlock(t, f->name, l);
1110     if (f->numchars >= 256)
1111         wide = 1;
1112
1113     if (f->style & FONT_STYLE_BOLD)
1114         flags |= 2;
1115     if (f->style & FONT_STYLE_ITALIC)
1116         flags |= 4;
1117     if (f->style & FONT_ENCODING_ANSI)
1118         flags |= 8;
1119     if (f->style & FONT_ENCODING_SHIFTJIS)
1120         flags |= 16;
1121     if (f->style & FONT_ENCODING_UNICODE)
1122         flags |= 32;
1123
1124     swf_SetU8(t, (flags & 0xfe) | wide);
1125
1126     for (i = 0; i < f->numchars; i++) {
1127         if (f->glyph[i].shape) {
1128             int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1129             wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1130         }
1131     }
1132
1133     return 0;
1134 }
1135
1136 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1137 {
1138     int id = swf_GetTagID(t);
1139     if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1140         swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1141     else
1142         return -1;
1143     return 0;
1144 }
1145
1146 void swf_FontFree(SWFFONT * f)
1147 {
1148     int i;
1149     if (!f)
1150         return;
1151
1152     if (f->glyph)
1153     {
1154         for (i = 0; i < f->numchars; i++)
1155             if (f->glyph[i].shape)
1156             {
1157                 swf_ShapeFree(f->glyph[i].shape);
1158                 f->glyph[i].shape = NULL;
1159             }
1160             rfx_free(f->glyph);
1161             f->glyph = NULL;
1162     }
1163     if (f->ascii2glyph)
1164     {
1165         rfx_free(f->ascii2glyph);
1166         f->ascii2glyph = NULL;
1167     }
1168     if (f->glyph2ascii)
1169     {
1170         rfx_free(f->glyph2ascii);
1171         f->glyph2ascii = NULL;
1172     }
1173     font_freename(f);
1174     font_freelayout(f);
1175     font_freeglyphnames(f);
1176     font_freeusage(f);
1177
1178     rfx_free(f);
1179 }
1180
1181 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1182 {
1183     U8 flags;
1184     if (!t)
1185         return -1;
1186
1187     flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1188         | (y ? TF_HASYOFFSET : 0);
1189
1190     swf_SetU8(t, flags);
1191     if (font)
1192         swf_SetU16(t, font->id);
1193     if (color) {
1194         if (swf_GetTagID(t) == ST_DEFINETEXT2)
1195             swf_SetRGBA(t, color);
1196         else
1197             swf_SetRGB(t, color);
1198     }
1199     if (x) {
1200         if(x != SET_TO_ZERO) {
1201             if(x>32767 || x<-32768)
1202                 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1203             swf_SetS16(t, x);
1204         } else {
1205             swf_SetS16(t, 0);
1206         }
1207     }
1208     if (y) {
1209         if(y != SET_TO_ZERO) {
1210             if(y>32767 || y<-32768)
1211                 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1212             swf_SetS16(t, y);
1213         } else {
1214             swf_SetS16(t, 0);
1215         }
1216     }
1217     if (font)
1218         swf_SetU16(t, size);
1219
1220     return 0;
1221 }
1222
1223 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1224 {
1225     U16 g, a;
1226     char utf8 = 0;
1227     if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1228         return -1;
1229     g = a = 0;
1230
1231     if (!strcmp(encoding, "UTF8"))
1232         utf8 = 1;
1233     else if (!strcmp(encoding, "iso-8859-1"))
1234         utf8 = 0;
1235     else
1236         fprintf(stderr, "Unknown encoding: %s", encoding);
1237
1238     while (*s) {
1239         int glyph = -1, c;
1240
1241         if (!utf8)
1242             c = *s++;
1243         else
1244             c = readUTF8char(&s);
1245
1246         if (c < font->maxascii)
1247             glyph = font->ascii2glyph[c];
1248         if (glyph >= 0) {
1249             g = swf_CountUBits(glyph, g);
1250             a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1251         }
1252     }
1253
1254     if (gbits)
1255         gbits[0] = (U8) g;
1256     if (abits)
1257         abits[0] = (U8) a;
1258     return 0;
1259 }
1260
1261 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1262 {
1263     int l = 0, pos;
1264     char utf8 = 0;
1265
1266     if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1267         return -1;
1268
1269     if (!strcmp(encoding, "UTF8"))
1270         utf8 = 1;
1271     else if (!strcmp(encoding, "iso-8859-1"))
1272         utf8 = 0;
1273     else
1274         fprintf(stderr, "Unknown encoding: %s", encoding);
1275
1276     pos = t->len;
1277     swf_SetU8(t, l);            //placeholder
1278
1279     while (*s) {
1280         int g = -1, c;
1281
1282         if (!utf8)
1283             c = *s++;
1284         else
1285             c = readUTF8char(&s);
1286
1287         if (c < font->maxascii)
1288             g = font->ascii2glyph[c];
1289         if (g >= 0) {
1290             swf_SetBits(t, g, gbits);
1291             swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1292             l++;
1293             /* We split into 127 characters per text field.
1294                We could do 255, by the (formerly wrong) flash specification,
1295                but some SWF parsing code out there still assumes that char blocks
1296                are at max 127 characters, and it would save only a few bits.
1297             */
1298             if (l == 0x7f)
1299                 break;
1300         }
1301     }
1302
1303     PUT8(&t->data[pos], l);
1304
1305     swf_ResetWriteBits(t);
1306     return 0;
1307 }
1308
1309 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1310 {
1311     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1312 }
1313
1314 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1315 {
1316     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1317 }
1318
1319 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1320 {
1321     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1322 }
1323
1324 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1325 {
1326     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1327 }
1328
1329 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1330 {
1331     U32 res = 0;
1332
1333     if (font && s) {
1334         while (s[0]) {
1335             int g = -1;
1336             if (*s < font->maxascii)
1337                 g = font->ascii2glyph[*s];
1338             if (g >= 0)
1339                 res += font->glyph[g].advance / 20;
1340             s++;
1341         }
1342         if (scale)
1343             res = (res * scale) / 100;
1344     }
1345     return res;
1346 }
1347
1348 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1349 {
1350     int xpos = 0;
1351     int ypos = 0;
1352     SRECT r;
1353     swf_GetRect(0, &r);
1354     while (*s) {
1355         int c = readUTF8char(&s);
1356         if(c==13 || c==10) {
1357             if(s[0] == 10) {
1358                 s++;
1359             }
1360             xpos=0;
1361             ypos+=font->layout->leading;
1362             continue;
1363         }
1364         if (c < font->maxascii) {
1365             int g = font->ascii2glyph[c];
1366             if (g >= 0) {
1367                 SRECT rn = font->layout->bounds[g];
1368                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1369                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1370                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1371                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1372                 swf_ExpandRect2(&r, &rn);
1373                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1374             }
1375         }
1376     }
1377     return r;
1378 }
1379
1380
1381 SWFFONT *swf_ReadFont(const char *filename)
1382 {
1383     int f;
1384     SWF swf;
1385     if (!filename)
1386         return 0;
1387     f = open(filename, O_RDONLY|O_BINARY);
1388
1389     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1390         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1391         close(f);
1392         return 0;
1393     } else {
1394         SWFFONT *font;
1395         close(f);
1396         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1397             return 0;
1398         swf_FreeTags(&swf);
1399         return font;
1400     }
1401 }
1402
1403 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)
1404 {
1405     swf_SetRect(tag, &r);
1406     swf_ResetWriteBits(tag);
1407
1408     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1409     if (text)
1410         flags |= ET_HASTEXT;
1411     if (color)
1412         flags |= ET_HASTEXTCOLOR;
1413     if (maxlength)
1414         flags |= ET_HASMAXLENGTH;
1415     if (font)
1416         flags |= ET_HASFONT;
1417     if (layout)
1418         flags |= ET_HASLAYOUT;
1419
1420     swf_SetBits(tag, flags, 16);
1421
1422     if (flags & ET_HASFONT) {
1423         swf_SetU16(tag, font);  //font
1424         swf_SetU16(tag, height);        //fontheight
1425     }
1426     if (flags & ET_HASTEXTCOLOR) {
1427         swf_SetRGBA(tag, color);
1428     }
1429     if (flags & ET_HASMAXLENGTH) {
1430         swf_SetU16(tag, maxlength);     //maxlength
1431     }
1432     if (flags & ET_HASLAYOUT) {
1433         swf_SetU8(tag, layout->align);  //align
1434         swf_SetU16(tag, layout->leftmargin);    //left margin
1435         swf_SetU16(tag, layout->rightmargin);   //right margin
1436         swf_SetU16(tag, layout->indent);        //indent
1437         swf_SetU16(tag, layout->leading);       //leading
1438     }
1439     swf_SetString(tag, variable);
1440     if (flags & ET_HASTEXT)
1441         swf_SetString(tag, text);
1442 }
1443
1444 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1445 {
1446     SRECT r;
1447     U8 gbits, abits;
1448     U8 *utext = (U8 *) strdup(text);
1449     U8 *upos = utext;
1450     int x = 0, y = 0;
1451     int pos = 0;
1452     int ystep = 0;
1453     if (font->layout) {
1454         r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1455         ystep = font->layout->leading;
1456     } else {
1457         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1458         /* Hm, without layout information, we can't compute a bounding
1459            box. We could call swf_FontCreateLayout to create a layout,
1460            but the caller probably doesn't want us to mess up his font
1461            structure.
1462          */
1463         r.xmin = r.ymin = 0;
1464         r.xmax = r.ymax = 1024 * 20;
1465         ystep = 100;
1466     }
1467
1468     swf_SetRect(tag, &r);
1469
1470     /* The text matrix is pretty boring, as it doesn't apply to
1471        individual characters, but rather whole text objects (or
1472        at least whole char records- haven't tested).
1473        So it can't do anything which we can't already do with
1474        the placeobject tag we use for placing the text on the scene.
1475      */
1476     swf_SetMatrix(tag, 0);
1477
1478     swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1479     swf_SetU8(tag, gbits);
1480     swf_SetU8(tag, abits);
1481
1482     while(*upos) {
1483         U8*next = upos;
1484         int count = 0;
1485
1486         swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y);      //scale
1487         x = 0;
1488
1489         while(*next && *next!=13 && *next!=10 && count<127) {
1490             readUTF8char(&next);
1491             count++;
1492         }
1493         if(next[0] == 13 || next[0] == 10) {
1494             x = SET_TO_ZERO;
1495             y += ystep;
1496         }
1497
1498         if(next[0] == 13 && next[1] == 10)
1499             next++;
1500
1501         if(next[0] == 13 || next[0] == 10) {
1502             *next = 0;
1503             next++;
1504         }
1505
1506         /* now set the text params- notice that a font size of
1507            1024 (or 1024*20 for definefont3) means that the glyphs will 
1508            be displayed exactly as they would be in/with a defineshape.
1509            This is not documented in the specs.
1510          */
1511
1512         /* set the actual text- notice that we just pass our scale
1513            parameter over, as TextSetCharRecord calculates with
1514            percent, too */
1515         swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1516
1517         upos= next;
1518     }
1519     free(utext);
1520
1521     swf_SetU8(tag, 0);
1522     return r;
1523 }
1524
1525 void swf_FontCreateLayout(SWFFONT * f)
1526 {
1527     S16 leading = 0;
1528     int t;
1529     if (f->layout)
1530         return;
1531     if (!f->numchars)
1532         return;
1533
1534     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1535     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1536     f->layout->ascent = 0;
1537     f->layout->descent = 0;
1538
1539     for (t = 0; t < f->numchars; t++) {
1540         SHAPE2 *shape2;
1541         SRECT bbox;
1542         int width;
1543         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1544         if (!shape2) {
1545             fprintf(stderr, "Shape parse error\n");
1546             exit(1);
1547         }
1548         bbox = swf_GetShapeBoundingBox(shape2);
1549         swf_Shape2Free(shape2);
1550         f->layout->bounds[t] = bbox;
1551
1552         width = (bbox.xmax);
1553
1554         /* The following is a heuristic- it may be that extractfont_DefineText
1555            has already found out some widths for individual characters (from the way
1556            they are used)- we now have to guess whether that width might be possible,
1557            which is the case if it isn't either much too big or much too small */
1558         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1559             f->glyph[t].advance = width;
1560
1561         if (-bbox.ymin > f->layout->ascent)
1562             f->layout->ascent = -bbox.ymin;
1563         if (bbox.ymax > f->layout->descent)
1564             f->layout->descent = bbox.ymax;
1565     }
1566 }
1567
1568 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1569 {
1570     U8 *s = (U8 *) text;
1571     int advance = 0;
1572     while (*s) {
1573         SHAPE *shape;
1574         SHAPE2 *shape2;
1575         SHAPELINE *l;
1576         U32 c = readUTF8char(&s);
1577         int g = font->ascii2glyph[c];
1578         shape = font->glyph[g].shape;
1579         if (((int) g) < 0) {
1580             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1581             continue;
1582         }
1583         shape2 = swf_ShapeToShape2(shape);
1584         l = shape2->lines;
1585         while (l) {
1586             if (l->type == moveTo) {
1587                 FPOINT to;
1588                 to.x = l->x * size / 100.0 / 20.0 + advance;
1589                 to.y = l->y * size / 100.0 / 20.0;
1590                 draw->moveTo(draw, &to);
1591             } else if (l->type == lineTo) {
1592                 FPOINT to;
1593                 to.x = l->x * size / 100.0 / 20.0 + advance;
1594                 to.y = l->y * size / 100.0 / 20.0;
1595                 draw->lineTo(draw, &to);
1596             } else if (l->type == splineTo) {
1597                 FPOINT mid, to;
1598                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1599                 mid.y = l->sy * size / 100.0 / 20.0;
1600                 to.x = l->x * size / 100.0 / 20.0 + advance;
1601                 to.y = l->y * size / 100.0 / 20.0;
1602                 draw->splineTo(draw, &mid, &to);
1603             }
1604             l = l->next;
1605         }
1606         swf_Shape2Free(shape2);
1607         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1608     }
1609 }
1610
1611 void swf_WriteFont_AS3(SWFFONT * font, char *filename)
1612 {
1613     if(!font->layout) 
1614         swf_FontCreateLayout(font);
1615     
1616     SWF swf;
1617     memset(&swf, 0, sizeof(SWF));
1618     swf.fileVersion = 9;
1619     swf.frameRate = 0x4000;
1620     swf.movieSize.xmax = 200;
1621     swf.movieSize.ymax = 200;
1622     
1623     if(!font->id) font->id=1;
1624
1625     TAG *tag;
1626     swf.firstTag = tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1627     swf_FontSetDefine2(tag, font);
1628
1629     char*name = font->name?(char*)font->name:"font";
1630
1631     tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1632     swf_SetU16(tag, font->id);
1633     swf_SetString(tag, name);
1634     tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1635     swf_SetU16(tag, 1);
1636     swf_SetU16(tag, font->id);
1637     swf_SetString(tag, name);
1638     tag = swf_AddAS3FontDefine(tag, font->id, (char*)font->name);
1639     
1640     tag = swf_InsertTag(tag, ST_END);
1641     swf_SaveSWF(&swf, filename);
1642     swf_FreeTags(&swf);
1643 }
1644
1645 void swf_WriteFont(SWFFONT * font, char *filename)
1646 {
1647     if(!font->layout)
1648         swf_FontCreateLayout(font);
1649
1650     char viewer = 1;
1651     U16 id = 1;
1652     U16 depth = 1;
1653
1654     font->id = id++;
1655     
1656     SWF swf;
1657     memset(&swf, 0, sizeof(SWF));
1658     swf.fileVersion = 8;
1659     swf.frameRate = 0x4000;
1660     swf.movieSize.xmax = 1024*20;
1661     swf.movieSize.ymax = 768*20;
1662     
1663     TAG *tag;
1664     swf.firstTag = tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1665     swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xe0);swf_SetU8(tag, 0xff);
1666
1667     tag = swf_InsertTag(tag, ST_DEFINEFONT3);
1668     swf_FontSetDefine2(tag, font);
1669
1670     if(font->glyphnames) {
1671         int c;
1672         tag = swf_InsertTag(tag, ST_GLYPHNAMES);
1673         swf_SetU16(tag, font->id);
1674         swf_SetU16(tag, font->numchars);
1675         for (c = 0; c < font->numchars; c++) {
1676             if (font->glyphnames[c])
1677                 swf_SetString(tag, font->glyphnames[c]);
1678             else
1679                 swf_SetString(tag, "");
1680         }
1681     }
1682
1683     if(viewer)
1684     {
1685         RGBA white = {255,255,255,255};
1686         RGBA black = {255,0,0,0};
1687         RGBA gray50 = {255,128,128,128};
1688         RGBA green = {255,0,255,0};
1689         int t;
1690         SCOORD miny = SCOORD_MAX;
1691         SCOORD maxy = SCOORD_MIN;
1692         double width = 0;
1693         U16 max_advance = 0;
1694         char*flags = rfx_calloc(font->numchars);
1695         double*xmin = rfx_calloc(sizeof(double)*(font->numchars+1));
1696         double*xmax = rfx_calloc(sizeof(double)*(font->numchars+1));
1697         int*xpos = rfx_calloc(sizeof(int)*(font->numchars+1));
1698         for(t=0;t<font->numchars;t++) {
1699             SHAPE*s = font->glyph[t].shape;
1700             SHAPE2*s2 = swf_ShapeToShape2(s);
1701             SRECT r = swf_GetShapeBoundingBox(s2);
1702
1703             // inside a definefont3, everything is 20x the resolution:
1704             double rx1 = r.xmin / 20.0;
1705             double ry1 = r.ymin / 20.0;
1706             double rx2 = r.xmax / 20.0;
1707             double ry2 = r.ymax / 20.0;
1708             
1709             xmin[t]= rx1;
1710             xmax[t]= rx2;
1711
1712             if(ry1<miny) {miny=ry1;}
1713             if(ry2>maxy) {maxy=ry2;}
1714             swf_Shape2Free(s2);free(s2);
1715             width += font->glyph[t].advance;
1716             if(font->glyph[t].advance>max_advance)
1717                 max_advance = font->glyph[t].advance;
1718         }
1719
1720         if(miny==SCOORD_MAX) miny=maxy=0;
1721         if(miny==maxy) maxy=miny+1;
1722
1723         /* scale the font so that it's 256 pixels high */
1724         double scale = (int)((256.0*1024.0/(maxy-miny))*20.0);
1725         double overlarge_factor;
1726         int fontsize;
1727         if(scale > 32767) {
1728             fontsize = 32767;
1729             overlarge_factor = scale / 32767.0;
1730         } else {
1731             fontsize = scale;
1732             overlarge_factor = 1.0;
1733         }
1734
1735         int textid = id++;
1736         int spriteid = id++;
1737         SRECT r;
1738         r.xmin = 0;
1739         r.ymin = miny*fontsize/1024;
1740         r.xmax = width*fontsize/20480;
1741         r.ymax = maxy*fontsize/1024;
1742         tag = swf_InsertTag(tag, ST_DEFINETEXT);
1743         swf_SetU16(tag, textid);
1744         swf_SetRect(tag, &r);
1745         swf_SetMatrix(tag, NULL);
1746
1747         U8 abits = 15;
1748         U8 gbits = swf_CountBits(font->numchars, 0);
1749         swf_SetU8(tag, gbits);
1750         swf_SetU8(tag, abits);
1751
1752         RGBA rgb = {255,0,0,0};
1753
1754         swf_TextSetInfoRecord(tag, font, fontsize, &rgb, SET_TO_ZERO, SET_TO_ZERO);
1755         ActionTAG*array = 0;
1756         double x=0;
1757         array = action_PushString(array, "xpos");
1758         for(t=0;t<font->numchars;t++) {
1759             swf_SetU8(tag, 1);
1760             int width = abs((xmax[t] - xmin[t+1])*fontsize/1024) + 60;
1761             array = action_PushInt(array, x/20 +(xmin[t]*scale/1024)/20);
1762             x += width * overlarge_factor;
1763             swf_SetBits(tag, t, gbits);
1764             swf_SetBits(tag, width, abits);
1765             swf_SetU8(tag, 128);
1766         }
1767         array = action_PushInt(array, x/20);
1768         array = action_PushInt(array, font->numchars+1);
1769         array = action_InitArray(array);
1770         array = action_SetVariable(array);
1771         swf_SetU8(tag, 0);
1772
1773         if(font->layout) {
1774             tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1775             SHAPE* s;
1776             swf_ShapeNew(&s);
1777             int ls = swf_ShapeAddLineStyle(s,20,&white);
1778             int shapeid = id++;
1779             swf_SetU16(tag,shapeid);
1780             SRECT r;
1781             r.xmin = 0;
1782             r.xmax = 1024*20;
1783             r.ymin = 0;
1784             r.ymax = 256*20;
1785             swf_SetRect(tag,&r);
1786             swf_SetShapeHeader(tag,s);
1787             swf_ShapeSetAll(tag,s,0,0,ls,0,0);
1788
1789             /* Ç and Â are good chars to test ascent/descent extend */
1790             int y1 = (-font->layout->ascent-miny*20.0)*256.0/(maxy-miny);
1791             int y2 = (font->layout->descent-miny*20.0)*256.0/(maxy-miny);
1792
1793             swf_ShapeSetMove(tag,s,0,y1);
1794             swf_ShapeSetLine(tag,s,width,0);
1795             swf_ShapeSetMove(tag,s,0,y2);
1796             swf_ShapeSetLine(tag,s,width,0);
1797
1798             swf_ShapeSetEnd(tag);
1799             swf_ShapeFree(s);
1800             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1801             swf_ObjectPlace(tag, shapeid, depth++, NULL, NULL, NULL);
1802         }
1803
1804         /* shapes */
1805         
1806         for(t=0;t<font->numchars;t++) {
1807             tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1808             SHAPE* s;
1809             swf_ShapeNew(&s);
1810             int ls = swf_ShapeAddLineStyle(s,20*2,&black);
1811             int ls2 = swf_ShapeAddLineStyle(s,20*2,&green);
1812             int fs = swf_ShapeAddSolidFillStyle(s, &gray50);
1813             int shapeid = id++;
1814             swf_SetU16(tag,shapeid);
1815             SRECT r;
1816             r.xmin = 0;
1817             r.xmax = 1024*20;
1818             r.ymin = 0;
1819             r.ymax = 512*20;
1820             swf_SetRect(tag,&r);
1821             swf_SetShapeHeader(tag,s);
1822             swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
1823             SHAPE2*s2 = swf_ShapeToShape2(font->glyph[t].shape);
1824             SHAPELINE*l = s2->lines;
1825             int lastx=0,lasty=0;
1826
1827             double x1 = (1024*20 - (xmax[t] - xmin[t])*20*2*scale/20480.0)/2;
1828             double y1 = -miny*20*scale*2/20480.0;
1829             double scalex = scale*2/20480.0;
1830             double scaley = scale*2/20480.0;
1831
1832             while(l) {
1833                 int lx = (l->x)*scalex+x1;
1834                 int ly = (l->y)*scaley+y1;
1835                 int sx = (l->sx)*scalex+x1;
1836                 int sy = (l->sy)*scaley+y1;
1837                 if(l->type == moveTo) {
1838                     swf_ShapeSetMove(tag,s,lx,ly);
1839                 } else if(l->type == lineTo) {
1840                     swf_ShapeSetLine(tag,s,lx-lastx,ly-lasty);
1841                 } else if(l->type == splineTo) {
1842                     swf_ShapeSetCurve(tag,s,sx-lastx,sy-lasty,lx-sx,ly-sy);
1843                 }
1844                 lastx = lx;
1845                 lasty = ly;
1846                 l = l->next;
1847             }
1848             
1849             if(font->alignzones) {
1850                 ALIGNZONE*zone = &font->alignzones[t];
1851                 swf_ShapeSetAll(tag,s,0,0,ls2,SET_TO_ZERO,SET_TO_ZERO);
1852                 if((zone->x&zone->dx)!=0xffff) {
1853                     double x = F16toFloat(zone->x)*20480.0*scalex+x1;
1854                     double dx = (F16toFloat(zone->x)+F16toFloat(zone->dx))*20480.0*scalex+x1;
1855                     swf_ShapeSetMove(tag,s,x,0);
1856                     swf_ShapeSetLine(tag,s,0,1024*20);
1857                     swf_ShapeSetMove(tag,s,dx,0);
1858                     swf_ShapeSetLine(tag,s,0,1024*20);
1859                 }
1860                 if((zone->y&zone->dy)!=0xffff) {
1861                     double y = -F16toFloat(zone->y)*20480.0*scaley+y1;
1862                     double dy = -(F16toFloat(zone->y)+F16toFloat(zone->dy))*20480.0*scaley+y1;
1863                     swf_ShapeSetMove(tag,s,0,y);
1864                     swf_ShapeSetLine(tag,s,1024*20,0);
1865                     swf_ShapeSetMove(tag,s,0,dy);
1866                     swf_ShapeSetLine(tag,s,1024*20,0);
1867                 }
1868             }
1869
1870             swf_ShapeSetEnd(tag);
1871             swf_ShapeFree(s);
1872         
1873             tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1874             U16 spriteid=id++;
1875             swf_SetU16(tag, spriteid);
1876             swf_SetU16(tag, 1);
1877             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1878             swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1879             tag = swf_InsertTag(tag, ST_END);
1880             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1881             MATRIX m;
1882             swf_GetMatrix(0, &m);
1883             m.ty = 20000;
1884             char txt[80];
1885             sprintf(txt, "char%d", font->numchars-t);
1886             swf_ObjectPlace(tag, spriteid, depth++, &m, NULL, txt);
1887         }
1888         
1889         /* marker */
1890         tag = swf_InsertTag(tag, ST_DEFINESHAPE2);
1891         int shapeid=id++;
1892         RGBA blue = {0xff,0xc0,0xc0,0xff};
1893         swf_ShapeSetRectangle(tag, shapeid, 20, 20, &blue);
1894         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1895         U16 spriteid2=id++;
1896         swf_SetU16(tag, spriteid2);
1897         swf_SetU16(tag, 1);
1898         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1899         swf_ObjectPlace(tag, shapeid, 1, NULL, NULL, NULL);
1900         tag = swf_InsertTag(tag, ST_END);
1901         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1902         swf_ObjectPlace(tag, spriteid2, depth++, NULL, NULL, "marker");
1903         
1904         /* textbar */
1905         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1906         swf_SetU16(tag, spriteid);
1907         swf_SetU16(tag, 1);
1908         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1909         MATRIX m;
1910         swf_GetMatrix(0, &m);
1911         m.sx = 65536 * overlarge_factor;
1912         m.sy = 65536 * overlarge_factor;
1913         m.tx = 0;
1914         m.ty = -miny*256*20/(maxy-miny);
1915         swf_ObjectPlace(tag, textid, 1, &m, NULL, NULL);
1916         tag = swf_InsertTag(tag, ST_END);
1917         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1918         swf_ObjectPlace(tag, spriteid, depth++, NULL, NULL, "textbar");
1919         
1920         /* marker2 */
1921         RGBA blue2 = {0x80,0x80,0xff,0x80};
1922         tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1923         int shapeid2=id++;
1924         swf_ShapeSetRectangleWithBorder(tag, shapeid2, 20, 20, &blue2, 0, &white);
1925         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1926         U16 spriteid3=id++;
1927         swf_SetU16(tag, spriteid3);
1928         swf_SetU16(tag, 1);
1929         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1930         swf_ObjectPlace(tag, shapeid2, 1, NULL, NULL, NULL);
1931         tag = swf_InsertTag(tag, ST_END);
1932         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1933         swf_ObjectPlace(tag, spriteid3, depth++, NULL, NULL, "marker2");
1934
1935
1936 char*data = 
1937 " var mouseListener = new Object();"
1938 " var speed = 0;"
1939 " var myx = 0;"
1940 " var currentMouseOver, currentChar;"
1941 " mouseListener.onMouseDown = function() { "
1942 "     eval(\"_root.char\"+currentChar)._y = 20000;"
1943 "     currentChar = currentMouseOver;"
1944 "     var i = currentMouseOver;"
1945 "     eval(\"_root.char\"+i)._y = 256;"
1946 "     _root.marker2._yscale=256*100;"
1947 "     _root.marker2._xscale=(xpos[i-1]-xpos[i])*100;"
1948 "     _root.marker2._x=xpos[i]+myx;"
1949 " };"
1950 " mouseListener.onMouseMove = function() { "
1951 "     if(_ymouse<256) {"
1952 "          speed = Math.abs(_xmouse-512)>256?(512-_xmouse)/8:0;"
1953 "     } else {"
1954 "          speed = 0;"
1955 "     }; "
1956 " }; "
1957 " setInterval( function(){ "
1958 "     if(_ymouse<256) {"
1959 "         var i, x=_xmouse-_root.textbar._x;"
1960 "         for(i=xpos.length-1;i>0;i--) {"
1961 "             if(x<xpos[i-1]) break;"
1962 "         }"
1963 "         currentMouseOver = i;"
1964 "         _root.marker._yscale=256*100;"
1965 "         _root.marker._xscale=(xpos[i-1]-xpos[i])*100;"
1966 "         _root.marker._x=xpos[i]+myx;"
1967 "         _root.textbar._x += 0.05;"
1968 "     }"
1969 "     if(myx+speed>0) {"
1970 "         speed=0;"
1971 "     } else if(myx+speed<-xpos[0]+1024) {"
1972 "         speed=0;"
1973 "     }"
1974 "     myx+=speed;"
1975 "     _root.textbar._x = myx;"
1976 "     _root.marker._x += speed;"
1977 "     _root.marker2._x += speed;"
1978 " }, 20);"
1979 " Mouse.addListener(mouseListener);"
1980 ;
1981         ActionTAG* atag = swf_ActionCompile(data, 6);
1982
1983         tag = swf_InsertTag(tag, ST_DOACTION);
1984         swf_ActionSet(tag, array);
1985         swf_ActionSet(tag, atag);
1986         swf_SetU8(tag, 0);
1987         swf_ActionFree(atag);
1988
1989         tag = swf_InsertTag(tag, ST_SHOWFRAME);
1990
1991         free(flags);
1992         free(xmin);
1993         free(xmax);
1994     }
1995
1996     tag = swf_InsertTag(tag, ST_END);
1997
1998     swf.compressed = -1;
1999     swf_SaveSWF(&swf, filename);
2000     swf_FreeTags(&swf);
2001 }