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