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