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