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