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