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