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