removed MAX_CHAR_PER_FONT, made TTF support work.
[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  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #define TF_TEXTCONTROL  0x80
25 #define TF_HASFONT      0x08
26 #define TF_HASCOLOR     0x04
27 #define TF_HASYOFFSET   0x02
28 #define TF_HASXOFFSET   0x01
29
30 #define FF_WIDECODES    0x01
31 #define FF_BOLD         0x02
32 #define FF_ITALIC       0x04
33 #define FF_ANSI         0x08
34 #define FF_SHIFTJIS     0x10
35 #define FF_UNICODE      0x20
36
37 #define FF2_BOLD         0x01
38 #define FF2_ITALIC       0x02
39 #define FF2_WIDECODES    0x04
40 #define FF2_WIDEOFFSETS  0x08
41 #define FF2_ANSI         0x10
42 #define FF2_UNICODE      0x20
43 #define FF2_SHIFTJIS     0x40
44 #define FF2_LAYOUT       0x80
45
46 int swf_FontIsItalic(SWFFONT * f) { return f->style&FONT_STYLE_ITALIC;}
47 int swf_FontIsBold(SWFFONT * f)   { return f->style&FONT_STYLE_BOLD;}
48
49 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
50
51 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
52 { int n;
53   TAG * t;
54   if (!swf) return -1;
55   t = swf->firstTag;
56   n = 0;
57
58   while (t)
59   { if (swf_GetTagID(t)==ST_DEFINEFONTINFO || swf_GetTagID(t)==ST_DEFINEFONTINFO2 ||
60           swf_GetTagID(t)==ST_DEFINEFONT2)
61     { n++;
62       if (FontCallback)
63       { U16 id;
64         int l;
65         U8 s[257];
66         swf_SaveTagPos(t);
67         swf_SetTagPos(t,0);
68         
69         id  = swf_GetU16(t);
70         if(swf_GetTagID(t) == ST_DEFINEFONT2)
71             swf_GetU16(t);
72         l   = swf_GetU8(t);
73         swf_GetBlock(t,s,l);
74         s[l] = 0;
75
76         (FontCallback)(id,s); 
77       
78         swf_RestoreTagPos(t);
79       }
80     }
81     t = swf_NextTag(t);
82   }
83   return n;
84 }
85
86 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)
87 { U16 fid;
88   swf_SaveTagPos(t);
89   swf_SetTagPos(t,0);
90
91   fid = swf_GetU16(t);
92   if ((!id)||(id==fid))
93   { U16 of;
94     int n,i;
95       
96     id = fid;
97     f->version = 1;
98     f->id = fid;
99
100     of = swf_GetU16(t);
101     n = of/2;
102     f->numchars = n;
103     f->glyph = malloc(sizeof(SWFGLYPH)*n);
104     memset(f->glyph, 0, sizeof(SWFGLYPH)*n);
105
106     for (i=1;i<n;i++) swf_GetU16(t);
107     for (i=0;i<n;i++) swf_GetSimpleShape(t,&f->glyph[i].shape);
108   }
109
110   swf_RestoreTagPos(t);
111   return id;
112 }
113
114 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)
115 { U16 fid;
116   U16 maxcode;
117   U8 flags;
118   swf_SaveTagPos(t);
119   swf_SetTagPos(t,0);
120
121   fid = swf_GetU16(t);
122   if (fid==id)
123   { U8 l = swf_GetU8(t);
124     int i;
125   
126     if(f->version>1) {
127       /* Especially with Flash MX, DefineFont2 may have FontInfo fields,
128          too. However, they only add little information to what's already
129          inside the DefineFont2 tag */
130       return id;
131     }
132     
133     if (f->name) free(f->name);
134
135     f->name = (U8*)malloc(l+1);
136     swf_GetBlock(t,f->name,l);
137     f->name[l] = 0;
138     
139     flags = swf_GetU8(t);
140     if(flags & 2)
141         f->style |= FONT_STYLE_BOLD;
142     if(flags & 4)
143         f->style |= FONT_STYLE_ITALIC;
144     if(flags & 8)
145         f->encoding |= FONT_ENCODING_ANSI;
146     if(flags & 16)
147         f->encoding |= FONT_ENCODING_SHIFTJIS;
148     if(flags & 32)
149         f->encoding |= FONT_ENCODING_UNICODE;
150
151     if(t->id == ST_DEFINEFONTINFO2) {
152         f->language = swf_GetU8(t);
153     }
154
155     f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars);
156     maxcode = 0;
157     for(i=0; i < f->numchars; i++) {
158       f->glyph2ascii[i] = ((flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
159       if(f->glyph2ascii[i] > maxcode)
160           maxcode = f->glyph2ascii[i];
161     }
162     maxcode++;
163     if(maxcode<256)
164         maxcode=256;
165     f->maxascii = maxcode;
166     f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
167     memset(f->ascii2glyph, -1, sizeof(int)*maxcode);
168      
169     for(i = 0; i < f->numchars; i++)
170       f->ascii2glyph[f->glyph2ascii[i]] = i;
171   }
172
173   swf_RestoreTagPos(t);
174   return id;
175 }
176
177 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)
178 {
179     int t, glyphcount;
180     int maxcode;
181     int fid;
182     U8 flags1,flags2,namelen;
183     swf_SaveTagPos(tag);
184     swf_SetTagPos(tag,0);
185     font->version=2;
186     fid = swf_GetU16(tag);
187     if(id && id!=fid)
188         return id;
189     font->id = fid;
190     flags1 = swf_GetU8(tag);
191     flags2 = swf_GetU8(tag); //reserved flags
192
193     if(flags1 & 1)
194         font->style |= FONT_STYLE_BOLD;
195     if(flags1 & 2)
196         font->style |= FONT_STYLE_ITALIC;
197     if(flags1 & 16)
198         font->encoding |= FONT_ENCODING_ANSI;
199     if(flags1 & 32)
200         font->encoding |= FONT_ENCODING_UNICODE;
201     if(flags1 & 64)
202         font->encoding |= FONT_ENCODING_SHIFTJIS;
203
204     namelen = swf_GetU8(tag);
205     font->name = (U8*)malloc(namelen+1);
206     font->name[namelen]=0;
207     swf_GetBlock(tag, font->name, namelen);
208     font->version = 2;
209     glyphcount = swf_GetU16(tag);
210     font->numchars = glyphcount;
211     
212     font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
213     memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
214     font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount);
215     memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount);
216
217     if(flags1&8) { // wide offsets
218         for(t=0;t<glyphcount;t++)
219             swf_GetU32(tag); //offset[t]
220         
221         if(glyphcount) /* this _if_ is not in the specs */
222             swf_GetU32(tag); // fontcodeoffset
223     } else {
224         for(t=0;t<glyphcount;t++)
225             swf_GetU16(tag); //offset[t]
226
227         if(glyphcount) /* this _if_ is not in the specs */
228             swf_GetU16(tag); // fontcodeoffset
229     }
230     for(t=0;t<glyphcount;t++)
231         swf_GetSimpleShape(tag,&(font->glyph[t].shape));
232
233     maxcode = 0;
234     for(t=0;t<glyphcount;t++) {
235         int code;
236         if(flags1&4) // wide codes
237             code = swf_GetU16(tag);
238         else
239             code = swf_GetU8(tag);
240         font->glyph2ascii[t] = code;
241         if(code > maxcode)
242             maxcode = code;
243     }
244     maxcode++;
245     if(maxcode<256)
246         maxcode=256;
247     font->maxascii = maxcode;
248     font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
249     memset(font->ascii2glyph, -1, sizeof(int)*maxcode);
250     for(t=0;t<glyphcount;t++) 
251     {
252         font->ascii2glyph[font->glyph2ascii[t]] = t;
253     }
254
255     if(flags1&128) { // has layout
256         U16 kerningcount;
257         font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
258         font->layout->ascent=swf_GetU16(tag);
259         font->layout->descent=swf_GetU16(tag);
260         font->layout->leading=swf_GetU16(tag);
261         for(t=0;t<glyphcount;t++) {
262             S16 advance = swf_GetS16(tag);
263             font->glyph[t].advance = advance;
264         }
265         font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
266         for(t=0;t<glyphcount;t++) {
267             swf_ResetReadBits(tag);
268             swf_GetRect(tag, &font->layout->bounds[t]);
269         }
270
271         kerningcount = swf_GetU16(tag);
272         font->layout->kerningcount = kerningcount;
273
274         font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
275         if(kerningcount) {
276             font->layout->kerning = 
277                 malloc(sizeof(*font->layout->kerning)* kerningcount);
278             for(t=0;t<kerningcount;t++)
279             {
280                 if(flags1&4) { // wide codes
281                     font->layout->kerning[t].char1 = swf_GetU16(tag);
282                     font->layout->kerning[t].char2 = swf_GetU16(tag);
283                 } else {
284                     font->layout->kerning[t].char1 = swf_GetU8(tag);
285                     font->layout->kerning[t].char2 = swf_GetU8(tag);
286                 }
287                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
288             }
289         }
290     }
291     swf_RestoreTagPos(t);
292     return font->id;
293 }
294
295
296 #define FEDTJ_PRINT  0x01
297 #define FEDTJ_MODIFY 0x02
298 #define FEDTJ_CALLBACK 0x04
299
300 int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs, 
301         void(*callback)(int*chars, int nr, int fontid))
302 { U16    cid;
303   SRECT  r;
304   MATRIX m;
305   U8     gbits, abits, flags;
306   int    fid;
307
308   fid = 0;
309
310   swf_SaveTagPos(t);
311   swf_SetTagPos(t,0);
312
313   cid = swf_GetU16(t);
314   swf_GetRect(t,&r);
315   swf_GetMatrix(t,&m);
316   gbits = swf_GetU8(t);
317   abits = swf_GetU8(t);
318
319   flags = swf_GetU8(t);
320   
321   while(flags)
322   { 
323     // FIXME: according to open-swf@macromedia.com, this is wrong.
324     // it should alternate textcontrol and text arrays, not
325     // rely on the high bit. (and length can be 0-255).
326     if (flags&TF_TEXTCONTROL)
327     { if (flags&TF_HASFONT) fid = swf_GetU16(t);
328       if (flags&TF_HASCOLOR)
329       { swf_GetU8(t); // rgb
330         swf_GetU8(t);
331         swf_GetU8(t);
332         if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t);
333       }
334       if (flags&TF_HASXOFFSET) swf_GetS16(t);
335       if (flags&TF_HASYOFFSET) swf_GetS16(t);
336       if (flags&TF_HASFONT) swf_GetU16(t);
337     }
338     else
339     { int i;
340       int buf[256];
341       for (i=0;i<flags;i++)
342       { int glyph;
343         int adv;
344         glyph = swf_GetBits(t,gbits);
345         adv = swf_GetBits(t,abits);
346         if (id==fid)                    // mitlesen ?
347           if (jobs&FEDTJ_PRINT) {
348             { int code = f->glyph2ascii[glyph];
349               printf("%c",code);
350           }
351           if (jobs&FEDTJ_MODIFY)
352             /*if (!f->glyph[code].advance)*/ f->glyph[glyph].advance = adv;
353         }
354         buf[i] = glyph;
355       }
356       if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
357       if (jobs&FEDTJ_CALLBACK)
358           callback(buf, flags, fid);
359     }
360     flags = swf_GetU8(t);
361   }
362   
363   swf_RestoreTagPos(t);
364   return id;
365 }  
366
367 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
368 {
369     return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0);
370 }
371
372 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
373 { TAG * t;
374   SWFFONT * f;
375     
376   if ((!swf)||(!font)) return -1;
377
378   f = (SWFFONT *)malloc(sizeof(SWFFONT));
379   memset(f,0x00,sizeof(SWFFONT));
380
381   t = swf->firstTag;
382
383   while (t)
384   { int nid = 0;
385     switch (swf_GetTagID(t))
386     { case ST_DEFINEFONT:
387         nid = swf_FontExtract_DefineFont(id,f,t);
388         break;
389     
390       case ST_DEFINEFONT2:
391         nid = swf_FontExtract_DefineFont2(id,f,t);
392         break;
393         
394       case ST_DEFINEFONTINFO:
395       case ST_DEFINEFONTINFO2:
396         nid = swf_FontExtract_DefineFontInfo(id,f,t);
397         break;
398         
399       case ST_DEFINETEXT:
400       case ST_DEFINETEXT2:
401         nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
402         break;
403     }
404     if (nid>0) id = nid;
405     t = swf_NextTag(t);
406   }
407   if(f->id != id) {
408       free(f);
409       f=0;
410   }
411   font[0] = f;
412   return 0;
413 }
414
415 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
416
417 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
418 { int i,j;
419   if ((!f)||(!use)) return -1;
420
421   j = 0;
422   for (i=0;i<f->numchars;i++)
423     if (f->glyph[i].shape)
424     { if (f->glyph2ascii[i]<f->numchars&& 
425             use->code[f->glyph2ascii[i]])
426       { f->ascii2glyph[f->glyph2ascii[i]] = j;
427         f->glyph2ascii[j] = f->glyph2ascii[i];
428         f->glyph[j] = f->glyph[i];
429         j++;
430       }
431       else
432       { swf_ShapeFree(f->glyph[i].shape);
433         f->ascii2glyph[f->glyph2ascii[i]] = -1;
434         f->glyph2ascii[i] = 0;
435         f->glyph[i].shape   = NULL;
436         f->glyph[i].advance = 0;
437       }
438     } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
439
440   f->numchars = j;
441     
442   return j;
443 }
444
445 int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use)
446 { if (!use) return -1;
447   use->code = malloc(sizeof(use->code[0])*f->numchars);
448   memset(use->code,0,sizeof(use->code[0])*f->numchars);
449   return 0;
450 }
451
452 void swf_FontClearUsage(SWFFONT* f, FONTUSAGE * use)
453 { if (!use) return;
454   free(use->code);
455 }
456
457 int swf_FontUse(FONTUSAGE * use,U8 * s)
458 { if ((!use)||(!s)) return -1;
459   while (s[0])
460   { use->code[s[0]] = 1;
461     s++;
462   }
463   return 0;  
464 }
465
466 int swf_FontSetDefine(TAG * t,SWFFONT * f)
467 { U16*ofs = (U16*)malloc(f->numchars*2);
468   int p,i,j;
469     
470   if ((!t)||(!f)) return -1;
471   swf_ResetWriteBits(t);
472   swf_SetU16(t,f->id);
473
474   p = 0; j = 0;
475   for (i=0;i<f->numchars;i++)
476     if (f->glyph[i].shape)
477     { ofs[j++] = p;
478       p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
479     }
480
481   for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
482   if(!j) {
483       fprintf(stderr, "rfxswf: warning: Font is empty\n");
484       swf_SetU16(t, 0);
485   }
486   
487   for (i=0;i<f->numchars;i++)
488     if (f->glyph[i].shape)
489       swf_SetSimpleShape(t,f->glyph[i].shape);
490   
491   swf_ResetWriteBits(t);
492   free(ofs);
493   return 0;
494 }
495
496 static inline int fontSize(SWFFONT*font)
497 {
498     int t;
499     int size = 0;
500     for(t=0;t<font->numchars;t++) {
501         int l = (font->glyph[t].shape->bitlen+7)/8;
502         size += l+1;
503     }
504     return size + (font->numchars+1)*2;
505 }
506
507 int swf_FontSetDefine2(TAG *tag, SWFFONT * f)
508 {
509     U8 flags = 0;
510     int t;
511     int pos;
512     int pos2;
513     swf_SetU16(tag, f->id);
514
515     if(f->layout) 
516         flags |= 128; // haslayout
517     if(f->numchars>256)
518         flags |= 4; // widecodes
519     if(f->style & FONT_STYLE_BOLD)
520         flags |= 1; // bold
521     if(f->style & FONT_STYLE_ITALIC)
522         flags |= 2; // italic
523     if(f->maxascii>=256)
524         flags |= 4; //wide codecs
525     if(fontSize(f)>65535)
526         flags |= 8; //wide offsets
527     flags |= 8; //FIXME: the above check doesn't work
528
529     if(f->encoding & FONT_ENCODING_ANSI)
530         flags |= 16; // ansi
531     if(f->encoding & FONT_ENCODING_UNICODE)
532         flags |= 32; // unicode
533     if(f->encoding & FONT_ENCODING_SHIFTJIS)
534         flags |= 64; // shiftjis
535
536     swf_SetU8(tag, flags);
537     swf_SetU8(tag, 0); //reserved flags
538     if(f->name) {
539         /* font name */
540         swf_SetU8(tag, strlen(f->name));
541         swf_SetBlock(tag, f->name, strlen(f->name));
542     } else {
543         /* font name (="") */
544         swf_SetU8(tag, 0); /*placeholder*/
545     }
546     /* number of glyphs */
547     swf_SetU16(tag, f->numchars);
548     /* font offset table */
549     pos = tag->len;
550     for(t=0;t<=f->numchars;t++)
551     {
552         if(flags&8)
553             swf_SetU32(tag, /* fontoffset */ 0); /*placeholder*/
554         else
555             swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/
556     }
557
558     for(t=0;t<=f->numchars;t++) {
559         if(flags&8) {
560             tag->data[pos + t*4    ] = (tag->len-pos);
561             tag->data[pos + t*4 + 1] = (tag->len-pos) >> 8;
562             tag->data[pos + t*4 + 2] = (tag->len-pos) >> 16;
563             tag->data[pos + t*4 + 3] = (tag->len-pos) >> 24;
564         } else {
565             if(tag->len - pos > 65535) {
566                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
567                 exit(1);
568             }
569             tag->data[pos + t*2    ] = (tag->len-pos);
570             tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8;
571         }
572         if(t<f->numchars)
573             swf_SetSimpleShape(tag, f->glyph[t].shape);
574     }
575
576     
577     /* font code table */
578     if(flags & 4) /* wide codes */ {
579         for(t=0;t<f->numchars;t++) {
580             swf_SetU16(tag,f->glyph2ascii[t]);
581         }
582     } else {
583         for(t=0;t<f->numchars;t++)
584             swf_SetU8(tag,f->glyph2ascii[t]);
585     }
586     if(f->layout) 
587     {
588         swf_SetU16(tag,f->layout->ascent);
589         swf_SetU16(tag,f->layout->descent);
590         swf_SetU16(tag,f->layout->leading);
591         for(t=0;t<f->numchars;t++)
592             swf_SetU16(tag,f->glyph[t].advance);
593         for(t=0;t<f->numchars;t++) {
594             swf_ResetWriteBits(tag);
595             swf_SetRect(tag,&f->layout->bounds[t]);
596         }
597         swf_SetU16(tag, f->layout->kerningcount);
598         for(t=0;t<f->layout->kerningcount;t++) {
599             if(flags & 4) /* wide codes */ {
600                 swf_SetU16(tag,f->layout->kerning[t].char1);
601                 swf_SetU16(tag,f->layout->kerning[t].char2);
602             } else {
603                 swf_SetU8(tag,f->layout->kerning[t].char1);
604                 swf_SetU8(tag,f->layout->kerning[t].char2);
605             }
606             swf_SetU16(tag,f->layout->kerning[t].adjustment);
607         }
608     }
609     return 0;
610 }
611     
612 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
613 {
614     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
615     f->layout->ascent = ascent;
616     f->layout->descent = descent;
617     f->layout->leading = leading;
618     f->layout->kerningcount = 0;
619     f->layout->kerning = 0;
620     f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars);
621     memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars);
622 }
623
624 int swf_FontSetInfo(TAG * t,SWFFONT * f)
625 { int l,i;
626   U8 wide=0;
627   U8 flags = 0;
628   if ((!t)||(!f)) return -1;
629   swf_ResetWriteBits(t);
630   swf_SetU16(t,f->id);
631   l = f->name?strlen(f->name):0; if (l>255) l = 255;
632   swf_SetU8(t,l);
633   if(l)
634     swf_SetBlock(t,f->name,l);
635   if(f->numchars>=256)
636       wide=1;
637
638   if(f->style & FONT_STYLE_BOLD)
639       flags |= 2;
640   if(f->style & FONT_STYLE_ITALIC)
641       flags |= 4;
642   if(f->style & FONT_ENCODING_ANSI)
643       flags |= 8;
644   if(f->style & FONT_ENCODING_SHIFTJIS)
645       flags |= 16;
646   if(f->style & FONT_ENCODING_UNICODE)
647       flags |= 32;
648     
649   swf_SetU8(t,(flags&0xfe)|wide);
650
651   for (i=0;i<f->numchars;i++) {
652     if (f->glyph[i].shape)
653       wide?swf_SetU16(t,f->glyph2ascii[i]):
654            swf_SetU8(t,f->glyph2ascii[i]);
655   }
656   
657   return 0;
658 }
659
660 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
661 { int id = swf_GetTagID(t);
662   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
663     else return -1;
664   return 0;
665 }
666
667 void swf_LayoutFree(SWFLAYOUT * l)
668 { if (l)
669   { if (l->kerning) free(l->kerning);
670     l->kerning = NULL;
671     if (l->bounds) free(l->bounds);
672     l->bounds = NULL;
673   }
674   free(l);
675 }
676
677 void swf_FontFree(SWFFONT * f)
678 { if (f)
679   { int i;
680       
681     if (f->name) free(f->name);
682     if (f->layout) swf_LayoutFree(f->layout);
683
684     f->name = NULL;
685     f->layout = NULL;
686
687     if(f->glyph) {
688       for (i=0;i<f->numchars;i++)
689         if (f->glyph[i].shape)
690         { swf_ShapeFree(f->glyph[i].shape);
691           f->glyph[i].shape = NULL;
692         }
693       free(f->glyph);
694       f->glyph = NULL;
695     }
696     if(f->ascii2glyph) {
697       free(f->ascii2glyph);
698       f->ascii2glyph = NULL;
699     }
700     if(f->glyph2ascii) {
701       free(f->glyph2ascii);
702       f->glyph2ascii = NULL;
703     }
704     if(f->glyphnames) {
705       int t;
706       for(t=0;t<f->numchars;t++) {
707         free(f->glyphnames[t]);
708       }
709       free(f->glyphnames);
710     }
711   }
712   free(f);
713 }
714
715 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,int dy)
716 { U8 flags;
717   if (!t) return -1;
718
719   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
720
721   swf_SetU8(t,flags);
722   if (font) swf_SetU16(t,font->id);
723   if (color)
724   { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
725     else swf_SetRGB(t,color);
726   }
727   if (dx) swf_SetS16(t,dx);
728   if (dy) swf_SetS16(t,dy);
729   if (font) swf_SetU16(t,size);
730   
731   return 0;
732 }
733
734 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
735 { U16 g,a;
736   if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
737   g = a = 0;
738
739   while(s[0])
740   { 
741     int glyph = -1;
742     if(s[0] < font->maxascii)
743         glyph = font->ascii2glyph[s[0]];
744     if(glyph>=0) {
745        g = swf_CountUBits(glyph,g);
746        a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
747     }
748     s++;
749   }
750
751   if (gbits) gbits[0] = (U8)g;
752   if (abits) abits[0] = (U8)a;
753
754   return 0;
755 }
756
757 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
758 { int l=0,i,pos;
759     
760   if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
761
762   pos = t->len;
763   swf_SetU8(t, l); //placeholder
764
765   for (i=0;s[i];i++)
766   { 
767     int g = -1;
768     if(s[i] < font->maxascii) 
769         g = font->ascii2glyph[s[i]];
770     if(g>=0) {
771       swf_SetBits(t,g,gbits);
772       swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
773       l++;
774       if(l==0x7f)
775           break;
776     }
777   }
778
779   PUT8(&t->data[pos], l);
780
781   swf_ResetWriteBits(t);
782   return 0;
783 }
784
785 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
786 { U32 res = 0;
787
788   if (font&&s)
789   { while (s[0])
790     { 
791       int g = -1;
792       if(*s < font->maxascii) 
793           g = font->ascii2glyph[*s];
794       if(g>=0)
795         res += font->glyph[g].advance;
796       s++;
797     }
798     if (scale) res = (res*scale)/100;
799   }
800   return res;
801 }
802
803 SWFFONT* swf_ReadFont(char* filename)
804 {
805   int f;
806   SWF swf;
807   if(!filename)
808       return 0;
809   f = open(filename,O_RDONLY);
810   
811   if (f<0 || swf_ReadSWF(f,&swf)<0)
812   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
813     close(f);
814     return 0;
815   }
816   else
817   { SWFFONT*font;
818     close(f);
819     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
820        return 0;
821     swf_FreeTags(&swf);
822     return font;
823   }
824 }
825
826 void swf_WriteFont(SWFFONT*font, char* filename)
827 { SWF swf;
828   TAG * t;
829   SRECT r;
830   RGBA rgb;
831   int f;
832   int useDefineFont2 = 0;
833
834   if(font->layout)
835       useDefineFont2 = 1; /* the only thing new in definefont2 
836                              is layout information. */
837
838   font->id = WRITEFONTID; //"FN"
839
840   memset(&swf,0x00,sizeof(SWF));
841
842   swf.fileVersion    = 4;
843   swf.frameRate      = 0x4000;
844
845   /* if we use DefineFont1 to store the characters,
846      we have to build a textfield to store the
847      advance values. While at it, we can also
848      make the whole .swf viewable */
849
850   /* we now always create viewable swfs, even if we
851      did use definefont2 -mk*/
852   t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
853   swf.firstTag = t;
854         rgb.r = 0xef;
855         rgb.g = 0xef;
856         rgb.b = 0xff;
857         swf_SetRGB(t,&rgb);
858   if(!useDefineFont2) {
859     t = swf_InsertTag(t,ST_DEFINEFONT);
860     swf_FontSetDefine(t,font);
861     t = swf_InsertTag(t,ST_DEFINEFONTINFO);
862     swf_FontSetInfo(t,font);
863   } else {
864     t = swf_InsertTag(t,ST_DEFINEFONT2);
865     swf_FontSetDefine2(t,font);
866   }
867
868   if(1) //neccessary only for df1, but pretty to look at anyhow, so do it always
869   {
870         int textscale = 400;
871         int s;
872         int xmax = 0;
873         int ymax = 0;
874         int ypos = 1;
875         U8 gbits,abits;
876         int x,y,c;
877         
878         c=0;
879         for(s=0;s<font->maxascii;s++)
880         {
881             int g = font->ascii2glyph[s];
882             if(g>=0) {
883                if(font->glyph[g].advance*textscale/64 > xmax) {
884                    xmax = font->glyph[g].advance*textscale/64;
885                }
886                c++;
887             }
888             if((s&15)==0) {
889                 if(c) {
890                     ypos++;
891                 }
892                 c=0;
893             }
894         }
895         ymax = ypos*textscale*2;
896
897         swf.movieSize.xmax = xmax*20;
898         swf.movieSize.ymax = ymax;
899
900         t = swf_InsertTag(t,ST_DEFINETEXT);
901
902             swf_SetU16(t,font->id+1);            // ID
903
904             r.xmin = 0;
905             r.ymin = 0;
906             r.xmax = swf.movieSize.xmax;
907             r.ymax = swf.movieSize.ymax;
908             
909             swf_SetRect(t,&r);
910
911             swf_SetMatrix(t,NULL);
912
913             abits = swf_CountBits(xmax*16, 0);
914             gbits = 8;
915             
916             swf_SetU8(t,gbits);
917             swf_SetU8(t,abits);
918
919             rgb.r = 0x00;
920             rgb.g = 0x00;
921             rgb.b = 0x00;
922             ypos = 1;
923             for(y=0;y<((font->maxascii+15)/16);y++)
924             {
925                 int c=0,lastx=-1;
926                 for(x=0;x<16;x++) {
927                     int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
928                     if(g>=0 && font->glyph[g].shape) {
929                         c++;
930                         if(lastx<0) 
931                             lastx = x*xmax;
932                     }
933                 }
934                 if(c) {
935                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2);
936                   for(x=0;x<16;x++)
937                   {
938                       int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
939                       if(g>=0 && font->glyph[g].shape) {
940                         if(lastx != x*xmax) {
941                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
942                         }
943                         swf_SetU8(t,1);
944                         swf_SetBits(t, g, gbits);
945                         swf_SetBits(t, font->glyph[g].advance, abits);
946                         lastx = x*xmax+font->glyph[g].advance;
947                         swf_ResetWriteBits(t);
948                       }
949                   }
950                   ypos++;
951                 } 
952             }
953             swf_SetU8(t,0);
954
955         
956         t = swf_InsertTag(t,ST_PLACEOBJECT2);
957
958             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
959      
960         t = swf_InsertTag(t,ST_SHOWFRAME);
961
962   }
963   
964   t = swf_InsertTag(t,ST_END);
965
966   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
967   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
968   close(f);
969
970   swf_FreeTags(&swf);
971 }
972
973
974 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, 
975         int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
976 {
977     swf_SetRect(tag,&r);
978     swf_ResetWriteBits(tag);
979
980     flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
981     if(text) flags |= ET_HASTEXT;
982     if(color) flags |= ET_HASTEXTCOLOR;
983     if(maxlength) flags |= ET_HASMAXLENGTH;
984     if(font) flags |= ET_HASFONT;
985     if(layout) flags |= ET_HASLAYOUT;
986
987     swf_SetBits(tag, flags, 16);
988
989     if(flags & ET_HASFONT) {
990         swf_SetU16(tag, font); //font
991         swf_SetU16(tag, height); //fontheight
992     }
993     if(flags & ET_HASTEXTCOLOR) {
994         swf_SetRGBA(tag, color);
995     }
996     if(flags & ET_HASMAXLENGTH) {
997         swf_SetU16(tag, maxlength); //maxlength
998     }
999     if(flags & ET_HASLAYOUT) {
1000         swf_SetU8(tag,layout->align); //align
1001         swf_SetU16(tag,layout->leftmargin); //left margin
1002         swf_SetU16(tag,layout->rightmargin); //right margin
1003         swf_SetU16(tag,layout->indent); //indent
1004         swf_SetU16(tag,layout->leading); //leading
1005     }
1006     swf_SetString(tag, variable);
1007     if(flags & ET_HASTEXT)
1008         swf_SetString(tag,text);
1009 }
1010
1011 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
1012 {
1013     SRECT r;
1014     U8 gbits, abits;
1015     U8*c = (U8*)text;
1016     int pos = 0;
1017     swf_GetRect(0, &r);
1018     if(font->layout) {
1019         while(*c) {
1020             if(*c < font->maxascii) {
1021                 int g = font->ascii2glyph[*c];
1022                 if(g>=0) {
1023                     SRECT rn = font->layout->bounds[g];
1024                     rn.xmin = (rn.xmin * scale)/100 + pos;
1025                     rn.xmax = (rn.xmax * scale)/100 + pos;
1026                     rn.ymin = (rn.ymin * scale)/100;
1027                     rn.ymax = (rn.ymax * scale)/100;
1028                     swf_ExpandRect2(&r, &rn);
1029                     pos += (font->glyph[g].advance*scale*20)/100;
1030                 }
1031             }
1032             c++;
1033         }
1034     } else {
1035         /* Hm, without layout information, we can't compute a bounding
1036            box. We could call swf_FontCreateLayout to create a layout,
1037            but the caller probably doesn't want us to mess up his font
1038            structure.
1039         */
1040         r.xmin = r.ymin = 0;
1041         r.xmax = r.ymax = 1024*20;
1042     }
1043
1044     swf_SetRect(tag,&r);
1045     swf_SetMatrix(tag,NULL);
1046     swf_TextCountBits(font,text,scale*20,&gbits,&abits);
1047     swf_SetU8(tag,gbits);
1048     swf_SetU8(tag,abits);
1049
1050     /* now set the text params- notice that a font size of
1051        1024 means that the glyphs will be displayed exactly
1052        as they would be in/with a defineshape. (Try to find
1053        *that* in the flash specs)
1054      */
1055     swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
1056
1057     /* set the actual text- notice that we just pass our scale
1058        parameter over, as TextSetCharRecord calculates with 
1059        percent, too */
1060     swf_TextSetCharRecord(tag,font,text,scale*20,gbits,abits);
1061
1062     swf_SetU8(tag,0);
1063     return r;
1064 }
1065
1066 void swf_FontCreateLayout(SWFFONT*f)
1067 {
1068     S16 leading = 0;
1069     int t;
1070     if(f->layout)
1071         return;
1072     if(!f->numchars)
1073         return;
1074     
1075     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1076     memset(f->layout, 0, sizeof(SWFLAYOUT));
1077     f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1078     f->layout->ascent = -32767;
1079     f->layout->descent = -32767;
1080
1081     for(t=0;t<f->numchars;t++) {
1082         SHAPE2*shape2;
1083         SRECT bbox;
1084         int width;
1085         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1086         if(!shape2) { 
1087             fprintf(stderr, "Shape parse error\n");exit(1);
1088         }
1089         bbox = swf_GetShapeBoundingBox(shape2);
1090         swf_Shape2Free(shape2);
1091         f->layout->bounds[t] = bbox;
1092         /* FIXME */
1093         //width = (bbox.xmax - bbox.xmin)/20;
1094         width = (bbox.xmax)/20;
1095
1096         /* The following is a heuristic- it may be that extractfont_DefineText
1097            has already found out some widths for individual characters (from the way
1098            they are used)- we now have to guess whether that width might be possible,
1099            which is the case if it isn't either much too big or much too small */
1100         if(width > f->glyph[t].advance*3/2 ||
1101            width*2 < f->glyph[t].advance)
1102             f->glyph[t].advance = width;
1103
1104         if(-bbox.ymin > f->layout->ascent)
1105             f->layout->ascent = bbox.ymin;
1106         if(bbox.ymax > f->layout->descent)
1107             f->layout->descent = bbox.ymax;
1108     }
1109 }
1110         
1111 static U32 readUTF8char(char**text)
1112 {
1113     U32 c = 0;
1114     if(!(*(*text) & 0x80))
1115         return *((*text)++);
1116
1117     /* 0000 0080-0000 07FF   110xxxxx 10xxxxxx */
1118     if(((*text)[0] & 0xe0) == 0xc0 && (*text)[1])  
1119     {
1120         c = ((*text)[0] & 0x1f) << 6 | ((*text)[1] & 0x3f);
1121         (*text) += 2;
1122         return c;
1123     }
1124     /* 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx */
1125     if(((*text)[0] & 0xf0) == 0xe0 && (*text)[1] && (*text)[2])
1126     {
1127         c = ((*text)[0] & 0x0f) << 12 | ((*text)[1] & 0x3f) << 6 | ((*text)[2] & 0x3f);
1128         (*text) += 3;
1129         return c;
1130     }
1131     /* 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
1132     if(((*text)[0] & 0xf8) == 0xf0 && (*text)[1] && (*text)[2] && (*text)[3] )  
1133     {
1134         c = ((*text)[0] & 0x07) << 18 | ((*text)[1] & 0x3f) << 12 | ((*text)[2] & 0x3f)<<6 | ((*text)[3] & 0x3f);
1135         (*text) += 4;
1136         return c;
1137     }
1138     /* 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
1139     if(((*text)[0] & 0xfc) == 0xf8 && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4])  
1140     {
1141         c = ((*text)[0] & 0x03) << 24 | ((*text)[1] & 0x3f) << 18 | ((*text)[2] & 0x3f)<<12 | ((*text)[3] & 0x3f) << 6 | ((*text)[4] & 0x3f);
1142         (*text) += 5;
1143         return c;
1144     }
1145     /* 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx */
1146     if(((*text)[0] & 0xfe) == 0xfc && (*text)[1] && (*text)[2] && (*text)[3] && (*text)[4] && (*text)[5])  
1147     {
1148         c = ((*text)[0] & 0x01) << 30 | ((*text)[1] & 0x3f) << 24 | ((*text)[2] & 0x3f)<<18 | ((*text)[3] & 0x3f) << 12 | ((*text)[4] & 0x3f) << 6  | ((*text)[5] & 0x3f) << 6;
1149         (*text) += 6;
1150         return c;
1151     }
1152     return *((*text)++);
1153 }
1154
1155 void swf_DrawText(drawer_t*draw, SWFFONT*font, char*text)
1156 {
1157     char*s = text;
1158     int advance = 0;
1159     while(*s) {
1160         SHAPE*shape;
1161         SHAPE2*shape2;
1162         U32 c = readUTF8char(&s);
1163         int g = font->ascii2glyph[c];
1164         shape = font->glyph[g].shape;
1165         shape2 = swf_ShapeToShape2(shape);
1166         SHAPELINE*l = shape2->lines;
1167         while(l) {
1168             if(l->type == moveTo) {
1169                 FPOINT to;
1170                 to.x = l->x/20.0+advance;
1171                 to.y = l->y/20.0;
1172                 draw->moveTo(draw, &to);
1173             } else if(l->type == lineTo) {
1174                 FPOINT to;
1175                 to.x = l->x/20.0+advance;
1176                 to.y = l->y/20.0;
1177                 draw->lineTo(draw, &to);
1178             } else if(l->type == splineTo) {
1179                 FPOINT mid,to;
1180                 mid.x = l->sx/20.0+advance;
1181                 mid.y = l->sy/20.0;
1182                 to.x = l->x/20.0+advance;
1183                 to.y = l->y/20.0;
1184                 draw->splineTo(draw, &mid, &to);
1185             }
1186             l = l->next;
1187         }
1188         swf_Shape2Free(shape2);
1189         advance += font->glyph[g].advance;
1190     }
1191 }
1192
1193