win32 compile fixes
[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 = (SWFGLYPH*)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     swf_SaveTagPos(tag);
241     swf_SetTagPos(tag, 0);
242
243     fid = swf_GetU16(tag);
244
245     if (fid == id) {
246         int num = swf_GetU16(tag);
247         int t;
248         f->glyphnames = (char**)rfx_alloc(sizeof(char *) * num);
249         for (t = 0; t < num; t++) {
250             f->glyphnames[t] = strdup(swf_GetString(tag));
251         }
252     }
253
254     swf_RestoreTagPos(tag);
255     return id;
256 }
257
258
259 int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
260 {
261     int t, glyphcount;
262     int maxcode;
263     int fid;
264     U32 offset_start;
265     U32 *offset;
266     U8 flags1, flags2, namelen;
267     swf_SaveTagPos(tag);
268     swf_SetTagPos(tag, 0);
269     font->version = 2;
270     fid = swf_GetU16(tag);
271     if (id && id != fid)
272         return id;
273     font->id = fid;
274     flags1 = swf_GetU8(tag);
275     flags2 = swf_GetU8(tag);    //reserved flags
276
277     if (flags1 & 1)
278         font->style |= FONT_STYLE_BOLD;
279     if (flags1 & 2)
280         font->style |= FONT_STYLE_ITALIC;
281     if (flags1 & 16)
282         font->encoding |= FONT_ENCODING_ANSI;
283     if (flags1 & 32)
284         font->encoding |= FONT_ENCODING_UNICODE;
285     if (flags1 & 64)
286         font->encoding |= FONT_ENCODING_SHIFTJIS;
287
288     namelen = swf_GetU8(tag);
289     font->name = (U8 *) rfx_alloc(namelen + 1);
290     font->name[namelen] = 0;
291     swf_GetBlock(tag, font->name, namelen);
292     font->version = 2;
293     glyphcount = swf_GetU16(tag);
294     font->numchars = glyphcount;
295
296     font->glyph = (SWFGLYPH *) rfx_calloc(sizeof(SWFGLYPH) * glyphcount);
297     font->glyph2ascii = (U16 *) rfx_calloc(sizeof(U16) * glyphcount);
298
299     offset = (U32*)rfx_calloc(sizeof(U32)*(glyphcount+1));
300     offset_start = tag->pos;
301
302     if (flags1 & 8) {           // wide offsets
303         for (t = 0; t < glyphcount; t++)
304             offset[t] = swf_GetU32(tag);        //offset[t]
305
306         if (glyphcount)         /* this _if_ is not in the specs */
307             offset[glyphcount] = swf_GetU32(tag);       // fontcodeoffset
308         else
309             offset[glyphcount] = tag->pos;
310     } else {
311         for (t = 0; t < glyphcount; t++)
312             offset[t] = swf_GetU16(tag);        //offset[t]
313
314         if (glyphcount)         /* this _if_ is not in the specs */
315             offset[glyphcount] = swf_GetU16(tag);       // fontcodeoffset
316         else
317             offset[glyphcount] = tag->pos;
318     }
319     for (t = 0; t < glyphcount; t++) {
320         swf_SetTagPos(tag, offset[t]+offset_start);
321         swf_GetSimpleShape(tag, &(font->glyph[t].shape));
322     }
323
324     swf_SetTagPos(tag, offset[glyphcount]+offset_start);
325
326     free(offset);
327
328     maxcode = 0;
329     for (t = 0; t < glyphcount; t++) {
330         int code;
331         if (flags1 & 4)         // wide codes
332             code = swf_GetU16(tag);
333         else
334             code = swf_GetU8(tag);
335         font->glyph2ascii[t] = code;
336         if (code > maxcode)
337             maxcode = code;
338     }
339     maxcode++;
340     if (maxcode < 256)
341         maxcode = 256;
342     font->maxascii = maxcode;
343     font->ascii2glyph = (int *) rfx_alloc(sizeof(int) * maxcode);
344     memset(font->ascii2glyph, -1, sizeof(int) * maxcode);
345     for (t = 0; t < glyphcount; t++) {
346         font->ascii2glyph[font->glyph2ascii[t]] = t;
347     }
348
349     if (flags1 & 128) {         // has layout
350         U16 kerningcount;
351         font->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
352         font->layout->ascent = swf_GetU16(tag);
353         font->layout->descent = swf_GetU16(tag);
354         font->layout->leading = swf_GetU16(tag);
355         for (t = 0; t < glyphcount; t++) {
356             S16 advance = swf_GetS16(tag);
357             font->glyph[t].advance = advance;
358         }
359         font->layout->bounds = (SRECT*)rfx_alloc(glyphcount * sizeof(SRECT));
360         for (t = 0; t < glyphcount; t++) {
361             swf_ResetReadBits(tag);
362             swf_GetRect(tag, &font->layout->bounds[t]);
363         }
364
365         kerningcount = swf_GetU16(tag);
366         font->layout->kerningcount = kerningcount;
367
368         font->layout->kerning = (SWFKERNING *) rfx_alloc(sizeof(SWFKERNING) * kerningcount);
369         if (kerningcount) {
370             font->layout->kerning = (SWFKERNING*)rfx_alloc(sizeof(*font->layout->kerning) * kerningcount);
371             for (t = 0; t < kerningcount; t++) {
372                 if (flags1 & 4) {       // wide codes
373                     font->layout->kerning[t].char1 = swf_GetU16(tag);
374                     font->layout->kerning[t].char2 = swf_GetU16(tag);
375                 } else {
376                     font->layout->kerning[t].char1 = swf_GetU8(tag);
377                     font->layout->kerning[t].char2 = swf_GetU8(tag);
378                 }
379                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
380             }
381         }
382     }
383     swf_RestoreTagPos(t);
384     return font->id;
385 }
386
387
388 #define FEDTJ_PRINT  0x01
389 #define FEDTJ_MODIFY 0x02
390 #define FEDTJ_CALLBACK 0x04
391
392 static int
393 swf_FontExtract_DefineTextCallback(int id, SWFFONT * f, TAG * t, int jobs,
394                                    void (*callback) (void *self,
395                                                      int *chars, int *xpos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
396 {
397     U16 cid;
398     SRECT r;
399     MATRIX m;
400     U8 gbits, abits;
401     int fid = -1;
402     RGBA color;
403     int x = 0, y = 0;
404     int fontsize = 0;
405
406     memset(&color, 0, sizeof(color));
407
408     swf_SaveTagPos(t);
409     swf_SetTagPos(t, 0);
410
411     cid = swf_GetU16(t);
412     swf_GetRect(t, &r);
413     swf_GetMatrix(t, &m);
414     gbits = swf_GetU8(t);
415     abits = swf_GetU8(t);
416
417     while (1) {
418         int flags, num;
419         flags = swf_GetU8(t);
420         if (!flags)
421             break;
422
423         if (flags & TF_TEXTCONTROL) {
424             if (flags & TF_HASFONT)
425                 fid = swf_GetU16(t);
426             if (flags & TF_HASCOLOR) {
427                 color.r = swf_GetU8(t); // rgb
428                 color.g = swf_GetU8(t);
429                 color.b = swf_GetU8(t);
430                 if (swf_GetTagID(t) == ST_DEFINETEXT2)
431                     color.a = swf_GetU8(t);
432                 else
433                     color.a = 255;
434             }
435             if (flags & TF_HASXOFFSET)
436                 x = swf_GetS16(t);
437             if (flags & TF_HASYOFFSET)
438                 y = swf_GetS16(t);
439             if (flags & TF_HASFONT)
440                 fontsize = swf_GetU16(t);
441         }
442
443         num = swf_GetU8(t);
444         if (!num)
445             break;
446
447         {
448             int i;
449             int buf[256];
450             int advance[256];
451             int xpos = 0;
452             for (i = 0; i < num; i++) {
453                 int glyph;
454                 int adv = 0;
455                 advance[i] = xpos;
456                 glyph = swf_GetBits(t, gbits);
457                 adv = swf_GetBits(t, abits);
458                 xpos += adv;
459
460                 if (id == fid) {
461                     if (jobs & FEDTJ_PRINT) {
462                         int code = f->glyph2ascii[glyph];
463                         printf("%lc", code);
464                     }
465                     if (jobs & FEDTJ_MODIFY)
466                         f->glyph[glyph].advance = adv * 20;     //?
467                 }
468
469                 buf[i] = glyph;
470             }
471             if ((id == fid) && (jobs & FEDTJ_PRINT))
472                 printf("\n");
473             if (jobs & FEDTJ_CALLBACK)
474                 callback(self, buf, advance, num, fid, fontsize, x, y, &color);
475             x += xpos;
476         }
477     }
478
479     swf_RestoreTagPos(t);
480     return id;
481 }
482
483 int swf_ParseDefineText(TAG * tag,
484                     void (*callback) (void *self, int *chars, int *ypos, int nr, int fontid, int fontsize, int xstart, int ystart, RGBA * color), void *self)
485 {
486     return swf_FontExtract_DefineTextCallback(-1, 0, tag, FEDTJ_CALLBACK, callback, self);
487 }
488
489 int swf_FontExtract_DefineText(int id, SWFFONT * f, TAG * t, int jobs)
490 {
491     return swf_FontExtract_DefineTextCallback(id, f, t, jobs, 0, 0);
492 }
493
494 int swf_FontExtract(SWF * swf, int id, SWFFONT * *font)
495 {
496     TAG *t;
497     SWFFONT *f;
498
499     if ((!swf) || (!font))
500         return -1;
501
502     f = (SWFFONT *) rfx_calloc(sizeof(SWFFONT));
503
504     t = swf->firstTag;
505
506     while (t) {
507         int nid = 0;
508         switch (swf_GetTagID(t)) {
509         case ST_DEFINEFONT:
510             nid = swf_FontExtract_DefineFont(id, f, t);
511             break;
512
513         case ST_DEFINEFONT2:
514             nid = swf_FontExtract_DefineFont2(id, f, t);
515             break;
516
517         case ST_DEFINEFONTINFO:
518         case ST_DEFINEFONTINFO2:
519             nid = swf_FontExtract_DefineFontInfo(id, f, t);
520             break;
521
522         case ST_DEFINETEXT:
523         case ST_DEFINETEXT2:
524             nid = swf_FontExtract_DefineText(id, f, t, f->layout ? 0 : FEDTJ_MODIFY);
525             break;
526
527         case ST_GLYPHNAMES:
528             nid = swf_FontExtract_GlyphNames(id, f, t);
529             break;
530         }
531         if (nid > 0)
532             id = nid;
533         t = swf_NextTag(t);
534     }
535     if (f->id != id) {
536         rfx_free(f);
537         f = 0;
538     }
539     font[0] = f;
540     return 0;
541 }
542
543 int swf_FontSetID(SWFFONT * f, U16 id)
544 {
545     if (!f)
546         return -1;
547     f->id = id;
548     return 0;
549 }
550
551 void swf_LayoutFree(SWFLAYOUT * l)
552 {
553     if (l) {
554         if (l->kerning)
555             rfx_free(l->kerning);
556         l->kerning = NULL;
557         if (l->bounds)
558             rfx_free(l->bounds);
559         l->bounds = NULL;
560     }
561     rfx_free(l);
562 }
563
564
565 static void font_freeglyphnames(SWFFONT*f)
566 {
567     if (f->glyphnames)
568     {
569         int t;
570         for (t = 0; t < f->numchars; t++)
571         {
572             if (f->glyphnames[t])
573             {
574                 rfx_free(f->glyphnames[t]);
575                 f->glyphnames[t] = 0;
576             }
577         }
578         rfx_free(f->glyphnames);
579         f->glyphnames = 0;
580         }
581 }
582 static void font_freeusage(SWFFONT*f)
583 {
584     if (f->use) {
585         if(f->use->chars) {
586             rfx_free(f->use->chars);f->use->chars = 0;
587         }
588         rfx_free(f->use); f->use = 0;
589     }
590 }
591 static void font_freelayout(SWFFONT*f)
592 {
593     if (f->layout) {
594         swf_LayoutFree(f->layout);
595         f->layout = 0;
596     }
597 }
598 static void font_freename(SWFFONT*f)
599 {
600     if (f->name) {
601         rfx_free(f->name);
602         f->name = 0;
603     }
604 }
605
606 int swf_FontReduce_old(SWFFONT * f)
607 {
608     int i, j;
609     int max_unicode = 0;
610     if ((!f) || (!f->use) || f->use->is_reduced)
611         return -1;
612
613     j = 0;
614
615     for (i = 0; i < f->numchars; i++) {
616         if (f->glyph[i].shape && f->use->chars[i]) {
617             f->glyph2ascii[j] = f->glyph2ascii[i];
618             f->glyph[j] = f->glyph[i];
619             f->use->chars[i] = j;
620             j++;
621         } else {
622             f->glyph2ascii[i] = 0;
623             if(f->glyph[i].shape) {
624                 swf_ShapeFree(f->glyph[i].shape);
625                 f->glyph[i].shape = 0;
626                 f->glyph[i].advance = 0;
627             }
628             f->use->chars[i] = -1;
629             j++; //TODO: remove
630         }
631     }
632     for (i = 0; i < f->maxascii; i++) {
633         if(f->use->chars[f->ascii2glyph[i]]<0) {
634             f->ascii2glyph[i] = -1;
635         } else {
636             f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
637             max_unicode = i;
638         }
639     }
640     f->maxascii = max_unicode;
641     f->use->is_reduced = 1;
642     f->numchars = j;
643     font_freelayout(f);
644     font_freeglyphnames(f);
645     font_freename(f);
646     return j;
647 }
648
649 int swf_FontReduce_swfc(SWFFONT * f)
650 {
651     int i, j;
652     int max_unicode = 0;
653     if ((!f) || (!f->use) || f->use->is_reduced)
654         return -1;
655
656     font_freeglyphnames(f);
657
658     j = 0;
659     for (i = 0; i < f->numchars; i++) {
660         if (f->glyph[i].shape && f->use->chars[i]) {
661             f->glyph2ascii[j] = f->glyph2ascii[i];
662             if (f->layout)
663                 f->layout->bounds[j] = f->layout->bounds[i];
664             f->glyph[j] = f->glyph[i];
665             f->use->chars[i] = j;
666             j++;
667         } else {
668             f->glyph2ascii[i] = 0;
669             if(f->glyph[i].shape) {
670                 swf_ShapeFree(f->glyph[i].shape);
671                 f->glyph[i].shape = 0;
672                 f->glyph[i].advance = 0;
673             }
674             f->use->chars[i] = -1;
675         }
676     }
677     f->use->used_glyphs = j;
678     for (i = 0; i < f->maxascii; i++) {
679         if(f->ascii2glyph[i] > -1) {
680             if (f->use->chars[f->ascii2glyph[i]]<0) {
681                 f->use->chars[f->ascii2glyph[i]] = 0;
682                 f->ascii2glyph[i] = -1;
683             } else {
684                 f->ascii2glyph[i] = f->use->chars[f->ascii2glyph[i]];
685                 f->use->chars[f->ascii2glyph[i]] = 1;
686                 max_unicode = i + 1;
687             }
688         }
689     }
690     f->maxascii = max_unicode;
691     f->use->is_reduced = 1;
692     f->numchars = j;
693     font_freename(f);
694     return j;
695 }
696
697 int swf_FontReduce(SWFFONT * f)
698 {
699     int i;
700     int max_unicode = 0;
701     int max_glyph = 0;
702     if ((!f) || (!f->use) || f->use->is_reduced)
703         return -1;
704
705     font_freelayout(f);
706     font_freeglyphnames(f);
707
708     f->use->used_glyphs= 0;
709     for (i = 0; i < f->numchars; i++) {
710         if(!f->use->chars[i]) {
711             if(f->glyph2ascii) {
712                 f->glyph2ascii[i] = 0;
713             }
714             if(f->glyph[i].shape) {
715                 swf_ShapeFree(f->glyph[i].shape);
716                 f->glyph[i].shape = 0;
717                 f->glyph[i].advance = 0;
718             }
719 //          f->use->used_glyphs++;
720         } else {
721             f->use->used_glyphs++;
722             max_glyph = i+1;
723         }
724     }
725     for (i = 0; i < f->maxascii; i++) {
726         if(f->ascii2glyph[i] > -1 && !f->use->chars[f->ascii2glyph[i]]) {
727             if(f->ascii2glyph) {
728                 f->ascii2glyph[i] = -1;
729             }
730         } else {
731             max_unicode = i+1;
732         }
733     }
734     f->maxascii = max_unicode;
735     f->numchars = max_glyph;
736     font_freename(f);
737     return 0;
738 }
739
740 void swf_FontSort(SWFFONT * font)
741 {
742     int i, j;
743     int *newplace;
744     int *newpos;
745     if (!font)
746         return;
747
748     newplace = (int*)rfx_alloc(sizeof(int) * font->numchars);
749
750     for (i = 0; i < font->numchars; i++) {
751         newplace[i] = i;
752     }
753     for (i = 0; i < font->numchars; i++)
754         for (j = 0; j < i; j++) {
755             if (font->glyph2ascii[i] < font->glyph2ascii[j]) {
756                 int n1, n2;
757                 char *c1, *c2;
758                 SWFGLYPH g1, g2;
759                 SRECT r1, r2;
760                 n1 = newplace[i];
761                 n2 = newplace[j];
762                 newplace[j] = n1;
763                 newplace[i] = n2;
764                 n1 = font->glyph2ascii[i];
765                 n2 = font->glyph2ascii[j];
766                 font->glyph2ascii[j] = n1;
767                 font->glyph2ascii[i] = n2;
768                 g1 = font->glyph[i];
769                 g2 = font->glyph[j];
770                 font->glyph[j] = g1;
771                 font->glyph[i] = g2;
772                 if (font->glyphnames) {
773                     c1 = font->glyphnames[i];
774                     c2 = font->glyphnames[j];
775                     font->glyphnames[j] = c1;
776                     font->glyphnames[i] = c2;
777                 }
778                 if (font->layout) {
779                     r1 = font->layout->bounds[i];
780                     r2 = font->layout->bounds[j];
781                     font->layout->bounds[j] = r1;
782                     font->layout->bounds[i] = r2;
783                 }
784             }
785         }
786     newpos = (int*)rfx_alloc(sizeof(int) * font->numchars);
787     for (i = 0; i < font->numchars; i++) {
788         newpos[newplace[i]] = i;
789     }
790     for (i = 0; i < font->maxascii; i++) {
791         if (font->ascii2glyph[i] >= 0)
792             font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
793     }
794
795     rfx_free(newpos);
796     rfx_free(newplace);
797 }
798
799 void swf_FontPrepareForEditText(SWFFONT * font)
800 {
801     if (!font->layout)
802         swf_FontCreateLayout(font);
803     swf_FontSort(font);
804 }
805
806 int swf_FontInitUsage(SWFFONT * f)
807 {
808     if (!f)
809         return -1;
810     if(f->use) {
811         fprintf(stderr, "Usage initialized twice");
812         return -1;
813     }
814     f->use = (FONTUSAGE*)rfx_alloc(sizeof(FONTUSAGE));
815     f->use->is_reduced = 0;
816     f->use->used_glyphs = 0;
817     f->use->chars = (int*)rfx_calloc(sizeof(f->use->chars[0]) * f->numchars);
818     return 0;
819 }
820
821 void swf_FontClearUsage(SWFFONT * f)
822 {
823     if (!f || !f->use)
824         return;
825     rfx_free(f->use->chars); f->use->chars = 0;
826     rfx_free(f->use); f->use = 0;
827 }
828
829 int swf_FontUse(SWFFONT * f, U8 * s)
830 {
831     if( (!s))
832         return -1;
833     while (*s) {
834         if(*s < f->maxascii && f->ascii2glyph[*s]>=0)
835             swf_FontUseGlyph(f, f->ascii2glyph[*s]);
836         s++;
837     }
838     return 0;
839 }
840
841 int swf_FontUseUTF8(SWFFONT * f, U8 * s)
842 {
843     if( (!s))
844         return -1;
845     int ascii;
846     while (*s)
847     {
848         ascii = readUTF8char(&s);
849         if(ascii < f->maxascii && f->ascii2glyph[ascii]>=0)
850             swf_FontUseGlyph(f, f->ascii2glyph[ascii]);
851     }
852     return 0;
853 }
854
855 int swf_FontUseAll(SWFFONT* f)
856 {
857     int i;
858
859     if (!f->use)
860         swf_FontInitUsage(f);
861     for (i = 0; i < f->numchars; i++)
862         f->use->chars[i] = 1;
863     f->use->used_glyphs = f->numchars;
864     return 0;
865 }
866
867 int swf_FontUseGlyph(SWFFONT * f, int glyph)
868 {
869     if (!f->use)
870         swf_FontInitUsage(f);
871     if(glyph < 0 || glyph >= f->numchars)
872         return -1;
873     if(!f->use->chars[glyph])
874         f->use->used_glyphs++;
875     f->use->chars[glyph] = 1;
876     return 0;
877 }
878
879 int swf_FontSetDefine(TAG * t, SWFFONT * f)
880 {
881     U16 *ofs = (U16 *) rfx_alloc(f->numchars * 2);
882     int p, i, j;
883
884     if ((!t) || (!f))
885         return -1;
886     swf_ResetWriteBits(t);
887     swf_SetU16(t, f->id);
888
889     p = 0;
890     j = 0;
891     for (i = 0; i < f->numchars; i++)
892         if (f->glyph[i].shape) {
893             ofs[j++] = p;
894             p += swf_SetSimpleShape(NULL, f->glyph[i].shape);
895         }
896
897     for (i = 0; i < j; i++)
898         swf_SetU16(t, ofs[i] + j * 2);
899     if (!j) {
900         fprintf(stderr, "rfxswf: warning: Font is empty\n");
901         swf_SetU16(t, 0);
902     }
903
904     for (i = 0; i < f->numchars; i++)
905         if (f->glyph[i].shape)
906             swf_SetSimpleShape(t, f->glyph[i].shape);
907
908     swf_ResetWriteBits(t);
909     rfx_free(ofs);
910     return 0;
911 }
912
913 static inline int fontSize(SWFFONT * font)
914 {
915     int t;
916     int size = 0;
917     for (t = 0; t < font->numchars; t++) {
918         int l = 0;
919         if(font->glyph[t].shape)
920             l = (font->glyph[t].shape->bitlen + 7) / 8;
921         else
922             l = 8;
923         size += l + 1;
924     }
925     return size + (font->numchars + 1) * 2;
926 }
927
928 int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
929 {
930     U8 flags = 0;
931     int t;
932     int pos;
933     swf_SetU16(tag, f->id);
934
935     if (f->layout) flags |= 128;                // haslayout
936     if (f->numchars > 256)
937         flags |= 4;             // widecodes
938     if (f->style & FONT_STYLE_BOLD)
939         flags |= 1;             // bold
940     if (f->style & FONT_STYLE_ITALIC)
941         flags |= 2;             // italic
942     if (f->maxascii >= 256)
943         flags |= 4;             //wide codecs
944     if (fontSize(f) > 65535)
945         flags |= 8;             //wide offsets
946     flags |= 8 | 4;             //FIXME: the above check doesn't work
947
948     if (f->encoding & FONT_ENCODING_ANSI)
949         flags |= 16;            // ansi
950     if (f->encoding & FONT_ENCODING_UNICODE)
951         flags |= 32;            // unicode
952     if (f->encoding & FONT_ENCODING_SHIFTJIS)
953         flags |= 64;            // shiftjis
954
955     swf_SetU8(tag, flags);
956     swf_SetU8(tag, 0);          //reserved flags
957     if (f->name) {
958         /* font name */
959         swf_SetU8(tag, strlen((const char*)f->name));
960         swf_SetBlock(tag, f->name, strlen((const char*)f->name));
961     } else {
962         /* font name (="") */
963         swf_SetU8(tag, 0);
964     }
965     /* number of glyphs */
966     swf_SetU16(tag, f->numchars);
967     /* font offset table */
968     pos = tag->len;
969     for (t = 0; t <= f->numchars; t++) {
970         if (flags & 8)
971             swf_SetU32(tag, /* fontoffset */ 0);        /*placeholder */
972         else
973             swf_SetU16(tag, /* fontoffset */ 0);        /*placeholder */
974     }
975
976     for (t = 0; t <= f->numchars; t++) {
977         if (flags & 8) {
978             tag->data[pos + t * 4] = (tag->len - pos);
979             tag->data[pos + t * 4 + 1] = (tag->len - pos) >> 8;
980             tag->data[pos + t * 4 + 2] = (tag->len - pos) >> 16;
981             tag->data[pos + t * 4 + 3] = (tag->len - pos) >> 24;
982         } else {
983             if (tag->len - pos > 65535) {
984                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
985                 exit(1);
986             }
987             tag->data[pos + t * 2] = (tag->len - pos);
988             tag->data[pos + t * 2 + 1] = (tag->len - pos) >> 8;
989         }
990         if (t < f->numchars) {
991             if(f->glyph[t].shape) {
992                 swf_SetSimpleShape(tag, f->glyph[t].shape);
993             } else {
994                 swf_SetU8(tag, 0); //non-edge(1) + edge flags(5)
995             }
996         }
997     }
998
999
1000     /* font code table */
1001     for (t = 0; t < f->numchars; t++) {
1002         if (flags & 4) {                /* wide codes */
1003             if(f->glyph2ascii[t]) {
1004                 swf_SetU16(tag, f->glyph2ascii[t]);
1005             } else {
1006                 swf_SetU16(tag, 0);
1007             }
1008         } else {
1009             if(f->glyph2ascii[t]) {
1010                 swf_SetU8(tag, f->glyph2ascii[t]);
1011             } else {
1012                 swf_SetU8(tag, 0);
1013             }
1014         }
1015     }
1016
1017     if (f->layout) {
1018         swf_SetU16(tag, f->layout->ascent);
1019         swf_SetU16(tag, f->layout->descent);
1020         swf_SetU16(tag, f->layout->leading);
1021         for (t = 0; t < f->numchars; t++)
1022             swf_SetU16(tag, f->glyph[t].advance);
1023         for (t = 0; t < f->numchars; t++) {
1024             swf_ResetWriteBits(tag);
1025             swf_SetRect(tag, &f->layout->bounds[t]);
1026         }
1027         swf_SetU16(tag, f->layout->kerningcount);
1028         for (t = 0; t < f->layout->kerningcount; t++) {
1029             if (flags & 4) {    /* wide codes */
1030                 swf_SetU16(tag, f->layout->kerning[t].char1);
1031                 swf_SetU16(tag, f->layout->kerning[t].char2);
1032             } else {
1033                 swf_SetU8(tag, f->layout->kerning[t].char1);
1034                 swf_SetU8(tag, f->layout->kerning[t].char2);
1035             }
1036             swf_SetU16(tag, f->layout->kerning[t].adjustment);
1037         }
1038     }
1039     return 0;
1040 }
1041
1042 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
1043 {
1044     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
1045     f->layout->ascent = ascent;
1046     f->layout->descent = descent;
1047     f->layout->leading = leading;
1048     f->layout->kerningcount = 0;
1049     f->layout->kerning = 0;
1050     f->layout->bounds = (SRECT *) rfx_calloc(sizeof(SRECT) * f->numchars);
1051 }
1052
1053 int swf_FontSetInfo(TAG * t, SWFFONT * f)
1054 {
1055     int l, i;
1056     U8 wide = 0;
1057     U8 flags = 0;
1058     if ((!t) || (!f))
1059         return -1;
1060     swf_ResetWriteBits(t);
1061     swf_SetU16(t, f->id);
1062     l = f->name ? strlen((const char *)f->name) : 0;
1063     if (l > 255)
1064         l = 255;
1065     swf_SetU8(t, l);
1066     if (l)
1067         swf_SetBlock(t, f->name, l);
1068     if (f->numchars >= 256)
1069         wide = 1;
1070
1071     if (f->style & FONT_STYLE_BOLD)
1072         flags |= 2;
1073     if (f->style & FONT_STYLE_ITALIC)
1074         flags |= 4;
1075     if (f->style & FONT_ENCODING_ANSI)
1076         flags |= 8;
1077     if (f->style & FONT_ENCODING_SHIFTJIS)
1078         flags |= 16;
1079     if (f->style & FONT_ENCODING_UNICODE)
1080         flags |= 32;
1081
1082     swf_SetU8(t, (flags & 0xfe) | wide);
1083
1084     for (i = 0; i < f->numchars; i++) {
1085         if (f->glyph[i].shape) {
1086             int g2a = f->glyph2ascii?f->glyph2ascii[i]:0;
1087             wide ? swf_SetU16(t, g2a) : swf_SetU8(t, g2a);
1088         }
1089     }
1090
1091     return 0;
1092 }
1093
1094 int swf_TextPrintDefineText(TAG * t, SWFFONT * f)
1095 {
1096     int id = swf_GetTagID(t);
1097     if ((id == ST_DEFINETEXT) || (id == ST_DEFINETEXT2))
1098         swf_FontExtract_DefineText(f->id, f, t, FEDTJ_PRINT);
1099     else
1100         return -1;
1101     return 0;
1102 }
1103
1104 void swf_FontFree(SWFFONT * f)
1105 {
1106     int i;
1107     if (!f)
1108         return;
1109
1110     if (f->glyph)
1111     {
1112         for (i = 0; i < f->numchars; i++)
1113             if (f->glyph[i].shape)
1114             {
1115                 swf_ShapeFree(f->glyph[i].shape);
1116                 f->glyph[i].shape = NULL;
1117             }
1118             rfx_free(f->glyph);
1119             f->glyph = NULL;
1120     }
1121     if (f->ascii2glyph)
1122     {
1123         rfx_free(f->ascii2glyph);
1124         f->ascii2glyph = NULL;
1125     }
1126     if (f->glyph2ascii)
1127     {
1128         rfx_free(f->glyph2ascii);
1129         f->glyph2ascii = NULL;
1130     }
1131     font_freename(f);
1132     font_freelayout(f);
1133     font_freeglyphnames(f);
1134     font_freeusage(f);
1135
1136     rfx_free(f);
1137 }
1138
1139 int swf_TextSetInfoRecord(TAG * t, SWFFONT * font, U16 size, RGBA * color, int dx, int dy)
1140 {
1141     U8 flags;
1142     if (!t)
1143         return -1;
1144
1145     flags = TF_TEXTCONTROL | (font ? TF_HASFONT : 0) | (color ? TF_HASCOLOR : 0) | (dx ? TF_HASXOFFSET : 0)
1146         | (dy ? TF_HASYOFFSET : 0);
1147
1148     swf_SetU8(t, flags);
1149     if (font)
1150         swf_SetU16(t, font->id);
1151     if (color) {
1152         if (swf_GetTagID(t) == ST_DEFINETEXT2)
1153             swf_SetRGBA(t, color);
1154         else
1155             swf_SetRGB(t, color);
1156     }
1157     if (dx) {
1158         if(dx != SET_TO_ZERO) {
1159             if(dx>32767 || dx<-32768)
1160                 fprintf(stderr, "Warning: Horizontal char position overflow: %d\n", dx);
1161             swf_SetS16(t, dx);
1162         } else {
1163             swf_SetS16(t, 0);
1164         }
1165     }
1166     if (dy) {
1167         if(dy != SET_TO_ZERO) {
1168             if(dy>32767 || dy<-32768)
1169                 fprintf(stderr, "Warning: Vertical char position overflow: %d\n", dy);
1170             swf_SetS16(t, dy);
1171         } else {
1172             swf_SetS16(t, 0);
1173         }
1174     }
1175     if (font)
1176         swf_SetU16(t, size);
1177
1178     return 0;
1179 }
1180
1181 static int swf_TextCountBits2(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits, char *encoding)
1182 {
1183     U16 g, a;
1184     char utf8 = 0;
1185     if ((!s) || (!font) || ((!gbits) && (!abits)) || (!font->ascii2glyph))
1186         return -1;
1187     g = a = 0;
1188
1189     if (!strcmp(encoding, "UTF8"))
1190         utf8 = 1;
1191     else if (!strcmp(encoding, "iso-8859-1"))
1192         utf8 = 0;
1193     else
1194         fprintf(stderr, "Unknown encoding: %s", encoding);
1195
1196     while (*s) {
1197         int glyph = -1, c;
1198
1199         if (!utf8)
1200             c = *s++;
1201         else
1202             c = readUTF8char(&s);
1203
1204         if (c < font->maxascii)
1205             glyph = font->ascii2glyph[c];
1206         if (glyph >= 0) {
1207             g = swf_CountUBits(glyph, g);
1208             a = swf_CountBits(((((U32) font->glyph[glyph].advance) * scale) / 20) / 100, a);
1209         }
1210     }
1211
1212     if (gbits)
1213         gbits[0] = (U8) g;
1214     if (abits)
1215         abits[0] = (U8) a;
1216     return 0;
1217 }
1218
1219 static int swf_TextSetCharRecord2(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits, char *encoding)
1220 {
1221     int l = 0, pos;
1222     char utf8 = 0;
1223
1224     if ((!t) || (!font) || (!s) || (!font->ascii2glyph))
1225         return -1;
1226
1227     if (!strcmp(encoding, "UTF8"))
1228         utf8 = 1;
1229     else if (!strcmp(encoding, "iso-8859-1"))
1230         utf8 = 0;
1231     else
1232         fprintf(stderr, "Unknown encoding: %s", encoding);
1233
1234     pos = t->len;
1235     swf_SetU8(t, l);            //placeholder
1236
1237     while (*s) {
1238         int g = -1, c;
1239
1240         if (!utf8)
1241             c = *s++;
1242         else
1243             c = readUTF8char(&s);
1244
1245         if (c < font->maxascii)
1246             g = font->ascii2glyph[c];
1247         if (g >= 0) {
1248             swf_SetBits(t, g, gbits);
1249             swf_SetBits(t, ((((U32) font->glyph[g].advance) * scale) / 20) / 100, abits);
1250             l++;
1251             /* We split into 127 characters per text field.
1252                We could do 255, by the (formerly wrong) flash specification,
1253                but some SWF parsing code out there still assumes that char blocks
1254                are at max 127 characters, and it would save only a few bits.
1255             */
1256             if (l == 0x7f)
1257                 break;
1258         }
1259     }
1260
1261     PUT8(&t->data[pos], l);
1262
1263     swf_ResetWriteBits(t);
1264     return 0;
1265 }
1266
1267 int swf_TextCountBits(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1268 {
1269     return swf_TextCountBits2(font, s, scale, gbits, abits, "iso-8859-1");
1270 }
1271
1272 int swf_TextSetCharRecord(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1273 {
1274     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "iso-8859-1");
1275 }
1276
1277 int swf_TextCountBitsUTF8(SWFFONT * font, U8 * s, int scale, U8 * gbits, U8 * abits)
1278 {
1279     return swf_TextCountBits2(font, s, scale, gbits, abits, "UTF8");
1280 }
1281
1282 int swf_TextSetCharRecordUTF8(TAG * t, SWFFONT * font, U8 * s, int scale, U8 gbits, U8 abits)
1283 {
1284     return swf_TextSetCharRecord2(t, font, s, scale, gbits, abits, "UTF8");
1285 }
1286
1287 U32 swf_TextGetWidth(SWFFONT * font, U8 * s, int scale)
1288 {
1289     U32 res = 0;
1290
1291     if (font && s) {
1292         while (s[0]) {
1293             int g = -1;
1294             if (*s < font->maxascii)
1295                 g = font->ascii2glyph[*s];
1296             if (g >= 0)
1297                 res += font->glyph[g].advance / 20;
1298             s++;
1299         }
1300         if (scale)
1301             res = (res * scale) / 100;
1302     }
1303     return res;
1304 }
1305
1306 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font, U8 * s, int scale)
1307 {
1308     int xpos = 0;
1309     int ypos = 0;
1310     SRECT r;
1311     swf_GetRect(0, &r);
1312     while (*s) {
1313         int c = readUTF8char(&s);
1314         if(c==13 || c==10) {
1315             if(s[0] == 10) {
1316                 s++;
1317             }
1318             xpos=0;
1319             ypos+=font->layout->leading;
1320             continue;
1321         }
1322         if (c < font->maxascii) {
1323             int g = font->ascii2glyph[c];
1324             if (g >= 0) {
1325                 SRECT rn = font->layout->bounds[g];
1326                 rn.xmin = (rn.xmin * scale) / 20 / 100 + xpos;
1327                 rn.xmax = (rn.xmax * scale) / 20 / 100 + xpos;
1328                 rn.ymin = (rn.ymin * scale) / 20 / 100 + ypos;
1329                 rn.ymax = (rn.ymax * scale) / 20 / 100 + ypos;
1330                 swf_ExpandRect2(&r, &rn);
1331                 xpos += (font->glyph[g].advance * scale) / 20 / 100;
1332             }
1333         }
1334     }
1335     return r;
1336 }
1337
1338
1339 SWFFONT *swf_ReadFont(char *filename)
1340 {
1341     int f;
1342     SWF swf;
1343     if (!filename)
1344         return 0;
1345     f = open(filename, O_RDONLY|O_BINARY);
1346
1347     if (f < 0 || swf_ReadSWF(f, &swf) < 0) {
1348         fprintf(stderr, "%s is not a valid SWF font file or contains errors.\n", filename);
1349         close(f);
1350         return 0;
1351     } else {
1352         SWFFONT *font;
1353         close(f);
1354         if (swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1355             return 0;
1356         swf_FreeTags(&swf);
1357         return font;
1358     }
1359 }
1360
1361 void swf_WriteFont(SWFFONT * font, char *filename)
1362 {
1363     SWF swf;
1364     TAG *t;
1365     SRECT r;
1366     RGBA rgb;
1367     int f;
1368     int useDefineFont2 = 0;
1369     int storeGlyphNames = 1;
1370
1371     if (font->layout)
1372         useDefineFont2 = 1;     /* the only thing new in definefont2
1373                                    is layout information. */
1374
1375     font->id = WRITEFONTID;     //"FN"
1376
1377     memset(&swf, 0x00, sizeof(SWF));
1378
1379     swf.fileVersion = 4;
1380     swf.frameRate = 0x4000;
1381
1382     /* if we use DefineFont1 to store the characters,
1383        we have to build a textfield to store the
1384        advance values. While at it, we can also
1385        make the whole .swf viewable */
1386
1387     /* we now always create viewable swfs, even if we
1388        did use definefont2 -mk */
1389     t = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
1390     swf.firstTag = t;
1391     rgb.r = 0xef;
1392     rgb.g = 0xef;
1393     rgb.b = 0xff;
1394     swf_SetRGB(t, &rgb);
1395     if (!useDefineFont2) {
1396         t = swf_InsertTag(t, ST_DEFINEFONT);
1397         swf_FontSetDefine(t, font);
1398         t = swf_InsertTag(t, ST_DEFINEFONTINFO);
1399         swf_FontSetInfo(t, font);
1400     } else {
1401         t = swf_InsertTag(t, ST_DEFINEFONT2);
1402         swf_FontSetDefine2(t, font);
1403     }
1404
1405     if (storeGlyphNames && font->glyphnames) {
1406         int c;
1407         t = swf_InsertTag(t, ST_GLYPHNAMES);
1408         swf_SetU16(t, WRITEFONTID);
1409         swf_SetU16(t, font->numchars);
1410         for (c = 0; c < font->numchars; c++) {
1411             if (font->glyphnames[c])
1412                 swf_SetString(t, (U8*)font->glyphnames[c]);
1413             else
1414                 swf_SetString(t, (U8*)"");
1415         }
1416     }
1417
1418     if (1)                      //neccessary only for df1, but pretty to look at anyhow, so do it always
1419     {
1420         int textscale = 400;
1421         int s;
1422         int xmax = 0;
1423         int ymax = 0;
1424         int ypos = 1;
1425         U8 gbits, abits;
1426         int x, y, c;
1427         int range = font->maxascii;
1428
1429         c = 0;
1430         if (useDefineFont2 && range > 256) {
1431             range = 256;
1432         }
1433
1434         for (s = 0; s < range; s++) {
1435             int g = font->ascii2glyph[s];
1436             if (g >= 0) {
1437                 if ((font->glyph[g].advance * textscale / 20) / 64 > xmax) {
1438                     xmax = (font->glyph[g].advance * textscale / 20) / 64;
1439                 }
1440                 c++;
1441             }
1442             if ((s & 15) == 0) {
1443                 if (c) {
1444                     ypos++;
1445                 }
1446                 c = 0;
1447             }
1448         }
1449         ymax = ypos * textscale * 2;
1450
1451         swf.movieSize.xmax = xmax * 20;
1452         swf.movieSize.ymax = ymax;
1453
1454         t = swf_InsertTag(t, ST_DEFINETEXT);
1455
1456         swf_SetU16(t, font->id + 1);    // ID
1457
1458         r.xmin = 0;
1459         r.ymin = 0;
1460         r.xmax = swf.movieSize.xmax;
1461         r.ymax = swf.movieSize.ymax;
1462
1463         swf_SetRect(t, &r);
1464
1465         swf_SetMatrix(t, NULL);
1466
1467         abits = swf_CountBits(xmax * 16, 0);
1468         gbits = 8;
1469
1470         swf_SetU8(t, gbits);
1471         swf_SetU8(t, abits);
1472
1473         rgb.r = 0x00;
1474         rgb.g = 0x00;
1475         rgb.b = 0x00;
1476         ypos = 1;
1477         for (y = 0; y < ((range + 15) / 16); y++) {
1478             int c = 0, lastx = -1;
1479             for (x = 0; x < 16; x++) {
1480                 int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1481                 if (g >= 0 && font->glyph[g].shape) {
1482                     c++;
1483                     if (lastx < 0)
1484                         lastx = x * xmax;
1485                 }
1486             }
1487             if (c) {
1488                 swf_TextSetInfoRecord(t, font, textscale, &rgb, lastx + 1, textscale * ypos * 2);
1489                 for (x = 0; x < 16; x++) {
1490                     int g = (y * 16 + x < range) ? font->ascii2glyph[y * 16 + x] : -1;
1491                     if (g >= 0 && font->glyph[g].shape) {
1492                         if (lastx != x * xmax) {
1493                             swf_TextSetInfoRecord(t, 0, 0, 0, x * xmax + 1, 0);
1494                         }
1495                         swf_SetU8(t, 1);
1496                         swf_SetBits(t, g, gbits);
1497                         swf_SetBits(t, font->glyph[g].advance / 20, abits);
1498                         lastx = x * xmax + (font->glyph[g].advance / 20);
1499                         swf_ResetWriteBits(t);
1500                     }
1501                 }
1502                 ypos++;
1503             }
1504         }
1505         swf_SetU8(t, 0);
1506
1507
1508         t = swf_InsertTag(t, ST_PLACEOBJECT2);
1509
1510         swf_ObjectPlace(t, font->id + 1, 1, NULL, NULL, NULL);
1511
1512         t = swf_InsertTag(t, ST_SHOWFRAME);
1513
1514     }
1515
1516     t = swf_InsertTag(t, ST_END);
1517
1518     f = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
1519     if FAILED
1520         (swf_WriteSWF(f, &swf)) fprintf(stderr, "WriteSWF() failed in writeFont().\n");
1521     close(f);
1522
1523     swf_FreeTags(&swf);
1524 }
1525
1526
1527 void swf_SetEditText(TAG * tag, U16 flags, SRECT r, char *text, RGBA * color, int maxlength, U16 font, U16 height, EditTextLayout * layout, char *variable)
1528 {
1529     swf_SetRect(tag, &r);
1530     swf_ResetWriteBits(tag);
1531
1532     flags &= ~(ET_HASTEXT | ET_HASTEXTCOLOR | ET_HASMAXLENGTH | ET_HASFONT | ET_HASLAYOUT);
1533     if (text)
1534         flags |= ET_HASTEXT;
1535     if (color)
1536         flags |= ET_HASTEXTCOLOR;
1537     if (maxlength)
1538         flags |= ET_HASMAXLENGTH;
1539     if (font)
1540         flags |= ET_HASFONT;
1541     if (layout)
1542         flags |= ET_HASLAYOUT;
1543
1544     swf_SetBits(tag, flags, 16);
1545
1546     if (flags & ET_HASFONT) {
1547         swf_SetU16(tag, font);  //font
1548         swf_SetU16(tag, height);        //fontheight
1549     }
1550     if (flags & ET_HASTEXTCOLOR) {
1551         swf_SetRGBA(tag, color);
1552     }
1553     if (flags & ET_HASMAXLENGTH) {
1554         swf_SetU16(tag, maxlength);     //maxlength
1555     }
1556     if (flags & ET_HASLAYOUT) {
1557         swf_SetU8(tag, layout->align);  //align
1558         swf_SetU16(tag, layout->leftmargin);    //left margin
1559         swf_SetU16(tag, layout->rightmargin);   //right margin
1560         swf_SetU16(tag, layout->indent);        //indent
1561         swf_SetU16(tag, layout->leading);       //leading
1562     }
1563     swf_SetString(tag, (U8*)variable);
1564     if (flags & ET_HASTEXT)
1565         swf_SetString(tag, (U8*)text);
1566 }
1567
1568 SRECT swf_SetDefineText(TAG * tag, SWFFONT * font, RGBA * rgb, char *text, int scale)
1569 {
1570     SRECT r;
1571     U8 gbits, abits;
1572     U8 *utext = (U8 *) strdup(text);
1573     U8 *upos = utext;
1574     int x = 0, y = 0;
1575     int pos = 0;
1576     int ystep = 0;
1577     if (font->layout) {
1578         r = swf_TextCalculateBBoxUTF8(font, (U8*)text, scale * 20);
1579         ystep = font->layout->leading;
1580     } else {
1581         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1582         /* Hm, without layout information, we can't compute a bounding
1583            box. We could call swf_FontCreateLayout to create a layout,
1584            but the caller probably doesn't want us to mess up his font
1585            structure.
1586          */
1587         r.xmin = r.ymin = 0;
1588         r.xmax = r.ymax = 1024 * 20;
1589         ystep = 100;
1590     }
1591
1592     swf_SetRect(tag, &r);
1593
1594     /* The text matrix is pretty boring, as it doesn't apply to
1595        individual characters, but rather whole text objects (or
1596        at least whole char records- haven't tested).
1597        So it can't do anything which we can't already do with
1598        the placeobject tag we use for placing the text on the scene.
1599      */
1600     swf_SetMatrix(tag, 0);
1601
1602     swf_TextCountBitsUTF8(font, (U8*)text, scale * 20, &gbits, &abits);
1603     swf_SetU8(tag, gbits);
1604     swf_SetU8(tag, abits);
1605
1606     while(*upos) {
1607         U8*next = upos;
1608         int count = 0;
1609
1610         swf_TextSetInfoRecord(tag, font, (scale * 1024) / 100, rgb, x, y);      //scale
1611         x = 0;
1612
1613         while(*next && *next!=13 && *next!=10 && count<127) {
1614             readUTF8char(&next);
1615             count++;
1616         }
1617         if(next[0] == 13 || next[0] == 10) {
1618             x = SET_TO_ZERO;
1619             y += ystep;
1620         }
1621
1622         if(next[0] == 13 && next[1] == 10)
1623             next++;
1624
1625         if(next[0] == 13 || next[0] == 10) {
1626             *next = 0;
1627             next++;
1628         }
1629
1630         /* now set the text params- notice that a font size of
1631            1024 means that the glyphs will be displayed exactly
1632            as they would be in/with a defineshape. (Try to find
1633            *that* in the flash specs)
1634          */
1635         /* set the actual text- notice that we just pass our scale
1636            parameter over, as TextSetCharRecord calculates with
1637            percent, too */
1638         swf_TextSetCharRecordUTF8(tag, font, upos, scale * 20, gbits, abits);
1639
1640         upos= next;
1641     }
1642     free(utext);
1643
1644     swf_SetU8(tag, 0);
1645     return r;
1646 }
1647
1648 void swf_FontCreateLayout(SWFFONT * f)
1649 {
1650     S16 leading = 0;
1651     int t;
1652     if (f->layout)
1653         return;
1654     if (!f->numchars)
1655         return;
1656
1657     f->layout = (SWFLAYOUT *) rfx_calloc(sizeof(SWFLAYOUT));
1658     f->layout->bounds = (SRECT *) rfx_alloc(f->numchars * sizeof(SRECT));
1659     f->layout->ascent = -32767;
1660     f->layout->descent = -32767;
1661
1662     for (t = 0; t < f->numchars; t++) {
1663         SHAPE2 *shape2;
1664         SRECT bbox;
1665         int width;
1666         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1667         if (!shape2) {
1668             fprintf(stderr, "Shape parse error\n");
1669             exit(1);
1670         }
1671         bbox = swf_GetShapeBoundingBox(shape2);
1672         swf_Shape2Free(shape2);
1673         f->layout->bounds[t] = bbox;
1674
1675         width = (bbox.xmax);
1676
1677         /* The following is a heuristic- it may be that extractfont_DefineText
1678            has already found out some widths for individual characters (from the way
1679            they are used)- we now have to guess whether that width might be possible,
1680            which is the case if it isn't either much too big or much too small */
1681         if (width > f->glyph[t].advance * 3 / 2 || width < f->glyph[t].advance / 2)
1682             f->glyph[t].advance = width;
1683
1684         if (-bbox.ymin > f->layout->ascent)
1685             f->layout->ascent = bbox.ymin;
1686         if (bbox.ymax > f->layout->descent)
1687             f->layout->descent = bbox.ymax;
1688     }
1689 }
1690
1691 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, char *text)
1692 {
1693     U8 *s = (U8 *) text;
1694     int advance = 0;
1695     while (*s) {
1696         SHAPE *shape;
1697         SHAPE2 *shape2;
1698         SHAPELINE *l;
1699         U32 c = readUTF8char(&s);
1700         int g = font->ascii2glyph[c];
1701         shape = font->glyph[g].shape;
1702         if (((int) g) < 0) {
1703             fprintf(stderr, "No char %d in font %s\n", c, font->name ? (char *) font->name : "?");
1704             continue;
1705         }
1706         shape2 = swf_ShapeToShape2(shape);
1707         l = shape2->lines;
1708         while (l) {
1709             if (l->type == moveTo) {
1710                 FPOINT to;
1711                 to.x = l->x * size / 100.0 / 20.0 + advance;
1712                 to.y = l->y * size / 100.0 / 20.0;
1713                 draw->moveTo(draw, &to);
1714             } else if (l->type == lineTo) {
1715                 FPOINT to;
1716                 to.x = l->x * size / 100.0 / 20.0 + advance;
1717                 to.y = l->y * size / 100.0 / 20.0;
1718                 draw->lineTo(draw, &to);
1719             } else if (l->type == splineTo) {
1720                 FPOINT mid, to;
1721                 mid.x = l->sx * size / 100.0 / 20.0 + advance;
1722                 mid.y = l->sy * size / 100.0 / 20.0;
1723                 to.x = l->x * size / 100.0 / 20.0 + advance;
1724                 to.y = l->y * size / 100.0 / 20.0;
1725                 draw->splineTo(draw, &mid, &to);
1726             }
1727             l = l->next;
1728         }
1729         swf_Shape2Free(shape2);
1730         advance += font->glyph[g].advance * size / 100.0 / 20.0;
1731     }
1732 }