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