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