fixed UTF8 bounding box calculation.
[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 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale)
934 {
935     int pos=0;
936     SRECT r;
937     swf_GetRect(0, &r);
938     while(*s) {
939         int c = readUTF8char(&s);
940         if(c < font->maxascii) {
941             int g = font->ascii2glyph[c];
942             if(g>=0) {
943                 SRECT rn = font->layout->bounds[g];
944                 rn.xmin = (rn.xmin * scale)/20/100 + pos;
945                 rn.xmax = (rn.xmax * scale)/20/100 + pos;
946                 rn.ymin = (rn.ymin * scale)/20/100;
947                 rn.ymax = (rn.ymax * scale)/20/100;
948                 swf_ExpandRect2(&r, &rn);
949                 pos += (font->glyph[g].advance*scale)/20/100;
950             }
951         }
952         c++;
953     }
954     return r;
955 }
956
957
958 SWFFONT* swf_ReadFont(char* filename)
959 {
960   int f;
961   SWF swf;
962   if(!filename)
963       return 0;
964   f = open(filename,O_RDONLY);
965   
966   if (f<0 || swf_ReadSWF(f,&swf)<0)
967   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
968     close(f);
969     return 0;
970   }
971   else
972   { SWFFONT*font;
973     close(f);
974     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
975        return 0;
976     swf_FreeTags(&swf);
977     return font;
978   }
979 }
980
981 void swf_WriteFont(SWFFONT*font, char* filename)
982 { SWF swf;
983   TAG * t;
984   SRECT r;
985   RGBA rgb;
986   int f;
987   int useDefineFont2 = 0;
988   int storeGlyphNames = 1;
989
990   if(font->layout)
991       useDefineFont2 = 1; /* the only thing new in definefont2 
992                              is layout information. */
993
994   font->id = WRITEFONTID; //"FN"
995
996   memset(&swf,0x00,sizeof(SWF));
997
998   swf.fileVersion    = 4;
999   swf.frameRate      = 0x4000;
1000
1001   /* if we use DefineFont1 to store the characters,
1002      we have to build a textfield to store the
1003      advance values. While at it, we can also
1004      make the whole .swf viewable */
1005
1006   /* we now always create viewable swfs, even if we
1007      did use definefont2 -mk*/
1008   t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1009   swf.firstTag = t;
1010         rgb.r = 0xef;
1011         rgb.g = 0xef;
1012         rgb.b = 0xff;
1013         swf_SetRGB(t,&rgb);
1014   if(!useDefineFont2) {
1015     t = swf_InsertTag(t,ST_DEFINEFONT);
1016     swf_FontSetDefine(t,font);
1017     t = swf_InsertTag(t,ST_DEFINEFONTINFO);
1018     swf_FontSetInfo(t,font);
1019   } else {
1020     t = swf_InsertTag(t,ST_DEFINEFONT2);
1021     swf_FontSetDefine2(t,font);
1022   }
1023
1024   if(storeGlyphNames && font->glyphnames)
1025   {
1026     int c;
1027     t = swf_InsertTag(t,ST_GLYPHNAMES);
1028     swf_SetU16(t, WRITEFONTID);
1029     swf_SetU16(t, font->numchars);
1030     for(c=0;c<font->numchars;c++) {
1031         swf_SetString(t, font->glyphnames[c]);
1032     }
1033   }
1034
1035   if(1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1036   {
1037         int textscale = 400;
1038         int s;
1039         int xmax = 0;
1040         int ymax = 0;
1041         int ypos = 1;
1042         U8 gbits,abits;
1043         int x,y,c;
1044         int range = font->maxascii;
1045         
1046         c=0;
1047         if(useDefineFont2 && range > 256) {
1048             range = 256;
1049         }
1050
1051         for(s=0;s<range;s++)
1052         {
1053             int g = font->ascii2glyph[s];
1054             if(g>=0) {
1055                if((font->glyph[g].advance*textscale/20)/64 > xmax) {
1056                    xmax = (font->glyph[g].advance*textscale/20)/64;
1057                }
1058                c++;
1059             }
1060             if((s&15)==0) {
1061                 if(c) {
1062                     ypos++;
1063                 }
1064                 c=0;
1065             }
1066         }
1067         ymax = ypos*textscale*2;
1068
1069         swf.movieSize.xmax = xmax*20;
1070         swf.movieSize.ymax = ymax;
1071
1072         t = swf_InsertTag(t,ST_DEFINETEXT);
1073
1074             swf_SetU16(t,font->id+1);            // ID
1075
1076             r.xmin = 0;
1077             r.ymin = 0;
1078             r.xmax = swf.movieSize.xmax;
1079             r.ymax = swf.movieSize.ymax;
1080             
1081             swf_SetRect(t,&r);
1082
1083             swf_SetMatrix(t,NULL);
1084
1085             abits = swf_CountBits(xmax*16, 0);
1086             gbits = 8;
1087             
1088             swf_SetU8(t,gbits);
1089             swf_SetU8(t,abits);
1090
1091             rgb.r = 0x00;
1092             rgb.g = 0x00;
1093             rgb.b = 0x00;
1094             ypos = 1;
1095             for(y=0;y<((range+15)/16);y++)
1096             {
1097                 int c=0,lastx=-1;
1098                 for(x=0;x<16;x++) {
1099                     int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1100                     if(g>=0 && font->glyph[g].shape) {
1101                         c++;
1102                         if(lastx<0) 
1103                             lastx = x*xmax;
1104                     }
1105                 }
1106                 if(c) {
1107                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2);
1108                   for(x=0;x<16;x++)
1109                   {
1110                       int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1111                       if(g>=0 && font->glyph[g].shape) {
1112                         if(lastx != x*xmax) {
1113                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
1114                         }
1115                         swf_SetU8(t,1);
1116                         swf_SetBits(t, g, gbits);
1117                         swf_SetBits(t, font->glyph[g].advance/20, abits);
1118                         lastx = x*xmax+(font->glyph[g].advance/20);
1119                         swf_ResetWriteBits(t);
1120                       }
1121                   }
1122                   ypos++;
1123                 } 
1124             }
1125             swf_SetU8(t,0);
1126
1127         
1128         t = swf_InsertTag(t,ST_PLACEOBJECT2);
1129
1130             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
1131      
1132         t = swf_InsertTag(t,ST_SHOWFRAME);
1133
1134   }
1135   
1136   t = swf_InsertTag(t,ST_END);
1137
1138   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
1139   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
1140   close(f);
1141
1142   swf_FreeTags(&swf);
1143 }
1144
1145
1146 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, 
1147         int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
1148 {
1149     swf_SetRect(tag,&r);
1150     swf_ResetWriteBits(tag);
1151
1152     flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
1153     if(text) flags |= ET_HASTEXT;
1154     if(color) flags |= ET_HASTEXTCOLOR;
1155     if(maxlength) flags |= ET_HASMAXLENGTH;
1156     if(font) flags |= ET_HASFONT;
1157     if(layout) flags |= ET_HASLAYOUT;
1158
1159     swf_SetBits(tag, flags, 16);
1160
1161     if(flags & ET_HASFONT) {
1162         swf_SetU16(tag, font); //font
1163         swf_SetU16(tag, height); //fontheight
1164     }
1165     if(flags & ET_HASTEXTCOLOR) {
1166         swf_SetRGBA(tag, color);
1167     }
1168     if(flags & ET_HASMAXLENGTH) {
1169         swf_SetU16(tag, maxlength); //maxlength
1170     }
1171     if(flags & ET_HASLAYOUT) {
1172         swf_SetU8(tag,layout->align); //align
1173         swf_SetU16(tag,layout->leftmargin); //left margin
1174         swf_SetU16(tag,layout->rightmargin); //right margin
1175         swf_SetU16(tag,layout->indent); //indent
1176         swf_SetU16(tag,layout->leading); //leading
1177     }
1178     swf_SetString(tag, variable);
1179     if(flags & ET_HASTEXT)
1180         swf_SetString(tag,text);
1181 }
1182
1183 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
1184 {
1185     SRECT r;
1186     U8 gbits, abits;
1187     U8*c = (U8*)text;
1188     int pos = 0;
1189     if(font->layout) {
1190         r = swf_TextCalculateBBoxUTF8(font,text,scale*20);
1191     } else {
1192         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1193         /* Hm, without layout information, we can't compute a bounding
1194            box. We could call swf_FontCreateLayout to create a layout,
1195            but the caller probably doesn't want us to mess up his font
1196            structure.
1197         */
1198         r.xmin = r.ymin = 0;
1199         r.xmax = r.ymax = 1024*20;
1200     }
1201
1202     swf_SetRect(tag,&r);
1203     swf_SetMatrix(tag,NULL);
1204     swf_TextCountBitsUTF8(font,text,scale*20,&gbits,&abits);
1205     swf_SetU8(tag,gbits);
1206     swf_SetU8(tag,abits);
1207
1208     /* now set the text params- notice that a font size of
1209        1024 means that the glyphs will be displayed exactly
1210        as they would be in/with a defineshape. (Try to find
1211        *that* in the flash specs)
1212      */
1213     swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
1214
1215     /* set the actual text- notice that we just pass our scale
1216        parameter over, as TextSetCharRecord calculates with 
1217        percent, too */
1218     swf_TextSetCharRecordUTF8(tag,font,text,scale*20,gbits,abits);
1219
1220     swf_SetU8(tag,0);
1221     return r;
1222 }
1223
1224 void swf_FontCreateLayout(SWFFONT*f)
1225 {
1226     S16 leading = 0;
1227     int t;
1228     if(f->layout)
1229         return;
1230     if(!f->numchars)
1231         return;
1232     
1233     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1234     memset(f->layout, 0, sizeof(SWFLAYOUT));
1235     f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1236     f->layout->ascent = -32767;
1237     f->layout->descent = -32767;
1238
1239     for(t=0;t<f->numchars;t++) {
1240         SHAPE2*shape2;
1241         SRECT bbox;
1242         int width;
1243         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1244         if(!shape2) { 
1245             fprintf(stderr, "Shape parse error\n");exit(1);
1246         }
1247         bbox = swf_GetShapeBoundingBox(shape2);
1248         swf_Shape2Free(shape2);
1249         f->layout->bounds[t] = bbox;
1250         
1251         width = (bbox.xmax);
1252
1253         /* The following is a heuristic- it may be that extractfont_DefineText
1254            has already found out some widths for individual characters (from the way
1255            they are used)- we now have to guess whether that width might be possible,
1256            which is the case if it isn't either much too big or much too small */
1257         if(width > f->glyph[t].advance*3/2 ||
1258            width*2 < f->glyph[t].advance)
1259             f->glyph[t].advance = width;
1260
1261         if(-bbox.ymin > f->layout->ascent)
1262             f->layout->ascent = bbox.ymin;
1263         if(bbox.ymax > f->layout->descent)
1264             f->layout->descent = bbox.ymax;
1265     }
1266 }
1267         
1268 void swf_DrawText(drawer_t*draw, SWFFONT*font, int size, char*text)
1269 {
1270     U8*s = (U8*)text;
1271     int advance = 0;
1272     while(*s) {
1273         SHAPE*shape;
1274         SHAPE2*shape2;
1275         SHAPELINE*l;
1276         U32 c = readUTF8char(&s);
1277         int g = font->ascii2glyph[c];
1278         shape = font->glyph[g].shape;
1279         if(((int)g)<0) {
1280             fprintf(stderr, "No char %d in font %s\n", c, font->name?(char*)font->name:"?");
1281             continue;
1282         }
1283         shape2 = swf_ShapeToShape2(shape);
1284         l = shape2->lines;
1285         while(l) {
1286             if(l->type == moveTo) {
1287                 FPOINT to;
1288                 to.x = l->x*size/100.0/20.0+advance;
1289                 to.y = l->y*size/100.0/20.0;
1290                 draw->moveTo(draw, &to);
1291             } else if(l->type == lineTo) {
1292                 FPOINT to;
1293                 to.x = l->x*size/100.0/20.0+advance;
1294                 to.y = l->y*size/100.0/20.0;
1295                 draw->lineTo(draw, &to);
1296             } else if(l->type == splineTo) {
1297                 FPOINT mid,to;
1298                 mid.x = l->sx*size/100.0/20.0+advance;
1299                 mid.y = l->sy*size/100.0/20.0;
1300                 to.x = l->x*size/100.0/20.0+advance;
1301                 to.y = l->y*size/100.0/20.0;
1302                 draw->splineTo(draw, &mid, &to);
1303             }
1304             l = l->next;
1305         }
1306         swf_Shape2Free(shape2);
1307         advance += font->glyph[g].advance*size/100.0/20.0;
1308     }
1309 }
1310
1311