fixed for -1 values in ascii2swf (chars without a glyph assigned).
[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         nid = swf_FontExtract_DefineFontInfo(id,f,t);
382         break;
383         
384       case ST_DEFINETEXT:
385       case ST_DEFINETEXT2:
386         nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
387         break;
388     }
389     if (nid>0) id = nid;
390     t = swf_NextTag(t);
391   }
392   if(f->id != id) {
393       free(f);
394       f=0;
395   }
396   font[0] = f;
397   return 0;
398 }
399
400 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
401
402 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
403 { int i,j;
404   if ((!f)||(!use)) return -1;
405
406   j = 0;
407   for (i=0;i<f->numchars;i++)
408     if (f->glyph[i].shape)
409     { if (f->glyph2ascii[i]<MAX_CHAR_PER_FONT && 
410             use->code[f->glyph2ascii[i]])
411       { f->ascii2glyph[f->glyph2ascii[i]] = j;
412         f->glyph2ascii[j] = f->glyph2ascii[i];
413         f->glyph[j] = f->glyph[i];
414         j++;
415       }
416       else
417       { swf_ShapeFree(f->glyph[i].shape);
418         f->ascii2glyph[f->glyph2ascii[i]] = -1;
419         f->glyph2ascii[i] = 0;
420         f->glyph[i].shape   = NULL;
421         f->glyph[i].advance = 0;
422       }
423     } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
424
425   f->numchars = j;
426     
427   return j;
428 }
429
430 int swf_FontInitUsage(FONTUSAGE * use)
431 { if (!use) return -1;
432   memset(use->code,0,sizeof(use->code[0])*MAX_CHAR_PER_FONT);
433   return 0;
434 }
435
436 int swf_FontUse(FONTUSAGE * use,U8 * s)
437 { if ((!use)||(!s)) return -1;
438   while (s[0])
439   { use->code[s[0]] = 1;
440     s++;
441   }
442   return 0;  
443 }
444
445 int swf_FontSetDefine(TAG * t,SWFFONT * f)
446 { U16*ofs = (U16*)malloc(f->numchars*2);
447   int p,i,j;
448     
449   if ((!t)||(!f)) return -1;
450   swf_ResetWriteBits(t);
451   swf_SetU16(t,f->id);
452
453   p = 0; j = 0;
454   for (i=0;i<f->numchars;i++)
455     if (f->glyph[i].shape)
456     { ofs[j++] = p;
457       p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
458     }
459
460   for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
461   if(!j) {
462       fprintf(stderr, "rfxswf: warning: Font is empty\n");
463       swf_SetU16(t, 0);
464   }
465   
466   for (i=0;i<f->numchars;i++)
467     if (f->glyph[i].shape)
468       swf_SetSimpleShape(t,f->glyph[i].shape);
469   
470   swf_ResetWriteBits(t);
471   free(ofs);
472   return 0;
473 }
474
475 int swf_FontSetDefine2(TAG *tag, SWFFONT * f)
476 {
477     U8 flags = 0;
478     int t;
479     int pos;
480     int pos2;
481     swf_SetU16(tag, f->id);
482     if(f->layout) 
483         flags |= 128; // haslayout
484     if(f->numchars>256)
485         flags |= 4; // widecodes
486     if(f->style & FONT_STYLE_BOLD)
487         flags |= 1; // bold
488     if(f->style & FONT_STYLE_ITALIC)
489         flags |= 2; // italic
490     /* wideoffs 8 */
491     if(f->encoding & FONT_ENCODING_ANSI)
492         flags |= 16; // ansi
493     if(f->encoding & FONT_ENCODING_UNICODE)
494         flags |= 32; // unicode
495     if(f->encoding & FONT_ENCODING_SHIFTJIS)
496         flags |= 64; // shiftjis
497
498     swf_SetU8(tag, flags);
499     swf_SetU8(tag, 0); //reserved flags
500     if(f->name) {
501         /* font name */
502         swf_SetU8(tag, strlen(f->name));
503         swf_SetBlock(tag, f->name, strlen(f->name));
504     } else {
505         /* font name (="") */
506         swf_SetU8(tag, 0); /*placeholder*/
507     }
508     /* number of glyphs */
509     swf_SetU16(tag, f->numchars);
510     /* font offset table */
511     pos = tag->len;
512     for(t=0;t<f->numchars;t++)
513     {
514         swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/
515     }
516     pos2 = tag->len;
517     swf_SetU16(tag, 0); //fontcode-fontoffset
518     for(t=0;t<f->numchars;t++) {
519         tag->data[pos + t*2] = (tag->len-pos);
520         tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8;
521         swf_SetSimpleShape(tag, f->glyph[t].shape);
522     }
523
524     tag->data[pos2] = tag->len - pos;
525     tag->data[pos2 + 1] = (tag->len - pos) >> 8;
526     
527     /* font code table */
528     if(flags & 4) /* wide codes */ {
529         for(t=0;t<f->numchars;t++)
530             swf_SetU16(tag,f->glyph2ascii[t]);
531     } else {
532         for(t=0;t<f->numchars;t++)
533             swf_SetU8(tag,f->glyph2ascii[t]);
534     }
535     if(f->layout) 
536     {
537         swf_SetU16(tag,f->layout->ascent);
538         swf_SetU16(tag,f->layout->descent);
539         swf_SetU16(tag,f->layout->leading);
540         for(t=0;t<f->numchars;t++)
541             swf_SetU16(tag,f->glyph[t].advance);
542         for(t=0;t<f->numchars;t++) {
543             swf_ResetWriteBits(tag);
544             swf_SetRect(tag,&f->layout->bounds[t]);
545         }
546         swf_SetU16(tag, f->layout->kerningcount);
547         for(t=0;t<f->layout->kerningcount;t++) {
548             if(flags & 4) /* wide codes */ {
549                 swf_SetU8(tag,f->layout->kerning[t].char1);
550                 swf_SetU8(tag,f->layout->kerning[t].char2);
551             } else {
552                 swf_SetU16(tag,f->layout->kerning[t].char1);
553                 swf_SetU16(tag,f->layout->kerning[t].char2);
554             }
555             swf_SetU16(tag,f->layout->kerning[t].adjustment);
556         }
557     }
558     return 0;
559 }
560     
561 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
562 {
563     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
564     f->layout->ascent = ascent;
565     f->layout->descent = descent;
566     f->layout->leading = leading;
567     f->layout->kerningcount = 0;
568     f->layout->kerning = 0;
569     f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars);
570     memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars);
571 }
572
573 int swf_FontSetInfo(TAG * t,SWFFONT * f)
574 { int l,i;
575   U8 wide=0;
576   U8 flags = 0;
577   if ((!t)||(!f)) return -1;
578   swf_ResetWriteBits(t);
579   swf_SetU16(t,f->id);
580   l = f->name?strlen(f->name):0; if (l>255) l = 255;
581   swf_SetU8(t,l);
582   if(l)
583     swf_SetBlock(t,f->name,l);
584   if(f->numchars>=256)
585       wide=1;
586
587   if(f->style & FONT_STYLE_BOLD)
588       flags |= 2;
589   if(f->style & FONT_STYLE_ITALIC)
590       flags |= 4;
591   if(f->style & FONT_ENCODING_ANSI)
592       flags |= 8;
593   if(f->style & FONT_ENCODING_SHIFTJIS)
594       flags |= 16;
595   if(f->style & FONT_ENCODING_UNICODE)
596       flags |= 32;
597     
598   swf_SetU8(t,(flags&0xfe)|wide);
599
600   for (i=0;i<f->numchars;i++) {
601     if (f->glyph[i].shape)
602       wide?swf_SetU16(t,f->glyph2ascii[i]):
603            swf_SetU8(t,f->glyph2ascii[i]);
604   }
605   
606   return 0;
607 }
608
609 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
610 { int id = swf_GetTagID(t);
611   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
612     else return -1;
613   return 0;
614 }
615
616 void swf_LayoutFree(SWFLAYOUT * l)
617 { if (l)
618   { if (l->kerning) free(l->kerning);
619     l->kerning = NULL;
620     if (l->bounds) free(l->bounds);
621     l->bounds = NULL;
622   }
623   free(l);
624 }
625
626 void swf_FontFree(SWFFONT * f)
627 { if (f)
628   { int i;
629       
630     if (f->name) free(f->name);
631     if (f->layout) swf_LayoutFree(f->layout);
632
633     f->name = NULL;
634     f->layout = NULL;
635
636     if(f->glyph) {
637       for (i=0;i<f->numchars;i++)
638         if (f->glyph[i].shape)
639         { swf_ShapeFree(f->glyph[i].shape);
640           f->glyph[i].shape = NULL;
641         }
642       free(f->glyph);
643       f->glyph = NULL;
644     }
645     if(f->ascii2glyph) {
646       free(f->ascii2glyph);
647       f->ascii2glyph = NULL;
648     }
649     if(f->glyph2ascii) {
650       free(f->glyph2ascii);
651       f->glyph2ascii = NULL;
652     }
653   }
654   free(f);
655 }
656
657 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
658 { U8 flags;
659   if (!t) return -1;
660
661   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
662
663   swf_SetU8(t,flags);
664   if (font) swf_SetU16(t,font->id);
665   if (color)
666   { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
667     else swf_SetRGB(t,color);
668   }
669   if (dx) swf_SetS16(t,dx);
670   if (dy) swf_SetS16(t,dy);
671   if (font) swf_SetU16(t,size);
672   
673   return 0;
674 }
675
676 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
677 { U16 g,a;
678   if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
679   g = a = 0;
680
681   while(s[0])
682   { 
683     int glyph = -1;
684     if(s[0] < font->maxascii)
685         glyph = font->ascii2glyph[s[0]];
686     if(glyph>=0) {
687        g = swf_CountBits(glyph,g);
688        a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
689     }
690     s++;
691   }
692
693   if (gbits) gbits[0] = (U8)g;
694   if (abits) abits[0] = (U8)a;
695
696   return 0;
697 }
698
699 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
700 { int l=0,i,pos;
701     
702   if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
703
704   pos = t->len;
705   swf_SetU8(t, l); //placeholder
706
707   for (i=0;s[i];i++)
708   { 
709     int g = -1;
710     if(s[i] < font->maxascii) 
711         g = font->ascii2glyph[s[i]];
712     if(g>=0) {
713       swf_SetBits(t,g,gbits);
714       swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
715       l++;
716       if(l==0x7f)
717           break;
718     }
719   }
720
721   PUT8(&t->data[pos], l);
722
723   swf_ResetWriteBits(t);
724   return 0;
725 }
726
727 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
728 { U32 res = 0;
729
730   if (font&&s)
731   { while (s[0])
732     { 
733       int g = -1;
734       if(*s < font->maxascii) 
735           g = font->ascii2glyph[*s];
736       if(g>=0)
737         res += font->glyph[g].advance;
738       s++;
739     }
740     if (scale) res = (res*scale)/100;
741   }
742   return res;
743 }
744
745 SWFFONT* swf_ReadFont(char* filename)
746 {
747   int f;
748   SWF swf;
749   if(!filename)
750       return 0;
751   f = open(filename,O_RDONLY);
752   
753   if (f<0 || swf_ReadSWF(f,&swf)<0)
754   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
755     close(f);
756     return 0;
757   }
758   else
759   { SWFFONT*font;
760     close(f);
761     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
762        return 0;
763     swf_FreeTags(&swf);
764     return font;
765   }
766 }
767
768 void swf_WriteFont(SWFFONT*font, char* filename)
769 { SWF swf;
770   TAG * t;
771   SRECT r;
772   RGBA rgb;
773   int f;
774   int useDefineFont2 = 0;
775
776   if(font->layout)
777       useDefineFont2 = 1; /* the only thing new in definefont2 
778                              is layout information. */
779
780   font->id = WRITEFONTID; //"FN"
781
782   memset(&swf,0x00,sizeof(SWF));
783
784   swf.fileVersion    = 4;
785   swf.frameRate      = 0x4000;
786
787   /* if we use DefineFont1 to store the characters,
788      we have to build a textfield to store the
789      advance values. While at it, we can also
790      make the whole .swf viewable */
791
792   /* we now always create viewable swfs, even if we
793      did use definefont2 -mk*/
794   t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
795   swf.firstTag = t;
796         rgb.r = 0xff;
797         rgb.g = 0xff;
798         rgb.b = 0xff;
799         swf_SetRGB(t,&rgb);
800   if(!useDefineFont2) {
801     t = swf_InsertTag(t,ST_DEFINEFONT);
802     swf_FontSetDefine(t,font);
803     t = swf_InsertTag(t,ST_DEFINEFONTINFO);
804     swf_FontSetInfo(t,font);
805   } else {
806     t = swf_InsertTag(t,ST_DEFINEFONT2);
807     swf_FontSetDefine2(t,font);
808   }
809
810   if(1) //useDefineFont2
811   {     int textscale = 400;
812         int s;
813         int xmax = 0;
814         int ymax = textscale * 2 * (font->maxascii/16+1);
815         U8 gbits,abits;
816         U8 text[MAX_CHAR_PER_FONT+1];
817         int x,y;
818         text[MAX_CHAR_PER_FONT]=0;
819         for(s=0;s<font->maxascii;s++)
820         {
821             int g = font->ascii2glyph[s];
822             text[s] = s;
823             if(g>=0) {
824                if(font->glyph[g].advance*textscale/64 > xmax)
825                    xmax = font->glyph[g].advance*textscale/64;
826             }
827         }
828         swf.movieSize.xmax = xmax*20;
829         swf.movieSize.ymax = ymax;
830
831         t = swf_InsertTag(t,ST_DEFINETEXT);
832
833             swf_SetU16(t,font->id+1);            // ID
834
835             r.xmin = 0;
836             r.ymin = 0;
837             r.xmax = swf.movieSize.xmax*20;
838             r.ymax = swf.movieSize.ymax;
839             
840             swf_SetRect(t,&r);
841
842             swf_SetMatrix(t,NULL);
843
844             abits = swf_CountBits(xmax*16, 0);
845             gbits = 8;
846             
847             swf_SetU8(t,gbits);
848             swf_SetU8(t,abits);
849
850             rgb.r = 0x00;
851             rgb.g = 0x00;
852             rgb.b = 0x00;
853             for(y=0;y<=((font->maxascii-1)/16);y++)
854             {
855                 int c=0,lastx=-1;
856                 /* TODO: firstx?? */
857                 for(x=0;x<16;x++) {
858                     int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
859                     if(g>=0 && font->glyph[g].shape) {
860                         c++;
861                         if(lastx<0) 
862                             lastx = x*xmax;
863                     }
864                 }
865                 if(c) {
866                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y*2);
867                   for(x=0;x<16;x++)
868                   {
869                       int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
870                       if(g>=0 && font->glyph[g].shape) {
871                         if(lastx != x*xmax) {
872                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
873                         }
874                         swf_SetU8(t,1);
875                         swf_SetBits(t, g, gbits);
876                         swf_SetBits(t, font->glyph[g].advance, abits);
877                         lastx = x*xmax+font->glyph[g].advance;
878                         swf_ResetWriteBits(t);
879                       }
880                   }
881                 } 
882             }
883             swf_SetU8(t,0);
884
885         
886         t = swf_InsertTag(t,ST_PLACEOBJECT2);
887
888             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
889      
890         t = swf_InsertTag(t,ST_SHOWFRAME);
891   }
892   
893   t = swf_InsertTag(t,ST_END);
894
895   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
896   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
897   close(f);
898
899   swf_FreeTags(&swf);
900 }
901
902
903 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, 
904         int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
905 {
906     swf_SetRect(tag,&r);
907     swf_ResetWriteBits(tag);
908
909     flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
910     if(text) flags |= ET_HASTEXT;
911     if(color) flags |= ET_HASTEXTCOLOR;
912     if(maxlength) flags |= ET_HASMAXLENGTH;
913     if(font) flags |= ET_HASFONT;
914     if(layout) flags |= ET_HASLAYOUT;
915
916     swf_SetBits(tag, flags, 16);
917
918     if(flags & ET_HASFONT) {
919         swf_SetU16(tag, font); //font
920         swf_SetU16(tag, height); //fontheight
921     }
922     if(flags & ET_HASTEXTCOLOR) {
923         swf_SetRGBA(tag, color);
924     }
925     if(flags & ET_HASMAXLENGTH) {
926         swf_SetU16(tag, maxlength); //maxlength
927     }
928     if(flags & ET_HASLAYOUT) {
929         swf_SetU8(tag,layout->align); //align
930         swf_SetU16(tag,layout->leftmargin); //left margin
931         swf_SetU16(tag,layout->rightmargin); //right margin
932         swf_SetU16(tag,layout->indent); //indent
933         swf_SetU16(tag,layout->leading); //leading
934     }
935     swf_SetString(tag, variable);
936     if(flags & ET_HASTEXT)
937         swf_SetString(tag,text);
938 }
939
940 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
941 {
942     SRECT r;
943     U8 gbits, abits;
944     U8*c = (U8*)text;
945     int pos = 0;
946     swf_GetRect(0, &r);
947     if(font->layout) {
948         while(*c) {
949             if(*c < font->maxascii) {
950                 int g = font->ascii2glyph[*c];
951                 if(g>=0) {
952                     SRECT rn = font->layout->bounds[g];
953                     rn.xmin = (rn.xmin * scale)/100 + pos;
954                     rn.xmax = (rn.xmax * scale)/100 + pos;
955                     rn.ymin = (rn.ymin * scale)/100;
956                     rn.ymax = (rn.ymax * scale)/100;
957                     swf_ExpandRect2(&r, &rn);
958                     pos += (font->glyph[g].advance*scale*20)/100;
959                 }
960             }
961             c++;
962         }
963     } else {
964         /* Hm, without layout information, we can't compute a bounding
965            box. We could call swf_FontCreateLayout to create a layout,
966            but the caller probably doesn't want us to mess up his font
967            structure.
968         */
969         r.xmin = r.ymin = 0;
970         r.xmax = r.ymax = 1024*20;
971     }
972
973     swf_SetRect(tag,&r);
974     swf_SetMatrix(tag,NULL);
975     swf_TextCountBits(font,text,scale*20,&gbits,&abits);
976     swf_SetU8(tag,gbits);
977     swf_SetU8(tag,abits);
978
979     /* now set the text params- notice that a font size of
980        1024 means that the glyphs will be displayed exactly
981        as they would be in/with a defineshape. (Try to find
982        *that* in the flash specs)
983      */
984     swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale
985
986     /* set the actual text- notice that we just pass our scale
987        parameter over, as TextSetCharRecord calculates with 
988        percent, too */
989     swf_TextSetCharRecord(tag,font,text,scale*20,gbits,abits);
990
991     swf_SetU8(tag,0);
992     return r;
993 }
994
995 void swf_FontCreateLayout(SWFFONT*f)
996 {
997     S16 leading = 0;
998     int t;
999     if(f->layout)
1000         return;
1001     if(!f->numchars)
1002         return;
1003     
1004     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
1005     memset(f->layout, 0, sizeof(SWFLAYOUT));
1006     f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
1007     f->layout->ascent = -32767;
1008     f->layout->descent = -32767;
1009
1010     for(t=0;t<f->numchars;t++) {
1011         SHAPE2*shape2;
1012         SRECT bbox;
1013         int width;
1014         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
1015         if(!shape2) { 
1016             fprintf(stderr, "Shape parse error\n");exit(1);
1017         }
1018         bbox = swf_GetShapeBoundingBox(shape2->lines);
1019         swf_Shape2Free(shape2);
1020         f->layout->bounds[t] = bbox;
1021         /* FIXME */
1022         //width = (bbox.xmax - bbox.xmin)/20;
1023         width = (bbox.xmax)/20;
1024
1025         /* The following is a heuristic- it may be that extractfont_DefineText
1026            has already found out some widths for individual characters (from the way
1027            they are used)- we now have to guess whether that width might be possible,
1028            which is the case if it isn't either much too big or much too small */
1029         if(width > f->glyph[t].advance*3/2 ||
1030            width*2 < f->glyph[t].advance)
1031             f->glyph[t].advance = width;
1032
1033         if(-bbox.ymin > f->layout->ascent)
1034             f->layout->ascent = bbox.ymin;
1035         if(bbox.ymax > f->layout->descent)
1036             f->layout->descent = bbox.ymax;
1037     }
1038 }
1039         
1040