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