added swf_FontPrepareForEditText().
[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   /* TODO: layout, glyphnames */
523   j = 0;
524   for (i=0;i<f->numchars;i++)
525     if (f->glyph[i].shape)
526     { if (f->glyph2ascii[i]<f->maxascii&& 
527             use->code[f->glyph2ascii[i]])
528       { f->ascii2glyph[f->glyph2ascii[i]] = j;
529         f->glyph2ascii[j] = f->glyph2ascii[i];
530         f->glyph[j] = f->glyph[i];
531         j++;
532       }
533       else
534       { swf_ShapeFree(f->glyph[i].shape);
535         f->ascii2glyph[f->glyph2ascii[i]] = -1;
536         f->glyph2ascii[i] = 0;
537         f->glyph[i].shape   = NULL;
538         f->glyph[i].advance = 0;
539       }
540     } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
541
542   f->numchars = j;
543     
544   return j;
545 }
546 void swf_FontSort(SWFFONT * font)
547 {
548     if(!font) return;
549     int i,j,k;
550     int* newplace = malloc(sizeof(int)*font->numchars);
551     int* newpos;
552     
553     for(i=0;i<font->numchars;i++) {
554         newplace[i] = i;
555     }
556     for(i=0;i<font->numchars;i++)
557     for(j=0;j<i;j++) {
558         if(font->glyph2ascii[i] < font->glyph2ascii[j]) {
559             int n1,n2;
560             char* c1,*c2;
561             SWFGLYPH g1,g2;
562             SRECT r1,r2;
563             n1=newplace[i];
564             n2=newplace[j];
565             newplace[j] = n1;
566             newplace[i] = n2;
567             n1=font->glyph2ascii[i];
568             n2=font->glyph2ascii[j];
569             font->glyph2ascii[j] = n1;
570             font->glyph2ascii[i] = n2;
571             g1=font->glyph[i];
572             g2=font->glyph[j];
573             font->glyph[j] = g1;
574             font->glyph[i] = g2;
575             if(font->glyphnames) {
576                 c1 = font->glyphnames[i];
577                 c2 = font->glyphnames[j];
578                 font->glyphnames[j] = c1;
579                 font->glyphnames[i] = c2;
580             }
581             if(font->layout) {
582                 r1 = font->layout->bounds[i];
583                 r2 = font->layout->bounds[j];
584                 font->layout->bounds[j] = r1;
585                 font->layout->bounds[i] = r2;
586             }
587         }
588     }
589     newpos = malloc(sizeof(int)*font->numchars);
590     for(i=0;i<font->numchars;i++) {
591         newpos[newplace[i]] = i;
592     }
593     for(i=0;i<font->maxascii;i++) {
594         if(font->ascii2glyph[i]>=0)
595             font->ascii2glyph[i] = newpos[font->ascii2glyph[i]];
596     }
597
598     free(newpos);
599     free(newplace);
600 }
601
602 void swf_FontPrepareForEditText(SWFFONT * font)
603 {
604     if(!font->layout)
605         swf_FontCreateLayout(font);
606     swf_FontSort(font);
607 }
608
609 int swf_FontInitUsage(SWFFONT* f, FONTUSAGE * use)
610 { if (!use) return -1;
611   use->code = malloc(sizeof(use->code[0])*f->maxascii);
612   memset(use->code,0,sizeof(use->code[0])*f->maxascii);
613   return 0;
614 }
615
616 void swf_FontClearUsage(SWFFONT* f, FONTUSAGE * use)
617 { if (!use) return;
618   free(use->code);
619 }
620
621 int swf_FontUse(SWFFONT*f, FONTUSAGE * use,U8 * s)
622 { if ((!use)||(!s)) return -1;
623   while (s[0])
624   { use->code[s[0]] = 1;
625     s++;
626   }
627   return 0;  
628 }
629
630 int swf_FontSetDefine(TAG * t,SWFFONT * f)
631 { U16*ofs = (U16*)malloc(f->numchars*2);
632   int p,i,j;
633     
634   if ((!t)||(!f)) return -1;
635   swf_ResetWriteBits(t);
636   swf_SetU16(t,f->id);
637
638   p = 0; j = 0;
639   for (i=0;i<f->numchars;i++)
640     if (f->glyph[i].shape)
641     { ofs[j++] = p;
642       p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
643     }
644
645   for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
646   if(!j) {
647       fprintf(stderr, "rfxswf: warning: Font is empty\n");
648       swf_SetU16(t, 0);
649   }
650   
651   for (i=0;i<f->numchars;i++)
652     if (f->glyph[i].shape)
653       swf_SetSimpleShape(t,f->glyph[i].shape);
654   
655   swf_ResetWriteBits(t);
656   free(ofs);
657   return 0;
658 }
659
660 static inline int fontSize(SWFFONT*font)
661 {
662     int t;
663     int size = 0;
664     for(t=0;t<font->numchars;t++) {
665         int l = (font->glyph[t].shape->bitlen+7)/8;
666         size += l+1;
667     }
668     return size + (font->numchars+1)*2;
669 }
670
671 int swf_FontSetDefine2(TAG *tag, SWFFONT * f)
672 {
673     U8 flags = 0;
674     int t;
675     int pos;
676     int pos2;
677     swf_SetU16(tag, f->id);
678
679     if(f->layout) 
680         flags |= 128; // haslayout
681     if(f->numchars>256)
682         flags |= 4; // widecodes
683     if(f->style & FONT_STYLE_BOLD)
684         flags |= 1; // bold
685     if(f->style & FONT_STYLE_ITALIC)
686         flags |= 2; // italic
687     if(f->maxascii>=256)
688         flags |= 4; //wide codecs
689     if(fontSize(f)>65535)
690         flags |= 8; //wide offsets
691     flags |= 8|4; //FIXME: the above check doesn't work
692
693     if(f->encoding & FONT_ENCODING_ANSI)
694         flags |= 16; // ansi
695     if(f->encoding & FONT_ENCODING_UNICODE)
696         flags |= 32; // unicode
697     if(f->encoding & FONT_ENCODING_SHIFTJIS)
698         flags |= 64; // shiftjis
699
700     swf_SetU8(tag, flags);
701     swf_SetU8(tag, 0); //reserved flags
702     if(f->name) {
703         /* font name */
704         swf_SetU8(tag, strlen(f->name));
705         swf_SetBlock(tag, f->name, strlen(f->name));
706     } else {
707         /* font name (="") */
708         swf_SetU8(tag, 0); /*placeholder*/
709     }
710     /* number of glyphs */
711     swf_SetU16(tag, f->numchars);
712     /* font offset table */
713     pos = tag->len;
714     for(t=0;t<=f->numchars;t++)
715     {
716         if(flags&8)
717             swf_SetU32(tag, /* fontoffset */ 0); /*placeholder*/
718         else
719             swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/
720     }
721
722     for(t=0;t<=f->numchars;t++) {
723         if(flags&8) {
724             tag->data[pos + t*4    ] = (tag->len-pos);
725             tag->data[pos + t*4 + 1] = (tag->len-pos) >> 8;
726             tag->data[pos + t*4 + 2] = (tag->len-pos) >> 16;
727             tag->data[pos + t*4 + 3] = (tag->len-pos) >> 24;
728         } else {
729             if(tag->len - pos > 65535) {
730                 fprintf(stderr, "Internal error: Font too big and WideOffsets flag not set\n");
731                 exit(1);
732             }
733             tag->data[pos + t*2    ] = (tag->len-pos);
734             tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8;
735         }
736         if(t<f->numchars)
737             swf_SetSimpleShape(tag, f->glyph[t].shape);
738     }
739
740     
741     /* font code table */
742     if(flags & 4) /* wide codes */ {
743         for(t=0;t<f->numchars;t++) { 
744             swf_SetU16(tag,f->glyph2ascii[t]);
745         }
746     } else {
747         for(t=0;t<f->numchars;t++)
748             swf_SetU8(tag,f->glyph2ascii[t]);
749     }
750     if(f->layout) 
751     {
752         swf_SetU16(tag,f->layout->ascent);
753         swf_SetU16(tag,f->layout->descent);
754         swf_SetU16(tag,f->layout->leading);
755         for(t=0;t<f->numchars;t++)
756             swf_SetU16(tag,f->glyph[t].advance);
757         for(t=0;t<f->numchars;t++) {
758             swf_ResetWriteBits(tag);
759             swf_SetRect(tag,&f->layout->bounds[t]);
760         }
761         swf_SetU16(tag, f->layout->kerningcount);
762         for(t=0;t<f->layout->kerningcount;t++) {
763             if(flags & 4) /* wide codes */ {
764                 swf_SetU16(tag,f->layout->kerning[t].char1);
765                 swf_SetU16(tag,f->layout->kerning[t].char2);
766             } else {
767                 swf_SetU8(tag,f->layout->kerning[t].char1);
768                 swf_SetU8(tag,f->layout->kerning[t].char2);
769             }
770             swf_SetU16(tag,f->layout->kerning[t].adjustment);
771         }
772     }
773     return 0;
774 }
775     
776 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
777 {
778     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
779     f->layout->ascent = ascent;
780     f->layout->descent = descent;
781     f->layout->leading = leading;
782     f->layout->kerningcount = 0;
783     f->layout->kerning = 0;
784     f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars);
785     memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars);
786 }
787
788 int swf_FontSetInfo(TAG * t,SWFFONT * f)
789 { int l,i;
790   U8 wide=0;
791   U8 flags = 0;
792   if ((!t)||(!f)) return -1;
793   swf_ResetWriteBits(t);
794   swf_SetU16(t,f->id);
795   l = f->name?strlen(f->name):0; if (l>255) l = 255;
796   swf_SetU8(t,l);
797   if(l)
798     swf_SetBlock(t,f->name,l);
799   if(f->numchars>=256)
800       wide=1;
801
802   if(f->style & FONT_STYLE_BOLD)
803       flags |= 2;
804   if(f->style & FONT_STYLE_ITALIC)
805       flags |= 4;
806   if(f->style & FONT_ENCODING_ANSI)
807       flags |= 8;
808   if(f->style & FONT_ENCODING_SHIFTJIS)
809       flags |= 16;
810   if(f->style & FONT_ENCODING_UNICODE)
811       flags |= 32;
812     
813   swf_SetU8(t,(flags&0xfe)|wide);
814
815   for (i=0;i<f->numchars;i++) {
816     if (f->glyph[i].shape) {
817       int g2a = f->glyph2ascii[i];
818       wide?swf_SetU16(t,g2a):swf_SetU8(t,g2a);
819     }
820   }
821   
822   return 0;
823 }
824
825 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
826 { int id = swf_GetTagID(t);
827   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
828     else return -1;
829   return 0;
830 }
831
832 void swf_LayoutFree(SWFLAYOUT * l)
833 { if (l)
834   { if (l->kerning) free(l->kerning);
835     l->kerning = NULL;
836     if (l->bounds) free(l->bounds);
837     l->bounds = NULL;
838   }
839   free(l);
840 }
841
842 void swf_FontFree(SWFFONT * f)
843 { if (f)
844   { int i;
845       
846     if (f->name) free(f->name);
847     if (f->layout) swf_LayoutFree(f->layout);
848
849     f->name = NULL;
850     f->layout = NULL;
851
852     if(f->glyph) {
853       for (i=0;i<f->numchars;i++)
854         if (f->glyph[i].shape)
855         { swf_ShapeFree(f->glyph[i].shape);
856           f->glyph[i].shape = NULL;
857         }
858       free(f->glyph);
859       f->glyph = NULL;
860     }
861     if(f->ascii2glyph) {
862       free(f->ascii2glyph);
863       f->ascii2glyph = NULL;
864     }
865     if(f->glyph2ascii) {
866       free(f->glyph2ascii);
867       f->glyph2ascii = NULL;
868     }
869     if(f->glyphnames) {
870       int t;
871       for(t=0;t<f->numchars;t++) {
872         if(f->glyphnames[t])
873             free(f->glyphnames[t]);
874       }
875       free(f->glyphnames);
876     }
877   }
878   free(f);
879 }
880
881 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,int dx,int dy)
882 { U8 flags;
883   if (!t) return -1;
884
885   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
886
887   swf_SetU8(t,flags);
888   if (font) swf_SetU16(t,font->id);
889   if (color)
890   { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
891     else swf_SetRGB(t,color);
892   }
893   if (dx) swf_SetS16(t,dx);
894   if (dy) swf_SetS16(t,dy);
895   if (font) swf_SetU16(t,size);
896   
897   return 0;
898 }
899
900 static int swf_TextCountBits2(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits, char*encoding)
901 { U16 g,a;
902   char utf8=0;
903   if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
904   g = a = 0;
905
906   if(!strcmp(encoding, "UTF8")) utf8=1;
907   else if(!strcmp(encoding, "iso-8859-1")) utf8=0;
908   else fprintf(stderr, "Unknown encoding: %s", encoding);
909
910   while(*s)
911   { 
912     int glyph = -1,c;
913     
914     if(!utf8) c = *s++;
915     else c = readUTF8char(&s);
916
917     if(c < font->maxascii)
918         glyph = font->ascii2glyph[c];
919     if(glyph>=0) {
920        g = swf_CountUBits(glyph,g);
921        a = swf_CountBits(((((U32)font->glyph[glyph].advance)*scale)/20)/100,a);
922     }
923   }
924
925   if (gbits) gbits[0] = (U8)g;
926   if (abits) abits[0] = (U8)a;
927   return 0;
928 }
929
930 static int swf_TextSetCharRecord2(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits, char*encoding)
931 { int l=0,pos;
932   char utf8=0;
933     
934   if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
935   
936   if(!strcmp(encoding, "UTF8")) utf8=1;
937   else if(!strcmp(encoding, "iso-8859-1")) utf8=0;
938   else fprintf(stderr, "Unknown encoding: %s", encoding);
939
940   pos = t->len;
941   swf_SetU8(t, l); //placeholder
942
943   while(*s)
944   { 
945     int g = -1,c;
946     
947     if(!utf8) c = *s++;
948     else c = readUTF8char(&s);
949
950     if(c < font->maxascii) 
951         g = font->ascii2glyph[c];
952     if(g>=0) {
953       swf_SetBits(t,g,gbits);
954       swf_SetBits(t,((((U32)font->glyph[g].advance)*scale)/20)/100,abits);
955       l++;
956       if(l==0x7f)
957           break;
958     }
959   }
960
961   PUT8(&t->data[pos], l);
962
963   swf_ResetWriteBits(t);
964   return 0;
965 }
966
967 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) {
968     return swf_TextCountBits2(font,s,scale,gbits,abits,"iso-8859-1");
969 }
970 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) {
971     return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"iso-8859-1");
972 }
973 int swf_TextCountBitsUTF8(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) {
974     return swf_TextCountBits2(font,s,scale,gbits,abits,"UTF8");
975 }
976 int swf_TextSetCharRecordUTF8(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) {
977     return swf_TextSetCharRecord2(t,font,s,scale,gbits,abits,"UTF8");
978 }
979
980 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
981 { U32 res = 0;
982
983   if (font&&s)
984   { while (s[0])
985     { 
986       int g = -1;
987       if(*s < font->maxascii) 
988           g = font->ascii2glyph[*s];
989       if(g>=0)
990         res += font->glyph[g].advance/20;
991       s++;
992     }
993     if (scale) res = (res*scale)/100;
994   }
995   return res;
996 }
997
998 SRECT swf_TextCalculateBBoxUTF8(SWFFONT * font,U8 * s,int scale)
999 {
1000     int pos=0;
1001     SRECT r;
1002     swf_GetRect(0, &r);
1003     while(*s) {
1004         int c = readUTF8char(&s);
1005         if(c < font->maxascii) {
1006             int g = font->ascii2glyph[c];
1007             if(g>=0) {
1008                 SRECT rn = font->layout->bounds[g];
1009                 rn.xmin = (rn.xmin * scale)/20/100 + pos;
1010                 rn.xmax = (rn.xmax * scale)/20/100 + pos;
1011                 rn.ymin = (rn.ymin * scale)/20/100;
1012                 rn.ymax = (rn.ymax * scale)/20/100;
1013                 swf_ExpandRect2(&r, &rn);
1014                 pos += (font->glyph[g].advance*scale)/20/100;
1015             }
1016         }
1017         c++;
1018     }
1019     return r;
1020 }
1021
1022
1023 SWFFONT* swf_ReadFont(char* filename)
1024 {
1025   int f;
1026   SWF swf;
1027   if(!filename)
1028       return 0;
1029   f = open(filename,O_RDONLY);
1030   
1031   if (f<0 || swf_ReadSWF(f,&swf)<0)
1032   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
1033     close(f);
1034     return 0;
1035   }
1036   else
1037   { SWFFONT*font;
1038     close(f);
1039     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
1040        return 0;
1041     swf_FreeTags(&swf);
1042     return font;
1043   }
1044 }
1045
1046 void swf_WriteFont(SWFFONT*font, char* filename)
1047 { SWF swf;
1048   TAG * t;
1049   SRECT r;
1050   RGBA rgb;
1051   int f;
1052   int useDefineFont2 = 0;
1053   int storeGlyphNames = 1;
1054
1055   if(font->layout)
1056       useDefineFont2 = 1; /* the only thing new in definefont2 
1057                              is layout information. */
1058
1059   font->id = WRITEFONTID; //"FN"
1060
1061   memset(&swf,0x00,sizeof(SWF));
1062
1063   swf.fileVersion    = 4;
1064   swf.frameRate      = 0x4000;
1065
1066   /* if we use DefineFont1 to store the characters,
1067      we have to build a textfield to store the
1068      advance values. While at it, we can also
1069      make the whole .swf viewable */
1070
1071   /* we now always create viewable swfs, even if we
1072      did use definefont2 -mk*/
1073   t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1074   swf.firstTag = t;
1075         rgb.r = 0xef;
1076         rgb.g = 0xef;
1077         rgb.b = 0xff;
1078         swf_SetRGB(t,&rgb);
1079   if(!useDefineFont2) {
1080     t = swf_InsertTag(t,ST_DEFINEFONT);
1081     swf_FontSetDefine(t,font);
1082     t = swf_InsertTag(t,ST_DEFINEFONTINFO);
1083     swf_FontSetInfo(t,font);
1084   } else {
1085     t = swf_InsertTag(t,ST_DEFINEFONT2);
1086     swf_FontSetDefine2(t,font);
1087   }
1088
1089   if(storeGlyphNames && font->glyphnames)
1090   {
1091     int c;
1092     t = swf_InsertTag(t,ST_GLYPHNAMES);
1093     swf_SetU16(t, WRITEFONTID);
1094     swf_SetU16(t, font->numchars);
1095     for(c=0;c<font->numchars;c++) {
1096         if(font->glyphnames[c])
1097             swf_SetString(t, font->glyphnames[c]);
1098         else
1099             swf_SetString(t, "");
1100     }
1101   }
1102
1103   if(1) //neccessary only for df1, but pretty to look at anyhow, so do it always
1104   {
1105         int textscale = 400;
1106         int s;
1107         int xmax = 0;
1108         int ymax = 0;
1109         int ypos = 1;
1110         U8 gbits,abits;
1111         int x,y,c;
1112         int range = font->maxascii;
1113         
1114         c=0;
1115         if(useDefineFont2 && range > 256) {
1116             range = 256;
1117         }
1118
1119         for(s=0;s<range;s++)
1120         {
1121             int g = font->ascii2glyph[s];
1122             if(g>=0) {
1123                if((font->glyph[g].advance*textscale/20)/64 > xmax) {
1124                    xmax = (font->glyph[g].advance*textscale/20)/64;
1125                }
1126                c++;
1127             }
1128             if((s&15)==0) {
1129                 if(c) {
1130                     ypos++;
1131                 }
1132                 c=0;
1133             }
1134         }
1135         ymax = ypos*textscale*2;
1136
1137         swf.movieSize.xmax = xmax*20;
1138         swf.movieSize.ymax = ymax;
1139
1140         t = swf_InsertTag(t,ST_DEFINETEXT);
1141
1142             swf_SetU16(t,font->id+1);            // ID
1143
1144             r.xmin = 0;
1145             r.ymin = 0;
1146             r.xmax = swf.movieSize.xmax;
1147             r.ymax = swf.movieSize.ymax;
1148             
1149             swf_SetRect(t,&r);
1150
1151             swf_SetMatrix(t,NULL);
1152
1153             abits = swf_CountBits(xmax*16, 0);
1154             gbits = 8;
1155             
1156             swf_SetU8(t,gbits);
1157             swf_SetU8(t,abits);
1158
1159             rgb.r = 0x00;
1160             rgb.g = 0x00;
1161             rgb.b = 0x00;
1162             ypos = 1;
1163             for(y=0;y<((range+15)/16);y++)
1164             {
1165                 int c=0,lastx=-1;
1166                 for(x=0;x<16;x++) {
1167                     int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1168                     if(g>=0 && font->glyph[g].shape) {
1169                         c++;
1170                         if(lastx<0) 
1171                             lastx = x*xmax;
1172                     }
1173                 }
1174                 if(c) {
1175                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*ypos*2);
1176                   for(x=0;x<16;x++)
1177                   {
1178                       int g = (y*16+x<range)?font->ascii2glyph[y*16+x]:-1;
1179                       if(g>=0 && font->glyph[g].shape) {
1180                         if(lastx != x*xmax) {
1181                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
1182                         }
1183                         swf_SetU8(t,1);
1184                         swf_SetBits(t, g, gbits);
1185                         swf_SetBits(t, font->glyph[g].advance/20, abits);
1186                         lastx = x*xmax+(font->glyph[g].advance/20);
1187                         swf_ResetWriteBits(t);
1188                       }
1189                   }
1190                   ypos++;
1191                 } 
1192             }
1193             swf_SetU8(t,0);
1194
1195         
1196         t = swf_InsertTag(t,ST_PLACEOBJECT2);
1197
1198             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
1199      
1200         t = swf_InsertTag(t,ST_SHOWFRAME);
1201
1202   }
1203   
1204   t = swf_InsertTag(t,ST_END);
1205
1206   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
1207   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
1208   close(f);
1209
1210   swf_FreeTags(&swf);
1211 }
1212
1213
1214 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, 
1215         int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
1216 {
1217     swf_SetRect(tag,&r);
1218     swf_ResetWriteBits(tag);
1219
1220     flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
1221     if(text) flags |= ET_HASTEXT;
1222     if(color) flags |= ET_HASTEXTCOLOR;
1223     if(maxlength) flags |= ET_HASMAXLENGTH;
1224     if(font) flags |= ET_HASFONT;
1225     if(layout) flags |= ET_HASLAYOUT;
1226
1227     swf_SetBits(tag, flags, 16);
1228
1229     if(flags & ET_HASFONT) {
1230         swf_SetU16(tag, font); //font
1231         swf_SetU16(tag, height); //fontheight
1232     }
1233     if(flags & ET_HASTEXTCOLOR) {
1234         swf_SetRGBA(tag, color);
1235     }
1236     if(flags & ET_HASMAXLENGTH) {
1237         swf_SetU16(tag, maxlength); //maxlength
1238     }
1239     if(flags & ET_HASLAYOUT) {
1240         swf_SetU8(tag,layout->align); //align
1241         swf_SetU16(tag,layout->leftmargin); //left margin
1242         swf_SetU16(tag,layout->rightmargin); //right margin
1243         swf_SetU16(tag,layout->indent); //indent
1244         swf_SetU16(tag,layout->leading); //leading
1245     }
1246     swf_SetString(tag, variable);
1247     if(flags & ET_HASTEXT)
1248         swf_SetString(tag,text);
1249 }
1250
1251 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
1252 {
1253     SRECT r;
1254     U8 gbits, abits;
1255     U8*c = (U8*)text;
1256     int pos = 0;
1257     if(font->layout) {
1258         r = swf_TextCalculateBBoxUTF8(font,text,scale*20);
1259     } else {
1260         fprintf(stderr, "No layout information- can't compute text bbox accurately");
1261         /* Hm, without layout information, we can't compute a bounding
1262            box. We could call swf_FontCreateLayout to create a layout,
1263            but the caller probably doesn't want us to mess up his font
1264            structure.
1265         */
1266         r.xmin = r.ymin = 0;
1267         r.xmax = r.ymax = 1024*20;
1268     }
1269
1270     swf_SetRect(tag,&r);
1271
1272     /* The text matrix is pretty boring, as it doesn't apply to
1273        individual characters, but rather whole text objects (or
1274        at least whole char records- haven't tested).
1275        So it can't do anything which we can't already do with
1276        the placeobject tag we use for placing the text on the scene.
1277     */
1278     swf_SetMatrix(tag,0);
1279
1280     swf_TextCountBitsUTF8(font,text,scale*20,&gbits,&abits);
1281     swf_SetU8(tag,gbits);
1282     swf_SetU8(tag,abits);
1283
1284     /* now set the text params- notice that a font size of
1285        1024 means that the glyphs will be displayed exactly
1286        as they would be in/with a defineshape. (Try to find
1287        *that* in the flash specs)
1288      */
1289     swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
1290
1291     /* set the actual text- notice that we just pass our scale
1292        parameter over, as TextSetCharRecord calculates with 
1293        percent, too */
1294     swf_TextSetCharRecordUTF8(tag,font,text,scale*20,gbits,abits);
1295
1296     swf_SetU8(tag,0);
1297     return r;
1298 }
1299
1300 void swf_FontCreateLayout(SWFFONT*f)
1301 {
1302     S16 leading = 0;
1303     int t;
1304     if(f->layout)
1305         return;
1306     if(!f->numchars)
1307         return;
1308     
1309     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1310     memset(f->layout, 0, sizeof(SWFLAYOUT));
1311     f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1312     f->layout->ascent = -32767;
1313     f->layout->descent = -32767;
1314
1315     for(t=0;t<f->numchars;t++) {
1316         SHAPE2*shape2;
1317         SRECT bbox;
1318         int width;
1319         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1320         if(!shape2) { 
1321             fprintf(stderr, "Shape parse error\n");exit(1);
1322         }
1323         bbox = swf_GetShapeBoundingBox(shape2);
1324         swf_Shape2Free(shape2);
1325         f->layout->bounds[t] = bbox;
1326         
1327         width = (bbox.xmax);
1328
1329         /* The following is a heuristic- it may be that extractfont_DefineText
1330            has already found out some widths for individual characters (from the way
1331            they are used)- we now have to guess whether that width might be possible,
1332            which is the case if it isn't either much too big or much too small */
1333         if(width > f->glyph[t].advance*3/2 ||
1334            width < f->glyph[t].advance/2)
1335             f->glyph[t].advance = width;
1336
1337         if(-bbox.ymin > f->layout->ascent)
1338             f->layout->ascent = bbox.ymin;
1339         if(bbox.ymax > f->layout->descent)
1340             f->layout->descent = bbox.ymax;
1341     }
1342 }
1343         
1344 void swf_DrawText(drawer_t*draw, SWFFONT*font, int size, char*text)
1345 {
1346     U8*s = (U8*)text;
1347     int advance = 0;
1348     while(*s) {
1349         SHAPE*shape;
1350         SHAPE2*shape2;
1351         SHAPELINE*l;
1352         U32 c = readUTF8char(&s);
1353         int g = font->ascii2glyph[c];
1354         shape = font->glyph[g].shape;
1355         if(((int)g)<0) {
1356             fprintf(stderr, "No char %d in font %s\n", c, font->name?(char*)font->name:"?");
1357             continue;
1358         }
1359         shape2 = swf_ShapeToShape2(shape);
1360         l = shape2->lines;
1361         while(l) {
1362             if(l->type == moveTo) {
1363                 FPOINT to;
1364                 to.x = l->x*size/100.0/20.0+advance;
1365                 to.y = l->y*size/100.0/20.0;
1366                 draw->moveTo(draw, &to);
1367             } else if(l->type == lineTo) {
1368                 FPOINT to;
1369                 to.x = l->x*size/100.0/20.0+advance;
1370                 to.y = l->y*size/100.0/20.0;
1371                 draw->lineTo(draw, &to);
1372             } else if(l->type == splineTo) {
1373                 FPOINT mid,to;
1374                 mid.x = l->sx*size/100.0/20.0+advance;
1375                 mid.y = l->sy*size/100.0/20.0;
1376                 to.x = l->x*size/100.0/20.0+advance;
1377                 to.y = l->y*size/100.0/20.0;
1378                 draw->splineTo(draw, &mid, &to);
1379             }
1380             l = l->next;
1381         }
1382         swf_Shape2Free(shape2);
1383         advance += font->glyph[g].advance*size/100.0/20.0;
1384     }
1385 }
1386
1387