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 #ifndef __C2MAN__
23 #include <math.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #endif
28 
29 #include "font.h"
30 #include "method.h"
31 #include "utf8.h"
32 #include "character.h"
33 #include "error.h"
34 #include "movie.h"
35 #include "libming.h"
36 #include "shape.h"
37 #include "fdbfont.h"
38 #include "ttffont.h"
39 #include "ming_config.h"
40 
41 struct textList
42 {
43 	struct textList* next;
44 	SWFTextRecord text;
45 };
46 
47 struct SWFFontCharacter_s
48 {
49 	struct SWFCharacter_s character;
50 
51 	SWFFont font;
52 	byte flags;
53 
54 	/* add all font charactes. usefull for textfield */
55 	byte dump;
56 
57 	// list of text records that reference this font
58 	struct textList* textList;
59 	struct textList* currentList;
60 
61 	// list of chars used in text objects that reference this font-
62 	// idx into this table is stored in text records
63 	int nGlyphs;
64 	unsigned short* codeTable;
65 
66 	SWFOutput out;
67 };
68 
69 void
SWFFont_buildReverseMapping(SWFFont font)70 SWFFont_buildReverseMapping(SWFFont font)
71 {
72 	int i;
73 
74 	if ( font->flags & SWF_FONT_WIDECODES )
75 	{
76 		font->codeToGlyph.wideMap = (unsigned short**)malloc(256 * sizeof(unsigned short*));
77 
78 		for ( i=0; i<256; ++i )
79 			font->codeToGlyph.wideMap[i] = NULL;
80 
81 		for ( i=0; i<font->nGlyphs; ++i )
82 		{
83 			unsigned short charcode = font->glyphToCode[i];
84 			byte high = charcode >> 8;
85 			byte low = charcode & 0xff;
86 
87 			if ( font->codeToGlyph.wideMap[high] == NULL )
88 			{
89 				font->codeToGlyph.wideMap[high] = (unsigned short*)malloc(256 * sizeof(unsigned short));
90 				memset(font->codeToGlyph.wideMap[high], 0, 256 * sizeof(unsigned short));
91 			}
92 
93 			font->codeToGlyph.wideMap[high][low] = i;
94 		}
95 	}
96 	else
97 	{
98 		font->codeToGlyph.charMap = (byte*) malloc(256 * sizeof(char));
99 		memset(font->codeToGlyph.charMap, 0, 256 * sizeof(char));
100 
101 		for ( i=0; i<font->nGlyphs; ++i )
102 		{
103 		 if (font->glyphToCode[i]<256)
104 			font->codeToGlyph.charMap[font->glyphToCode[i]] = i;
105 		 else
106 		 	SWF_warn("No such glyph %d in map\n",i);
107 		}
108 	}
109 }
110 
111 static void
112 SWFFontCharacter_resolveTextCodes(SWFFontCharacter);
113 
114 static void
115 SWFFontCharacter_dumpTable(SWFFontCharacter);
116 
117 static int
completeSWFFontCharacter(SWFBlock block)118 completeSWFFontCharacter(SWFBlock block)
119 {
120 	SWFFontCharacter inst = (SWFFontCharacter)block;
121 	SWFFont font = inst->font;
122 	SWFOutput buffer;
123 	int i, tablen, offset;
124 	char c, *string;
125 
126 	if(inst->dump)
127 		SWFFontCharacter_dumpTable(inst);
128 	else
129 		SWFFontCharacter_resolveTextCodes(inst);
130 
131 	SWF_assert(!inst->out);
132 	inst->out = newSWFOutput();
133 	SWFOutput_writeUInt16(inst->out, CHARACTERID(inst));
134 	SWFOutput_writeUInt8(inst->out, inst->flags);
135 	SWFOutput_writeUInt8(inst->out, font->langCode);
136 
137 	SWFOutput_writeUInt8(inst->out, strlen(font->name));
138 	string = font->name;
139 	while ( (c = *(string++)) != 0 )
140 		SWFOutput_writeUInt8(inst->out, c);
141 
142 	SWFOutput_writeUInt16(inst->out, inst->nGlyphs);
143 
144 	tablen = (inst->nGlyphs+1) *
145 		(inst->flags & SWF_FONT_WIDEOFFSETS ? 4 : 2);
146 	buffer = newSWFOutput();
147 	for (i = 0; i < inst->nGlyphs; ++i)
148 	{
149 		int glyph = SWFFont_findGlyphCode(font,inst->codeTable[i]);
150 		SWFShape shape = font->shapes[glyph];
151 		offset = SWFOutput_getLength(buffer) + tablen;
152 		SWFOutput_writeGlyphShape(buffer, shape);
153 		if(inst->flags & SWF_FONT_WIDEOFFSETS)
154 			SWFOutput_writeUInt32(inst->out, offset);
155 		else
156 			SWFOutput_writeUInt16(inst->out, offset);
157 	}
158 	// codeTableOffset
159 	offset = SWFOutput_getLength(buffer) + tablen;
160 	if(inst->flags & SWF_FONT_WIDEOFFSETS)
161 		SWFOutput_writeUInt32(inst->out, offset);
162 	else
163 		SWFOutput_writeUInt16(inst->out, offset);
164 
165 	/* user buffer from here! */
166 	SWFOutput_setNext(inst->out, buffer);
167 
168 	for (i = 0; i < inst->nGlyphs; ++i)
169 	{
170 		unsigned short code = inst->codeTable[i];
171 		if (inst->flags & SWF_FONT_WIDECODES)
172 			SWFOutput_writeUInt16(buffer, code);
173 		else
174 			SWFOutput_writeUInt8(buffer, code);
175 	}
176 
177 	/* write font layout */
178 	if (inst->flags & SWF_FONT_HASLAYOUT )
179 	{	SWFOutput_writeUInt16(buffer, font->ascent);
180 		SWFOutput_writeUInt16(buffer, font->descent);
181 		SWFOutput_writeUInt16(buffer, font->leading);
182 		for (i = 0; i < inst->nGlyphs; ++i) {
183 			int glyph = SWFFont_findGlyphCode(font,inst->codeTable[i]);
184 			SWFOutput_writeSInt16(buffer,font->advances[glyph]);
185 		}
186 		for (i = 0; i < inst->nGlyphs; ++i) {
187 			int glyph = SWFFont_findGlyphCode(font,inst->codeTable[i]);
188 			SWFOutput_writeRect(buffer, SWFFont_getGlyphBounds(font, glyph));
189 			SWFOutput_byteAlign(buffer);
190 		}
191 		SWFOutput_writeUInt16(buffer, 0); /* no kerning FIXME ! */
192 	}
193 	return SWFOutput_getLength(inst->out);
194 }
195 
196 
197 void
writeSWFFontCharacterToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)198 writeSWFFontCharacterToMethod(SWFBlock block,
199                               SWFByteOutputMethod method, void *data)
200 {
201 	SWFFontCharacter inst = (SWFFontCharacter)block;
202 	SWFOutput_writeToMethod(inst->out, method, data);
203 }
204 
205 
206 void
destroySWFFont(SWFFont font)207 destroySWFFont(SWFFont font)
208 {
209 	if(font->shapes)
210 	{
211 		int i = 0;
212 		for(i = 0; i < font->nGlyphs; i++)
213 			destroySWFShape(font->shapes[i]);
214 		free(font->shapes);
215 	}
216 
217 	if ( font->flags & SWF_FONT_WIDECODES )
218 	{
219 		if ( font->codeToGlyph.wideMap != NULL )
220 		{
221 			int i;
222 
223 			for ( i = 0; i < 256; ++i )
224 			{
225 				if ( font->codeToGlyph.wideMap[i] != NULL )
226 					free(font->codeToGlyph.wideMap[i]);
227 			}
228 
229 			free(font->codeToGlyph.wideMap);
230 		}
231 	}
232 	else
233 	{
234 		if ( font->codeToGlyph.charMap != NULL )
235 			free(font->codeToGlyph.charMap);
236 	}
237 
238 	if ( font->name != NULL )
239 		free(font->name);
240 
241 	if ( font->kernTable.k != NULL )	// union of pointers ...
242 		free(font->kernTable.k);
243 
244 	if ( font->glyphToCode != NULL )
245 		free(font->glyphToCode);
246 
247 	if ( font->advances != NULL )
248 		free(font->advances);
249 
250 	free(font);
251 }
252 
253 
254 void
destroySWFFontCharacter(SWFFontCharacter font)255 destroySWFFontCharacter(SWFFontCharacter font)
256 {
257 	struct textList* text = font->textList;
258 
259 	while ( text != NULL )
260 	{
261 		struct textList* next = text->next;
262 		free(text);
263 		text = next;
264 	}
265 
266 	if ( font->codeTable != NULL )
267 		free(font->codeTable);
268 	if( font->out != NULL)
269 		destroySWFOutput(font->out);
270 	free(font);
271 }
272 
273 
274 SWFFont
newSWFFont()275 newSWFFont()
276 {
277 	SWFFont font = (SWFFont) malloc(sizeof(struct SWFFont_s));
278 
279 	SWFBlockInit((SWFBlock)font);
280 
281 	BLOCK(font)->type = SWF_MINGFONT;
282 	BLOCK(font)->writeBlock = NULL;
283 	BLOCK(font)->complete = NULL;
284 	BLOCK(font)->dtor = (destroySWFBlockMethod) destroySWFFont;
285 
286 	font->name = NULL;
287 	font->flags = 0;
288 	font->langCode = 0;
289 
290 	font->nGlyphs = 0;
291 	font->glyphToCode = NULL;
292 
293 	font->advances = NULL;
294 
295 	font->ascent = 0;
296 	font->descent = 0;
297 	font->leading = 0;
298 
299 	font->kernCount = 0;
300 	font->kernTable.k = NULL;
301 	font->kernTable.w = NULL;
302 
303 	font->shapes = NULL;
304 
305 	return font;
306 }
307 
308 // file magic: fonts:0 string  \000\001\000\000\000    TrueType font data
true_type_check(char * header)309 static inline int true_type_check(char *header)
310 {
311 	if(header[0] == 0 &&
312 		header[1] == 1 &&
313 		header[2] == 0 &&
314 		header[3] == 0 &&
315 		header[4] == 0)
316 		return 1;
317 	return 0;
318 }
319 
fdb_check(char * header)320 static inline int fdb_check(char *header)
321 {
322 	if(header[0] == 'f' &&
323 		header[1] == 'd' &&
324 		header[2] == 'b' &&
325 		header[3] == '0')
326 		return 1;
327 	return 0;
328 }
329 
ttc_check(char * header)330 static inline int ttc_check(char *header)
331 {
332 	if(header[0] == 't' &&
333 		header[1] == 't' &&
334 		header[2] == 'c')
335 		return 1;
336 	return 0;
337 }
338 
339 /* load a collection of fonts (experimental)
340  * currently only TTC (TTF collection) format is supported
341  */
newSWFFontCollection_fromFile(const char * filename)342 SWFFontCollection newSWFFontCollection_fromFile(const char *filename /* filename */)
343 {
344 	FILE *file;
345 	char header[5];
346 	file = fopen(filename, "rb");
347 	if(file == NULL)
348 	{
349 		SWF_warn("open font file failed\n");
350 		return NULL;
351 	}
352 
353 	if(fread(header, 5, 1, file) < 1)
354 	{
355 		fclose(file);
356 		return NULL;
357 	}
358 	rewind(file);
359 
360 	if(ttc_check(header))
361 	{
362 		fclose(file);
363 #if USE_FREETYPE
364 		return loadTTFCollection(filename);
365 #else
366 		SWF_warn("SWFFont:: new SWFFont (ttf): "
367 		         "freetype is not available.\n");
368 		return NULL;
369 #endif
370 	}
371 	else
372 	{
373 		SWF_warn("Unknown font file\n");
374 		fclose(file);
375 		return NULL;
376 	}
377 }
378 
379 
380 /* load a font from file
381  * This function creates a new SWFFont object from a font file. It accepts
382  * and autodetects FDB and TTF fonts.
383  * returns a SWFFont object if a valid fontfile is found, NULL otherwise
384  */
newSWFFont_fromFile(const char * filename)385 SWFFont newSWFFont_fromFile(const char *filename /* filename for fontfile */)
386 {
387 	FILE *file;
388 	char header[5];
389 	file = fopen(filename, "rb");
390 	if(file == NULL)
391 	{
392 		SWF_warn("open font file failed\n");
393 		return NULL;
394 	}
395 
396 	if(fread(header, 5, 1, file) < 1)
397 	{
398 		fclose(file);
399 		return NULL;
400 	}
401 	rewind(file);
402 
403 	if(true_type_check(header))
404 	{
405 		fclose(file);
406 #if USE_FREETYPE
407 		return loadSWFFontTTF(filename);
408 #else
409 		SWF_warn("SWFFont:: new SWFFont (ttf): "
410 		         "freetype is not available.\n");
411 		return NULL;
412 #endif
413 	}
414 	else if(fdb_check(header))
415 	{
416 		SWFFont font = loadSWFFont_fromFdbFile(file);
417 		fclose(file);
418 		return font;
419 	}
420 	else
421 	{
422 		SWF_warn("Unknown font file\n");
423 		fclose(file);
424 		return NULL;
425 	}
426 }
427 
428 
429 SWFFontCharacter
newSWFFontCharacter(SWFFont font)430 newSWFFontCharacter(SWFFont font)
431 {
432 	SWFFontCharacter inst;
433 
434 	inst = (SWFFontCharacter) malloc(sizeof(struct SWFFontCharacter_s));
435 	SWFCharacterInit((SWFCharacter)inst);
436 
437 	BLOCK(inst)->type = SWF_DEFINEFONT2;
438 	BLOCK(inst)->writeBlock = writeSWFFontCharacterToMethod;
439 	BLOCK(inst)->complete = completeSWFFontCharacter;
440 	BLOCK(inst)->dtor = (destroySWFBlockMethod) destroySWFFontCharacter;
441 
442 	CHARACTERID(inst) = ++SWF_gNumCharacters;
443 	inst->font = font;
444 	inst->flags = font->flags; // (unsigned char)(font->flags & /*(~SWF_FONT_HASLAYOUT) &*/ (~SWF_FONT_WIDEOFFSETS));
445 
446 	inst->nGlyphs = 0;
447 	inst->codeTable = NULL;
448 	inst->dump = 0;
449 	inst->textList = NULL;
450 	inst->currentList = NULL;
451 
452 	inst->out = NULL;
453 
454 	return inst;
455 }
456 
457 SWFFontCharacter
newSWFDummyFontCharacter()458 newSWFDummyFontCharacter()
459 {	SWFFontCharacter ret = (SWFFontCharacter) malloc(sizeof (struct SWFFontCharacter_s));
460 	SWFCharacterInit((SWFCharacter) ret);
461 	BLOCK(ret)->type = SWF_DEFINEFONT;
462 	BLOCK(ret)->complete = completeSWFImportCharacter;
463 	BLOCK(ret)->writeBlock = NULL;
464 	BLOCK(ret)->dtor = NULL;
465 	CHARACTERID(ret) = ++SWF_gNumCharacters;
466 
467 	ret->flags = SWF_FONT_HASLAYOUT;
468 	ret->nGlyphs = 1;
469 	ret->codeTable = NULL;
470 	ret->out = NULL;
471 
472 	return ret;
473 }
474 
475 int
SWFFont_findGlyphCode(SWFFont font,unsigned short c)476 SWFFont_findGlyphCode(SWFFont font, unsigned short c)
477 {
478 	if ( font->flags & SWF_FONT_WIDECODES )
479 	{
480 		byte high = c >> 8;
481 		byte low = c & 0xff;
482 
483 		if ( font->codeToGlyph.wideMap[high] != NULL )
484 			return font->codeToGlyph.wideMap[high][low];
485 		else
486 			return -1;
487 	}
488 	else
489 	{
490 		if ( (c & 0xff00) == 0 )
491 			return font->codeToGlyph.charMap[(byte)c];
492 		else
493 			return -1;
494 	}
495 }
496 
497 void
SWFFontCharacter_addTextToList(SWFFontCharacter font,SWFTextRecord text)498 SWFFontCharacter_addTextToList(SWFFontCharacter font, SWFTextRecord text)
499 {
500 	struct textList* textList = (struct textList* )malloc(sizeof(struct textList));
501 
502 	textList->next = font->textList;
503 	textList->text = text;
504 
505 	font->textList = textList;
506 }
507 
508 
509 static int
findCodeValue(unsigned short c,unsigned short * list,int start,int end)510 findCodeValue(unsigned short c, unsigned short* list, int start, int end)
511 {
512 	int pos;
513 
514 	if ( start == end )
515 		return start;
516 
517 	if ( c <= list[start] )
518 		return start;
519 
520 	pos = (start + end) / 2;
521 
522 	if ( c < list[pos] )
523 		return findCodeValue(c, list, start, pos);
524 	else if ( c > list[pos] )
525 		return findCodeValue(c, list, pos+1, end);
526 	else
527 		return pos;
528 }
529 
530 
531 #define CODETABLE_INCREMENT 32
532 
533 void
SWFFontCharacter_addCharToTable(SWFFontCharacter font,unsigned short c)534 SWFFontCharacter_addCharToTable(SWFFontCharacter font, unsigned short c)
535 {
536 	// insert the char into font's codeTable if it isn't already there
537 
538 	int p;
539 
540 	p = findCodeValue(c, font->codeTable, 0, font->nGlyphs);
541 
542 	if ( font->codeTable != NULL && p != font->nGlyphs && font->codeTable[p] == c )
543 		return;
544 
545 	if ( font->nGlyphs % CODETABLE_INCREMENT == 0 )
546 	{
547 		font->codeTable = (unsigned short*) realloc(font->codeTable,
548 			(font->nGlyphs + CODETABLE_INCREMENT) *
549 				sizeof(unsigned short));
550 		memset(font->codeTable+font->nGlyphs, 0,
551 			CODETABLE_INCREMENT*sizeof(unsigned short));
552 	}
553 
554 	// keep list sorted
555 
556 	if ( p < font->nGlyphs )
557 	{
558 		memmove(&font->codeTable[p + 1], &font->codeTable[p],
559 						(font->nGlyphs - p) * sizeof(*font->codeTable));
560 	}
561 
562 	font->codeTable[p] = c;
563 	++font->nGlyphs;
564 }
565 
566 void
SWFFontCharacter_addWideChars(SWFFontCharacter font,unsigned short * string,int len)567 SWFFontCharacter_addWideChars(SWFFontCharacter font, unsigned short *string, int len)
568 {
569 	while(--len >= 0)
570 		SWFFontCharacter_addCharToTable(font, *string++);
571 }
572 
573 /*
574  * add all utf-8 characters in the given string to the SWF file.
575  * The font-block in the resulting SWF file will include all the
576  * utf-8 characters in the given string.
577  */
578 void
SWFFontCharacter_addUTF8Chars(SWFFontCharacter font,const char * string)579 SWFFontCharacter_addUTF8Chars(SWFFontCharacter font, const char *string)
580 {
581 	unsigned short *widestring;
582 	int len;
583 	len = UTF8ExpandString(string, &widestring);
584 	SWFFontCharacter_addWideChars(font, widestring, len);
585 	free(widestring);
586 }
587 
588 /*
589  * add all characters in the given string to the SWF file.
590  * The font-block in the resulting SWF file will include all the
591  * characters in the given string.
592  */
593 void
SWFFontCharacter_addChars(SWFFontCharacter font,const char * string)594 SWFFontCharacter_addChars(SWFFontCharacter font, const char *string)
595 {
596 	while(*string)
597 		SWFFontCharacter_addCharToTable(font, *string++ & 0xff);
598 }
599 
600 SWFFont
SWFFontCharacter_getFont(SWFFontCharacter font)601 SWFFontCharacter_getFont(SWFFontCharacter font)
602 {
603 	return font->font;
604 }
605 
606 
607 void
SWFFontCharacter_exportCharacterRange(SWFFontCharacter font,unsigned short start,unsigned short end)608 SWFFontCharacter_exportCharacterRange(SWFFontCharacter font,
609 						 unsigned short start, unsigned short end)
610 {
611 	// insert the char into font's codeTable if it isn't already there
612 
613 	//int p = findCodeValue(start, font->codeTable, 0, font->nGlyphs);
614 	//int q = findCodeValue(end, font->codeTable, 0, font->nGlyphs);
615 
616 	// XXX
617 }
618 
619 
620 int
SWFFontCharacter_findGlyphCode(SWFFontCharacter font,unsigned short c)621 SWFFontCharacter_findGlyphCode(SWFFontCharacter font, unsigned short c)
622 {
623 	// return the index in font->codeTable for the given character
624 
625 	int p = findCodeValue(c, font->codeTable, 0, font->nGlyphs);
626 
627 	if ( font->codeTable[p] == c )
628 		return p;
629 
630 	return -1;
631 }
632 
633 static void
SWFFontCharacter_dumpTable(SWFFontCharacter fc)634 SWFFontCharacter_dumpTable(SWFFontCharacter fc)
635 {
636 	int i;
637 	SWFFont font = fc->font;
638 	for (i = 0; i < font->nGlyphs; ++i)
639 	{
640 		unsigned short charcode = font->glyphToCode[i];
641 		SWFFontCharacter_addCharToTable(fc, charcode);
642 	}
643 }
644 
645 static void
SWFFontCharacter_resolveTextCodes(SWFFontCharacter font)646 SWFFontCharacter_resolveTextCodes(SWFFontCharacter font)
647 {
648 	struct textList* text = font->textList;
649 	unsigned short* string;
650 	int len, i;
651 
652 	// find out which characters from this font are being used
653 
654 	while ( text != NULL )
655 	{
656 		len = SWFTextRecord_getString(text->text, &string);
657 
658 		for ( i=0; i<len; ++i )
659 			SWFFontCharacter_addCharToTable(font, string[i]);
660 
661 		text = text->next;
662 	}
663 
664 	// check availability of a font glyph for each fontchar codetable entry
665 
666 	for ( i=0; i<font->nGlyphs; ++i )
667 	{
668 		int code;
669 		code = SWFFont_findGlyphCode(font->font, font->codeTable[i]);
670 		if(code < 0)
671 		{
672 			SWF_warn("SWFFontCharacter_resolveTextCodes: Character not found %i\n",
673 				font->codeTable[i]);
674 			SWF_warn("This is either an encoding error (likely)");
675 			SWF_warn("or the used font does not provide all characters (unlikely)\n");
676 			SWF_error("Stopped\n");
677 		}
678 	}
679 }
680 
681 /*
682  * adds all characters/glyphs to the SWF
683  * This function is usefull if an full export of the font is intended.
684  */
685 void
SWFFontCharacter_addAllChars(SWFFontCharacter fc)686 SWFFontCharacter_addAllChars(SWFFontCharacter fc)
687 {
688 	fc->dump = 1;
689 }
690 
691 const char*
SWFFont_getName(SWFFont font)692 SWFFont_getName(SWFFont font)
693 {
694 	return (const char*) font->name;
695 }
696 
697 
698 byte
SWFFont_getFlags(SWFFont font)699 SWFFont_getFlags(SWFFont font)
700 {
701 	return font->flags;
702 }
703 
SWFFont_getGlyphCount(SWFFont font)704 int SWFFont_getGlyphCount(SWFFont font)
705 {
706 	return font->nGlyphs;
707 }
708 
709 int
SWFFontCharacter_getNGlyphs(SWFFontCharacter font)710 SWFFontCharacter_getNGlyphs(SWFFontCharacter font)
711 {
712 	return font->nGlyphs;
713 }
714 
715 
716 int
SWFFont_getScaledWideStringWidth(SWFFont font,const unsigned short * string,int len)717 SWFFont_getScaledWideStringWidth(SWFFont font,const unsigned short* string, int len)
718 {
719 	/* return length of given string in whatever units these are we're using */
720 
721 	int i;
722 	int width = 0;
723 	int glyph;
724 
725 	for ( i=0; i<len; ++i )
726 	{
727 		glyph = SWFFont_findGlyphCode(font, string[i]);
728 
729 		if ( glyph == -1 )
730 			continue; // XXX - ???
731 
732 		if ( font->advances )
733 			width += font->advances[glyph];
734 
735 		// looking in kernTable
736 
737 		if ( i < len-1 ) {
738 			width += SWFFont_getCharacterKern(font, string[i], string[i+1]);
739 		}
740 	}
741 
742 	return width;
743 }
744 
745 
746 int
SWFFont_getScaledStringWidth(SWFFont font,const char * string)747 SWFFont_getScaledStringWidth(SWFFont font, const char* string)
748 {
749 	unsigned short* widestr;
750 	int len = strlen(string);
751 	int n, width;
752 	widestr = (unsigned short*) malloc(2 * len);
753 	for(n = 0 ; n < len ; n++)
754 		widestr[n] = (unsigned char)string[n];
755 	width = SWFFont_getScaledWideStringWidth(font, widestr, len);
756 	free(widestr);
757 	return width;
758 }
759 
760 int
SWFFont_getScaledUTF8StringWidth(SWFFont font,const char * string)761 SWFFont_getScaledUTF8StringWidth(SWFFont font, const char* string)
762 {
763 	unsigned short* widestr;
764 	int len = UTF8ExpandString(string, &widestr);
765 	int width = SWFFont_getScaledWideStringWidth(font, widestr, len);
766 
767 	free(widestr);
768 
769 	return width;
770 }
771 
772 
773 /* get some font metrics */
774 short
SWFFont_getScaledAscent(SWFFont font)775 SWFFont_getScaledAscent(SWFFont font)
776 {
777 	return font->ascent;
778 }
779 
780 
781 short
SWFFont_getScaledDescent(SWFFont font)782 SWFFont_getScaledDescent(SWFFont font)
783 {
784 	return font->descent;
785 }
786 
787 
788 short
SWFFont_getScaledLeading(SWFFont font)789 SWFFont_getScaledLeading(SWFFont font)
790 {
791 	return font->leading;
792 }
793 
794 
795 unsigned short
SWFFontCharacter_getGlyphCode(SWFFontCharacter font,unsigned short glyphcode)796 SWFFontCharacter_getGlyphCode(SWFFontCharacter font, unsigned short glyphcode)
797 {
798 	if ( glyphcode >= font->nGlyphs )
799         	SWF_error("SWFFontCharacter_getGlyphCode: No such row in codeTable");
800 	return font->codeTable[glyphcode];
801 }
802 
803 unsigned short
SWFFont_getGlyphCode(SWFFont font,unsigned short glyphcode)804 SWFFont_getGlyphCode(SWFFont font, unsigned short glyphcode)
805 {
806 	if ( glyphcode >= font->nGlyphs )
807         SWF_error("SWFFont_getGlyphCode: glyphcode >= nGlyphs");
808 
809 	return font->glyphToCode[glyphcode];
810 }
811 
812 
813 SWFRect
SWFFont_getGlyphBounds(SWFFont font,unsigned short glyphcode)814 SWFFont_getGlyphBounds(SWFFont font, unsigned short glyphcode)
815 {
816 	if ( glyphcode >= font->nGlyphs )
817 		SWF_error("SWFFont_getGlyphBounds: glyphcode >= nGlyphs");
818 
819 	// return &font->bounds[glyphcode];
820 	return SWFCharacter_getBounds(CHARACTER(font->shapes[glyphcode])); // &font->bounds[glyphcode];
821 }
822 
823 
824 int
SWFFont_getCharacterAdvance(SWFFont font,unsigned short glyphcode)825 SWFFont_getCharacterAdvance(SWFFont font, unsigned short glyphcode)
826 {
827 	if ( font->advances )
828 	{
829 		if ( glyphcode >= font->nGlyphs )
830 			SWF_error("SWFFont_getCharacterAdvance: glyphcode >= nGlyphs");
831 
832 		return font->advances[glyphcode];
833 	}
834 
835 	return 0;
836 }
837 
838 
839 int
SWFFont_getCharacterKern(SWFFont font,unsigned short code1,unsigned short code2)840 SWFFont_getCharacterKern(SWFFont font, unsigned short code1, unsigned short code2)
841 {
842 	int j = font->kernCount;
843 
844 	// XXX - kernTable should be sorted to make this faster
845 
846 	if(font->flags & SWF_FONT_WIDECODES) {
847 		if( !font->kernTable.w ) {
848 			return 0;
849 		}
850 		while ( --j >= 0 )
851 		{
852 			if ( code1 == font->kernTable.w[j].code1 &&
853 					 code2 == font->kernTable.w[j].code2 )
854 			{
855 				return font->kernTable.w[j].adjustment;
856 			}
857 		}
858 	} else {
859 		if( !font->kernTable.k ) {
860 			return 0;
861 		}
862 		while ( --j >= 0 )
863 		{
864 			if ( code1 == font->kernTable.k[j].code1 &&
865 					 code2 == font->kernTable.k[j].code2 )
866 			{
867 				return font->kernTable.k[j].adjustment;
868 			}
869 		}
870 	}
871 	return 0;
872 }
873 
SWFFont_getGlyph(SWFFont font,unsigned short c)874 SWFShape SWFFont_getGlyph(SWFFont font, unsigned short c)
875 {
876 	int index;
877 
878 	index = SWFFont_findGlyphCode(font, c);
879 	if(index < 0)
880 		return NULL;
881 
882 	return font->shapes[index];
883 }
884 
SWFFontCollection_addFont(SWFFontCollection collection,SWFFont font)885 void SWFFontCollection_addFont(SWFFontCollection collection, SWFFont font)
886 {
887 	if(!collection || !font)
888 		return;
889 
890 	collection->fontList = (SWFFont*)realloc(collection->fontList,
891 		(collection->numFonts + 1) * sizeof(SWFFont));
892 	collection->fontList[collection->numFonts] = font;
893 	collection->numFonts++;
894 }
895 
destroySWFFontCollection(SWFFontCollection collection)896 void destroySWFFontCollection(SWFFontCollection collection)
897 {
898 	int i;
899 	if(!collection)
900 		return;
901 
902 	for(i = 0; i < collection->numFonts; i++)
903 		destroySWFFont(collection->fontList[i]);
904 	free(collection->fontList);
905 	free(collection);
906 }
907 
newSWFFontCollection()908 SWFFontCollection newSWFFontCollection()
909 {
910 	SWFFontCollection collection;
911 
912 	collection = (SWFFontCollection) malloc(sizeof(struct SWFFontCollection_s));
913 	collection->fontList = NULL;
914 	collection->numFonts = 0;
915 
916 	return collection;
917 }
918 
SWFFontCollection_getFontCount(SWFFontCollection collection)919 int SWFFontCollection_getFontCount(SWFFontCollection collection)
920 {
921 	if(collection == NULL)
922 		return -1;
923 	return collection->numFonts;
924 }
925 
SWFFontCollection_getFont(SWFFontCollection collection,int index)926 SWFFont SWFFontCollection_getFont(SWFFontCollection collection, int index)
927 {
928 	if(index < 0 || index >= collection->numFonts)
929 		return NULL;
930 
931 	return collection->fontList[index];
932 }
933 
SWFFontCollection_getFonts(SWFFontCollection collection,int * count)934 SWFFont *SWFFontCollection_getFonts(SWFFontCollection collection, int *count)
935 {
936 	if(!collection)
937 	{
938 		*count = 0;
939 		return NULL;
940 	}
941 	*count = collection->numFonts;
942 	return collection->fontList;
943 }
944 
945 /*
946  * Local variables:
947  * tab-width: 2
948  * c-basic-offset: 2
949  * End:
950  */
951