* zlib is now optional
[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 = font->ascii2glyph[s[0]];
684     if(glyph>=0) {
685        g = swf_CountBits(glyph,g);
686        a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
687     }
688     s++;
689   }
690
691   if (gbits) gbits[0] = (U8)g;
692   if (abits) abits[0] = (U8)a;
693
694   return 0;
695 }
696
697 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
698 { int l,i;
699     
700   if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
701
702   l = strlen(s);
703   if (l>0x7f) l = 0x7f;
704   swf_SetU8(t,l);
705
706   for (i=0;i<l;i++)
707   { 
708     int g = font->ascii2glyph[s[i]];
709     if(g>=0) {
710       swf_SetBits(t,g,gbits);
711       swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
712     }
713   }
714
715   swf_ResetWriteBits(t);
716   return 0;
717 }
718
719 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
720 { U32 res = 0;
721
722   if (font&&s)
723   { while (s[0])
724     { 
725       int g = font->ascii2glyph[*s];
726       if(g>=0)
727         res += font->glyph[g].advance;
728       s++;
729     }
730     if (scale) res = (res*scale)/100;
731   }
732   return res;
733 }
734
735 SWFFONT* swf_ReadFont(char* filename)
736 {
737   int f;
738   SWF swf;
739   if(!filename)
740       return 0;
741   f = open(filename,O_RDONLY);
742   
743   if (f<0 || swf_ReadSWF(f,&swf)<0)
744   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
745     close(f);
746     return 0;
747   }
748   else
749   { SWFFONT*font;
750     close(f);
751     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
752        return 0;
753     swf_FreeTags(&swf);
754     return font;
755   }
756 }
757
758 void swf_WriteFont(SWFFONT*font, char* filename)
759 { SWF swf;
760   TAG * t;
761   SRECT r;
762   RGBA rgb;
763   int f;
764   int useDefineFont2 = 0;
765
766   if(font->layout)
767       useDefineFont2 = 1; /* the only thing new in definefont2 
768                              is layout information. */
769
770   font->id = WRITEFONTID; //"FN"
771
772   memset(&swf,0x00,sizeof(SWF));
773
774   swf.fileVersion    = 4;
775   swf.frameRate      = 0x4000;
776
777   /* if we use DefineFont1 to store the characters,
778      we have to build a textfield to store the
779      advance values. While at it, we can also
780      make the whole .swf viewable */
781
782   /* we now always create viewable swfs, even if we
783      did use definefont2 -mk*/
784   t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
785   swf.firstTag = t;
786         rgb.r = 0xff;
787         rgb.g = 0xff;
788         rgb.b = 0xff;
789         swf_SetRGB(t,&rgb);
790   if(!useDefineFont2) {
791     t = swf_InsertTag(t,ST_DEFINEFONT);
792     swf_FontSetDefine(t,font);
793     t = swf_InsertTag(t,ST_DEFINEFONTINFO);
794     swf_FontSetInfo(t,font);
795   } else {
796     t = swf_InsertTag(t,ST_DEFINEFONT2);
797     swf_FontSetDefine2(t,font);
798   }
799
800   if(1) //useDefineFont2
801   {     int textscale = 400;
802         int s;
803         int xmax = 0;
804         int ymax = textscale * 2 * (font->maxascii/16+1);
805         U8 gbits,abits;
806         char text[MAX_CHAR_PER_FONT+1];
807         int x,y;
808         text[MAX_CHAR_PER_FONT]=0;
809         for(s=0;s<font->maxascii;s++)
810         {
811             int g = font->ascii2glyph[s];
812             text[s] = s;
813             if(g>=0) {
814                if(font->glyph[g].advance*textscale/64 > xmax)
815                    xmax = font->glyph[g].advance*textscale/64;
816             }
817         }
818         swf.movieSize.xmax = xmax*20;
819         swf.movieSize.ymax = ymax;
820
821         t = swf_InsertTag(t,ST_DEFINETEXT);
822
823             swf_SetU16(t,font->id+1);            // ID
824
825             r.xmin = 0;
826             r.ymin = 0;
827             r.xmax = swf.movieSize.xmax*20;
828             r.ymax = swf.movieSize.ymax;
829             
830             swf_SetRect(t,&r);
831
832             swf_SetMatrix(t,NULL);
833
834             abits = swf_CountBits(xmax*16, 0);
835             gbits = 8;
836             
837             swf_SetU8(t,gbits);
838             swf_SetU8(t,abits);
839
840             rgb.r = 0x00;
841             rgb.g = 0x00;
842             rgb.b = 0x00;
843             for(y=0;y<=((font->maxascii-1)/16);y++)
844             {
845                 int c=0,lastx=-1;
846                 /* TODO: firstx?? */
847                 for(x=0;x<16;x++) {
848                     int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
849                     if(g>=0 && font->glyph[g].shape) {
850                         c++;
851                         if(lastx<0) 
852                             lastx = x*xmax;
853                     }
854                 }
855                 if(c) {
856                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y*2);
857                   for(x=0;x<16;x++)
858                   {
859                       int g = (y*16+x<font->maxascii)?font->ascii2glyph[y*16+x]:-1;
860                       if(g>=0 && font->glyph[g].shape) {
861                         if(lastx != x*xmax) {
862                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
863                         }
864                         swf_SetU8(t,1);
865                         swf_SetBits(t, g, gbits);
866                         swf_SetBits(t, font->glyph[g].advance, abits);
867                         lastx = x*xmax+font->glyph[g].advance;
868                         swf_ResetWriteBits(t);
869                       }
870                   }
871                 } 
872             }
873             swf_SetU8(t,0);
874
875         
876         t = swf_InsertTag(t,ST_PLACEOBJECT2);
877
878             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
879      
880         t = swf_InsertTag(t,ST_SHOWFRAME);
881   }
882   
883   t = swf_InsertTag(t,ST_END);
884
885   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
886   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
887   close(f);
888
889   swf_FreeTags(&swf);
890 }
891
892
893 void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, 
894         int maxlength, U16 font, U16 height, EditTextLayout*layout, char*variable)
895 {
896     swf_SetRect(tag,&r);
897     swf_ResetWriteBits(tag);
898
899     flags &= ~(ET_HASTEXT|ET_HASTEXTCOLOR|ET_HASMAXLENGTH|ET_HASFONT|ET_HASLAYOUT);
900     if(text) flags |= ET_HASTEXT;
901     if(color) flags |= ET_HASTEXTCOLOR;
902     if(maxlength) flags |= ET_HASMAXLENGTH;
903     if(font) flags |= ET_HASFONT;
904     if(layout) flags |= ET_HASLAYOUT;
905
906     swf_SetBits(tag, flags, 16);
907
908     if(flags & ET_HASFONT) {
909         swf_SetU16(tag, font); //font
910         swf_SetU16(tag, height); //fontheight
911     }
912     if(flags & ET_HASTEXTCOLOR) {
913         swf_SetRGBA(tag, color);
914     }
915     if(flags & ET_HASMAXLENGTH) {
916         swf_SetU16(tag, maxlength); //maxlength
917     }
918     if(flags & ET_HASLAYOUT) {
919         swf_SetU8(tag,layout->align); //align
920         swf_SetU16(tag,layout->leftmargin); //left margin
921         swf_SetU16(tag,layout->rightmargin); //right margin
922         swf_SetU16(tag,layout->indent); //indent
923         swf_SetU16(tag,layout->leading); //leading
924     }
925     swf_SetString(tag, variable);
926     if(flags & ET_HASTEXT)
927         swf_SetString(tag,text);
928 }
929
930 SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale)
931 {
932     SRECT r;
933     U8 gbits, abits;
934     U8*c = (U8*)text;
935     int pos = 0;
936     swf_GetRect(0, &r);
937     if(font->layout) {
938         while(*c) {
939             if(*c < font->maxascii) {
940                 int g = font->ascii2glyph[*c];
941                 SRECT rn = font->layout->bounds[g];
942                 rn.xmin = (rn.xmin * scale)/2000 + pos;
943                 rn.xmax = (rn.xmax * scale)/2000 + pos;
944                 rn.ymin = (rn.ymin * scale)/2000;
945                 rn.ymax = (rn.ymax * scale)/2000;
946                 swf_ExpandRect2(&r, &rn);
947                 pos += (font->glyph[g].advance*scale)/100;
948             }
949             c++;
950         }
951     } else {
952         /* Hm, without layout information, we can't compute a bounding
953            box. We could call swf_FontCreateLayout to create a layout,
954            but the caller probably doesn't want us to mess up his font
955            structure.
956         */
957         r.xmin = r.ymin = 0;
958         r.xmax = r.ymax = 1024*20;
959     }
960
961     swf_SetRect(tag,&r);
962     swf_SetMatrix(tag,NULL);
963     swf_TextCountBits(font,text,scale,&gbits,&abits);
964     swf_SetU8(tag,gbits);
965     swf_SetU8(tag,abits);
966     swf_TextSetInfoRecord(tag,font,scale/2 /*?? why /2? */,rgb,0,0); //scale
967     swf_TextSetCharRecord(tag,font,text,scale,gbits,abits);
968     swf_SetU8(tag,0);
969     return r;
970 }
971
972 void swf_FontCreateLayout(SWFFONT*f)
973 {
974     S16 leading = 0;
975     int t;
976     if(f->layout)
977         return;
978     if(!f->numchars)
979         return;
980     
981     f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
982     memset(f->layout, 0, sizeof(SWFLAYOUT));
983     f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT));
984     f->layout->ascent = -32767;
985     f->layout->descent = -32767;
986
987     for(t=0;t<f->numchars;t++) {
988         SHAPE2*shape2;
989         SRECT bbox;
990         int width;
991         shape2 = swf_ShapeToShape2(f->glyph[t].shape);
992         if(!shape2) { 
993             fprintf(stderr, "Shape parse error\n");exit(1);
994         }
995         bbox = swf_GetShapeBoundingBox(shape2->lines);
996         swf_Shape2Free(shape2);
997         f->layout->bounds[t] = bbox;
998         /* FIXME */
999         //width = (bbox.xmax - bbox.xmin)/20;
1000         width = (bbox.xmax)/20;
1001
1002         /* The following is a heuristic- it may be that extractfont_DefineText
1003            has already found out some widths for individual characters (from the way
1004            they are used)- we now have to guess whether that width might be possible,
1005            which is the case if it isn't either much too big or much too small */
1006         if(width > f->glyph[t].advance*3/2 ||
1007            width*2 < f->glyph[t].advance)
1008             f->glyph[t].advance = width;
1009
1010         if(-bbox.ymin > f->layout->ascent)
1011             f->layout->ascent = bbox.ymin;
1012         if(bbox.ymax > f->layout->descent)
1013             f->layout->descent = bbox.ymax;
1014     }
1015 }
1016         
1017