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