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