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