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