added a temporary swf_FontReduce() solution
[swftools.git] / lib / modules / swftext.c
1 /* swftext.c
2
3    Text and font routines
4       
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9    Copyright (c) 2003,2004 Matthias Kramm
10  
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
24
25 static U32 readUTF8char(U8 ** text)
26 {
27     U32 c = 0;
28     if (!(*(*text) & 0x80))
29         return *((*text)++);
30
31     /* 0000 0080-0000 07FF   110xxxxx 10xxxxxx */
32     if (((*text)[0] & 0xe0) == 0xc0 && (*text)[1]) {
33         c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
34         (*text) += 2;
35         return c;
36     }
37     /* 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx */
38     if (((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2]) {
39         c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
40         (*text) += 3;
41         return c;
42     }
43     /* 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
44     if (((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2]
45         && (*text)[3]) {
46         c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f) << 6 | ((*text)[3] & 0x3f);
47         (*text) += 4;
48         return c;
49     }
50     /* 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
51     if (((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2]
52         && (*text)[3]
53         && (*text)[4]) {
54         c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f) << 12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
55         (*text) += 5;
56         return c;
57     }
58     /* 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx */
59     if (((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2]
60         && (*text)[3]
61         && (*text)[4] && (*text)[5]) {
62         c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 |
63             ((*text)[2] & 0x3f) << 18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6 | ((*text)[5] & 0x3f) << 6;
64         (*text) += 6;
65         return c;
66     }
67     return *((*text)++);
68 }
69
70 #define TF_TEXTCONTROL  0x80
71 #define TF_HASFONT      0x08
72 #define TF_HASCOLOR     0x04
73 #define TF_HASYOFFSET   0x02
74 #define TF_HASXOFFSET   0x01
75
76 #define FF_WIDECODES    0x01
77 #define FF_BOLD         0x02
78 #define FF_ITALIC       0x04
79 #define FF_ANSI         0x08
80 #define FF_SHIFTJIS     0x10
81 #define FF_UNICODE      0x20
82
83 #define FF2_BOLD         0x01
84 #define FF2_ITALIC       0x02
85 #define FF2_WIDECODES    0x04
86 #define FF2_WIDEOFFSETS  0x08
87 #define FF2_ANSI         0x10
88 #define FF2_UNICODE      0x20
89 #define FF2_SHIFTJIS     0x40
90 #define FF2_LAYOUT       0x80
91
92 int swf_FontIsItalic(SWFFONT * f)
93 {
94     return f->style & FONT_STYLE_ITALIC;
95 }
96
97 int swf_FontIsBold(SWFFONT * f)
98 {
99     return f->style & FONT_STYLE_BOLD;
100 }
101
102 static const int WRITEFONTID = 0x4e46;  // font id for WriteFont and ReadFont
103
104 int swf_FontEnumerate(SWF * swf, void (*FontCallback) (void*, U16, U8 *), void*self)
105 {
106     int n;
107     TAG *t;
108     if (!swf)
109         return -1;
110     t = swf->firstTag;
111     n = 0;
112
113     while (t) {
114         if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
115             n++;
116             if (FontCallback) {
117                 U16 id;
118                 int l;
119                 U8 s[257];
120                 s[0] = 0;
121                 swf_SaveTagPos(t);
122                 swf_SetTagPos(t, 0);
123
124                 id = swf_GetU16(t);
125                 if (swf_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONTINFO || swf_GetTagID(t) == ST_DEFINEFONTINFO2) {
126                     swf_GetU16(t);
127                     l = swf_GetU8(t);
128                     swf_GetBlock(t, s, l);
129                     s[l] = 0;
130                 }
131
132                 (FontCallback) (self, id, s);
133
134                 swf_RestoreTagPos(t);
135             }
136         }
137         t = swf_NextTag(t);
138     }
139     return n;
140 }
141
142 int swf_FontExtract_DefineFont(int id, SWFFONT * f, TAG * t)
143 {
144     U16 fid;
145     swf_SaveTagPos(t);
146     swf_SetTagPos(t, 0);
147
148     fid = swf_GetU16(t);
149     if ((!id) || (id == fid)) {
150         U16 of;
151         int n, i;
152
153         id = fid;
154         f->version = 1;
155         f->id = fid;
156
157         of = swf_GetU16(t);
158         n = of / 2;
159         f->numchars = n;
160         f->glyph = rfx_calloc(sizeof(SWFGLYPH) * n);
161
162         for (i = 1; i < n; i++)
163             swf_GetU16(t);
164         for (i = 0; i < n; i++)
165             swf_GetSimpleShape(t, &f->glyph[i].shape);
166     }
167
168     swf_RestoreTagPos(t);
169     return id;
170 }
171
172 int swf_FontExtract_DefineFontInfo(int id, SWFFONT * f, TAG * t)
173 {
174     U16 fid;
175     U16 maxcode;
176     U8 flags;
177     swf_SaveTagPos(t);
178     swf_SetTagPos(t, 0);
179
180     fid = swf_GetU16(t);
181     if (fid == id) {
182         U8 l = swf_GetU8(t);
183         int i;
184
185         if (f->version > 1) {
186             /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
187                too. However, they only add little information to what's already
188                inside the DefineFont2 tag */
189             return id;
190         }
191
192         if (f->name)
193             rfx_free(f->name);
194
195         f->name = (U8 *) rfx_alloc(l + 1);
196         swf_GetBlock(t, f->name, l);
197         f->name[l] = 0;
198
199         flags = swf_GetU8(t);
200         if (flags & 2)
201             f->style |= FONT_STYLE_BOLD;
202         if (flags & 4)
203             f->style |= FONT_STYLE_ITALIC;
204         if (flags & 8)
205             f->encoding |= FONT_ENCODING_ANSI;
206         if (flags & 16)
207             f->encoding |= FONT_ENCODING_SHIFTJIS;
208         if (flags & 32)
209             f->encoding |= FONT_ENCODING_UNICODE;
210
211         if (t->id == ST_DEFINEFONTINFO2) {
212             f->language = swf_GetU8(t);
213         }
214
215         f->glyph2ascii = (U16 *) rfx_alloc(sizeof(U16) * f->numchars);
216         maxcode = 0;
217         for (i = 0; i < f->numchars; i++) {
218             f->glyph2ascii[i] = ((flags & FF_WIDECODES) ? swf_GetU16(t) : swf_GetU8(t));
219             if (f->glyph2ascii[i] > maxcode)
220                 maxcode = f->glyph2ascii[i];
221         }
222         maxcode++;
223         if (maxcode < 256)
224             maxcode = 256;
225         f->maxascii = maxcode;
226         f->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
227         memset(f->ascii2glyph, -1, sizeof(int) * maxcode);
228
229         for (i = 0; i < f->numchars; i++)
230             f->ascii2glyph[f->glyph2ascii[i]] = i;
231     }
232
233     swf_RestoreTagPos(t);
234     return id;
235 }
236
237 int swf_FontExtract_GlyphNames(int id, SWFFONT * f, TAG * tag)
238 {
239     U16 fid;
240     U16 maxcode;
241     U8 flags;
242     swf_SaveTagPos(tag);
243     swf_SetTagPos(tag, 0);
244
245     fid = swf_GetU16(tag);
246
247     if (fid == id) {
248         int num = swf_GetU16(tag);
249         int t;
250         f->glyphnames = rfx_alloc(sizeof(char *) * num);
251         for (t = 0; t < num; t++) {
252             f->glyphnames[t] = strdup(swf_GetString(tag));
253         }
254     }
255
256     swf_RestoreTagPos(tag);
257     return id;
258 }
259
260
261 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
262 {
263     int t, glyphcount;
264     int maxcode;
265     int fid;
266     U8 flags1, flags2, namelen;
267     swf_SaveTagPos(tag);
268     swf_SetTagPos(tag, 0);
269     font->version = 2;
270     fid = swf_GetU16(tag);
271     if (id && id != fid)
272         return id;
273     font->id = fid;
274     flags1 = swf_GetU8(tag);
275     flags2 = swf_GetU8(tag);    //reserved flags
276
277     if (flags1 & 1)
278         font->style |= FONT_STYLE_BOLD;
279     if (flags1 & 2)
280         font->style |= FONT_STYLE_ITALIC;
281     if (flags1 & 16)
282         font->encoding |= FONT_ENCODING_ANSI;
283     if (flags1 & 32)
284         font->encoding |= FONT_ENCODING_UNICODE;
285     if (flags1 & 64)
286         font->encoding |= FONT_ENCODING_SHIFTJIS;
287
288     namelen = swf_GetU8(tag);
289     font->name = (U8 *) rfx_alloc(namelen + 1);
290     font->name[namelen] = 0;
291     swf_GetBlock(tag, font->name, namelen);
292     font->version = 2;
293     glyphcount = swf_GetU16(tag);
294     font->numchars = glyphcount;
295
296     font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
297     font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
298
299     if (flags1 & 8) {           // wide offsets
300         for (t = 0; t < glyphcount; t++)
301             swf_GetU32(tag);    //offset[t]
302
303         if (glyphcount)         /* this _if_ is not in the specs */
304             swf_GetU32(tag);    // fontcodeoffset
305     } else {
306         for (t = 0; t < glyphcount; t++)
307             swf_GetU16(tag);    //offset[t]
308
309         if (glyphcount)         /* this _if_ is not in the specs */
310             swf_GetU16(tag);    // fontcodeoffset
311     }
312     /* TODO: we should use the offset positions, not just
313              blindly read in shapes */
314     for (t = 0; t < glyphcount; t++)
315         swf_GetSimpleShape(tag, &(font->glyph[t].shape));
316
317     maxcode = 0;
318     for (t = 0; t < glyphcount; t++) {
319         int code;
320         if (flags1 & 4)         // wide codes
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 = 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 = 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     swf_RestoreTagPos(t);
373     return font->id;
374 }
375
376
377 #define FEDTJ_PRINT  0x01
378 #define FEDTJ_MODIFY 0x02
379 #define FEDTJ_CALLBACK 0x04
380
381 static int
382 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
383                                    void (*callback) (void *self,
384                                                      int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
385 {
386     U16 cid;
387     SRECT r;
388     MATRIX m;
389     U8 gbits, abits;
390     int fid = 0;
391     RGBA color;
392     int x = 0, y = 0;
393     int fontsize = 0;
394
395     memset(&color, 0, sizeof(color));
396
397     swf_SaveTagPos(t);
398     swf_SetTagPos(t, 0);
399
400     cid = swf_GetU16(t);
401     swf_GetRect(t, &r);
402     swf_GetMatrix(t, &m);
403     gbits = swf_GetU8(t);
404     abits = swf_GetU8(t);
405
406     while (1) {
407         int flags, num;
408         flags = swf_GetU8(t);
409         if (!flags)
410             break;
411
412         if (flags & TF_TEXTCONTROL) {
413             if (flags & TF_HASFONT)
414                 fid = swf_GetU16(t);
415             if (flags & TF_HASCOLOR) {
416                 color.r = swf_GetU8(t); // rgb
417                 color.g = swf_GetU8(t);
418                 color.b = swf_GetU8(t);
419                 if (swf_GetTagID(t) == ST_DEFINETEXT2)
420                     color.a = swf_GetU8(t);
421             }
422             if (flags & TF_HASXOFFSET)
423                 x = swf_GetS16(t);
424             if (flags & TF_HASYOFFSET)
425                 y = swf_GetS16(t);
426             if (flags & TF_HASFONT)
427                 fontsize = swf_GetU16(t);
428         }
429
430         num = swf_GetU8(t);
431         if (!num)
432             break;
433
434         {
435             int i;
436             int buf[256];
437             int advance[256];
438             int xpos = 0;
439             for (i = 0; i < num; i++) {
440                 int glyph;
441                 int adv = 0;
442                 advance[i] = xpos;
443                 glyph = swf_GetBits(t, gbits);
444                 adv = swf_GetBits(t, abits);
445                 xpos += adv;
446
447                 // <deprecated>
448                 if (id == fid) {
449                     if (jobs & FEDTJ_PRINT) {
450                         int code = f->glyph2ascii[glyph];
451                         printf("%c", code);
452                     }
453                     if (jobs & FEDTJ_MODIFY)
454                         f->glyph[glyph].advance = adv * 20;     //?
455                 } else {
456                     if (jobs & FEDTJ_PRINT) {
457                         printf("?");
458                     }
459                 }
460                 // </deprecated>
461
462                 buf[i] = glyph;
463             }
464             if ((id == fid) && (jobs & FEDTJ_PRINT))
465                 printf("\n");
466             if (jobs & FEDTJ_CALLBACK)
467                 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
468             x += xpos;
469         }
470     }
471
472     swf_RestoreTagPos(t);
473     return id;
474 }
475
476 int swf_ParseDefineText(TAG * tag,
477                     void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
478 {
479     return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
480 }
481
482 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
483 {
484     return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
485 }
486
487 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
488 {
489     TAG *t;
490     SWFFONT *f;
491
492     if ((!swf) || (!font))
493         return -1;
494
495     f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
496
497     t = swf->firstTag;
498
499     while (t) {
500         int nid = 0;
501         switch (swf_GetTagID(t)) {
502         case ST_DEFINEFONT:
503             nid = swf_FontExtract_DefineFont(id, f, t);
504             break;
505
506         case ST_DEFINEFONT2:
507             nid = swf_FontExtract_DefineFont2(id, f, t);
508             break;
509
510         case ST_DEFINEFONTINFO:
511         case ST_DEFINEFONTINFO2:
512             nid = swf_FontExtract_DefineFontInfo(id, f, t);
513             break;
514
515         case ST_DEFINETEXT:
516         case ST_DEFINETEXT2:
517             nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
518             break;
519
520         case ST_GLYPHNAMES:
521             nid = swf_FontExtract_GlyphNames(id, f, t);
522             break;
523         }
524         if (nid > 0)
525             id = nid;
526         t = swf_NextTag(t);
527     }
528     if (f->id != id) {
529         rfx_free(f);
530         f = 0;
531     }
532     font[0] = f;
533     return 0;
534 }
535
536 int swf_FontSetID(SWFFONT * f, U16 id)
537 {
538     if (!f)
539         return -1;
540     f->id = id;
541     return 0;
542 }
543
544 void swf_LayoutFree(SWFLAYOUT * l)
545 {
546     if (l) {
547         if (l->kerning)
548             rfx_free(l->kerning);
549         l->kerning = NULL;
550         if (l->bounds)
551             rfx_free(l->bounds);
552         l->bounds = NULL;
553     }
554     rfx_free(l);
555 }
556
557
558 static void font_freeglyphnames(SWFFONT*f)
559 {
560     if (f->glyphnames) {
561         int t;
562         for (t = 0; t < f->numchars; t++) {
563             if (f->glyphnames[t])
564                 rfx_free(f->glyphnames[t]);
565         }
566         rfx_free(f->glyphnames);
567         f->glyphnames = 0;
568     }
569
570 }
571 static void font_freeusage(SWFFONT*f)
572 {
573     if (f->use) {
574         if(f->use->chars) {
575             rfx_free(f->use->chars);f->use->chars = 0;
576         }
577         rfx_free(f->use); f->use = 0;
578     }
579 }
580 static void font_freelayout(SWFFONT*f)
581 {
582     if (f->layout) {
583         swf_LayoutFree(f->layout);
584         f->layout = 0;
585     }
586 }
587 static void font_freename(SWFFONT*f)
588 {
589     if (f->name) {
590         rfx_free(f->name);
591         f->name = 0;
592     }
593 }
594
595 int swf_FontReduce_old(SWFFONT * f)
596 {
597     int i, j;
598     int max_unicode = 0;
599     if ((!f) || (!f->use) || f->use->is_reduced)
600         return -1;
601
602     j = 0;
603
604     for (i = 0; i < f->numchars; i++) {
605         if (f->glyph[i].shape && f->use->chars[i]) {
606             f->glyph2ascii[j] = f->glyph2ascii[i];
607             f->glyph[j] = f->glyph[i];
608             f->use->chars[i] = j;
609             j++;
610         } else {
611             f->glyph2ascii[i] = 0;
612             if(f->glyph[i].shape) {
613                 swf_ShapeFree(f->glyph[i].shape);
614                 f->glyph[i].shape = 0;
615                 f->glyph[i].advance = 0;
616             }
617             f->use->chars[i] = -1;
618             j++; //TODO: remove
619         }
620     }
621     for (i = 0; i < f->maxascii; i++) {
622         if(f->use->chars[f->ascii2glyph[i]]<0) {
623             f->ascii2glyph[i] = -1;
624         } else {
625             f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
626             max_unicode = i;
627         }
628     }
629     f->maxascii = max_unicode;
630     f->use->is_reduced = 1;
631     f->numchars = j;
632     font_freelayout(f);
633     font_freeglyphnames(f);
634     font_freename(f);
635     return j;
636 }
637
638 int swf_FontReduce(SWFFONT * f)
639 {
640     int i;
641     int max_unicode = 0;
642     int max_glyph = 0;
643     if ((!f) || (!f->use) || f->use->is_reduced)
644         return -1;
645
646     for (i = 0; i < f->numchars; i++) {
647         if(!f->use->chars[i]) {
648             f->glyph2ascii[i] = 0;
649             if(f->glyph[i].shape) {
650                 swf_ShapeFree(f->glyph[i].shape);
651                 f->glyph[i].shape = 0;
652                 f->glyph[i].advance = 0;
653             }
654         } else {
655             max_glyph = i+1;
656         }
657     }
658     for (i = 0; i < f->maxascii; i++) {
659         if(!f->use->chars[f->ascii2glyph[i]]) {
660             f->ascii2glyph[i] = -1;
661         } else {
662             max_unicode = i+1;
663         }
664     }
665     f->maxascii = max_unicode;
666     f->numchars = max_glyph;
667     font_freelayout(f);
668     font_freeglyphnames(f);
669     font_freename(f);
670     return 0;
671 }
672
673 void swf_FontSort(SWFFONT * font)
674 {
675     int i, j, k;
676     int *newplace;
677     int *newpos;
678     if (!font)
679         return;
680     
681     newplace = rfx_alloc(sizeof(int) * font->numchars);
682
683     for (i = 0; i < font->numchars; i++) {
684         newplace[i] = i;
685     }
686     for (i = 0; i < font->numchars; i++)
687         for (j = 0; j < i; j++) {
688             if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
689                 int n1, n2;
690                 char *c1, *c2;
691                 SWFGLYPH g1, g2;
692                 SRECT r1, r2;
693                 n1 = newplace[i];
694                 n2 = newplace[j];
695                 newplace[j] = n1;
696                 newplace[i] = n2;
697                 n1 = font->glyph2ascii[i];
698                 n2 = font->glyph2ascii[j];
699                 font->glyph2ascii[j] = n1;
700                 font->glyph2ascii[i] = n2;
701                 g1 = font->glyph[i];
702                 g2 = font->glyph[j];
703                 font->glyph[j] = g1;
704                 font->glyph[i] = g2;
705                 if (font->glyphnames) {
706                     c1 = font->glyphnames[i];
707                     c2 = font->glyphnames[j];
708                     font->glyphnames[j] = c1;
709                     font->glyphnames[i] = c2;
710                 }
711                 if (font->layout) {
712                     r1 = font->layout->bounds[i];
713                     r2 = font->layout->bounds[j];
714                     font->layout->bounds[j] = r1;
715                     font->layout->bounds[i] = r2;
716                 }
717             }
718         }
719     newpos = rfx_alloc(sizeof(int) * font->numchars);
720     for (i = 0; i < font->numchars; i++) {
721         newpos[newplace[i]] = i;
722     }
723     for (i = 0; i < font->maxascii; i++) {
724         if (font->ascii2glyph[i] >= 0)
725             font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
726     }
727
728     rfx_free(newpos);
729     rfx_free(newplace);
730 }
731
732 void swf_FontPrepareForEditText(SWFFONT * font)
733 {
734     if (!font->layout)
735         swf_FontCreateLayout(font);
736     swf_FontSort(font);
737 }
738
739 int swf_FontInitUsage(SWFFONT * f)
740 {
741     if (!f)
742         return -1;
743     if(f->use) {
744         fprintf(stderr, "Usage initialized twice");
745         return -1;
746     }
747     f->use = rfx_alloc(sizeof(FONTUSAGE));
748     f->use->is_reduced = 0;
749     f->use->chars = rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
750     return 0;
751 }
752
753 void swf_FontClearUsage(SWFFONT * f)
754 {
755     if (!f || !f->use)
756         return;
757     rfx_free(f->use->chars); f->use->chars = 0;
758     rfx_free(f->use); f->use = 0;
759 }
760
761 int swf_FontUse(SWFFONT * f, U8 * s)
762 {
763     if (!f->use) 
764         swf_FontInitUsage(f);
765     if( (!s))
766         return -1;
767     while (*s) {
768         if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
769             f->use->chars[f->ascii2glyph[*s]] = 1;
770         s++;
771     }
772     return 0;
773 }
774
775 int swf_FontUseGlyph(SWFFONT * f, int glyph)
776 {
777     if (!f->use) 
778         swf_FontInitUsage(f);
779     if(glyph < 0 || glyph >= f->numchars)
780         return -1;
781     f->use->chars[glyph] = 1;
782     return 0;
783 }
784
785 int swf_FontSetDefine(TAG * t, SWFFONT * f)
786 {
787     U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
788     int p, i, j;
789
790     if ((!t) || (!f))
791         return -1;
792     swf_ResetWriteBits(t);
793     swf_SetU16(t, f->id);
794
795     p = 0;
796     j = 0;
797     for (i = 0; i < f->numchars; i++)
798         if (f->glyph[i].shape) {
799             ofs[j++] = p;
800             p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
801         }
802
803     for (i = 0; i < j; i++)
804         swf_SetU16(t, ofs[i] + j * 2);
805     if (!j) {
806         fprintf(stderr, "rfxswf: warning: Font is empty\n");
807         swf_SetU16(t, 0);
808     }
809
810     for (i = 0; i < f->numchars; i++)
811         if (f->glyph[i].shape)
812             swf_SetSimpleShape(t, f->glyph[i].shape);
813
814     swf_ResetWriteBits(t);
815     rfx_free(ofs);
816     return 0;
817 }
818
819 static inline int fontSize(SWFFONT * font)
820 {
821     int t;
822     int size = 0;
823     for (t = 0; t < font->numchars; t++) {
824         int l = 0;
825         if(font->glyph[t].shape) 
826             l = (font->glyph[t].shape->bitlen + 7) / 8;
827         else
828             l = 8;
829         size += l + 1;
830     }
831     return size + (font->numchars + 1) * 2;
832 }
833
834 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
835 {
836     U8 flags = 0;
837     int t;
838     int pos;
839     int pos2;
840     swf_SetU16(tag, f->id);
841
842     if (f->layout) flags |= 128;                // haslayout
843     if (f->numchars > 256)
844         flags |= 4;             // widecodes
845     if (f->style & FONT_STYLE_BOLD)
846         flags |= 1;             // bold
847     if (f->style & FONT_STYLE_ITALIC)
848         flags |= 2;             // italic
849     if (f->maxascii >= 256)
850         flags |= 4;             //wide codecs
851     if (fontSize(f) > 65535)
852         flags |= 8;             //wide offsets
853     flags |= 8 | 4;             //FIXME: the above check doesn't work
854
855     if (f->encoding & FONT_ENCODING_ANSI)
856         flags |= 16;            // ansi
857     if (f->encoding & FONT_ENCODING_UNICODE)
858         flags |= 32;            // unicode
859     if (f->encoding & FONT_ENCODING_SHIFTJIS)
860         flags |= 64;            // shiftjis
861
862     swf_SetU8(tag, flags);
863     swf_SetU8(tag, 0);          //reserved flags
864     if (f->name) {
865         /* font name */
866         swf_SetU8(tag, strlen(f->name));
867         swf_SetBlock(tag, f->name, strlen(f->name));
868     } else {
869         /* font name (="") */
870         swf_SetU8(tag, 0);
871     }
872     /* number of glyphs */
873     swf_SetU16(tag, f->numchars);
874     /* font offset table */
875     pos = tag->len;
876     for (t = 0; t <= f->numchars; t++) {
877         if (flags & 8)
878             swf_SetU32(tag, /* fontoffset */ 0);        /*placeholder */
879         else
880             swf_SetU16(tag, /* fontoffset */ 0);        /*placeholder */
881     }
882
883     for (t = 0; t <= f->numchars; t++) {
884         if (flags & 8) {
885             tag->data[pos + t * 4] = (tag->len - pos);
886             tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
887             tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
888             tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
889         } else {
890             if (tag->len - pos > 65535) {
891                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
892                 exit(1);
893             }
894             tag->data[pos + t * 2] = (tag->len - pos);
895             tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
896         }
897         if (t < f->numchars) {
898             if(f->glyph[t].shape) {
899                 swf_SetSimpleShape(tag, f->glyph[t].shape);
900             } else {
901                 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
902             }
903         }
904     }
905
906
907     /* font code table */
908     if (flags & 4) {            /* wide codes */
909         for (t = 0; t < f->numchars; t++) {
910             swf_SetU16(tag, f->glyph2ascii[t]);
911         }
912     } else {
913         for (t = 0; t < f->numchars; t++)
914             swf_SetU8(tag, f->glyph2ascii[t]);
915     }
916     if (f->layout) {
917         swf_SetU16(tag, f->layout->ascent);
918         swf_SetU16(tag, f->layout->descent);
919         swf_SetU16(tag, f->layout->leading);
920         for (t = 0; t < f->numchars; t++)
921             swf_SetU16(tag, f->glyph[t].advance);
922         for (t = 0; t < f->numchars; t++) {
923             swf_ResetWriteBits(tag);
924             swf_SetRect(tag, &f->layout->bounds[t]);
925         }
926         swf_SetU16(tag, f->layout->kerningcount);
927         for (t = 0; t < f->layout->kerningcount; t++) {
928             if (flags & 4) {    /* wide codes */
929                 swf_SetU16(tag, f->layout->kerning[t].char1);
930                 swf_SetU16(tag, f->layout->kerning[t].char2);
931             } else {
932                 swf_SetU8(tag, f->layout->kerning[t].char1);
933                 swf_SetU8(tag, f->layout->kerning[t].char2);
934             }
935             swf_SetU16(tag, f->layout->kerning[t].adjustment);
936         }
937     }
938     return 0;
939 }
940
941 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
942 {
943     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
944     f->layout->ascent = ascent;
945     f->layout->descent = descent;
946     f->layout->leading = leading;
947     f->layout->kerningcount = 0;
948     f->layout->kerning = 0;
949     f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
950 }
951
952 int swf_FontSetInfo(TAG * t, SWFFONT * f)
953 {
954     int l, i;
955     U8 wide = 0;
956     U8 flags = 0;
957     if ((!t) || (!f))
958         return -1;
959     swf_ResetWriteBits(t);
960     swf_SetU16(t, f->id);
961     l = f->name ? strlen(f->name) : 0;
962     if (l > 255)
963         l = 255;
964     swf_SetU8(t, l);
965     if (l)
966         swf_SetBlock(t, f->name, l);
967     if (f->numchars >= 256)
968         wide = 1;
969
970     if (f->style & FONT_STYLE_BOLD)
971         flags |= 2;
972     if (f->style & FONT_STYLE_ITALIC)
973         flags |= 4;
974     if (f->style & FONT_ENCODING_ANSI)
975         flags |= 8;
976     if (f->style & FONT_ENCODING_SHIFTJIS)
977         flags |= 16;
978     if (f->style & FONT_ENCODING_UNICODE)
979         flags |= 32;
980
981     swf_SetU8(t, (flags & 0xfe) | wide);
982
983     for (i = 0; i < f->numchars; i++) {
984         if (f->glyph[i].shape) {
985             int g2a = f->glyph2ascii[i];
986             wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
987         }
988     }
989
990     return 0;
991 }
992
993 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
994 {
995     int id = swf_GetTagID(t);
996     if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
997         swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
998     else
999         return -1;
1000     return 0;
1001 }
1002
1003 void swf_FontFree(SWFFONT * f)
1004 {
1005     int i;
1006     if (!f)
1007         return;
1008
1009     if (f->glyph) {
1010         for (i = 0; i < f->numchars; i++)
1011             if (f->glyph[i].shape) {
1012                 swf_ShapeFree(f->glyph[i].shape);
1013                 f->glyph[i].shape = NULL;
1014             }
1015         rfx_free(f->glyph);
1016         f->glyph = NULL;
1017     }
1018     if (f->ascii2glyph) {
1019         rfx_free(f->ascii2glyph);
1020         f->ascii2glyph = NULL;
1021     }
1022     if (f->glyph2ascii) {
1023         rfx_free(f->glyph2ascii);
1024         f->glyph2ascii = NULL;
1025     }
1026     font_freename(f);
1027     font_freelayout(f);
1028     font_freeglyphnames(f);
1029     font_freeusage(f);
1030
1031     rfx_free(f);
1032 }
1033
1034 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1035 {
1036     U8 flags;
1037     if (!t)
1038         return -1;
1039
1040     flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1041         | (dy ? TF_HASYOFFSET : 0);
1042
1043     swf_SetU8(t, flags);
1044     if (font)
1045         swf_SetU16(t, font->id);
1046     if (color) {
1047         if (swf_GetTagID(t) == ST_DEFINETEXT2)
1048             swf_SetRGBA(t, color);
1049         else
1050             swf_SetRGB(t, color);
1051     }
1052     if (dx) {
1053         if(dx != SET_TO_ZERO) {
1054             if(dx>32767 || dx<-32768)
1055                 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1056             swf_SetS16(t, dx);
1057         } else {
1058             swf_SetS16(t, 0);
1059         }
1060     }
1061     if (dy) {
1062         if(dy != SET_TO_ZERO) {
1063             if(dy>32767 || dy<-32768)
1064                 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1065             swf_SetS16(t, dy);
1066         } else {
1067             swf_SetS16(t, 0);
1068         }
1069     }
1070     if (font)
1071         swf_SetU16(t, size);
1072
1073     return 0;
1074 }
1075
1076 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1077 {
1078     U16 g, a;
1079     char utf8 = 0;
1080     if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1081         return -1;
1082     g = a = 0;
1083
1084     if (!strcmp(encoding, "UTF8"))
1085         utf8 = 1;
1086     else if (!strcmp(encoding, "iso-8859-1"))
1087         utf8 = 0;
1088     else
1089         fprintf(stderr, "Unknown encoding: %s", encoding);
1090
1091     while (*s) {
1092         int glyph = -1, c;
1093
1094         if (!utf8)
1095             c = *s++;
1096         else
1097             c = readUTF8char(&s);
1098
1099         if (c < font->maxascii)
1100             glyph = font->ascii2glyph[c];
1101         if (glyph >= 0) {
1102             g = swf_CountUBits(glyph, g);
1103             a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1104         }
1105     }
1106
1107     if (gbits)
1108         gbits[0] = (U8) g;
1109     if (abits)
1110         abits[0] = (U8) a;
1111     return 0;
1112 }
1113
1114 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1115 {
1116     int l = 0, pos;
1117     char utf8 = 0;
1118
1119     if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1120         return -1;
1121
1122     if (!strcmp(encoding, "UTF8"))
1123         utf8 = 1;
1124     else if (!strcmp(encoding, "iso-8859-1"))
1125         utf8 = 0;
1126     else
1127         fprintf(stderr, "Unknown encoding: %s", encoding);
1128
1129     pos = t->len;
1130     swf_SetU8(t, l);            //placeholder
1131
1132     while (*s) {
1133         int g = -1, c;
1134
1135         if (!utf8)
1136             c = *s++;
1137         else
1138             c = readUTF8char(&s);
1139
1140         if (c < font->maxascii)
1141             g = font->ascii2glyph[c];
1142         if (g >= 0) {
1143             swf_SetBits(t, g, gbits);
1144             swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1145             l++;
1146             if (l == 0x7f)
1147                 break;
1148         }
1149     }
1150
1151     PUT8(&t->data[pos], l);
1152
1153     swf_ResetWriteBits(t);
1154     return 0;
1155 }
1156
1157 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1158 {
1159     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1160 }
1161
1162 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1163 {
1164     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1165 }
1166
1167 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1168 {
1169     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1170 }
1171
1172 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1173 {
1174     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1175 }
1176
1177 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1178 {
1179     U32 res = 0;
1180
1181     if (font && s) {
1182         while (s[0]) {
1183             int g = -1;
1184             if (*s < font->maxascii)
1185                 g = font->ascii2glyph[*s];
1186             if (g >= 0)
1187                 res += font->glyph[g].advance / 20;
1188             s++;
1189         }
1190         if (scale)
1191             res = (res * scale) / 100;
1192     }
1193     return res;
1194 }
1195
1196 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1197 {
1198     int xpos = 0;
1199     int ypos = 0;
1200     SRECT r;
1201     swf_GetRect(0, &r);
1202     while (*s) {
1203         int c = readUTF8char(&s);
1204         if (c < font->maxascii) {
1205             int g = font->ascii2glyph[c];
1206             if (g >= 0) {
1207                 SRECT rn = font->layout->bounds[g];
1208                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1209                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1210                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1211                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1212                 swf_ExpandRect2(&r, &rn);
1213                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1214             }
1215         }
1216         c++;
1217     }
1218     return r;
1219 }
1220
1221
1222 SWFFONT *swf_ReadFont(char *filename)
1223 {
1224     int f;
1225     SWF swf;
1226     if (!filename)
1227         return 0;
1228     f = open(filename, O_RDONLY|O_BINARY);
1229
1230     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1231         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1232         close(f);
1233         return 0;
1234     } else {
1235         SWFFONT *font;
1236         close(f);
1237         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1238             return 0;
1239         swf_FreeTags(&swf);
1240         return font;
1241     }
1242 }
1243
1244 void swf_WriteFont(SWFFONT * font, char *filename)
1245 {
1246     SWF swf;
1247     TAG *t;
1248     SRECT r;
1249     RGBA rgb;
1250     int f;
1251     int useDefineFont2 = 0;
1252     int storeGlyphNames = 1;
1253
1254     if (font->layout)
1255         useDefineFont2 = 1;     /* the only thing new in definefont2 
1256                                    is layout information. */
1257
1258     font->id = WRITEFONTID;     //"FN"
1259
1260     memset(&swf, 0x00, sizeof(SWF));
1261
1262     swf.fileVersion = 4;
1263     swf.frameRate = 0x4000;
1264
1265     /* if we use DefineFont1 to store the characters,
1266        we have to build a textfield to store the
1267        advance values. While at it, we can also
1268        make the whole .swf viewable */
1269
1270     /* we now always create viewable swfs, even if we
1271        did use definefont2 -mk */
1272     t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1273     swf.firstTag = t;
1274     rgb.r = 0xef;
1275     rgb.g = 0xef;
1276     rgb.b = 0xff;
1277     swf_SetRGB(t, &rgb);
1278     if (!useDefineFont2) {
1279         t = swf_InsertTag(t, ST_DEFINEFONT);
1280         swf_FontSetDefine(t, font);
1281         t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1282         swf_FontSetInfo(t, font);
1283     } else {
1284         t = swf_InsertTag(t, ST_DEFINEFONT2);
1285         swf_FontSetDefine2(t, font);
1286     }
1287
1288     if (storeGlyphNames && font->glyphnames) {
1289         int c;
1290         t = swf_InsertTag(t, ST_GLYPHNAMES);
1291         swf_SetU16(t, WRITEFONTID);
1292         swf_SetU16(t, font->numchars);
1293         for (c = 0; c < font->numchars; c++) {
1294             if (font->glyphnames[c])
1295                 swf_SetString(t, font->glyphnames[c]);
1296             else
1297                 swf_SetString(t, "");
1298         }
1299     }
1300
1301     if (1)                      //neccessary only for df1, but pretty to look at anyhow, so do it always
1302     {
1303         int textscale = 400;
1304         int s;
1305         int xmax = 0;
1306         int ymax = 0;
1307         int ypos = 1;
1308         U8 gbits, abits;
1309         int x, y, c;
1310         int range = font->maxascii;
1311
1312         c = 0;
1313         if (useDefineFont2 && range > 256) {
1314             range = 256;
1315         }
1316
1317         for (s = 0; s < range; s++) {
1318             int g = font->ascii2glyph[s];
1319             if (g >= 0) {
1320                 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1321                     xmax = (font->glyph[g].advance * textscale / 20) / 64;
1322                 }
1323                 c++;
1324             }
1325             if ((s & 15) == 0) {
1326                 if (c) {
1327                     ypos++;
1328                 }
1329                 c = 0;
1330             }
1331         }
1332         ymax = ypos * textscale * 2;
1333
1334         swf.movieSize.xmax = xmax * 20;
1335         swf.movieSize.ymax = ymax;
1336
1337         t = swf_InsertTag(t, ST_DEFINETEXT);
1338
1339         swf_SetU16(t, font->id + 1);    // ID
1340
1341         r.xmin = 0;
1342         r.ymin = 0;
1343         r.xmax = swf.movieSize.xmax;
1344         r.ymax = swf.movieSize.ymax;
1345
1346         swf_SetRect(t, &r);
1347
1348         swf_SetMatrix(t, NULL);
1349
1350         abits = swf_CountBits(xmax * 16, 0);
1351         gbits = 8;
1352
1353         swf_SetU8(t, gbits);
1354         swf_SetU8(t, abits);
1355
1356         rgb.r = 0x00;
1357         rgb.g = 0x00;
1358         rgb.b = 0x00;
1359         ypos = 1;
1360         for (y = 0; y < ((range + 15) / 16); y++) {
1361             int c = 0, lastx = -1;
1362             for (x = 0; x < 16; x++) {
1363                 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1364                 if (g >= 0 && font->glyph[g].shape) {
1365                     c++;
1366                     if (lastx < 0)
1367                         lastx = x * xmax;
1368                 }
1369             }
1370             if (c) {
1371                 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1372                 for (x = 0; x < 16; x++) {
1373                     int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1374                     if (g >= 0 && font->glyph[g].shape) {
1375                         if (lastx != x * xmax) {
1376                             swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1377                         }
1378                         swf_SetU8(t, 1);
1379                         swf_SetBits(t, g, gbits);
1380                         swf_SetBits(t, font->glyph[g].advance / 20, abits);
1381                         lastx = x * xmax + (font->glyph[g].advance / 20);
1382                         swf_ResetWriteBits(t);
1383                     }
1384                 }
1385                 ypos++;
1386             }
1387         }
1388         swf_SetU8(t, 0);
1389
1390
1391         t = swf_InsertTag(t, ST_PLACEOBJECT2);
1392
1393         swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1394
1395         t = swf_InsertTag(t, ST_SHOWFRAME);
1396
1397     }
1398
1399     t = swf_InsertTag(t, ST_END);
1400
1401     f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1402     if FAILED
1403         (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1404     close(f);
1405
1406     swf_FreeTags(&swf);
1407 }
1408
1409
1410 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1411 {
1412     swf_SetRect(tag, &r);
1413     swf_ResetWriteBits(tag);
1414
1415     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1416     if (text)
1417         flags |= ET_HASTEXT;
1418     if (color)
1419         flags |= ET_HASTEXTCOLOR;
1420     if (maxlength)
1421         flags |= ET_HASMAXLENGTH;
1422     if (font)
1423         flags |= ET_HASFONT;
1424     if (layout)
1425         flags |= ET_HASLAYOUT;
1426
1427     swf_SetBits(tag, flags, 16);
1428
1429     if (flags & ET_HASFONT) {
1430         swf_SetU16(tag, font);  //font
1431         swf_SetU16(tag, height);        //fontheight
1432     }
1433     if (flags & ET_HASTEXTCOLOR) {
1434         swf_SetRGBA(tag, color);
1435     }
1436     if (flags & ET_HASMAXLENGTH) {
1437         swf_SetU16(tag, maxlength);     //maxlength
1438     }
1439     if (flags & ET_HASLAYOUT) {
1440         swf_SetU8(tag, layout->align);  //align
1441         swf_SetU16(tag, layout->leftmargin);    //left margin
1442         swf_SetU16(tag, layout->rightmargin);   //right margin
1443         swf_SetU16(tag, layout->indent);        //indent
1444         swf_SetU16(tag, layout->leading);       //leading
1445     }
1446     swf_SetString(tag, variable);
1447     if (flags & ET_HASTEXT)
1448         swf_SetString(tag, text);
1449 }
1450
1451 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1452 {
1453     SRECT r;
1454     U8 gbits, abits;
1455     U8 *c = (U8 *) text;
1456     int pos = 0;
1457     if (font->layout) {
1458         r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1459     } else {
1460         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1461         /* Hm, without layout information, we can't compute a bounding
1462            box. We could call swf_FontCreateLayout to create a layout,
1463            but the caller probably doesn't want us to mess up his font
1464            structure.
1465          */
1466         r.xmin = r.ymin = 0;
1467         r.xmax = r.ymax = 1024 * 20;
1468     }
1469
1470     swf_SetRect(tag, &r);
1471
1472     /* The text matrix is pretty boring, as it doesn't apply to
1473        individual characters, but rather whole text objects (or
1474        at least whole char records- haven't tested).
1475        So it can't do anything which we can't already do with
1476        the placeobject tag we use for placing the text on the scene.
1477      */
1478     swf_SetMatrix(tag, 0);
1479
1480     swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1481     swf_SetU8(tag, gbits);
1482     swf_SetU8(tag, abits);
1483
1484     /* now set the text params- notice that a font size of
1485        1024 means that the glyphs will be displayed exactly
1486        as they would be in/with a defineshape. (Try to find
1487        *that* in the flash specs)
1488      */
1489     swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, 0, 0);  //scale
1490
1491     /* set the actual text- notice that we just pass our scale
1492        parameter over, as TextSetCharRecord calculates with 
1493        percent, too */
1494     swf_TextSetCharRecordUTF8(tag, font, text, scale * 20, gbits, abits);
1495
1496     swf_SetU8(tag, 0);
1497     return r;
1498 }
1499
1500 void swf_FontCreateLayout(SWFFONT * f)
1501 {
1502     S16 leading = 0;
1503     int t;
1504     if (f->layout)
1505         return;
1506     if (!f->numchars)
1507         return;
1508
1509     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1510     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1511     f->layout->ascent = -32767;
1512     f->layout->descent = -32767;
1513
1514     for (t = 0; t < f->numchars; t++) {
1515         SHAPE2 *shape2;
1516         SRECT bbox;
1517         int width;
1518         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1519         if (!shape2) {
1520             fprintf(stderr, "Shape parse error\n");
1521             exit(1);
1522         }
1523         bbox = swf_GetShapeBoundingBox(shape2);
1524         swf_Shape2Free(shape2);
1525         f->layout->bounds[t] = bbox;
1526
1527         width = (bbox.xmax);
1528
1529         /* The following is a heuristic- it may be that extractfont_DefineText
1530            has already found out some widths for individual characters (from the way
1531            they are used)- we now have to guess whether that width might be possible,
1532            which is the case if it isn't either much too big or much too small */
1533         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1534             f->glyph[t].advance = width;
1535
1536         if (-bbox.ymin > f->layout->ascent)
1537             f->layout->ascent = bbox.ymin;
1538         if (bbox.ymax > f->layout->descent)
1539             f->layout->descent = bbox.ymax;
1540     }
1541 }
1542
1543 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1544 {
1545     U8 *s = (U8 *) text;
1546     int advance = 0;
1547     while (*s) {
1548         SHAPE *shape;
1549         SHAPE2 *shape2;
1550         SHAPELINE *l;
1551         U32 c = readUTF8char(&s);
1552         int g = font->ascii2glyph[c];
1553         shape = font->glyph[g].shape;
1554         if (((int) g) < 0) {
1555             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1556             continue;
1557         }
1558         shape2 = swf_ShapeToShape2(shape);
1559         l = shape2->lines;
1560         while (l) {
1561             if (l->type == moveTo) {
1562                 FPOINT to;
1563                 to.x = l->x * size / 100.0 / 20.0 + advance;
1564                 to.y = l->y * size / 100.0 / 20.0;
1565                 draw->moveTo(draw, &to);
1566             } else if (l->type == lineTo) {
1567                 FPOINT to;
1568                 to.x = l->x * size / 100.0 / 20.0 + advance;
1569                 to.y = l->y * size / 100.0 / 20.0;
1570                 draw->lineTo(draw, &to);
1571             } else if (l->type == splineTo) {
1572                 FPOINT mid, to;
1573                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1574                 mid.y = l->sy * size / 100.0 / 20.0;
1575                 to.x = l->x * size / 100.0 / 20.0 + advance;
1576                 to.y = l->y * size / 100.0 / 20.0;
1577                 draw->splineTo(draw, &mid, &to);
1578             }
1579             l = l->next;
1580         }
1581         swf_Shape2Free(shape2);
1582         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1583     }
1584 }