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