6bd59f0522dec352b663463736aa333d237e2b8d
[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 #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_GetTagID(t) == ST_DEFINEFONT2 || swf_GetTagID(t) == ST_DEFINEFONT) {
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 = 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     font->version = 2;
282     glyphcount = swf_GetU16(tag);
283     font->numchars = glyphcount;
284
285     font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
286     font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
287
288     offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
289     offset_start = tag->pos;
290
291     if (flags1 & 8) {           // wide offsets
292         for (t = 0; t < glyphcount; t++)
293             offset[t] = swf_GetU32(tag);        //offset[t]
294
295         if (glyphcount)         /* this _if_ is not in the specs */
296             offset[glyphcount] = swf_GetU32(tag);       // fontcodeoffset
297         else
298             offset[glyphcount] = tag->pos;
299     } else {
300         for (t = 0; t < glyphcount; t++)
301             offset[t] = swf_GetU16(tag);        //offset[t]
302
303         if (glyphcount)         /* this _if_ is not in the specs */
304             offset[glyphcount] = swf_GetU16(tag);       // fontcodeoffset
305         else
306             offset[glyphcount] = tag->pos;
307     }
308     for (t = 0; t < glyphcount; t++) {
309         swf_SetTagPos(tag, offset[t]+offset_start);
310         swf_GetSimpleShape(tag, &(font->glyph[t].shape));
311     }
312
313     if(glyphcount)
314         swf_SetTagPos(tag, offset[glyphcount]+offset_start);
315
316     free(offset);
317
318     maxcode = 0;
319     for (t = 0; t < glyphcount; t++) {
320         int code;
321         if (flags1 & 4)         // wide codes (always on for definefont3)
322             code = swf_GetU16(tag);
323         else
324             code = swf_GetU8(tag);
325         font->glyph2ascii[t] = code;
326         if (code > maxcode)
327             maxcode = code;
328     }
329     maxcode++;
330     if (maxcode < 256)
331         maxcode = 256;
332     font->maxascii = maxcode;
333     font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
334     memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
335     for (t = 0; t < glyphcount; t++) {
336         font->ascii2glyph[font->glyph2ascii[t]] = t;
337     }
338
339     if (flags1 & 128) {         // has layout
340         U16 kerningcount;
341         font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
342         font->layout->ascent = swf_GetU16(tag);
343         font->layout->descent = swf_GetU16(tag);
344         font->layout->leading = swf_GetU16(tag);
345         for (t = 0; t < glyphcount; t++) {
346             S16 advance = swf_GetS16(tag);
347             font->glyph[t].advance = advance;
348         }
349         font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
350         for (t = 0; t < glyphcount; t++) {
351             swf_ResetReadBits(tag);
352             swf_GetRect(tag, &font->layout->bounds[t]);
353         }
354
355         kerningcount = swf_GetU16(tag);
356         font->layout->kerningcount = kerningcount;
357
358         font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
359         if (kerningcount) {
360             font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
361             for (t = 0; t < kerningcount; t++) {
362                 if (flags1 & 4) {       // wide codes
363                     font->layout->kerning[t].char1 = swf_GetU16(tag);
364                     font->layout->kerning[t].char2 = swf_GetU16(tag);
365                 } else {
366                     font->layout->kerning[t].char1 = swf_GetU8(tag);
367                     font->layout->kerning[t].char2 = swf_GetU8(tag);
368                 }
369                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
370             }
371         }
372     }
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 = -1;
391     RGBA color;
392     int x = 0, y = 0;
393     int fontsize = 0;
394
395     memset(&color, 0, sizeof(color));
396
397     swf_SetTagPos(t, 0);
398
399     cid = swf_GetU16(t);
400     swf_GetRect(t, &r);
401     swf_GetMatrix(t, &m);
402     gbits = swf_GetU8(t);
403     abits = swf_GetU8(t);
404
405     while (1) {
406         int flags, num;
407         flags = swf_GetU8(t);
408         if (!flags)
409             break;
410
411         if (flags & TF_TEXTCONTROL) {
412             if (flags & TF_HASFONT)
413                 fid = swf_GetU16(t);
414             if (flags & TF_HASCOLOR) {
415                 color.r = swf_GetU8(t); // rgb
416                 color.g = swf_GetU8(t);
417                 color.b = swf_GetU8(t);
418                 if (swf_GetTagID(t) == ST_DEFINETEXT2)
419                     color.a = swf_GetU8(t);
420                 else
421                     color.a = 255;
422             }
423             if (flags & TF_HASXOFFSET)
424                 x = swf_GetS16(t);
425             if (flags & TF_HASYOFFSET)
426                 y = swf_GetS16(t);
427             if (flags & TF_HASFONT)
428                 fontsize = swf_GetU16(t);
429         }
430
431         num = swf_GetU8(t);
432         if (!num)
433             break;
434
435         {
436             int i;
437             int buf[256];
438             int advance[256];
439             int xpos = 0;
440             for (i = 0; i < num; i++) {
441                 int glyph;
442                 int adv = 0;
443                 advance[i] = xpos;
444                 glyph = swf_GetBits(t, gbits);
445                 adv = swf_GetBits(t, abits);
446                 xpos += adv;
447
448                 if (id == fid) {
449                     if (jobs & FEDTJ_PRINT) {
450                         int code = f->glyph2ascii[glyph];
451                         printf("%lc", code);
452                     }
453                     if (jobs & FEDTJ_MODIFY)
454                         f->glyph[glyph].advance = adv * 20;     //?
455                 }
456
457                 buf[i] = glyph;
458             }
459             if ((id == fid) && (jobs & FEDTJ_PRINT))
460                 printf("\n");
461             if (jobs & FEDTJ_CALLBACK)
462                 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
463             x += xpos;
464         }
465     }
466
467     return id;
468 }
469
470 int swf_ParseDefineText(TAG * tag,
471                     void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
472 {
473     return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
474 }
475
476 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
477 {
478     return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
479 }
480
481 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
482 {
483     TAG *t;
484     SWFFONT *f;
485
486     if ((!swf) || (!font))
487         return -1;
488
489     f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
490
491     t = swf->firstTag;
492
493     while (t) {
494         int nid = 0;
495         switch (swf_GetTagID(t)) {
496         case ST_DEFINEFONT:
497             nid = swf_FontExtract_DefineFont(id, f, t);
498             break;
499
500         case ST_DEFINEFONT2:
501         case ST_DEFINEFONT3:
502             nid = swf_FontExtract_DefineFont2(id, f, t);
503             break;
504
505         case ST_DEFINEFONTINFO:
506         case ST_DEFINEFONTINFO2:
507             nid = swf_FontExtract_DefineFontInfo(id, f, t);
508             break;
509
510         case ST_DEFINETEXT:
511         case ST_DEFINETEXT2:
512             nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
513             break;
514
515         case ST_GLYPHNAMES:
516             nid = swf_FontExtract_GlyphNames(id, f, t);
517             break;
518         }
519         if (nid > 0)
520             id = nid;
521         t = swf_NextTag(t);
522     }
523     if (f->id != id) {
524         rfx_free(f);
525         f = 0;
526     }
527     font[0] = f;
528     return 0;
529 }
530
531 int swf_FontSetID(SWFFONT * f, U16 id)
532 {
533     if (!f)
534         return -1;
535     f->id = id;
536     return 0;
537 }
538
539 void swf_LayoutFree(SWFLAYOUT * l)
540 {
541     if (l) {
542         if (l->kerning)
543             rfx_free(l->kerning);
544         l->kerning = NULL;
545         if (l->bounds)
546             rfx_free(l->bounds);
547         l->bounds = NULL;
548     }
549     rfx_free(l);
550 }
551
552
553 static void font_freeglyphnames(SWFFONT*f)
554 {
555     if (f->glyphnames)
556     {
557         int t;
558         for (t = 0; t < f->numchars; t++)
559         {
560             if (f->glyphnames[t])
561             {
562                 rfx_free(f->glyphnames[t]);
563                 f->glyphnames[t] = 0;
564             }
565         }
566         rfx_free(f->glyphnames);
567         f->glyphnames = 0;
568         }
569 }
570 static void font_freeusage(SWFFONT*f)
571 {
572     if (f->use) {
573         if(f->use->chars) {
574             rfx_free(f->use->chars);f->use->chars = 0;
575         }
576         rfx_free(f->use); f->use = 0;
577     }
578 }
579 static void font_freelayout(SWFFONT*f)
580 {
581     if (f->layout) {
582         swf_LayoutFree(f->layout);
583         f->layout = 0;
584     }
585 }
586 static void font_freename(SWFFONT*f)
587 {
588     if (f->name) {
589         rfx_free(f->name);
590         f->name = 0;
591     }
592 }
593
594 int swf_FontReduce_old(SWFFONT * f)
595 {
596     int i, j;
597     int max_unicode = 0;
598     if ((!f) || (!f->use) || f->use->is_reduced)
599         return -1;
600
601     j = 0;
602
603     for (i = 0; i < f->numchars; i++) {
604         if (f->glyph[i].shape && f->use->chars[i]) {
605             f->glyph2ascii[j] = f->glyph2ascii[i];
606             f->glyph[j] = f->glyph[i];
607             f->use->chars[i] = j;
608             j++;
609         } else {
610             f->glyph2ascii[i] = 0;
611             if(f->glyph[i].shape) {
612                 swf_ShapeFree(f->glyph[i].shape);
613                 f->glyph[i].shape = 0;
614                 f->glyph[i].advance = 0;
615             }
616             f->use->chars[i] = -1;
617             j++; //TODO: remove
618         }
619     }
620     for (i = 0; i < f->maxascii; i++) {
621         if(f->use->chars[f->ascii2glyph[i]]<0) {
622             f->ascii2glyph[i] = -1;
623         } else {
624             f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
625             max_unicode = i;
626         }
627     }
628     f->maxascii = max_unicode;
629     f->use->is_reduced = 1;
630     f->numchars = j;
631     font_freelayout(f);
632     font_freeglyphnames(f);
633     font_freename(f);
634     return j;
635 }
636
637 int swf_FontReduce_swfc(SWFFONT * f)
638 {
639     int i, j;
640     int max_unicode = 0;
641     if ((!f) || (!f->use) || f->use->is_reduced)
642         return -1;
643
644     font_freeglyphnames(f);
645
646     j = 0;
647     for (i = 0; i < f->numchars; i++) {
648         if (f->glyph[i].shape && f->use->chars[i]) {
649             f->glyph2ascii[j] = f->glyph2ascii[i];
650             if (f->layout)
651                 f->layout->bounds[j] = f->layout->bounds[i];
652             f->glyph[j] = f->glyph[i];
653             f->use->chars[i] = j;
654             j++;
655         } else {
656             f->glyph2ascii[i] = 0;
657             if(f->glyph[i].shape) {
658                 swf_ShapeFree(f->glyph[i].shape);
659                 f->glyph[i].shape = 0;
660                 f->glyph[i].advance = 0;
661             }
662             f->use->chars[i] = -1;
663         }
664     }
665     f->use->used_glyphs = j;
666     for (i = 0; i < f->maxascii; i++) {
667         if(f->ascii2glyph[i] > -1) {
668             if (f->use->chars[f->ascii2glyph[i]]<0) {
669                 f->use->chars[f->ascii2glyph[i]] = 0;
670                 f->ascii2glyph[i] = -1;
671             } else {
672                 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
673                 f->use->chars[f->ascii2glyph[i]] = 1;
674                 max_unicode = i + 1;
675             }
676         }
677     }
678     f->maxascii = max_unicode;
679     f->use->is_reduced = 1;
680     f->numchars = j;
681     font_freename(f);
682     return j;
683 }
684
685 int swf_FontReduce(SWFFONT * f)
686 {
687     int i;
688     int max_unicode = 0;
689     int max_glyph = 0;
690     if ((!f) || (!f->use) || f->use->is_reduced)
691         return -1;
692
693     font_freelayout(f);
694     font_freeglyphnames(f);
695
696     f->use->used_glyphs= 0;
697     for (i = 0; i < f->numchars; i++) {
698         if(!f->use->chars[i]) {
699             if(f->glyph2ascii) {
700                 f->glyph2ascii[i] = 0;
701             }
702             if(f->glyph[i].shape) {
703                 swf_ShapeFree(f->glyph[i].shape);
704                 f->glyph[i].shape = 0;
705                 f->glyph[i].advance = 0;
706             }
707 //          f->use->used_glyphs++;
708         } else {
709             f->use->used_glyphs++;
710             max_glyph = i+1;
711         }
712     }
713     for (i = 0; i < f->maxascii; i++) {
714         if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
715             if(f->ascii2glyph) {
716                 f->ascii2glyph[i] = -1;
717             }
718         } else {
719             max_unicode = i+1;
720         }
721     }
722     f->maxascii = max_unicode;
723     f->numchars = max_glyph;
724     font_freename(f);
725     return 0;
726 }
727
728 void swf_FontSort(SWFFONT * font)
729 {
730     int i, j;
731     int *newplace;
732     int *newpos;
733     if (!font)
734         return;
735
736     newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
737
738     for (i = 0; i < font->numchars; i++) {
739         newplace[i] = i;
740     }
741     for (i = 0; i < font->numchars; i++)
742         for (j = 0; j < i; j++) {
743             if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
744                 int n1, n2;
745                 char *c1, *c2;
746                 SWFGLYPH g1, g2;
747                 SRECT r1, r2;
748                 n1 = newplace[i];
749                 n2 = newplace[j];
750                 newplace[j] = n1;
751                 newplace[i] = n2;
752                 n1 = font->glyph2ascii[i];
753                 n2 = font->glyph2ascii[j];
754                 font->glyph2ascii[j] = n1;
755                 font->glyph2ascii[i] = n2;
756                 g1 = font->glyph[i];
757                 g2 = font->glyph[j];
758                 font->glyph[j] = g1;
759                 font->glyph[i] = g2;
760                 if (font->glyphnames) {
761                     c1 = font->glyphnames[i];
762                     c2 = font->glyphnames[j];
763                     font->glyphnames[j] = c1;
764                     font->glyphnames[i] = c2;
765                 }
766                 if (font->layout) {
767                     r1 = font->layout->bounds[i];
768                     r2 = font->layout->bounds[j];
769                     font->layout->bounds[j] = r1;
770                     font->layout->bounds[i] = r2;
771                 }
772             }
773         }
774     newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
775     for (i = 0; i < font->numchars; i++) {
776         newpos[newplace[i]] = i;
777     }
778     for (i = 0; i < font->maxascii; i++) {
779         if (font->ascii2glyph[i] >= 0)
780             font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
781     }
782
783     rfx_free(newpos);
784     rfx_free(newplace);
785 }
786
787 void swf_FontPrepareForEditText(SWFFONT * font)
788 {
789     if (!font->layout)
790         swf_FontCreateLayout(font);
791     swf_FontSort(font);
792 }
793
794 int swf_FontInitUsage(SWFFONT * f)
795 {
796     if (!f)
797         return -1;
798     if(f->use) {
799         fprintf(stderr, "Usage initialized twice");
800         return -1;
801     }
802     f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
803     f->use->is_reduced = 0;
804     f->use->used_glyphs = 0;
805     f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
806     f->use->glyphs_specified = 0;
807     return 0;
808 }
809
810 void swf_FontClearUsage(SWFFONT * f)
811 {
812     if (!f || !f->use)
813         return;
814     rfx_free(f->use->chars); f->use->chars = 0;
815     rfx_free(f->use); f->use = 0;
816 }
817
818 int swf_FontUse(SWFFONT * f, U8 * s)
819 {
820     if( (!s))
821         return -1;
822     while (*s) {
823         if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
824             swf_FontUseGlyph(f, f->ascii2glyph[*s]);
825         s++;
826     }
827     return 0;
828 }
829
830 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
831 {
832     if( (!s))
833         return -1;
834     int ascii;
835     while (*s)
836     {
837         ascii = readUTF8char(&s);
838         if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
839             swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
840     }
841     return 0;
842 }
843
844 int swf_FontUseAll(SWFFONT* f)
845 {
846     int i;
847
848     if (!f->use)
849         swf_FontInitUsage(f);
850     for (i = 0; i < f->numchars; i++)
851         f->use->chars[i] = 1;
852     f->use->used_glyphs = f->numchars;
853     return 0;
854 }
855
856 int swf_FontUseGlyph(SWFFONT * f, int glyph)
857 {
858     if (!f->use)
859         swf_FontInitUsage(f);
860     if(glyph < 0 || glyph >= f->numchars)
861         return -1;
862     if(!f->use->chars[glyph])
863         f->use->used_glyphs++;
864     f->use->chars[glyph] = 1;
865     return 0;
866 }
867
868 int swf_FontSetDefine(TAG * t, SWFFONT * f)
869 {
870     U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
871     int p, i, j;
872
873     if ((!t) || (!f))
874         return -1;
875     swf_ResetWriteBits(t);
876     swf_SetU16(t, f->id);
877
878     p = 0;
879     j = 0;
880     for (i = 0; i < f->numchars; i++)
881         if (f->glyph[i].shape) {
882             ofs[j++] = p;
883             p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
884         }
885
886     for (i = 0; i < j; i++)
887         swf_SetU16(t, ofs[i] + j * 2);
888     if (!j) {
889         fprintf(stderr, "rfxswf: warning: Font is empty\n");
890         swf_SetU16(t, 0);
891     }
892
893     for (i = 0; i < f->numchars; i++)
894         if (f->glyph[i].shape)
895             swf_SetSimpleShape(t, f->glyph[i].shape);
896
897     swf_ResetWriteBits(t);
898     rfx_free(ofs);
899     return 0;
900 }
901
902 static inline int fontSize(SWFFONT * font)
903 {
904     int t;
905     int size = 0;
906     for (t = 0; t < font->numchars; t++) {
907         int l = 0;
908         if(font->glyph[t].shape)
909             l = (font->glyph[t].shape->bitlen + 7) / 8;
910         else
911             l = 8;
912         size += l + 1;
913     }
914     return size + (font->numchars + 1) * 2;
915 }
916
917 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
918 {
919     U8 flags = 0;
920     int t;
921     int pos;
922     swf_SetU16(tag, f->id);
923
924     if (f->layout) flags |= 128;                // haslayout
925     if (f->numchars > 256)
926         flags |= 4;             // widecodes
927     if (f->style & FONT_STYLE_BOLD)
928         flags |= 1;             // bold
929     if (f->style & FONT_STYLE_ITALIC)
930         flags |= 2;             // italic
931     if (f->maxascii >= 256)
932         flags |= 4;             //wide codecs
933     if (fontSize(f) > 65535)
934         flags |= 8;             //wide offsets
935     flags |= 8 | 4;             //FIXME: the above check doesn't work
936
937     if (f->encoding & FONT_ENCODING_ANSI)
938         flags |= 16;            // ansi
939     if (f->encoding & FONT_ENCODING_UNICODE)
940         flags |= 32;            // unicode
941     if (f->encoding & FONT_ENCODING_SHIFTJIS)
942         flags |= 64;            // shiftjis
943
944     swf_SetU8(tag, flags);
945     swf_SetU8(tag, 0);          //reserved flags
946     if (f->name) {
947         /* font name */
948         swf_SetU8(tag, strlen((const char*)f->name)+1);
949         swf_SetBlock(tag, f->name, strlen((const char*)f->name)+1);
950     } else {
951         /* font name (="") */
952         swf_SetU8(tag, 1);
953         swf_SetU8(tag, 0);
954     }
955     /* number of glyphs */
956     swf_SetU16(tag, f->numchars);
957     /* font offset table */
958     pos = tag->len;
959     for (t = 0; t <= f->numchars; t++) {
960         if (flags & 8)
961             swf_SetU32(tag, /* fontoffset */ 0);        /*placeholder */
962         else
963             swf_SetU16(tag, /* fontoffset */ 0);        /*placeholder */
964     }
965
966     for (t = 0; t <= f->numchars; t++) {
967         if (flags & 8) {
968             tag->data[pos + t * 4] = (tag->len - pos);
969             tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
970             tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
971             tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
972         } else {
973             if (tag->len - pos > 65535) {
974                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
975                 exit(1);
976             }
977             tag->data[pos + t * 2] = (tag->len - pos);
978             tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
979         }
980         if (t < f->numchars) {
981             if(f->glyph[t].shape) {
982                 swf_SetSimpleShape(tag, f->glyph[t].shape);
983             } else {
984                 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
985             }
986         }
987     }
988
989
990     /* font code table */
991     for (t = 0; t < f->numchars; t++) {
992         if (flags & 4) {                /* wide codes */
993             if(f->glyph2ascii[t]) {
994                 swf_SetU16(tag, f->glyph2ascii[t]);
995             } else {
996                 swf_SetU16(tag, 0);
997             }
998         } else {
999             if(f->glyph2ascii[t]) {
1000                 swf_SetU8(tag, f->glyph2ascii[t]);
1001             } else {
1002                 swf_SetU8(tag, 0);
1003             }
1004         }
1005     }
1006
1007     if (f->layout) {
1008         swf_SetU16(tag, f->layout->ascent);
1009         swf_SetU16(tag, f->layout->descent);
1010         swf_SetU16(tag, f->layout->leading);
1011         for (t = 0; t < f->numchars; t++)
1012             swf_SetU16(tag, f->glyph[t].advance);
1013         for (t = 0; t < f->numchars; t++) {
1014             swf_ResetWriteBits(tag);
1015             swf_SetRect(tag, &f->layout->bounds[t]);
1016         }
1017         swf_SetU16(tag, f->layout->kerningcount);
1018         for (t = 0; t < f->layout->kerningcount; t++) {
1019             if (flags & 4) {    /* wide codes */
1020                 swf_SetU16(tag, f->layout->kerning[t].char1);
1021                 swf_SetU16(tag, f->layout->kerning[t].char2);
1022             } else {
1023                 swf_SetU8(tag, f->layout->kerning[t].char1);
1024                 swf_SetU8(tag, f->layout->kerning[t].char2);
1025             }
1026             swf_SetU16(tag, f->layout->kerning[t].adjustment);
1027         }
1028     }
1029     return 0;
1030 }
1031
1032 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1033 {
1034     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1035     f->layout->ascent = ascent;
1036     f->layout->descent = descent;
1037     f->layout->leading = leading;
1038     f->layout->kerningcount = 0;
1039     f->layout->kerning = 0;
1040     f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1041 }
1042
1043 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1044 {
1045     int l, i;
1046     U8 wide = 0;
1047     U8 flags = 0;
1048     if ((!t) || (!f))
1049         return -1;
1050     swf_ResetWriteBits(t);
1051     swf_SetU16(t, f->id);
1052     l = f->name ? strlen((const char *)f->name) : 0;
1053     if (l > 255)
1054         l = 255;
1055     swf_SetU8(t, l);
1056     if (l)
1057         swf_SetBlock(t, f->name, l);
1058     if (f->numchars >= 256)
1059         wide = 1;
1060
1061     if (f->style & FONT_STYLE_BOLD)
1062         flags |= 2;
1063     if (f->style & FONT_STYLE_ITALIC)
1064         flags |= 4;
1065     if (f->style & FONT_ENCODING_ANSI)
1066         flags |= 8;
1067     if (f->style & FONT_ENCODING_SHIFTJIS)
1068         flags |= 16;
1069     if (f->style & FONT_ENCODING_UNICODE)
1070         flags |= 32;
1071
1072     swf_SetU8(t, (flags & 0xfe) | wide);
1073
1074     for (i = 0; i < f->numchars; i++) {
1075         if (f->glyph[i].shape) {
1076             int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1077             wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1078         }
1079     }
1080
1081     return 0;
1082 }
1083
1084 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1085 {
1086     int id = swf_GetTagID(t);
1087     if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1088         swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1089     else
1090         return -1;
1091     return 0;
1092 }
1093
1094 void swf_FontFree(SWFFONT * f)
1095 {
1096     int i;
1097     if (!f)
1098         return;
1099
1100     if (f->glyph)
1101     {
1102         for (i = 0; i < f->numchars; i++)
1103             if (f->glyph[i].shape)
1104             {
1105                 swf_ShapeFree(f->glyph[i].shape);
1106                 f->glyph[i].shape = NULL;
1107             }
1108             rfx_free(f->glyph);
1109             f->glyph = NULL;
1110     }
1111     if (f->ascii2glyph)
1112     {
1113         rfx_free(f->ascii2glyph);
1114         f->ascii2glyph = NULL;
1115     }
1116     if (f->glyph2ascii)
1117     {
1118         rfx_free(f->glyph2ascii);
1119         f->glyph2ascii = NULL;
1120     }
1121     font_freename(f);
1122     font_freelayout(f);
1123     font_freeglyphnames(f);
1124     font_freeusage(f);
1125
1126     rfx_free(f);
1127 }
1128
1129 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int x, int y)
1130 {
1131     U8 flags;
1132     if (!t)
1133         return -1;
1134
1135     flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (x ? TF_HASXOFFSET : 0)
1136         | (y ? TF_HASYOFFSET : 0);
1137
1138     swf_SetU8(t, flags);
1139     if (font)
1140         swf_SetU16(t, font->id);
1141     if (color) {
1142         if (swf_GetTagID(t) == ST_DEFINETEXT2)
1143             swf_SetRGBA(t, color);
1144         else
1145             swf_SetRGB(t, color);
1146     }
1147     if (x) {
1148         if(x != SET_TO_ZERO) {
1149             if(x>32767 || x<-32768)
1150                 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", x);
1151             swf_SetS16(t, x);
1152         } else {
1153             swf_SetS16(t, 0);
1154         }
1155     }
1156     if (y) {
1157         if(y != SET_TO_ZERO) {
1158             if(y>32767 || y<-32768)
1159                 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", y);
1160             swf_SetS16(t, y);
1161         } else {
1162             swf_SetS16(t, 0);
1163         }
1164     }
1165     if (font)
1166         swf_SetU16(t, size);
1167
1168     return 0;
1169 }
1170
1171 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1172 {
1173     U16 g, a;
1174     char utf8 = 0;
1175     if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1176         return -1;
1177     g = a = 0;
1178
1179     if (!strcmp(encoding, "UTF8"))
1180         utf8 = 1;
1181     else if (!strcmp(encoding, "iso-8859-1"))
1182         utf8 = 0;
1183     else
1184         fprintf(stderr, "Unknown encoding: %s", encoding);
1185
1186     while (*s) {
1187         int glyph = -1, c;
1188
1189         if (!utf8)
1190             c = *s++;
1191         else
1192             c = readUTF8char(&s);
1193
1194         if (c < font->maxascii)
1195             glyph = font->ascii2glyph[c];
1196         if (glyph >= 0) {
1197             g = swf_CountUBits(glyph, g);
1198             a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1199         }
1200     }
1201
1202     if (gbits)
1203         gbits[0] = (U8) g;
1204     if (abits)
1205         abits[0] = (U8) a;
1206     return 0;
1207 }
1208
1209 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1210 {
1211     int l = 0, pos;
1212     char utf8 = 0;
1213
1214     if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1215         return -1;
1216
1217     if (!strcmp(encoding, "UTF8"))
1218         utf8 = 1;
1219     else if (!strcmp(encoding, "iso-8859-1"))
1220         utf8 = 0;
1221     else
1222         fprintf(stderr, "Unknown encoding: %s", encoding);
1223
1224     pos = t->len;
1225     swf_SetU8(t, l);            //placeholder
1226
1227     while (*s) {
1228         int g = -1, c;
1229
1230         if (!utf8)
1231             c = *s++;
1232         else
1233             c = readUTF8char(&s);
1234
1235         if (c < font->maxascii)
1236             g = font->ascii2glyph[c];
1237         if (g >= 0) {
1238             swf_SetBits(t, g, gbits);
1239             swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1240             l++;
1241             /* We split into 127 characters per text field.
1242                We could do 255, by the (formerly wrong) flash specification,
1243                but some SWF parsing code out there still assumes that char blocks
1244                are at max 127 characters, and it would save only a few bits.
1245             */
1246             if (l == 0x7f)
1247                 break;
1248         }
1249     }
1250
1251     PUT8(&t->data[pos], l);
1252
1253     swf_ResetWriteBits(t);
1254     return 0;
1255 }
1256
1257 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1258 {
1259     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1260 }
1261
1262 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1263 {
1264     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1265 }
1266
1267 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1268 {
1269     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1270 }
1271
1272 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1273 {
1274     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1275 }
1276
1277 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1278 {
1279     U32 res = 0;
1280
1281     if (font && s) {
1282         while (s[0]) {
1283             int g = -1;
1284             if (*s < font->maxascii)
1285                 g = font->ascii2glyph[*s];
1286             if (g >= 0)
1287                 res += font->glyph[g].advance / 20;
1288             s++;
1289         }
1290         if (scale)
1291             res = (res * scale) / 100;
1292     }
1293     return res;
1294 }
1295
1296 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1297 {
1298     int xpos = 0;
1299     int ypos = 0;
1300     SRECT r;
1301     swf_GetRect(0, &r);
1302     while (*s) {
1303         int c = readUTF8char(&s);
1304         if(c==13 || c==10) {
1305             if(s[0] == 10) {
1306                 s++;
1307             }
1308             xpos=0;
1309             ypos+=font->layout->leading;
1310             continue;
1311         }
1312         if (c < font->maxascii) {
1313             int g = font->ascii2glyph[c];
1314             if (g >= 0) {
1315                 SRECT rn = font->layout->bounds[g];
1316                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1317                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1318                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1319                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1320                 swf_ExpandRect2(&r, &rn);
1321                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1322             }
1323         }
1324     }
1325     return r;
1326 }
1327
1328
1329 SWFFONT *swf_ReadFont(const char *filename)
1330 {
1331     int f;
1332     SWF swf;
1333     if (!filename)
1334         return 0;
1335     f = open(filename, O_RDONLY|O_BINARY);
1336
1337     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1338         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1339         close(f);
1340         return 0;
1341     } else {
1342         SWFFONT *font;
1343         close(f);
1344         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1345             return 0;
1346         swf_FreeTags(&swf);
1347         return font;
1348     }
1349 }
1350
1351 void swf_WriteFont(SWFFONT * font, char *filename)
1352 {
1353     SWF swf;
1354     TAG *t;
1355     SRECT r;
1356     RGBA rgb;
1357     int f;
1358     int useDefineFont2 = 0;
1359     int storeGlyphNames = 1;
1360
1361     if (font->layout)
1362         useDefineFont2 = 1;     /* the only thing new in definefont2
1363                                    is layout information. */
1364
1365     font->id = WRITEFONTID;     //"FN"
1366
1367     memset(&swf, 0x00, sizeof(SWF));
1368
1369     swf.fileVersion = 9;
1370     swf.frameRate = 0x4000;
1371
1372     /* if we use DefineFont1 to store the characters,
1373        we have to build a textfield to store the
1374        advance values. While at it, we can also
1375        make the whole .swf viewable */
1376
1377     /* we now always create viewable swfs, even if we
1378        did use definefont2 -mk */
1379     t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1380     swf.firstTag = t;
1381     rgb.r = 0xef;
1382     rgb.g = 0xef;
1383     rgb.b = 0xff;
1384     swf_SetRGB(t, &rgb);
1385     if (!useDefineFont2) {
1386         t = swf_InsertTag(t, ST_DEFINEFONT);
1387         swf_FontSetDefine(t, font);
1388         t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1389         swf_FontSetInfo(t, font);
1390     } else {
1391         t = swf_InsertTag(t, ST_DEFINEFONT2);
1392         swf_FontSetDefine2(t, font);
1393     }
1394     if(font->name) {
1395         t = swf_InsertTag(t, ST_NAMECHARACTER);
1396         swf_SetU16(t, WRITEFONTID);
1397         swf_SetString(t, (char*)font->name);
1398         t = swf_InsertTag(t, ST_EXPORTASSETS);
1399         swf_SetU16(t, 1);
1400         swf_SetU16(t, WRITEFONTID);
1401         swf_SetString(t, (char*)font->name);
1402
1403         t = swf_AddAS3FontDefine(t, WRITEFONTID, (char*)font->name);
1404     }
1405
1406     if (storeGlyphNames && font->glyphnames) {
1407         int c;
1408         t = swf_InsertTag(t, ST_GLYPHNAMES);
1409         swf_SetU16(t, WRITEFONTID);
1410         swf_SetU16(t, font->numchars);
1411         for (c = 0; c < font->numchars; c++) {
1412             if (font->glyphnames[c])
1413                 swf_SetString(t, font->glyphnames[c]);
1414             else
1415                 swf_SetString(t, "");
1416         }
1417     }
1418
1419     if (1)                      //neccessary only for df1, but pretty to look at anyhow, so do it always
1420     {
1421         int textscale = 400;
1422         int s;
1423         int xmax = 0;
1424         int ymax = 0;
1425         int ypos = 1;
1426         U8 gbits, abits;
1427         int x, y, c;
1428         int range = font->maxascii;
1429
1430         c = 0;
1431         if (useDefineFont2 && range > 256) {
1432             range = 256;
1433         }
1434
1435         for (s = 0; s < range; s++) {
1436             int g = font->ascii2glyph[s];
1437             if (g >= 0) {
1438                 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1439                     xmax = (font->glyph[g].advance * textscale / 20) / 64;
1440                 }
1441                 c++;
1442             }
1443             if ((s & 15) == 0) {
1444                 if (c) {
1445                     ypos++;
1446                 }
1447                 c = 0;
1448             }
1449         }
1450         ymax = ypos * textscale * 2;
1451
1452         swf.movieSize.xmax = xmax * 20;
1453         swf.movieSize.ymax = ymax;
1454
1455         t = swf_InsertTag(t, ST_DEFINETEXT);
1456
1457         swf_SetU16(t, font->id + 1);    // ID
1458
1459         r.xmin = 0;
1460         r.ymin = 0;
1461         r.xmax = swf.movieSize.xmax;
1462         r.ymax = swf.movieSize.ymax;
1463
1464         swf_SetRect(t, &r);
1465
1466         swf_SetMatrix(t, NULL);
1467
1468         abits = swf_CountBits(xmax * 16, 0);
1469         gbits = 8;
1470
1471         swf_SetU8(t, gbits);
1472         swf_SetU8(t, abits);
1473
1474         rgb.r = 0x00;
1475         rgb.g = 0x00;
1476         rgb.b = 0x00;
1477         ypos = 1;
1478         for (y = 0; y < ((range + 15) / 16); y++) {
1479             int c = 0, lastx = -1;
1480             for (x = 0; x < 16; x++) {
1481                 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1482                 if (g >= 0 && font->glyph[g].shape) {
1483                     c++;
1484                     if (lastx < 0)
1485                         lastx = x * xmax;
1486                 }
1487             }
1488             if (c) {
1489                 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1490                 for (x = 0; x < 16; x++) {
1491                     int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1492                     if (g >= 0 && font->glyph[g].shape) {
1493                         if (lastx != x * xmax) {
1494                             swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1495                         }
1496                         swf_SetU8(t, 1);
1497                         swf_SetBits(t, g, gbits);
1498                         swf_SetBits(t, font->glyph[g].advance / 20, abits);
1499                         lastx = x * xmax + (font->glyph[g].advance / 20);
1500                         swf_ResetWriteBits(t);
1501                     }
1502                 }
1503                 ypos++;
1504             }
1505         }
1506         swf_SetU8(t, 0);
1507
1508
1509         t = swf_InsertTag(t, ST_PLACEOBJECT2);
1510
1511         swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1512
1513         t = swf_InsertTag(t, ST_SHOWFRAME);
1514
1515     }
1516
1517     t = swf_InsertTag(t, ST_END);
1518
1519     f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1520     if FAILED
1521         (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1522     close(f);
1523
1524     swf_FreeTags(&swf);
1525 }
1526
1527
1528 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)
1529 {
1530     swf_SetRect(tag, &r);
1531     swf_ResetWriteBits(tag);
1532
1533     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1534     if (text)
1535         flags |= ET_HASTEXT;
1536     if (color)
1537         flags |= ET_HASTEXTCOLOR;
1538     if (maxlength)
1539         flags |= ET_HASMAXLENGTH;
1540     if (font)
1541         flags |= ET_HASFONT;
1542     if (layout)
1543         flags |= ET_HASLAYOUT;
1544
1545     swf_SetBits(tag, flags, 16);
1546
1547     if (flags & ET_HASFONT) {
1548         swf_SetU16(tag, font);  //font
1549         swf_SetU16(tag, height);        //fontheight
1550     }
1551     if (flags & ET_HASTEXTCOLOR) {
1552         swf_SetRGBA(tag, color);
1553     }
1554     if (flags & ET_HASMAXLENGTH) {
1555         swf_SetU16(tag, maxlength);     //maxlength
1556     }
1557     if (flags & ET_HASLAYOUT) {
1558         swf_SetU8(tag, layout->align);  //align
1559         swf_SetU16(tag, layout->leftmargin);    //left margin
1560         swf_SetU16(tag, layout->rightmargin);   //right margin
1561         swf_SetU16(tag, layout->indent);        //indent
1562         swf_SetU16(tag, layout->leading);       //leading
1563     }
1564     swf_SetString(tag, variable);
1565     if (flags & ET_HASTEXT)
1566         swf_SetString(tag, text);
1567 }
1568
1569 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, const char *text, int scale)
1570 {
1571     SRECT r;
1572     U8 gbits, abits;
1573     U8 *utext = (U8 *) strdup(text);
1574     U8 *upos = utext;
1575     int x = 0, y = 0;
1576     int pos = 0;
1577     int ystep = 0;
1578     if (font->layout) {
1579         r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1580         ystep = font->layout->leading;
1581     } else {
1582         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1583         /* Hm, without layout information, we can't compute a bounding
1584            box. We could call swf_FontCreateLayout to create a layout,
1585            but the caller probably doesn't want us to mess up his font
1586            structure.
1587          */
1588         r.xmin = r.ymin = 0;
1589         r.xmax = r.ymax = 1024 * 20;
1590         ystep = 100;
1591     }
1592
1593     swf_SetRect(tag, &r);
1594
1595     /* The text matrix is pretty boring, as it doesn't apply to
1596        individual characters, but rather whole text objects (or
1597        at least whole char records- haven't tested).
1598        So it can't do anything which we can't already do with
1599        the placeobject tag we use for placing the text on the scene.
1600      */
1601     swf_SetMatrix(tag, 0);
1602
1603     swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1604     swf_SetU8(tag, gbits);
1605     swf_SetU8(tag, abits);
1606
1607     while(*upos) {
1608         U8*next = upos;
1609         int count = 0;
1610
1611         swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y);      //scale
1612         x = 0;
1613
1614         while(*next && *next!=13 && *next!=10 && count<127) {
1615             readUTF8char(&next);
1616             count++;
1617         }
1618         if(next[0] == 13 || next[0] == 10) {
1619             x = SET_TO_ZERO;
1620             y += ystep;
1621         }
1622
1623         if(next[0] == 13 && next[1] == 10)
1624             next++;
1625
1626         if(next[0] == 13 || next[0] == 10) {
1627             *next = 0;
1628             next++;
1629         }
1630
1631         /* now set the text params- notice that a font size of
1632            1024 means that the glyphs will be displayed exactly
1633            as they would be in/with a defineshape. (Try to find
1634            *that* in the flash specs)
1635          */
1636         /* set the actual text- notice that we just pass our scale
1637            parameter over, as TextSetCharRecord calculates with
1638            percent, too */
1639         swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1640
1641         upos= next;
1642     }
1643     free(utext);
1644
1645     swf_SetU8(tag, 0);
1646     return r;
1647 }
1648
1649 void swf_FontCreateLayout(SWFFONT * f)
1650 {
1651     S16 leading = 0;
1652     int t;
1653     if (f->layout)
1654         return;
1655     if (!f->numchars)
1656         return;
1657
1658     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1659     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1660     f->layout->ascent = -32767;
1661     f->layout->descent = -32767;
1662
1663     for (t = 0; t < f->numchars; t++) {
1664         SHAPE2 *shape2;
1665         SRECT bbox;
1666         int width;
1667         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1668         if (!shape2) {
1669             fprintf(stderr, "Shape parse error\n");
1670             exit(1);
1671         }
1672         bbox = swf_GetShapeBoundingBox(shape2);
1673         swf_Shape2Free(shape2);
1674         f->layout->bounds[t] = bbox;
1675
1676         width = (bbox.xmax);
1677
1678         /* The following is a heuristic- it may be that extractfont_DefineText
1679            has already found out some widths for individual characters (from the way
1680            they are used)- we now have to guess whether that width might be possible,
1681            which is the case if it isn't either much too big or much too small */
1682         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1683             f->glyph[t].advance = width;
1684
1685         if (-bbox.ymin > f->layout->ascent)
1686             f->layout->ascent = bbox.ymin;
1687         if (bbox.ymax > f->layout->descent)
1688             f->layout->descent = bbox.ymax;
1689     }
1690 }
1691
1692 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
1693 {
1694     U8 *s = (U8 *) text;
1695     int advance = 0;
1696     while (*s) {
1697         SHAPE *shape;
1698         SHAPE2 *shape2;
1699         SHAPELINE *l;
1700         U32 c = readUTF8char(&s);
1701         int g = font->ascii2glyph[c];
1702         shape = font->glyph[g].shape;
1703         if (((int) g) < 0) {
1704             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1705             continue;
1706         }
1707         shape2 = swf_ShapeToShape2(shape);
1708         l = shape2->lines;
1709         while (l) {
1710             if (l->type == moveTo) {
1711                 FPOINT to;
1712                 to.x = l->x * size / 100.0 / 20.0 + advance;
1713                 to.y = l->y * size / 100.0 / 20.0;
1714                 draw->moveTo(draw, &to);
1715             } else if (l->type == lineTo) {
1716                 FPOINT to;
1717                 to.x = l->x * size / 100.0 / 20.0 + advance;
1718                 to.y = l->y * size / 100.0 / 20.0;
1719                 draw->lineTo(draw, &to);
1720             } else if (l->type == splineTo) {
1721                 FPOINT mid, to;
1722                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1723                 mid.y = l->sy * size / 100.0 / 20.0;
1724                 to.x = l->x * size / 100.0 / 20.0 + advance;
1725                 to.y = l->y * size / 100.0 / 20.0;
1726                 draw->splineTo(draw, &mid, &to);
1727             }
1728             l = l->next;
1729         }
1730         swf_Shape2Free(shape2);
1731         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1732     }
1733 }