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