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