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