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