* enumerate also definefont2 tags
[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  
10    This file is distributed under the GPL, see file COPYING for details 
11
12 */
13
14 #define TF_TEXTCONTROL  0x80
15 #define TF_HASFONT      0x08
16 #define TF_HASCOLOR     0x04
17 #define TF_HASYOFFSET   0x02
18 #define TF_HASXOFFSET   0x01
19
20 #define FF_WIDECODES    0x01
21 #define FF_BOLD         0x02
22 #define FF_ITALIC       0x04
23 #define FF_ANSI         0x08
24 #define FF_SHIFTJIS     0x10
25 #define FF_UNICODE      0x20
26
27 #define FF2_BOLD         0x01
28 #define FF2_ITALIC       0x02
29 #define FF2_WIDECODES    0x04
30 #define FF2_WIDEOFFSETS  0x08
31 #define FF2_ANSI         0x10
32 #define FF2_UNICODE      0x20
33 #define FF2_SHIFTJIS     0x40
34 #define FF2_LAYOUT       0x80
35
36 int swf_FontIsItalic(SWFFONT * f) { return f->version==2?f->flags&FF2_ITALIC:f->flags&FF_ITALIC; }
37 int swf_FontIsBold(SWFFONT * f)   { return f->version==2?f->flags&FF2_BOLD:f->flags&FF_BOLD; }
38
39 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
40
41 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
42 { int n;
43   TAG * t;
44   if (!swf) return -1;
45   t = swf->firstTag;
46   n = 0;
47
48   while (t)
49   { if (swf_GetTagID(t)==ST_DEFINEFONTINFO ||
50           swf_GetTagID(t)==ST_DEFINEFONT2)
51     { n++;
52       if (FontCallback)
53       { U16 id;
54         int l;
55         U8 s[257];
56         swf_SaveTagPos(t);
57         swf_SetTagPos(t,0);
58         
59         id  = swf_GetU16(t);
60         if(swf_GetTagID(t) == ST_DEFINEFONT2)
61             swf_GetU16(t);
62         l   = swf_GetU8(t);
63         swf_GetBlock(t,s,l);
64         s[l] = 0;
65
66         (FontCallback)(id,s); 
67       
68         swf_RestoreTagPos(t);
69       }
70     }
71     t = swf_NextTag(t);
72   }
73   return n;
74 }
75
76 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)
77 { U16 fid;
78   swf_SaveTagPos(t);
79   swf_SetTagPos(t,0);
80
81   fid = swf_GetU16(t);
82   if ((!id)||(id==fid))
83   { U16 of,*ofs;
84     int n,i;
85       
86     id = fid;
87     f->version = 1;
88     f->id = fid;
89
90     of = swf_GetU16(t);
91     n = of/2;
92     f->numchars = n;
93     f->glyph = malloc(sizeof(SWFGLYPH)*n);
94     memset(f->glyph, 0, sizeof(SWFGLYPH)*n);
95
96     for (i=1;i<n;i++) swf_GetU16(t);
97     for (i=0;i<n;i++) swf_GetSimpleShape(t,&f->glyph[i].shape);
98   }
99
100   swf_RestoreTagPos(t);
101   return id;
102 }
103
104 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)
105 { U16 fid;
106   U16 maxcode;
107   swf_SaveTagPos(t);
108   swf_SetTagPos(t,0);
109
110   if(f->version>1) {
111       // DefineFont2 doesn't have FontInfo fields
112       fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n");
113       return -1;
114   }
115
116   fid = swf_GetU16(t);
117   if (fid==id)
118   { U8 l = swf_GetU8(t);
119     int i;
120     
121     if (l)
122     { if (f->name) free(f->name);
123       f->name = (U8*)malloc(l+1);
124       if (f->name)
125       { swf_GetBlock(t,f->name,l);
126         f->name[l] = 0;
127       }
128       else
129       { swf_RestoreTagPos(t);
130         return -1;
131       }
132     }
133     f->flags = swf_GetU8(t);
134
135     f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars);
136     maxcode = 0;
137     for(i=0; i < f->numchars; i++) {
138       f->glyph2ascii[i] = ((f->flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
139       if(f->glyph2ascii[i] > maxcode)
140           maxcode = f->glyph2ascii[i];
141     }
142     maxcode++;
143     if(maxcode<256)
144         maxcode=256;
145     f->maxascii = maxcode;
146     f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
147     memset(f->ascii2glyph, -1, sizeof(int)*maxcode);
148      
149     for(i = 0; i < f->numchars; i++)
150       f->ascii2glyph[f->glyph2ascii[i]] = i;
151   }
152
153   swf_RestoreTagPos(t);
154   return id;
155 }
156
157 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)
158 {
159     int t, glyphcount;
160     int maxcode;
161     U8 flags1,flags2,namelen;
162     font->version=2;
163     font->id = swf_GetU16(tag);
164     flags1 = swf_GetU8(tag);
165     flags2 = swf_GetU8(tag); //reserved flags
166     namelen = swf_GetU8(tag);
167     font->flags = flags1;
168     font->name = (U8*)malloc(namelen+1);
169     font->name[namelen]=0;
170     swf_GetBlock(tag, font->name, namelen);
171     font->version = 2;
172     glyphcount = swf_GetU16(tag);
173     font->numchars = glyphcount;
174     
175     font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
176     memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
177     font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount);
178     memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount);
179
180     if(flags1&8) { // wide offsets
181         for(t=0;t<glyphcount;t++)
182             swf_GetU32(tag); //offset[t]
183         swf_GetU32(tag); // fontcodeoffset
184     } else {
185         for(t=0;t<glyphcount;t++)
186             swf_GetU16(tag); //offset[t]
187         swf_GetU16(tag); // fontcodeoffset
188     }
189     for(t=0;t<glyphcount;t++)
190         swf_GetSimpleShape(tag,&(font->glyph[t].shape));
191
192     maxcode = 0;
193     for(t=0;t<glyphcount;t++) {
194         int code;
195         if(flags1&4) // wide codes
196             code = swf_GetU16(tag);
197         else
198             code = swf_GetU8(tag);
199         font->glyph2ascii[t] = code;
200         if(code > maxcode)
201             maxcode = code;
202     }
203     maxcode++;
204     if(maxcode<256)
205         maxcode=256;
206     font->maxascii = maxcode;
207     font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
208     memset(font->ascii2glyph, -1, sizeof(int)*maxcode);
209     for(t=0;t<glyphcount;t++) 
210     {
211         font->ascii2glyph[font->glyph2ascii[t]] = t;
212     }
213
214     if(flags1&128) { // has layout
215         U16 kerningcount;
216         font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
217         font->layout->ascent=swf_GetU16(tag);
218         font->layout->descent=swf_GetU16(tag);
219         font->layout->leading=swf_GetU16(tag);
220         for(t=0;t<glyphcount;t++) {
221             S16 advance = swf_GetS16(tag);
222             font->glyph[t].advance = advance;
223         }
224         font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
225         for(t=0;t<glyphcount;t++) {
226             swf_ResetReadBits(tag);
227             swf_GetRect(tag, font->layout->bounds);
228         }
229         kerningcount = swf_GetU16(tag);
230         font->layout->kerningcount = kerningcount;
231         font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
232         if(kerningcount) {
233             font->layout->kerning = 
234                 malloc(sizeof(*font->layout->kerning)* kerningcount);
235             for(t=0;t<kerningcount;t++)
236             {
237                 if(flags1&4) { // wide codes
238                     font->layout->kerning[t].char1 = swf_GetU16(tag);
239                     font->layout->kerning[t].char2 = swf_GetU16(tag);
240                 } else {
241                     font->layout->kerning[t].char1 = swf_GetU16(tag);
242                     font->layout->kerning[t].char2 = swf_GetU16(tag);
243                 }
244                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
245             }
246         }
247     }
248     return font->id;
249 }
250
251
252 #define FEDTJ_PRINT  0x01
253 #define FEDTJ_MODIFY 0x02
254
255 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
256 { U16    cid;
257   SRECT  r;
258   MATRIX m;
259   U8     gbits, abits, flags;
260   int    fid;
261
262   fid = 0;
263
264   swf_SaveTagPos(t);
265   swf_SetTagPos(t,0);
266
267   cid = swf_GetU16(t);
268   swf_GetRect(t,&r);
269   swf_GetMatrix(t,&m);
270   gbits = swf_GetU8(t);
271   abits = swf_GetU8(t);
272
273   flags = swf_GetU8(t);
274   
275   while(flags)
276   { if (flags&TF_TEXTCONTROL)
277     { if (flags&TF_HASFONT) fid = swf_GetU16(t);
278       if (flags&TF_HASCOLOR)
279       { swf_GetU8(t); // rgb
280         swf_GetU8(t);
281         swf_GetU8(t);
282         if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t);
283       }
284       if (flags&TF_HASXOFFSET) swf_GetS16(t);
285       if (flags&TF_HASYOFFSET) swf_GetS16(t);
286       if (flags&TF_HASFONT) swf_GetU16(t);
287     }
288     else
289     { int i;
290       for (i=0;i<flags;i++)
291       { int glyph;
292         int adv;
293         glyph = swf_GetBits(t,gbits);
294         adv = swf_GetBits(t,abits);
295         if (id==fid)                    // mitlesen ?
296         { int code = f->glyph2ascii[glyph];
297           if (jobs&FEDTJ_PRINT) printf("%c",code);
298           if (jobs&FEDTJ_MODIFY)
299             /*if (!f->glyph[code].advance)*/ f->glyph[glyph].advance = adv;
300         }
301       }
302       if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
303     }
304     flags = swf_GetU8(t);
305   }
306   
307   swf_RestoreTagPos(t);
308   return id;
309 }  
310
311 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
312 { TAG * t;
313   SWFFONT * f;
314     
315   if ((!swf)||(!font)) return -1;
316
317   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
318   if (!f) return -1;
319   
320   memset(f,0x00,sizeof(SWFFONT));
321
322   t = swf->firstTag;
323
324   while (t)
325   { int nid = 0;
326     switch (swf_GetTagID(t))
327     { case ST_DEFINEFONT:
328         nid = swf_FontExtract_DefineFont(id,f,t);
329         break;
330     
331       case ST_DEFINEFONT2:
332         nid = swf_FontExtract_DefineFont2(id,f,t);
333         break;
334         
335       case ST_DEFINEFONTINFO:
336         nid = swf_FontExtract_DefineFontInfo(id,f,t);
337         break;
338         
339       case ST_DEFINETEXT:
340       case ST_DEFINETEXT2:
341         nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
342         break;
343     }
344     if (nid>0) id = nid;
345     t = swf_NextTag(t);
346   }
347   return 0;
348 }
349
350 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
351
352 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
353 { int i,j,num;
354   if ((!f)||(!use)) return -1;
355
356   j = 0;
357   for (i=0;i<f->numchars;i++)
358     if (f->glyph[i].shape)
359     { if (f->glyph2ascii[i]<MAX_CHAR_PER_FONT && 
360             use->code[f->glyph2ascii[i]])
361       { f->ascii2glyph[f->glyph2ascii[i]] = j;
362         f->glyph2ascii[j] = f->glyph2ascii[i];
363         f->glyph[j] = f->glyph[i];
364         j++;
365       }
366       else
367       { swf_ShapeFree(f->glyph[i].shape);
368         f->ascii2glyph[f->glyph2ascii[i]] = -1;
369         f->glyph2ascii[i] = 0;
370         f->glyph[i].shape   = 0;
371         f->glyph[i].advance = 0;
372       }
373     } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
374
375   f->numchars = j;
376     
377   return j;
378 }
379
380 int swf_FontInitUsage(FONTUSAGE * use)
381 { if (!use) return -1;
382   memset(use->code,0,sizeof(use->code[0])*MAX_CHAR_PER_FONT);
383   return 0;
384 }
385
386 int swf_FontUse(FONTUSAGE * use,U8 * s)
387 { if ((!use)||(!s)) return -1;
388   while (s[0])
389   { use->code[s[0]] = 1;
390     s++;
391   }
392   return 0;  
393 }
394
395 int swf_FontSetDefine(TAG * t,SWFFONT * f)
396 { U16*ofs = (U16*)malloc(f->numchars*2);
397   int p,i,j;
398     
399   if ((!t)||(!f)) return -1;
400   swf_ResetWriteBits(t);
401   swf_SetU16(t,f->id);
402
403   p = 0; j = 0;
404   for (i=0;i<f->numchars;i++)
405     if (f->glyph[i].shape)
406     { ofs[j++] = p;
407       p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
408     }
409
410   for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
411   
412   for (i=0;i<f->numchars;i++)
413     if (f->glyph[i].shape)
414       swf_SetSimpleShape(t,f->glyph[i].shape);
415   
416   swf_ResetWriteBits(t);
417   free(ofs);
418   return 0;
419 }
420
421 int swf_FontSetInfo(TAG * t,SWFFONT * f)
422 { int l,i;
423   U8 wide=0;
424   if ((!t)||(!f)) return -1;
425   swf_ResetWriteBits(t);
426   swf_SetU16(t,f->id);
427   l = strlen(f->name); if (l>255) l = 255;
428   swf_SetU8(t,l);
429   swf_SetBlock(t,f->name,l);
430   if(f->numchars>=256)
431       wide=1;
432   swf_SetU8(t,(f->flags&0xfe)|wide);
433
434   for (i=0;i<f->numchars;i++) {
435     if (f->glyph[i].shape)
436       wide?swf_SetU16(t,f->glyph2ascii[i]):
437            swf_SetU8(t,f->glyph2ascii[i]);
438   }
439   
440   return 0;
441 }
442
443 int swf_FontExport(int handle,SWFFONT * f)
444 { int l;
445   int i;
446   if (!f) return 0;
447
448   l = sizeof(SWFFONT);
449   if (handle>=0)
450     if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1;
451
452   if (f->name)
453   { U16 ln = strlen(f->name);
454     l+=2+ln;
455     if (handle>=0)
456     { if (write(handle,&ln,2)!=2) return -1;
457       if (write(handle,f->name,ln)!=ln) return -1;
458     }
459   }
460
461   if (f->layout)
462   { l+=sizeof(SWFLAYOUT);
463     if (handle>=0)
464       if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1;
465 /*    new kerning struct. hope commenting this out doesn't break things
466       if (f->layout->kerning.data)
467     { l+=f->layout->kerning.count*4;
468       if (handle>=0)
469         if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1;
470     }*/
471   }
472
473   for (i=0;i<f->numchars;i++)
474   { if (f->glyph[i].shape)
475     { int ll = swf_ShapeExport(handle,f->glyph[i].shape);
476       if (ll<0) return -1;
477       l+=ll;
478     }  
479   }
480
481   return l;
482 }
483
484 int swf_FontImport(int handle,SWFFONT * * font)
485 { SWFFONT * f;
486   int layout;
487   int i = 0;
488
489   if ((!font)||(handle<0)) return -1;
490
491   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
492   if (!f) return -1;
493
494   memset(f,0x00,sizeof(SWFFONT));
495   
496   if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler;
497
498   layout = (f->layout)?1:0;             // avoid illegal free()
499   f->layout = NULL;
500
501   if (f->name)
502   { U16 ln;
503     f->name = NULL;
504     if (read(handle,&ln,2)!=2) goto fehler;
505     f->name = (U8*)malloc(ln+1);
506     if (!f->name) goto fehler;
507     if (read(handle,f->name,ln)!=ln) goto fehler;
508     f->name[ln] = 0;
509   }
510
511   if (f->layout)
512   { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT));
513     if (!f->layout) goto fehler;
514     if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler;
515     /* new kerning struct. hope commenting this out doesn't break things
516     if (f->layout->kerning.data)
517     { int l = f->layout->kerning.count*4;
518       f->layout->kerning.data = (U8*)malloc(l);
519       if (!f->layout->kerning.data) goto fehler;
520       if (read(handle,f->layout->kerning.data,l)!=l) goto fehler;
521     } */
522   }
523
524   for (i=0;i<f->numchars;i++)
525   { if (f->glyph[i].shape)
526     { if (swf_ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler;
527     }
528   }
529
530   f->id = 0;
531   
532   return 0;
533   
534 fehler:
535   if (f) for (;i<MAX_CHAR_PER_FONT;i++) f->glyph[i].shape = NULL;
536   swf_FontFree(f);
537   font[0] = NULL;
538   return -1;
539 }
540
541 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
542 { int id = swf_GetTagID(t);
543   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
544     else return -1;
545   return 0;
546 }
547
548 void swf_LayoutFree(SWFLAYOUT * l)
549 { if (l)
550   { if (l->kerning) free(l->kerning);
551     l->kerning = NULL;
552     if (l->bounds) free(l->bounds);
553     l->bounds = NULL;
554   }
555   free(l);
556 }
557
558 void swf_FontFree(SWFFONT * f)
559 { if (f)
560   { int i;
561       
562     if (f->name) free(f->name);
563     if (f->layout) swf_LayoutFree(f->layout);
564
565     f->name = NULL;
566     f->layout = NULL;
567
568     if(f->glyph) {
569       for (i=0;i<f->numchars;i++)
570         if (f->glyph[i].shape)
571         { swf_ShapeFree(f->glyph[i].shape);
572           f->glyph[i].shape = NULL;
573         }
574       free(f->glyph);
575       f->glyph = NULL;
576     }
577     if(f->ascii2glyph) {
578       free(f->ascii2glyph);
579       f->ascii2glyph = NULL;
580     }
581     if(f->glyph2ascii) {
582       free(f->glyph2ascii);
583       f->glyph2ascii = NULL;
584     }
585   }
586   free(f);
587 }
588
589 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
590 { U8 flags;
591   if (!t) return -1;
592
593   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
594
595   swf_SetU8(t,flags);
596   if (font) swf_SetU16(t,font->id);
597   if (color)
598   { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
599     else swf_SetRGB(t,color);
600   }
601   if (dx) swf_SetS16(t,dx);
602   if (dy) swf_SetS16(t,dy);
603   if (font) swf_SetU16(t,size);
604   
605   return 0;
606 }
607
608 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
609 { U16 g,a;
610   if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
611   g = a = 0;
612
613   while(s[0])
614   { 
615     int glyph = font->ascii2glyph[s[0]];
616     if(glyph>=0) {
617        g = swf_CountBits(glyph,g);
618        a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
619     }
620     s++;
621   }
622
623   if (gbits) gbits[0] = (U8)g;
624   if (abits) abits[0] = (U8)a;
625
626   return 0;
627 }
628
629 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
630 { int l,i;
631     
632   if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
633
634   l = strlen(s);
635   if (l>0x7f) l = 0x7f;
636   swf_SetU8(t,l);
637
638   for (i=0;i<l;i++)
639   { 
640     int g = font->ascii2glyph[s[i]];
641     if(g>=0) {
642       swf_SetBits(t,g,gbits);
643       swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
644     }
645   }
646
647   swf_ResetWriteBits(t);
648   return 0;
649 }
650
651 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
652 { U32 res = 0;
653
654   if (font&&s)
655   { while (s[0])
656     { 
657       int g = font->ascii2glyph[*s];
658       if(g>=0)
659         res += font->glyph[g].advance;
660       s++;
661     }
662     if (scale) res = (res*scale)/100;
663   }
664   return res;
665 }
666
667 void swf_WriteFont(SWFFONT*font, char* filename, int useDefineFont2)
668 { SWF swf;
669   TAG * t;
670   SRECT r;
671   RGBA rgb;
672   int f;
673
674   if(useDefineFont2) {
675       fprintf(stderr, "DefineFont2 is not yet supported!\n");
676       useDefineFont2 = 0;
677   }
678
679   font->id = WRITEFONTID; //"FN"
680
681   memset(&swf,0x00,sizeof(SWF));
682
683   swf.fileVersion    = 4;
684   swf.frameRate      = 0x4000;
685   swf.movieSize.xmax = 20*640;
686   swf.movieSize.ymax = 20*480;
687
688   if(!useDefineFont2)
689   /* if we use DefineFont1 to store the characters,
690      we have to build a textfield to store the
691      advance values. While at it, we can also
692      make the whole .swf viewable */
693   {
694       t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
695       swf.firstTag = t;
696             rgb.r = 0xff;
697             rgb.g = 0xff;
698             rgb.b = 0xff;
699             swf_SetRGB(t,&rgb);
700       t = swf_InsertTag(t,ST_DEFINEFONT);
701   }
702   else
703   {
704       t = swf_InsertTag(NULL,ST_DEFINEFONT);
705       swf.firstTag = t;
706   }
707
708         swf_FontSetDefine(t,font);
709   
710   t = swf_InsertTag(t,ST_DEFINEFONTINFO);
711         swf_FontSetInfo(t,font);
712
713   if(!useDefineFont2)
714   {
715         int textscale = 400;
716         int s;
717         int xmax = 0;
718         int ymax = textscale * 20;
719         U8 gbits,abits;
720         char text[257];
721         int x,y;
722         text[256]=0;
723         for(s=0;s<256;s++)
724         {
725             int g = font->ascii2glyph[s];
726             text[s] = s;
727             if(g>=0) {
728                if(font->glyph[g].advance*textscale/100 > xmax)
729                    xmax = font->glyph[g].advance*textscale/100;
730             }
731         }
732         swf.movieSize.xmax = xmax*20;
733         swf.movieSize.ymax = ymax;
734
735         t = swf_InsertTag(t,ST_DEFINETEXT);
736
737             swf_SetU16(t,font->id+1);            // ID
738
739             r.xmin = 0;
740             r.ymin = 0;
741             r.xmax = swf.movieSize.xmax*20;
742             r.ymax = swf.movieSize.ymax;
743             
744             swf_SetRect(t,&r);
745
746             swf_SetMatrix(t,NULL);
747
748             abits = swf_CountBits(xmax*16, 0);
749             gbits = 8;
750             
751             swf_SetU8(t,gbits);
752             swf_SetU8(t,abits);
753
754             rgb.r = 0x00;
755             rgb.g = 0x00;
756             rgb.b = 0x00;
757             for(y=0;y<16;y++)
758             {
759                 int c=0,lastx=-1, firstx=0;
760                 for(x=0;x<16;x++) {
761                     int g = font->ascii2glyph[y*16+x];
762                     if(g>=0 && font->glyph[g].shape) {
763                         c++;
764                         if(lastx<0) 
765                             lastx = x*xmax;
766                     }
767                 }
768                 if(c) {
769                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y);
770                   for(x=0;x<16;x++)
771                   {
772                       int g = font->ascii2glyph[y*16+x];
773                       if(g>=0 && font->glyph[g].shape) {
774                         if(lastx != x*xmax) {
775                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
776                         }
777                         swf_SetU8(t,1);
778                         swf_SetBits(t, g, gbits);
779                         swf_SetBits(t, font->glyph[g].advance, abits);
780                         lastx = x*xmax+font->glyph[g].advance;
781                         swf_ResetWriteBits(t);
782                       }
783                   }
784                 } 
785             }
786             swf_SetU8(t,0);
787         
788         t = swf_InsertTag(t,ST_PLACEOBJECT2);
789
790             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
791      
792         t = swf_InsertTag(t,ST_SHOWFRAME);
793   }
794   
795   t = swf_InsertTag(t,ST_END);
796
797   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
798   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
799   close(f);
800
801   swf_FreeTags(&swf);
802 }
803
804 SWFFONT* swf_ReadFont(char* filename)
805 {
806   int f;
807   SWF swf;
808   if(!filename)
809       return 0;
810   f = open(filename,O_RDONLY);
811   
812   if (f<0 || swf_ReadSWF(f,&swf)<0)
813   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
814     close(f);
815     return 0;
816   }
817   else
818   { SWFFONT*font;
819     close(f);
820     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
821        return 0;
822     swf_FreeTags(&swf);
823     return font;
824   }
825 }
826