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