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