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