1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* $Id$ */
21
22 #include <math.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "font.h"
27 #include "method.h"
28 #include "utf8.h"
29 #include "character.h"
30 #include "error.h"
31 #include "movie.h"
32 #include "libming.h"
33 #include "input.h"
34 #include "shape.h"
35
36 static void
readBounds(SWFInput input,struct SWFRect_s * bounds)37 readBounds(SWFInput input, struct SWFRect_s* bounds)
38 {
39 int nBits;
40
41 SWFInput_byteAlign(input);
42
43 nBits = SWFInput_readBits(input, 5);
44 bounds->minX = SWFInput_readSBits(input, nBits);
45 bounds->maxX = SWFInput_readSBits(input, nBits);
46 bounds->minY = SWFInput_readSBits(input, nBits);
47 bounds->maxY = SWFInput_readSBits(input, nBits);
48 }
49
50 static void
readKernInfo(SWFInput input,struct kernInfo * kern)51 readKernInfo(SWFInput input, struct kernInfo *kern)
52 {
53 kern->code1 = SWFInput_getChar(input);
54 kern->code2 = SWFInput_getChar(input);
55 kern->adjustment = SWFInput_getSInt16(input);
56 }
57
58 static void
readKernInfo16(SWFInput input,struct kernInfo16 * kern)59 readKernInfo16(SWFInput input, struct kernInfo16 *kern)
60 {
61 kern->code1 = SWFInput_getUInt16(input);
62 kern->code2 = SWFInput_getUInt16(input);
63 kern->adjustment = SWFInput_getSInt16(input);
64 }
65
66
checkShapeHeader(SWFInput input,int * numFillBits,int * numLineBits)67 static inline void checkShapeHeader(SWFInput input,
68 int *numFillBits,
69 int *numLineBits)
70 {
71 SWFInput_byteAlign(input);
72 if ( (*numFillBits = SWFInput_readBits(input, 4)) != 1 ) /* fill bits */
73 SWF_error("FdbFont read glyph: bad file format (was expecting fill bits = 1)\n");
74
75 if ( (*numLineBits = SWFInput_readBits(input, 4)) > 0 ) /* line bits */
76 SWF_error("FdbFont read glyph: bad file format (was expecting line bits = 0)\n");
77 }
78
checkShapeStyle(SWFInput input,char style,int numFillBits,int numLineBits)79 static inline void checkShapeStyle(SWFInput input, char style,
80 int numFillBits, int numLineBits)
81 {
82 if ( style & 1 )
83 if ( SWFInput_readBits(input, numFillBits) != 0 ) /* fill0 = 0 */
84 SWF_warn("SWFFont_getShape: bad file format (was expecting fill0 = 0)\n");
85 if ( style & 2 )
86 if ( SWFInput_readBits(input, numFillBits) != 1 ) /* fill1 = 1 */
87 SWF_warn("SWFFont_getShape: bad file format (was expecting fill1 = 1)\n");
88 if ( style & 4 )
89 if ( SWFInput_readBits(input, numLineBits) != 0 ) /* line = 1 */
90 SWF_warn("SWFFont_getShape: bad file format (was expecting line = 0)\n");
91 }
92
translateShapeRecord(SWFInput input,SWFShape shape)93 static int translateShapeRecord(SWFInput input, SWFShape shape)
94 {
95 int moveBits, x = 0, y = 0;
96 int straight, numBits;
97
98 if ( SWFInput_readBits(input, 1) == 0 )
99 {
100 /* it's a moveTo or a shape end */
101 if ( SWFInput_readBits(input, 5) == 0 )
102 return 0; /* shape end */
103
104 moveBits = SWFInput_readBits(input, 5);
105 x = SWFInput_readSBits(input, moveBits);
106 y = SWFInput_readSBits(input, moveBits);
107 SWFShape_moveScaledPenTo(shape, x, y);
108 return 1;
109 }
110
111 straight = SWFInput_readBits(input, 1);
112 numBits = SWFInput_readBits(input, 4) + 2;
113 if (straight == 1)
114 {
115 if ( SWFInput_readBits(input, 1) ) /* general line */
116 {
117 x = SWFInput_readSBits(input, numBits);
118 y = SWFInput_readSBits(input, numBits);
119 }
120 else
121 {
122 if ( SWFInput_readBits(input, 1) ) /* vert = 1 */
123 y = SWFInput_readSBits(input, numBits);
124 else
125 x = SWFInput_readSBits(input, numBits);
126 }
127 SWFShape_drawScaledLine(shape, x, y);
128 }
129 else
130 {
131 int controlX = SWFInput_readSBits(input, numBits);
132 int controlY = SWFInput_readSBits(input, numBits);
133 int anchorX = SWFInput_readSBits(input, numBits);
134 int anchorY = SWFInput_readSBits(input, numBits);
135
136 SWFShape_drawScaledCurve(shape, controlX, controlY,
137 anchorX, anchorY);
138 }
139 return 1;
140 }
141
readGlyphShape(SWFInput input)142 static SWFShape readGlyphShape(SWFInput input)
143 {
144 int numFillBits, numLineBits, moveBits, x, y;
145 char style;
146 SWFShape shape;
147
148 checkShapeHeader(input, &numFillBits, &numLineBits);
149
150 SWFInput_readBits(input, 2); /* type 0, newstyles */
151 style = SWFInput_readBits(input, 3);
152
153 shape = newSWFGlyphShape();
154 if (SWFInput_readBits(input, 1))
155 { moveBits = SWFInput_readBits(input, 5);
156 x = SWFInput_readSBits(input, moveBits);
157 y = SWFInput_readSBits(input, moveBits);
158 SWFShape_moveScaledPenTo(shape, x, y);
159 }
160 else if (style == 0) /* no style, no move => space character */
161 {
162 return shape;
163 }
164 checkShapeStyle(input, style, numFillBits, numLineBits);
165
166 /* translate the glyph's shape records into drawing commands */
167 while (translateShapeRecord(input, shape))
168 ;
169
170 return shape;
171 }
172
readFontLayout(SWFInput input,SWFFont font)173 static inline int readFontLayout(SWFInput input, SWFFont font)
174 {
175 int i;
176 struct SWFRect_s __rect;
177
178 font->advances = (short *)malloc(
179 font->nGlyphs * sizeof(short));
180 font->ascent = SWFInput_getSInt16(input);
181 font->descent = SWFInput_getSInt16(input);
182 font->leading = SWFInput_getSInt16(input);
183
184 /* get advances */
185 for (i = 0; i < font->nGlyphs; ++i )
186 font->advances[i] = SWFInput_getSInt16(input);
187
188 // temp hack
189 for (i = 0; i < font->nGlyphs; ++i )
190 readBounds(input, &__rect);
191
192 /* get kern table */
193 font->kernCount = SWFInput_getUInt16(input);
194
195 if ( font->kernCount > 0 )
196 {
197 if(font->flags & SWF_FONT_WIDECODES)
198 font->kernTable.w = (struct kernInfo16*) malloc(sizeof(struct kernInfo16) * font->kernCount);
199 else
200 font->kernTable.k = (struct kernInfo*)malloc(sizeof(struct kernInfo) * font->kernCount);
201 }
202 else
203 font->kernTable.k = NULL;
204
205 if(font->flags & SWF_FONT_WIDECODES)
206 {
207 for (i = 0; i < font->kernCount; ++i )
208 readKernInfo16(input, &(font->kernTable.w[i]));
209 }
210 else
211 {
212 for (i = 0; i < font->kernCount; ++i )
213 readKernInfo(input, &(font->kernTable.k[i]));
214 }
215 return 0;
216 }
217
checkFdbHeader(SWFInput input)218 static inline int checkFdbHeader(SWFInput input)
219 {
220 char f, d, b, z;
221 f = SWFInput_getChar(input);
222 d = SWFInput_getChar(input);
223 b = SWFInput_getChar(input);;
224 z = SWFInput_getChar(input);
225
226 if(f != 'f' || d != 'd' || b != 'b' || z != '0')
227 {
228 SWF_warn("loadSWFFont: not a fdb file\n");
229 return -1;
230 }
231
232 return 0;
233 }
234
loadSWFFontFromInput(SWFInput input)235 SWFFont loadSWFFontFromInput(SWFInput input)
236 {
237 SWFFont font;
238 int namelen, flags, i, nGlyphs;
239
240 if(input == NULL)
241 return NULL;
242
243 if(checkFdbHeader(input) < 0)
244 return NULL;
245
246
247 font = newSWFFont();
248 flags = SWFInput_getChar(input);
249 font->flags = flags;
250 font->langCode = SWFInput_getChar(input);
251 namelen = SWFInput_getChar(input);
252 font->name = (char *) malloc(namelen + 1);
253 for ( i=0; i < namelen; ++i )
254 font->name[i] = SWFInput_getChar(input);
255 font->name[namelen] = '\0';
256
257 nGlyphs = SWFInput_getUInt16(input);
258
259 font->nGlyphs = nGlyphs;
260 font->glyphToCode = (unsigned short*)malloc(nGlyphs * sizeof(short));
261 if ( flags & SWF_FONT_WIDEOFFSETS )
262 {
263 for (i=0; i < nGlyphs; ++i)
264 SWFInput_getUInt32(input); // glyph offset
265 SWFInput_getUInt32(input); // code table offset
266 }
267 else
268 {
269 for(i=0; i < nGlyphs; ++i)
270 SWFInput_getUInt16(input); // glyph offset
271 SWFInput_getUInt16(input); // code table offset
272 }
273
274 font->shapes = (SWFShape *)malloc(nGlyphs * sizeof(SWFShape));
275 for(i = 0; i < nGlyphs; i++)
276 font->shapes[i] = readGlyphShape(input);
277
278 /* read glyph-to-code table */
279 if ( flags & SWF_FONT_WIDECODES )
280 {
281 for (i = 0; i < nGlyphs; ++i )
282 font->glyphToCode[i] = SWFInput_getUInt16(input);
283 }
284 else
285 {
286 for (i = 0; i < nGlyphs; ++i )
287 font->glyphToCode[i] = SWFInput_getChar(input);
288 }
289
290 if ( flags & SWF_FONT_HASLAYOUT )
291 readFontLayout(input, font);
292 SWFFont_buildReverseMapping(font);
293 return font;
294 }
295
296 /* pull font definition from fdb (font def block) file */
loadSWFFont_fromFdbFile(FILE * file)297 SWFFont loadSWFFont_fromFdbFile(FILE *file)
298 {
299 SWFInput input;
300 SWFFont font;
301 if ( file == NULL )
302 return NULL;
303
304 input = newSWFInput_file(file);
305 font = loadSWFFontFromInput(input);
306 destroySWFInput(input);
307 return font;
308 }
309
310
311
312 #if 0
313 /* retrieve glyph shape of a font */
314 #include <stdio.h>
315 #include <stdarg.h>
316 /* basic IO */
317
318 struct out
319 { char *buf, *ptr;
320 int len;
321 };
322
323 static void oprintf(struct out *op, const char *fmt, ...)
324 { va_list ap;
325 char buf[256];
326 int d, l;
327
328 va_start(ap, fmt);
329 l = vsprintf(buf, fmt, ap);
330 while((d = op->ptr - op->buf) + l >= op->len-1)
331 { op->buf = (char *) realloc(op->buf, op->len += 100);
332 op->ptr = op->buf + d;
333 }
334 for(d = 0 ; d < l ; d++)
335 *op->ptr++ = buf[d];
336 }
337
338 // return a malloc'ed string describing the glyph shape
339 char *
340 SWFFont_getShape(SWFFont font, unsigned short c)
341 {
342 byte *p = SWFFont_findGlyph(font, c);
343 byte **f = &p;
344 struct out o;
345 int moveBits, x = 0, y = 0;
346 int straight, numBits;
347 int numFillBits, numLineBits;
348 int startX = 0;
349 int startY = 0;
350 int style;
351
352 o.len = 0;
353 o.ptr = o.buf = (char *)malloc(1);
354 *o.ptr = 0;
355
356 byteAlign();
357
358 if ( (numFillBits = readBitsP(f, 4)) != 1 ) /* fill bits */
359 SWF_error("SWFFont_getShape: bad file format (was expecting fill bits = 1)");
360
361 if ( (numLineBits = readBitsP(f, 4)) > 1 ) /* line bits */
362 SWF_error("SWFFont_getShape: bad file format (was expecting line bits = 0)");
363
364 /* now we get to parse the shape commands. Oh boy.
365 the first one will be a non-edge block- grab the moveto loc */
366
367 readBitsP(f, 2); /* type 0, newstyles */
368 style = readBitsP(f, 3);
369
370 if(readBitsP(f, 1))
371 { moveBits = readBitsP(f, 5);
372 x = startX + readSBitsP(f, moveBits);
373 y = startY + readSBitsP(f, moveBits);
374
375 oprintf(&o, "moveto %d,%d\n", x, y);
376 }
377 else if(style == 0) /* no style, no move => space character */
378 return o.buf;
379
380 if ( style & 1 )
381 if ( readBitsP(f, numFillBits) != 0 ) /* fill0 = 0 */
382 SWF_error("SWFFont_getShape: bad file format (was expecting fill0 = 0)");
383 if ( style & 2 )
384 if ( readBitsP(f, numFillBits) != 1 ) /* fill1 = 1 */
385 SWF_error("SWFFont_getShape: bad file format (was expecting fill1 = 1)");
386 if ( style & 4 )
387 if ( readBitsP(f, numLineBits) != 0 ) /* line = 1 */
388 SWF_error("SWFFont_getShape: bad file format (was expecting line = 0)");
389
390 /* translate the glyph's shape records into drawing commands */
391
392 for ( ;; )
393 {
394 if ( readBitsP(f, 1) == 0 )
395 {
396 /* it's a moveTo or a shape end */
397
398 if ( readBitsP(f, 5) == 0 )
399 break;
400
401 moveBits = readBitsP(f, 5);
402 x = startX + readSBitsP(f, moveBits);
403 y = startY + readSBitsP(f, moveBits);
404
405 oprintf(&o, "moveto %d,%d\n", x, y);
406
407 continue;
408 }
409
410 straight = readBitsP(f, 1);
411 numBits = readBitsP(f, 4)+2;
412
413 if ( straight==1 )
414 {
415 if ( readBitsP(f, 1) ) /* general line */
416 {
417 x += readSBitsP(f, numBits);
418 y += readSBitsP(f, numBits);
419 }
420 else
421 {
422 if ( readBitsP(f, 1) ) /* vert = 1 */
423 y += readSBitsP(f, numBits);
424 else
425 x += readSBitsP(f, numBits);
426 }
427
428 oprintf(&o, "lineto %d,%d\n", x, y);
429 }
430 else
431 {
432 int controlX = readSBitsP(f, numBits);
433 int controlY = readSBitsP(f, numBits);
434 int anchorX = readSBitsP(f, numBits);
435 int anchorY = readSBitsP(f, numBits);
436
437 oprintf(&o, "curveto %d,%d %d,%d\n",
438 x+controlX, y+controlY,
439 x+controlX+anchorX, y+controlY+anchorY);
440
441 x += controlX + anchorX;
442 y += controlY + anchorY;
443 }
444 }
445
446 *o.ptr = 0;
447 return o.buf;
448 }
449 #endif
450