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