ef46afd07800eaaa1c964020be8ce50c0bf142b9
[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 int FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
28 { int n;
29   TAG * t;
30   if (!swf) return -1;
31   t = swf->FirstTag;
32   n = 0;
33
34   while (t)
35   { if (GetTagID(t)==ST_DEFINEFONTINFO)
36     { n++;
37       if (FontCallback)
38       { U16 id;
39         int l;
40         U8 s[257];
41         SaveTagPos(t);
42         SetTagPos(t,0);
43
44         id  = GetU16(t);
45         l   = GetU8(t);
46         GetBlock(t,s,l);
47         s[l] = 0;
48
49         (FontCallback)(id,s); 
50       
51         RestoreTagPos(t);
52       }
53     }
54     t = NextTag(t);
55   }
56   return n;
57 }
58
59 int FontExtract_DefineFont(int id,SWFFONT * f,TAG * t,SHAPE * * shapes)
60 { U16 fid;
61   SaveTagPos(t);
62   SetTagPos(t,0);
63
64   fid = GetU16(t);
65   if ((!id)||(id==fid))
66   { U16 ofs[MAX_CHAR_PER_FONT];
67     int n,i;
68       
69     id = fid;
70     f->id = fid;
71
72     ofs[0] = GetU16(t);
73     n = ofs[0]/2;
74
75     for (i=1;i<n;i++) if (i<MAX_CHAR_PER_FONT) ofs[i] = GetU16(t); else GetU16(t);
76     for (i=0;i<n;i++) if (i<MAX_CHAR_PER_FONT) GetSimpleShape(t,&shapes[i]);
77     
78   }
79
80   RestoreTagPos(t);
81   return id;
82 }
83
84 int FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t,SHAPE * * shapes)
85 { U16 fid;
86   SaveTagPos(t);
87   SetTagPos(t,0);
88
89   fid = GetU16(t);
90   if (fid==id)
91   { U8 l = GetU8(t);
92     int i;
93     
94     if (l)
95     { if (f->name) free(f->name);
96       f->name = (U8*)malloc(l+1);
97       if (f->name)
98       { GetBlock(t,f->name,l);
99         f->name[l] = 0;
100       }
101       else
102       { RestoreTagPos(t);
103         return -1;
104       }
105     }
106     f->flags = GetU8(t);
107
108     i = 0;
109     while (shapes[i])
110     { U16 code = ((f->flags&FF_WIDECODES)?GetU16(t):GetU8(t))%MAX_CHAR_PER_FONT;
111         
112       f->glyph[code].shape = shapes[i];
113       f->glyph[code].gid   = i;
114       if (i<MAX_CHAR_PER_FONT) f->codes[i] = code;
115
116       i++;
117     }
118   }
119
120   RestoreTagPos(t);
121   return id;
122 }
123
124 #define FEDTJ_PRINT  0x01
125 #define FEDTJ_MODIFY 0x02
126
127 int FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
128 { U16    cid;
129   SRECT  r;
130   MATRIX m;
131   U8     gbits, abits, flags;
132   int    fid;
133
134   fid = 0;
135
136   SaveTagPos(t);
137   SetTagPos(t,0);
138
139   cid = GetU16(t);
140   GetRect(t,&r);
141   GetMatrix(t,&m);
142   gbits = GetU8(t);
143   abits = GetU8(t);
144
145   flags = GetU8(t);
146   
147   while(flags)
148   { if (flags&TF_TEXTCONTROL)
149     { if (flags&TF_HASFONT) fid = GetU16(t);
150       if (flags&TF_HASCOLOR)
151       { GetU8(t); // rgb
152         GetU8(t);
153         GetU8(t);
154         if (GetTagID(t)==ST_DEFINETEXT2) GetU8(t);
155       }
156       if (flags&TF_HASXOFFSET) GetS16(t);
157       if (flags&TF_HASYOFFSET) GetS16(t);
158       if (flags&TF_HASFONT) GetU16(t);
159     }
160     else
161     { int i;
162       for (i=0;i<flags;i++)
163       { int glyph;
164         int adv;
165         glyph = GetBits(t,gbits);
166         adv = GetBits(t,abits);
167         if (id==fid)                    // mitlesen ?
168         { int code = f->codes[glyph];
169           if (jobs&FEDTJ_PRINT) printf("%c",code);
170           if (jobs&FEDTJ_MODIFY)
171             /*if (f->glyph[code].advance)*/ f->glyph[code].advance = adv;
172         }
173       }
174       if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
175     }
176     flags = GetU8(t);
177   }
178   
179   RestoreTagPos(t);
180   return id;
181 }  
182
183 int FontExtract(SWF * swf,int id,SWFFONT * * font)
184 { TAG * t;
185   SWFFONT * f;
186   SHAPE * shapes[MAX_CHAR_PER_FONT];
187     
188   if ((!swf)||(!font)) return -1;
189
190   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
191   if (!f) return -1;
192   
193   memset(shapes,0x00,sizeof(shapes));
194   memset(f,0x00,sizeof(SWFFONT));
195
196   t = swf->FirstTag;
197
198   while (t)
199   { int nid = 0;
200     switch (GetTagID(t))
201     { case ST_DEFINEFONT:
202         nid = FontExtract_DefineFont(id,f,t,shapes);
203         break;
204         
205       case ST_DEFINEFONTINFO:
206         nid = FontExtract_DefineFontInfo(id,f,t,shapes);
207         break;
208         
209       case ST_DEFINETEXT:
210       case ST_DEFINETEXT2:
211         nid = FontExtract_DefineText(id,f,t,FEDTJ_MODIFY);
212         break;
213     }
214     if (nid>0) id = nid;
215     t = NextTag(t);
216   }
217   return 0;
218 }
219
220 int FontIsItalic(SWFFONT * f) { return f->flags&FF_ITALIC; }
221 int FontIsBold(SWFFONT * f)   { return f->flags&FF_BOLD; }
222
223 int FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
224
225 int FontReduce(SWFFONT * f,FONTUSAGE * use)
226 { int i,j;
227   if ((!f)||(!use)) return -1;
228
229   memset(&f->codes,0x00,sizeof(f->codes));
230
231   j = 0;
232   for (i=0;i<MAX_CHAR_PER_FONT;i++)
233     if (f->glyph[i].shape)
234     { if (use->code[i])
235       { f->glyph[i].gid = j;
236         f->codes[j] = i;
237         j++;
238       }
239       else
240       { ShapeFree(f->glyph[i].shape);
241         f->glyph[i].shape   = 0;
242         f->glyph[i].gid     = 0;
243         f->glyph[i].advance = 0;
244       }
245     } else f->glyph[i].gid = 0;
246     
247   return j;
248 }
249
250 int FontInitUsage(FONTUSAGE * use)
251 { if (!use) return -1;
252   memset(&use->code,0x00,sizeof(use->code));
253   return 0;
254 }
255
256 int FontUse(FONTUSAGE * use,U8 * s)
257 { if ((!use)||(!s)) return -1;
258   while (s[0])
259   { use->code[s[0]] = 1;
260     s++;
261   }
262   return 0;  
263 }
264
265 int FontSetDefine(TAG * t,SWFFONT * f)
266 { U16 ofs[MAX_CHAR_PER_FONT];
267   int p,i,j;
268     
269   if ((!t)||(!f)) return -1;
270   ResetBitcount(t);
271   SetU16(t,f->id);
272
273   p = 0; j = 0;
274   for (i=0;i<MAX_CHAR_PER_FONT;i++)
275     if (f->glyph[i].shape)
276     { ofs[j++] = p;
277       p+=SetSimpleShape(NULL,f->glyph[i].shape);
278     }
279
280   for (i=0;i<j;i++) SetU16(t,ofs[i]+j*2);
281   
282   for (i=0;i<MAX_CHAR_PER_FONT;i++)
283     if (f->glyph[i].shape)
284       SetSimpleShape(t,f->glyph[i].shape);
285   
286   ResetBitcount(t);
287   return 0;
288 }
289
290 int FontSetInfo(TAG * t,SWFFONT * f)
291 { int l,i;
292   if ((!t)||(!f)) return -1;
293   ResetBitcount(t);
294   SetU16(t,f->id);
295   l = strlen(f->name); if (l>255) l = 255;
296   SetU8(t,l);
297   SetBlock(t,f->name,l);
298   SetU8(t,f->flags&0xfe); // no Wide-Codes
299
300   for (i=0;i<MAX_CHAR_PER_FONT;i++)
301     if (f->glyph[i].shape)
302       SetU8(t,i);
303   
304   return 0;
305 }
306
307 int FontExport(int handle,SWFFONT * f)
308 { int l;
309   int i;
310   if (!f) return 0;
311
312   l = sizeof(SWFFONT);
313   if (handle>=0)
314     if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1;
315
316   if (f->name)
317   { U16 ln = strlen(f->name);
318     l+=2+ln;
319     if (handle>=0)
320     { if (write(handle,&ln,2)!=2) return -1;
321       if (write(handle,f->name,ln)!=ln) return -1;
322     }
323   }
324
325   if (f->layout)
326   { l+=sizeof(SWFLAYOUT);
327     if (handle>=0)
328       if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1;
329     if (f->layout->kerning.data)
330     { l+=f->layout->kerning.count*4;
331       if (handle>=0)
332         if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1;
333     }
334   }
335
336   for (i=0;i<MAX_CHAR_PER_FONT;i++)
337   { if (f->glyph[i].shape)
338     { int ll = ShapeExport(handle,f->glyph[i].shape);
339       if (ll<0) return -1;
340       l+=ll;
341     }  
342   }
343
344   return l;
345 }
346
347 int FontImport(int handle,SWFFONT * * font)
348 { SWFFONT * f;
349   int layout;
350   int i = 0;
351
352   if ((!font)||(handle<0)) return -1;
353
354   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
355   if (!f) return -1;
356
357   memset(f,0x00,sizeof(SWFFONT));
358   
359   if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler;
360
361   layout = (f->layout)?1:0;             // avoid illegal free()
362   f->layout = NULL;
363
364   if (f->name)
365   { U16 ln;
366     f->name = NULL;
367     if (read(handle,&ln,2)!=2) goto fehler;
368     f->name = (U8*)malloc(ln+1);
369     if (!f->name) goto fehler;
370     if (read(handle,f->name,ln)!=ln) goto fehler;
371     f->name[ln] = 0;
372   }
373
374   if (f->layout)
375   { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT));
376     if (!f->layout) goto fehler;
377     if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler;
378     if (f->layout->kerning.data)
379     { int l = f->layout->kerning.count*4;
380       f->layout->kerning.data = (U8*)malloc(l);
381       if (!f->layout->kerning.data) goto fehler;
382       if (read(handle,f->layout->kerning.data,l)!=l) goto fehler;
383     }
384   }
385
386   for (i=0;i<MAX_CHAR_PER_FONT;i++)
387   { if (f->glyph[i].shape)
388     { if (ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler;
389     }
390   }
391
392   f->id = 0;
393   
394   return 0;
395   
396 fehler:
397   if (f) for (;i<MAX_CHAR_PER_FONT;i++) f->glyph[i].shape = NULL;
398   FontFree(f);
399   font[0] = NULL;
400   return -1;
401 }
402
403 int TextPrintDefineText(TAG * t,SWFFONT * f)
404 { int id = GetTagID(t);
405   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
406     else return -1;
407   return 0;
408 }
409
410 void LayoutFree(SWFLAYOUT * l)
411 { if (l)
412   { if (l->kerning.data) free(l->kerning.data);
413     l->kerning.data = NULL;
414   }
415   free(l);
416 }
417
418 void FontFree(SWFFONT * f)
419 { if (f)
420   { int i;
421       
422     if (f->name) free(f->name);
423     if (f->layout) LayoutFree(f->layout);
424
425     f->name = NULL;
426     f->layout = NULL;
427
428     for (i=0;i<MAX_CHAR_PER_FONT;i++)
429       if (f->glyph[i].shape)
430       { ShapeFree(f->glyph[i].shape);
431         f->glyph[i].shape = NULL;
432       }
433   }
434   free(f);
435 }
436
437 int TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
438 { U8 flags;
439   if (!t) return -1;
440
441   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
442
443   SetU8(t,flags);
444   if (font) SetU16(t,font->id);
445   if (color)
446   { if (GetTagID(t)==ST_DEFINETEXT2) SetRGBA(t,color);
447     else SetRGB(t,color);
448   }
449   if (dx) SetS16(t,dx);
450   if (dy) SetS16(t,dy);
451   if (font) SetU16(t,size);
452   
453   return 0;
454 }
455
456 int TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
457 { U16 g,a;
458   if ((!s)||(!font)||((!gbits)&&(!abits))) return -1;
459   g = a = 0;
460
461   while(s[0])
462   { g = CountBits(font->glyph[s[0]].gid,g);
463     a = CountBits((((U32)font->glyph[s[0]].advance)*scale)/100,a);
464     s++;
465   }
466
467   if (gbits) gbits[0] = (U8)g;
468   if (abits) abits[0] = (U8)a;
469
470   return 0;
471 }
472
473 int TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
474 { int l,i;
475     
476   if ((!t)||(!font)||(!s)) return -1;
477
478   l = strlen(s);
479   if (l>0x7f) l = 0x7f;
480   SetU8(t,l);
481
482   for (i=0;i<l;i++)
483   { SetBits(t,font->glyph[s[i]].gid,gbits);
484     SetBits(t,(((U32)font->glyph[s[i]].advance)*scale)/100,abits);
485   }
486
487   ResetBitcount(t);
488   return 0;
489 }
490
491 U32 TextGetWidth(SWFFONT * font,U8 * s,int scale)
492 { U32 res = 0;
493
494   if (font&&s)
495   { while (s[0])
496     { res += font->glyph[s[0]].advance;
497       s++;
498     }
499     if (scale) res = (res*scale)/100;
500   }
501   
502   return res;
503 }