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