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