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