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