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