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