added newline capability to swf_SetDefineText().
[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             /* We split into 127 characters per text field.
1165                We could do 255, by the (formerly wrong) flash specification,
1166                but some SWF parsing code out there still assumes that char blocks
1167                are at max 127 characters, and it would save only a few bits.
1168             */
1169             if (l == 0x7f)
1170                 break;
1171         }
1172     }
1173
1174     PUT8(&t->data[pos], l);
1175
1176     swf_ResetWriteBits(t);
1177     return 0;
1178 }
1179
1180 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1181 {
1182     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1183 }
1184
1185 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1186 {
1187     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1188 }
1189
1190 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1191 {
1192     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1193 }
1194
1195 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1196 {
1197     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1198 }
1199
1200 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1201 {
1202     U32 res = 0;
1203
1204     if (font && s) {
1205         while (s[0]) {
1206             int g = -1;
1207             if (*s < font->maxascii)
1208                 g = font->ascii2glyph[*s];
1209             if (g >= 0)
1210                 res += font->glyph[g].advance / 20;
1211             s++;
1212         }
1213         if (scale)
1214             res = (res * scale) / 100;
1215     }
1216     return res;
1217 }
1218
1219 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1220 {
1221     int xpos = 0;
1222     int ypos = 0;
1223     SRECT r;
1224     swf_GetRect(0, &r);
1225     while (*s) {
1226         int c = readUTF8char(&s);
1227         if(c==13 || c==10) {
1228             if(s[0] == 10) {
1229                 s++;
1230             }
1231             xpos=0;
1232             ypos+=font->layout->leading;
1233             continue;
1234         }
1235         if (c < font->maxascii) {
1236             int g = font->ascii2glyph[c];
1237             if (g >= 0) {
1238                 SRECT rn = font->layout->bounds[g];
1239                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1240                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1241                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1242                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1243                 swf_ExpandRect2(&r, &rn);
1244                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1245             }
1246         }
1247     }
1248     return r;
1249 }
1250
1251
1252 SWFFONT *swf_ReadFont(char *filename)
1253 {
1254     int f;
1255     SWF swf;
1256     if (!filename)
1257         return 0;
1258     f = open(filename, O_RDONLY|O_BINARY);
1259
1260     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1261         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1262         close(f);
1263         return 0;
1264     } else {
1265         SWFFONT *font;
1266         close(f);
1267         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1268             return 0;
1269         swf_FreeTags(&swf);
1270         return font;
1271     }
1272 }
1273
1274 void swf_WriteFont(SWFFONT * font, char *filename)
1275 {
1276     SWF swf;
1277     TAG *t;
1278     SRECT r;
1279     RGBA rgb;
1280     int f;
1281     int useDefineFont2 = 0;
1282     int storeGlyphNames = 1;
1283
1284     if (font->layout)
1285         useDefineFont2 = 1;     /* the only thing new in definefont2 
1286                                    is layout information. */
1287
1288     font->id = WRITEFONTID;     //"FN"
1289
1290     memset(&swf, 0x00, sizeof(SWF));
1291
1292     swf.fileVersion = 4;
1293     swf.frameRate = 0x4000;
1294
1295     /* if we use DefineFont1 to store the characters,
1296        we have to build a textfield to store the
1297        advance values. While at it, we can also
1298        make the whole .swf viewable */
1299
1300     /* we now always create viewable swfs, even if we
1301        did use definefont2 -mk */
1302     t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1303     swf.firstTag = t;
1304     rgb.r = 0xef;
1305     rgb.g = 0xef;
1306     rgb.b = 0xff;
1307     swf_SetRGB(t, &rgb);
1308     if (!useDefineFont2) {
1309         t = swf_InsertTag(t, ST_DEFINEFONT);
1310         swf_FontSetDefine(t, font);
1311         t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1312         swf_FontSetInfo(t, font);
1313     } else {
1314         t = swf_InsertTag(t, ST_DEFINEFONT2);
1315         swf_FontSetDefine2(t, font);
1316     }
1317
1318     if (storeGlyphNames && font->glyphnames) {
1319         int c;
1320         t = swf_InsertTag(t, ST_GLYPHNAMES);
1321         swf_SetU16(t, WRITEFONTID);
1322         swf_SetU16(t, font->numchars);
1323         for (c = 0; c < font->numchars; c++) {
1324             if (font->glyphnames[c])
1325                 swf_SetString(t, font->glyphnames[c]);
1326             else
1327                 swf_SetString(t, "");
1328         }
1329     }
1330
1331     if (1)                      //neccessary only for df1, but pretty to look at anyhow, so do it always
1332     {
1333         int textscale = 400;
1334         int s;
1335         int xmax = 0;
1336         int ymax = 0;
1337         int ypos = 1;
1338         U8 gbits, abits;
1339         int x, y, c;
1340         int range = font->maxascii;
1341
1342         c = 0;
1343         if (useDefineFont2 && range > 256) {
1344             range = 256;
1345         }
1346
1347         for (s = 0; s < range; s++) {
1348             int g = font->ascii2glyph[s];
1349             if (g >= 0) {
1350                 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1351                     xmax = (font->glyph[g].advance * textscale / 20) / 64;
1352                 }
1353                 c++;
1354             }
1355             if ((s & 15) == 0) {
1356                 if (c) {
1357                     ypos++;
1358                 }
1359                 c = 0;
1360             }
1361         }
1362         ymax = ypos * textscale * 2;
1363
1364         swf.movieSize.xmax = xmax * 20;
1365         swf.movieSize.ymax = ymax;
1366
1367         t = swf_InsertTag(t, ST_DEFINETEXT);
1368
1369         swf_SetU16(t, font->id + 1);    // ID
1370
1371         r.xmin = 0;
1372         r.ymin = 0;
1373         r.xmax = swf.movieSize.xmax;
1374         r.ymax = swf.movieSize.ymax;
1375
1376         swf_SetRect(t, &r);
1377
1378         swf_SetMatrix(t, NULL);
1379
1380         abits = swf_CountBits(xmax * 16, 0);
1381         gbits = 8;
1382
1383         swf_SetU8(t, gbits);
1384         swf_SetU8(t, abits);
1385
1386         rgb.r = 0x00;
1387         rgb.g = 0x00;
1388         rgb.b = 0x00;
1389         ypos = 1;
1390         for (y = 0; y < ((range + 15) / 16); y++) {
1391             int c = 0, lastx = -1;
1392             for (x = 0; x < 16; x++) {
1393                 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1394                 if (g >= 0 && font->glyph[g].shape) {
1395                     c++;
1396                     if (lastx < 0)
1397                         lastx = x * xmax;
1398                 }
1399             }
1400             if (c) {
1401                 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1402                 for (x = 0; x < 16; x++) {
1403                     int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1404                     if (g >= 0 && font->glyph[g].shape) {
1405                         if (lastx != x * xmax) {
1406                             swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1407                         }
1408                         swf_SetU8(t, 1);
1409                         swf_SetBits(t, g, gbits);
1410                         swf_SetBits(t, font->glyph[g].advance / 20, abits);
1411                         lastx = x * xmax + (font->glyph[g].advance / 20);
1412                         swf_ResetWriteBits(t);
1413                     }
1414                 }
1415                 ypos++;
1416             }
1417         }
1418         swf_SetU8(t, 0);
1419
1420
1421         t = swf_InsertTag(t, ST_PLACEOBJECT2);
1422
1423         swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1424
1425         t = swf_InsertTag(t, ST_SHOWFRAME);
1426
1427     }
1428
1429     t = swf_InsertTag(t, ST_END);
1430
1431     f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1432     if FAILED
1433         (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1434     close(f);
1435
1436     swf_FreeTags(&swf);
1437 }
1438
1439
1440 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1441 {
1442     swf_SetRect(tag, &r);
1443     swf_ResetWriteBits(tag);
1444
1445     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1446     if (text)
1447         flags |= ET_HASTEXT;
1448     if (color)
1449         flags |= ET_HASTEXTCOLOR;
1450     if (maxlength)
1451         flags |= ET_HASMAXLENGTH;
1452     if (font)
1453         flags |= ET_HASFONT;
1454     if (layout)
1455         flags |= ET_HASLAYOUT;
1456
1457     swf_SetBits(tag, flags, 16);
1458
1459     if (flags & ET_HASFONT) {
1460         swf_SetU16(tag, font);  //font
1461         swf_SetU16(tag, height);        //fontheight
1462     }
1463     if (flags & ET_HASTEXTCOLOR) {
1464         swf_SetRGBA(tag, color);
1465     }
1466     if (flags & ET_HASMAXLENGTH) {
1467         swf_SetU16(tag, maxlength);     //maxlength
1468     }
1469     if (flags & ET_HASLAYOUT) {
1470         swf_SetU8(tag, layout->align);  //align
1471         swf_SetU16(tag, layout->leftmargin);    //left margin
1472         swf_SetU16(tag, layout->rightmargin);   //right margin
1473         swf_SetU16(tag, layout->indent);        //indent
1474         swf_SetU16(tag, layout->leading);       //leading
1475     }
1476     swf_SetString(tag, variable);
1477     if (flags & ET_HASTEXT)
1478         swf_SetString(tag, text);
1479 }
1480
1481 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1482 {
1483     SRECT r;
1484     U8 gbits, abits;
1485     U8 *utext = (U8 *) strdup(text);
1486     U8 *upos = utext;
1487     int x = 0, y = 0;
1488     int pos = 0;
1489     int ystep = 0;
1490     if (font->layout) {
1491         r = swf_TextCalculateBBoxUTF8(font, text, scale * 20);
1492         ystep = font->layout->leading;
1493     } else {
1494         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1495         /* Hm, without layout information, we can't compute a bounding
1496            box. We could call swf_FontCreateLayout to create a layout,
1497            but the caller probably doesn't want us to mess up his font
1498            structure.
1499          */
1500         r.xmin = r.ymin = 0;
1501         r.xmax = r.ymax = 1024 * 20;
1502         ystep = 100;
1503     }
1504
1505     swf_SetRect(tag, &r);
1506
1507     /* The text matrix is pretty boring, as it doesn't apply to
1508        individual characters, but rather whole text objects (or
1509        at least whole char records- haven't tested).
1510        So it can't do anything which we can't already do with
1511        the placeobject tag we use for placing the text on the scene.
1512      */
1513     swf_SetMatrix(tag, 0);
1514
1515     swf_TextCountBitsUTF8(font, text, scale * 20, &gbits, &abits);
1516     swf_SetU8(tag, gbits);
1517     swf_SetU8(tag, abits);
1518
1519     while(*upos) {
1520         U8*next = upos;
1521         int count = 0;
1522         
1523         swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y);      //scale
1524         x = 0;
1525
1526         while(*next && *next!=13 && *next!=10 && count<127) {
1527             readUTF8char(&next);
1528             count++;
1529         }
1530         if(next[0] == 13 || next[0] == 10) {
1531             x = SET_TO_ZERO;
1532             y += ystep;
1533         }
1534
1535         if(next[0] == 13 && next[1] == 10)
1536             next++;
1537         
1538         if(next[0] == 13 || next[0] == 10) {
1539             *next = 0;
1540             next++;
1541         }
1542
1543         /* now set the text params- notice that a font size of
1544            1024 means that the glyphs will be displayed exactly
1545            as they would be in/with a defineshape. (Try to find
1546            *that* in the flash specs)
1547          */
1548         /* set the actual text- notice that we just pass our scale
1549            parameter over, as TextSetCharRecord calculates with 
1550            percent, too */
1551         swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1552
1553         upos= next;
1554
1555         printf("%s\n", upos);
1556     }
1557     free(utext);
1558
1559     swf_SetU8(tag, 0);
1560     return r;
1561 }
1562
1563 void swf_FontCreateLayout(SWFFONT * f)
1564 {
1565     S16 leading = 0;
1566     int t;
1567     if (f->layout)
1568         return;
1569     if (!f->numchars)
1570         return;
1571
1572     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1573     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1574     f->layout->ascent = -32767;
1575     f->layout->descent = -32767;
1576
1577     for (t = 0; t < f->numchars; t++) {
1578         SHAPE2 *shape2;
1579         SRECT bbox;
1580         int width;
1581         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1582         if (!shape2) {
1583             fprintf(stderr, "Shape parse error\n");
1584             exit(1);
1585         }
1586         bbox = swf_GetShapeBoundingBox(shape2);
1587         swf_Shape2Free(shape2);
1588         f->layout->bounds[t] = bbox;
1589
1590         width = (bbox.xmax);
1591
1592         /* The following is a heuristic- it may be that extractfont_DefineText
1593            has already found out some widths for individual characters (from the way
1594            they are used)- we now have to guess whether that width might be possible,
1595            which is the case if it isn't either much too big or much too small */
1596         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1597             f->glyph[t].advance = width;
1598
1599         if (-bbox.ymin > f->layout->ascent)
1600             f->layout->ascent = bbox.ymin;
1601         if (bbox.ymax > f->layout->descent)
1602             f->layout->descent = bbox.ymax;
1603     }
1604 }
1605
1606 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1607 {
1608     U8 *s = (U8 *) text;
1609     int advance = 0;
1610     while (*s) {
1611         SHAPE *shape;
1612         SHAPE2 *shape2;
1613         SHAPELINE *l;
1614         U32 c = readUTF8char(&s);
1615         int g = font->ascii2glyph[c];
1616         shape = font->glyph[g].shape;
1617         if (((int) g) < 0) {
1618             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1619             continue;
1620         }
1621         shape2 = swf_ShapeToShape2(shape);
1622         l = shape2->lines;
1623         while (l) {
1624             if (l->type == moveTo) {
1625                 FPOINT to;
1626                 to.x = l->x * size / 100.0 / 20.0 + advance;
1627                 to.y = l->y * size / 100.0 / 20.0;
1628                 draw->moveTo(draw, &to);
1629             } else if (l->type == lineTo) {
1630                 FPOINT to;
1631                 to.x = l->x * size / 100.0 / 20.0 + advance;
1632                 to.y = l->y * size / 100.0 / 20.0;
1633                 draw->lineTo(draw, &to);
1634             } else if (l->type == splineTo) {
1635                 FPOINT mid, to;
1636                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1637                 mid.y = l->sy * size / 100.0 / 20.0;
1638                 to.x = l->x * size / 100.0 / 20.0 + advance;
1639                 to.y = l->y * size / 100.0 / 20.0;
1640                 draw->splineTo(draw, &mid, &to);
1641             }
1642             l = l->next;
1643         }
1644         swf_Shape2Free(shape2);
1645         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1646     }
1647 }