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