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