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