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