1 /* libsswf_tag_font.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */
2 
3 /*
4 
5 Copyright (c) 2002-2008 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 /** \file
35  *
36  * \brief The implementation of the sswf::TagFont class
37  *
38  * This file declares the body of the functions which are not
39  * inline. It is part of the SSWF library.
40  */
41 
42 #include	"sswf/libsswf.h"
43 
44 using namespace sswf;
45 
46 
47 
48 /////////////////////////////////////////// TagFont
49 
50 
51 /** \class sswf::TagFont
52  *
53  * \brief Define a system or embedded font.
54  *
55  * This tag is used to define a font.
56  *
57  * Embedded fonts include definitions for each glyph as required.
58  *
59  * System fonts just define the name of the system font.
60  *
61  * \sa sswf::TagShape
62  * \sa <a href="../SWFalexref.html#tag_definefont">SWF Alexis' Reference&mdash;Define Font</a>
63  * \sa <a href="../SWFalexref.html#tag_definefont2">SWF Alexis' Reference&mdash;Define Font2</a>
64  * \sa <a href="../SWFalexref.html#tag_definefont3">SWF Alexis' Reference&mdash;Define Font3</a>
65  * \sa <a href="../SWFalexref.html#tag_definefontinfo">SWF Alexis' Reference&mdash;Define Font Info</a>
66  * \sa <a href="../SWFalexref.html#tag_definefontinfo2">SWF Alexis' Reference&mdash;Define Font Info2</a>
67  * \sa <a href="../SWFalexref.html#tag_definefontname">SWF Alexis' Reference&mdash;Define Font Name</a>
68  * \sa <a href="../SWFalexref.html#tag_definefontalignzones">SWF Alexis' Reference&mdash;Define Font Align Zones</a>
69  * \sa <a href="../SWFalexref.html#tag_defineshape">SWF Alexis' Reference&mdash;Define Shape</a>
70  * \sa <a href="../SWFalexref.html#swf_tag">SWF Alexis' Reference&mdash;swf_tag</a>
71  */
72 
73 
74 
75 /** \enum sswf::TagFont::font_type_t
76  *
77  * \brief The list of font types.
78  *
79  * This enumeration defines the different types of fonts available.
80  */
81 
82 /** \var sswf::TagFont::FONT_TYPE_BEST
83  *
84  * \brief Selects the best type which can be used.
85  *
86  * Use this type to let the font choose what it wants to make it all
87  * work properly.
88  */
89 
90 /** \var sswf::TagFont::FONT_TYPE_ASCII
91  *
92  * \brief Select the type ASCII.
93  *
94  * This type represents a font with at most 256 characters.
95  */
96 
97 /** \var sswf::TagFont::FONT_TYPE_UNICODE
98  *
99  * \brief Select the type UNICODE
100  *
101  * This type represents any font in all languages. It supports
102  * 65536 characters all together. The character numbers are defined
103  * by the Unicode consortium: http://www.unicode.org
104  *
105  * This is the prefered type since version 6.
106  */
107 
108 /** \var sswf::TagFont::FONT_TYPE_SHIFTJIS
109  *
110  * \brief Select the type SHIFTJIS
111  *
112  * This type represents Japanese. I'm not too sure how this was
113  * used. Now, Japanese as well as Chinese, Korean, and any other
114  * language character set is defined using Unicode.
115  */
116 
117 /** \enum sswf::TagFont::font_language_t
118  *
119  * \brief Language definition for a font.
120  *
121  * Before version 6, many strange things appeared in Flash including
122  * a language definition for a font. There is really no need for it.
123  * Just use Unicode.
124  */
125 
126 /** \var sswf::TagFont::FONT_LANGUAGE_UNKNOWN
127  *
128  * \brief This value is used to mark a font as not having a language.
129  *
130  * This is the default value for a font.
131  */
132 
133 /** \var sswf::TagFont::FONT_LANGUAGE_LOCALE
134  *
135  * \brief This value is used so the player uses the current locale.
136  *
137  * I'm not too sure what this was for. How can a font be defined by
138  * a changing locale?
139  */
140 
141 /** \var sswf::TagFont::FONT_LANGUAGE_LATIN
142  *
143  * \brief Latin-1 languages.
144  *
145  * This value was for fonts representing the Latin-1 character set.
146  * (code page 0x00 in Unicode.)
147  */
148 
149 /** \var sswf::TagFont::FONT_LANGUAGE_JAPANESE
150  *
151  * \brief Japanese language.
152  *
153  * This value was for fonts representing a set of Japanese glyphs.
154  */
155 
156 /** \var sswf::TagFont::FONT_LANGUAGE_KOREAN
157  *
158  * \brief Korean language.
159  *
160  * This value was for fonts representing a set of Korean glyphs.
161  */
162 
163 /** \var sswf::TagFont::FONT_LANGUAGE_SIMPLIFIED_CHINESE
164  *
165  * \brief Chinese language.
166  *
167  * This value was for fonts representing a set of simplified Chinese glyphs.
168  */
169 
170 /** \var sswf::TagFont::FONT_LANGUAGE_TRADITIONAL_CHINESE
171  *
172  * \brief Chinese language.
173  *
174  * This value was for fonts representing a set of traditional Chinese glyphs.
175  */
176 
177 /** \var sswf::TagFont::FONT_LANGUAGE_max
178  *
179  * \brief This represents the largest possible language code
180  *
181  * This can be used as a limit boundary.
182  */
183 
184 
185 /** \enum sswf::TagFont::font_thickness_t
186  *
187  * \brief Defines the thickness of the font.
188  *
189  * The Flash player will by default determine the thickness of a font
190  * using a lookup table. If the font isn't found in that table, then
191  * it uses the thickness defined in the SWF file.
192  */
193 
194 /** \var sswf::TagFont::FONT_THICKNESS_UNKNOWN
195  *
196  * \brief The default: the thickness is not specified.
197  *
198  * The thickness is a feature of the fonts since SWF version 8. By
199  * default the thickness is not specified.
200  */
201 
202 /** \var sswf::TagFont::FONT_THICKNESS_THIN
203  *
204  * \brief Defines the thickness of the font as thin.
205  *
206  * This is a thin font. This means thinner than normal (light).
207  */
208 
209 /** \var sswf::TagFont::FONT_THICKNESS_MEDIUM
210  *
211  * \brief Defines the thickness of the font as medium.
212  *
213  * This is a medium font. This means a mostly normal font.
214  */
215 
216 /** \var sswf::TagFont::FONT_THICKNESS_THICK
217  *
218  * \brief Defines the thickness of the font as thick.
219  *
220  * This is a thick font. This means thicker than normal (bold).
221  */
222 
223 
224 
225 
226 
227 
228 
229 /** \brief Initializes the font object.
230  *
231  * This function sets the font object to defaults.
232  *
233  * By default a font has no name, no display name, no copyrigth,
234  * no predefined language, no type, no specific style, no
235  * glyph, etc.
236  *
237  * \param[in] parent The TagHeader where the TagFont is included.
238  */
TagFont(TagBase * parent)239 TagFont::TagFont(TagBase *parent)
240 	: TagBaseID("font", parent)
241 {
242 	f_font_name = 0;
243 	f_display_name = 0;
244 	f_copyright = 0;
245 	f_language = FONT_LANGUAGE_UNKNOWN;
246 	f_type = FONT_TYPE_BEST;
247 	f_bold = false;
248 	f_italic = false;
249 	f_small_text = false;
250 	f_wide = false;
251 	f_has_wide_char = false;		// defined in PreSave2ndPass() and used in Save()
252 	f_has_wide_offsets = false;		// defined in PreSave2ndPass() and used in Save()
253 	f_has_layout = false;			// defined in PreSave2ndPass() and used in Save()
254 	f_used_by_edit_text = false;
255 	f_define_font2 = false;			// defined in PreSave2ndPass() and used in Save()
256 	f_thickness = FONT_THICKNESS_UNKNOWN;
257 	f_font_em_size = FONT_EM_SMALL;
258 	f_ascent = DefaultAscent();
259 	f_descent = DefaultDescent();
260 	f_leading_height = DefaultLeadingHeight();
261 	f_default_advance = 0;
262 	f_space_advance = LONG_MIN;
263 	f_offsets_max = 0;			// defined in PreSave2ndPass() and used in Save()
264 	f_offsets = 0;				// defined in PreSave2ndPass() and used in Save()
265 	f_count = 0;
266 	//f_save_glyphs = ...
267 	//f_glyphs = ...
268 	//f_kerns = ...
269 }
270 
271 
272 
273 /** \brief The flags defining a font.
274  *
275  * A font is a definition and it has an identifier.
276  *
277  * \return SWF_TYPE_DEFINE and SWF_TYPE_HAS_ID
278  */
TypeFlags(void) const279 TagBase::swf_type_t TagFont::TypeFlags(void) const
280 {
281 	return SWF_TYPE_DEFINE | SWF_TYPE_HAS_ID;
282 }
283 
284 
285 /** \brief Prepare the font for saving.
286  *
287  * This function ensures that the font will properly be saved (as
288  * obtimized as possible.)
289  *
290  * The main action of this function is to clear the
291  * \em in \em use flag of all the glyphs to \em false.
292  * This means no glyphs will be saved in that font. The
293  * next step is for the other tags to mark exactly which
294  * glyphs are necessary for them. For instance, an edit text
295  * box could ask for all capital letters (A-Z) and another
296  * ask for digits (0-9).
297  *
298  * In order to complete the preparations before the Save()
299  * function is called, the PreSave2ndPass() will be called.
300  * That's at that time that the font can determine the index
301  * of each glyph since now it knows which glyph will be saved
302  * in the final font.
303  *
304  * \return An error code or ErrorManager::ERROR_CODE_NONE
305  */
PreSave(void)306 ErrorManager::error_code_t TagFont::PreSave(void)
307 {
308 	long		idx;
309 
310 	// reset the IN USE flag of each glyph
311 	idx = f_glyphs.Count();
312 	while(idx > 0) {
313 		idx--;
314 		dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx))->f_in_use = false;
315 	}
316 
317 	f_used_by_edit_text = false;
318 
319 	// if not unknown it was defined by the user
320 	// if not locale, then we need v6.x
321 	if(f_language != FONT_LANGUAGE_UNKNOWN
322 	&& f_language != FONT_LANGUAGE_LOCALE) {
323 		MinimumVersion(6);
324 	}
325 
326 	// a font name with an underscore as the first
327 	// character is taken as a "direct font name"
328 	// and thus we need V6.x -- this way we avoid
329 	// testing specific names and not be forward
330 	// compatible at a later date when Macromedia
331 	// decides to add new names.
332 	if(f_font_name != 0 && *f_font_name == '_') {
333 		MinimumVersion(6);
334 	}
335 
336 	// the small text font hint appeared in version 7
337 	if(f_small_text) {
338 		MinimumVersion(7);
339 	}
340 
341 	// with a proper thickness, we need a V8 and the DefineFontAlignZone
342 	// for kerns to be useful, we need a V8 Flash animation
343 	if(f_font_em_size == FONT_EM_LARGE
344 	|| f_kerns.Count() > 0) {
345 		MinimumVersion(8);
346 	}
347 
348 	// license info; display name defaults to font name
349 	// if there is a copyright and no display name
350 	if(f_display_name != 0 || f_copyright != 0) {
351 		MinimumVersion(9);
352 	}
353 
354 	return ErrorManager::ERROR_CODE_NONE;
355 }
356 
357 
358 /** \brief Finilize the font preparations for saving.
359  *
360  * This function is called after all the other objects PreSave()
361  * was called giving them a chance to define which of the embedded
362  * glyphs they use.
363  *
364  * At this point we also know whether the font must be defined
365  * with a DefineFont2 and using Unicode (wide) characters.
366  *
367  * \return An error code or ErrorManager::ERROR_CODE_NONE
368  */
PreSave2ndPass(void)369 ErrorManager::error_code_t TagFont::PreSave2ndPass(void)
370 {
371 	font_glyph_t	*glyph;
372 	int		idx, rmax;
373 	unsigned long	extra;
374 	unsigned short	*short_offsets;
375 #if DEBUG
376 	sswf_ucs4_t	previous;
377 #endif
378 
379 	// Now we know what character is used and whether an
380 	// edit text is referencing this font - from the
381 	// Macromedia documents, we have to have a DefineFont2
382 	// if an edit text references a font
383 	// Also, if anything said to use v6.x then the fonts
384 	// must be saved in Unicode (no choice!)
385 	//
386 	// WARNING: it is not possible to change from prior
387 	//	    version 6 to version 6 or more in the
388 	//	    2nd pass
389 
390 	f_define_font2 = false;
391 
392 	// by default we use the user defined f_wide flag
393 	// which is forced to true if one or more glyph has
394 	// an ID of 256 or more or we are using v6+
395 	f_has_wide_char = f_wide || Version() >= 6;
396 
397 	// to know the size of the glyphs we need to compute it
398 	// and that means creating the actual buffer of all the
399 	// glyphs
400 	rmax = f_glyphs.Count();
401 
402 	// the default layout flag value is set to true if some
403 	// of the layout parameters are defined -- note that having
404 	// a layout in a font doesn't mean we will use them (we do
405 	// only if a DefineTextField -- an edit text -- references
406 	// the font)
407 	f_has_layout = f_ascent != DefaultAscent()
408 		|| f_descent != DefaultDescent()
409 		|| f_leading_height != DefaultLeadingHeight()
410 		|| f_kerns.Count() != 0;
411 		/* Note: Macromedia says they are not currently taking
412 		 * the kerning in account... what about other players?
413 		 * -- Update: this has changed since version 8 -- now
414 		 * Macromedia has its own font renderer which takes
415 		 * the kernel in account.
416 		 */
417 
418 	// try to avoid re-allocating the offsets buffer if possible
419 	if(f_offsets != 0) {
420 		if(f_offsets_max < rmax + 1) {
421 			MemClean(&f_offsets);
422 		}
423 	}
424 	if(f_offsets == 0) {
425 		f_offsets = (unsigned long *) MemAlloc((rmax + 1) * sizeof(unsigned long), "offsets to the glyphs");
426 		f_offsets_max = rmax + 1;
427 	}
428 	// by default we have no glyphs (use only the DefineFontInfo[2]
429 	// if no edit text references this font!)
430 #if DEBUG
431 	previous = -1;
432 #endif
433 	f_count = 0;
434 	f_save_glyphs.Empty();
435 	for(idx = 0; idx < rmax; idx++) {
436 		glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
437 
438 #if DEBUG
439 		// ensure that the glyphs are ordered properly
440 		assert((long) glyph->f_name > (long) previous,
441 			"TagFont::PreSave2ndPass() found unordered glyphs (%ld >= %ld)",
442 				(long) previous, (long) glyph->f_name);
443 		previous = glyph->f_name;
444 #endif
445 
446 //printf("Glyph [%c] %s\n", glyph->f_name, glyph->f_in_use ? "in use" : "never referenced");
447 
448 		if(!glyph->f_in_use) {
449 			// unused, just skip it
450 			continue;
451 		}
452 		if(glyph->f_name > 255) {
453 			f_has_wide_char = true;
454 		}
455 		/*
456 		 * Note: Macromedia says they don't use the per char
457 		 *       bounding boxes -- what about other players?
458 		 */
459 		if(glyph->f_shape->HasBounds()) {
460 			f_has_layout = true;
461 		}
462 		glyph->f_index = (unsigned short) f_count;		// index at which the glyph is being saved
463 		f_offsets[f_count] = f_save_glyphs.ByteSize();
464 		(const_cast<TagShape *>(glyph->f_shape))->SaveWithoutStyles(f_save_glyphs);
465 		f_save_glyphs.Align();
466 		f_count++;
467 	}
468 	// save the total size in the last offset entry
469 	f_offsets[f_count] = f_save_glyphs.ByteSize();
470 	f_count++;
471 	// got to include this last entry here to make sure we don't
472 	// overflow anything
473 
474 	// if an EditText tag references this font
475 	// if the EM square of the font is large
476 	//
477 	//	then we need a DefineFont2
478 	//
479 	//	otherwise it depends on whether we need large
480 	//		offsets to access the glyphs
481 	if(f_used_by_edit_text
482 	|| f_font_em_size == FONT_EM_LARGE) {
483 		// NOTE: the MinimumVersion(3) is useless since the
484 		//	 TagEditText forces v4.x already!
485 		//MinimumVersion(3);
486 		f_define_font2 = true;
487 	}
488 	else {
489 		// we don't want any layout if we don't have
490 		// an edit text (would be unused!)
491 		f_has_layout = false;
492 	}
493 
494 	// compute the size of the offset table
495 	extra = (f_count - 1) * 2 + (f_define_font2 ? 2 : 0);
496 	f_has_wide_offsets = f_offsets[f_count - 1] + extra > USHRT_MAX;
497 	if(f_has_wide_offsets) {
498 		MinimumVersion(3);
499 
500 		// only DefineFont2 accepts large offsets
501 		if(!f_define_font2) {
502 			f_define_font2 = true;
503 			extra += 2;
504 		}
505 
506 		// wide offsets! we need to add 2 x extra because
507 		// that's the actual size of the table! Also include
508 		// the offset to the map
509 		extra *= 2;
510 		for(idx = 0; (unsigned int) idx < f_count; idx++) {
511 #if BYTE_ORDER == BIG_ENDIAN
512 			f_offsets[idx] = swap_int(f_offsets[idx] + extra);
513 #else
514 			f_offsets[idx] += extra;
515 #endif
516 		}
517 	}
518 	else {
519 		short_offsets = reinterpret_cast<unsigned short *>(f_offsets);
520 		for(idx = 0; (unsigned int) idx < f_count; idx++) {
521 #if BYTE_ORDER == BIG_ENDIAN
522 			short_offsets[idx] = swap_short((unsigned short) (f_offsets[idx] + extra));
523 #else
524 			short_offsets[idx] = (unsigned short) (f_offsets[idx] + extra);
525 #endif
526 		}
527 	}
528 
529 	return ErrorManager::ERROR_CODE_NONE;
530 }
531 
532 
533 /** \brief Save the TagFont in the specified Data buffer
534  *
535  * This function saves the font in the specified Data buffer.
536  *
537  * It will save the glyphs in the DefineFont or DefineFont2 tag.
538  * And some extraneous information in a DefineFontInfo or
539  * DefineFontInfo2 tag. And it saves the name and license in a
540  * DefineFontName tag.
541  *
542  * To save the glyphs, the TagFont calls the
543  * sswf::TagShape::SaveWithoutStyles(Data& data) function.
544  *
545  * \param[in] data The Data buffer where the font tags are saved
546  *
547  * \return An error code or ErrorManager::ERROR_CODE_NONE
548  *
549  * \sa sswf::TagShape::SaveWithoutStyles(Data& data)
550  */
Save(Data & data)551 ErrorManager::error_code_t TagFont::Save(Data& data)
552 {
553 	Data			sub_data, kern_data;
554 	font_glyph_t		*glyph;
555 	font_kern_t		*kern;
556 	const char		*name, *license;
557 	int			idx, max, rmax, cnt, used, l1, l2;
558 	bool			has_align_zones;
559 
560 	rmax = f_glyphs.Count();
561 
562 // if the f_font_define2 is set, then we save that type of a
563 // font, otherwise save a define font + define font info if
564 // required
565 	if(f_define_font2) {
566 		SaveID(sub_data);
567 		sub_data.WriteBits(f_has_layout, 1);
568 
569 		// by default we assume that we have alignment zones
570 		// unless there are no glyphs
571 		has_align_zones = rmax != 0;
572 
573 		// can types be all set? it isn't clear in any doc.
574 		if(Version() <= 5) {
575 			switch(f_type) {
576 			case FONT_TYPE_BEST:
577 				sub_data.WriteBits(0, 3);		/* not specific */
578 				break;
579 
580 			case FONT_TYPE_ASCII:
581 				sub_data.WriteBits(1, 3);
582 				break;
583 
584 			/*
585 			 * this is now defined as always zero in v6.x doc.
586 			 * it was properly defined as the Unicode flag
587 			 * before and is perfectly valid in prior v6.x
588 			 * movies!
589 			 */
590 			case FONT_TYPE_UNICODE:
591 				sub_data.WriteBits(2, 3);
592 				break;
593 
594 			case FONT_TYPE_SHIFTJIS:
595 				sub_data.WriteBits(4, 3);
596 				break;
597 
598 			}
599 		}
600 		else {
601 			sub_data.WriteBits(0, 1);
602 			sub_data.WriteBits(f_small_text, 1);
603 			sub_data.WriteBits(0, 1);
604 		}
605 
606 		// determine whether we need to use wide offsets
607 		sub_data.WriteBits(f_has_wide_offsets, 1);
608 
609 		sub_data.WriteBits(f_has_wide_char, 1);
610 
611 		sub_data.WriteBits(f_italic, 1);
612 		sub_data.WriteBits(f_bold, 1);
613 
614 		// language in v6.x, 0 otherwise
615 		if(Version() <= 5) {
616 			sub_data.PutByte(0);
617 		}
618 		else {
619 			sub_data.PutByte(f_language);
620 		}
621 
622 		cnt = f_font_name == 0 ? 0 : strlen(f_font_name);
623 		if(cnt > 255) {
624 			OnError(ErrorManager::ERROR_CODE_NAME_TOO_LONG, "a font name cannot be more than 255 characters long, change \"%s\"", f_font_name);
625 			cnt = 255;
626 		}
627 		sub_data.PutByte(cnt);		/* this one is a Pstring, why is that, dunno... */
628 		sub_data.Write(f_font_name, cnt);
629 
630 		// save the number of glyphs
631 		// we MUST have one extra "offset" that actually represents the size of the
632 		// table so one can skip all the glyphs at once
633 		sub_data.PutShort((short) (f_count - 1));
634 
635 		// save the array of offsets
636 		sub_data.Write(f_offsets, f_count * (f_has_wide_offsets ? 4 : 2));
637 
638 		// save the shapes
639 		sub_data.Append(f_save_glyphs);
640 
641 		// save the mapping between the shapes and characters
642 		for(idx = 0; idx < rmax; idx++) {
643 			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
644 			if(!glyph->f_in_use) {
645 				// unused, just skip it
646 				continue;
647 			}
648 			if(f_has_wide_char) {
649 				sub_data.PutShort((unsigned short) glyph->f_name);
650 			}
651 			else {
652 				sub_data.PutByte((unsigned char) glyph->f_name);
653 			}
654 			if(!glyph->f_shape->HasAlignZone()) {
655 				has_align_zones = false;
656 			}
657 		}
658 
659 		if(f_has_layout) {
660 			sub_data.PutShort((short) f_ascent);
661 			sub_data.PutShort((short) f_descent);
662 			sub_data.PutShort((short) f_leading_height);
663 			for(idx = 0; idx < rmax; idx++) {
664 				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
665 				if(!glyph->f_in_use) {
666 					// unused, just skip it
667 					continue;
668 				}
669 				if(glyph->f_advance != LONG_MIN) {
670 					sub_data.PutShort((short) glyph->f_advance);
671 				}
672 				else {
673 					// if not specific to a character, use the default
674 					sub_data.PutShort((short) f_default_advance);
675 				}
676 			}
677 			for(idx = 0; idx < rmax; idx++) {
678 				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
679 				if(!glyph->f_in_use) {
680 					// unused, just skip it
681 					continue;
682 				}
683 				glyph->f_shape->Bounds(0).Save(sub_data);
684 				sub_data.Align();		// <- is this correct? shouldn't it be in the rectangle Save() function?
685 			}
686 			// New max (i.e. the # of kerning entries)
687 			max = f_kerns.Count();
688 			for(idx = 0, cnt = 0; idx < max; idx++) {
689 				kern = dynamic_cast<font_kern_t *>(f_kerns.Get(idx));
690 				/*
691 				 * before to save a kern we want to make sure it's not
692 				 * useless; we go through the list of glyph and ensures
693 				 * that BOTH the glyphs are defined in the font; if not
694 				 * then this kerning can't even happen so we don't need
695 				 * it and thus don't save it.
696 				 */
697 				for(idx = 0, used = 0; idx < rmax && used != 3; idx++) {
698 					glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
699 					if(glyph->f_name == kern->f_code[0]) {
700 						if(!glyph->f_in_use) {
701 							break;
702 						}
703 						used |= 1;
704 					}
705 					// don't put an 'else' here since code0 == code1
706 					// is possible! (though probably really rare?)
707 					if(glyph->f_name == kern->f_code[1]) {
708 						if(!glyph->f_in_use) {
709 							break;
710 						}
711 						used |= 2;
712 					}
713 				}
714 				if(used == 3) {
715 					if(f_has_wide_char) {
716 						kern_data.PutShort((unsigned short) kern->f_code[0]);
717 						kern_data.PutShort((unsigned short) kern->f_code[1]);
718 					}
719 					else {
720 						kern_data.PutByte((unsigned char) kern->f_code[0]);
721 						kern_data.PutByte((unsigned char) kern->f_code[1]);
722 					}
723 					kern_data.PutShort((short) kern->f_advance);
724 					cnt++;
725 				}
726 			}
727 			// now we can save the kerning tables
728 			sub_data.PutShort(cnt);
729 			sub_data.Append(kern_data);
730 		}
731 		SaveTag(data, f_font_em_size == FONT_EM_LARGE ? SWF_TAG_DEFINE_FONT3 : SWF_TAG_DEFINE_FONT2, sub_data.ByteSize());
732 		data.Append(sub_data);
733 
734 		// if we had zones, then we save them now
735 		if(has_align_zones) {
736 			if(f_font_em_size == FONT_EM_LARGE) {
737 				// There is no compression for this tag so we can compute the
738 				// size at once and avoid saving things in an intermediate buffer
739 				SaveTag(data, SWF_TAG_DEFINE_FONT_ALIGN_ZONES, 5 + (f_count - 1) * 8);
740 				data.PutShort(Identification());
741 				if(f_thickness == FONT_THICKNESS_UNKNOWN) {
742 					data.WriteBits(FONT_THICKNESS_MEDIUM, 2);
743 				}
744 				else {
745 					data.WriteBits(f_thickness, 2);
746 				}
747 				data.WriteBits(0, 6);
748 				data.PutByte(2);		// 2 entries per zone
749 				for(idx = 0; idx < rmax; idx++) {
750 					glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
751 					if(!glyph->f_in_use) {
752 						// unused, just skip it
753 						continue;
754 					}
755 					glyph->f_shape->SaveAlignZone(data);
756 				}
757 				data.WriteBits(1, 1);	// zone_x
758 				data.WriteBits(1, 1);	// zone_y
759 				data.WriteBits(0, 6);	// reserver
760 			}
761 			else {
762 				OnError(ErrorManager::ERROR_CODE_INVALID_EM_SQUARE, "alignment zones in glyphs cannot be saved unless the font is marked as having a Large EM Square");
763 			}
764 		}
765 	}
766 	else {
767 		// if there isn't any glyph we still need a DefineFont tag
768 		SaveID(sub_data);
769 		sub_data.Write(f_offsets, f_count == 1 ? 2 : (f_count - 1) * 2);
770 		sub_data.Append(f_save_glyphs);
771 		SaveTag(data, SWF_TAG_DEFINE_FONT, sub_data.ByteSize());
772 		data.Append(sub_data);
773 
774 		// in some cases we also want to save a DefineFontInfo
775 		if((f_font_name != 0 && *f_font_name != '\0')
776 		|| f_bold || f_italic
777 		|| (f_language != FONT_LANGUAGE_UNKNOWN && f_language != FONT_LANGUAGE_LOCALE)
778 		|| f_count == 1) {
779 			sub_data.Empty();
780 			SaveID(sub_data);	// same ID as the font
781 
782 			cnt = f_font_name == 0 ? 0 : strlen(f_font_name);
783 			if(cnt > 255) {
784 				OnError(ErrorManager::ERROR_CODE_NAME_TOO_LONG, "a font name cannot be more than 255 characters long, change \"%s\"", f_font_name);
785 				cnt = 255;
786 			}
787 			sub_data.PutByte(cnt);		/* this one is a Pstring, why is that, dunno... */
788 			sub_data.Write(f_font_name, cnt);
789 
790 			sub_data.WriteBits(0, 2);
791 			if(Version() >= 6) {
792 				sub_data.WriteBits(f_small_text, 1);
793 				sub_data.WriteBits(0, 2);
794 			}
795 			else {
796 				switch(f_type) {
797 				case FONT_TYPE_BEST:
798 					sub_data.WriteBits(0, 3);		/* not specific */
799 					break;
800 
801 				case FONT_TYPE_ASCII:
802 					sub_data.WriteBits(1, 3);
803 					break;
804 
805 				case FONT_TYPE_SHIFTJIS:
806 					sub_data.WriteBits(2, 3);
807 					break;
808 
809 				/*
810 				 * this is now defined as always zero in v6.x doc.
811 				 * it was properly defined as the Unicode flag
812 				 * before and is perfectly valid in prior v6.x
813 				 * movies!
814 				 */
815 				case FONT_TYPE_UNICODE:
816 					sub_data.WriteBits(4, 3);
817 					break;
818 
819 				}
820 			}
821 			sub_data.WriteBits(f_italic, 1);
822 			sub_data.WriteBits(f_bold, 1);
823 
824 			// here we know that f_has_wide_char is
825 			// already 1 when Version() >= 6
826 			sub_data.WriteBits(f_has_wide_char, 1);
827 
828 			if(Version() >= 6) {
829 				sub_data.PutByte(f_language);
830 			}
831 
832 			// save the mapping between the shapes and characters
833 			for(idx = 0; idx < rmax; idx++) {
834 				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
835 				if(!glyph->f_in_use) {
836 					// unused, just skip it
837 					continue;
838 				}
839 				if(f_has_wide_char) {
840 					sub_data.PutShort((unsigned short) glyph->f_name);
841 				}
842 				else {
843 					sub_data.PutByte((unsigned char) glyph->f_name);
844 				}
845 			}
846 
847 			SaveTag(data, Version() >= 6 ? SWF_TAG_DEFINE_FONT_INFO2 : SWF_TAG_DEFINE_FONT_INFO, sub_data.ByteSize());
848 			data.Append(sub_data);
849 		}
850 	}
851 
852 	// Add another tag when there is a display name and/or copyright
853 	if(f_display_name != 0 || f_copyright != 0) {
854 		name = f_display_name;
855 		if(name == 0) {
856 			// default to the other name if it exists
857 			name = f_font_name;
858 			if(name == 0) {
859 				// otherwise nothing
860 				name = "";
861 			}
862 		}
863 		l1 = strlen(name) + 1;
864 		license = f_copyright;
865 		if(license == 0) {
866 			// make sure we don't crash with strlen() + Write()
867 			license = "";
868 		}
869 		l2 = strlen(license) + 1;
870 		SaveTag(data, SWF_TAG_DEFINE_FONT_NAME, 2 + l1 + l2);
871 		SaveID(data);
872 		data.Write(name, l1);
873 		data.Write(license, l2);
874 	}
875 
876 	return ErrorManager::ERROR_CODE_NONE;
877 }
878 
879 
880 const char *	TagFont::g_font_language_name[FONT_LANGUAGE_max] = {
881 	"LOCALE",
882 	"LATIN",
883 	"JAPANESE",
884 	"KOREAN",
885 	"SIMPLIFIED_CHINESE",
886 	"TRADITIONAL_CHINESE"
887 };
888 
889 
890 /** \brief Defines the language number from its name.
891  *
892  * This function searches for a language by name and return the corresponding
893  * language code.
894  *
895  * \code
896  *	LOCALE
897  *	LATIN
898  *	JAPANESE
899  *	KOREAN
900  *	SIMPLIFIED_CHINESE
901  *	TRADITIONAL_CHINESE
902  * \endcode
903  *
904  * \param[in] language The name of the language this font is for
905  */
StringToLanguage(const char * language)906 TagFont::font_language_t TagFont::StringToLanguage(const char *language)
907 {
908 	font_language_t		idx;
909 
910 	for(idx = FONT_LANGUAGE_LOCALE; idx < FONT_LANGUAGE_max; idx = (font_language_t) ((int) idx + 1)) {
911 		if(strcasecmp(g_font_language_name[(int) idx], language) == 0) {
912 			return idx;
913 		}
914 	}
915 
916 	return FONT_LANGUAGE_UNKNOWN;
917 }
918 
919 
920 /** \brief Transform a language index to the corresponding name.
921  *
922  * This function transform a language index in a corresponding string.
923  *
924  * \param[in] language The language index to convert to a string.
925  *
926  * \return A constant string with the language name or "invalid".
927  */
LanguageToString(font_language_t language)928 const char *TagFont::LanguageToString(font_language_t language)
929 {
930 	if(language < 0 || language >= FONT_LANGUAGE_max) {
931 		return "invalid";
932 	}
933 
934 	return g_font_language_name[language];
935 }
936 
937 
938 /** \brief Add a glyph to an embedded font.
939  *
940  * This function adds the ref shape as the character defined with the code
941  * defined in the name parameter.
942  *
943  * If you want to use the normal advance for a character, set the advance
944  * paramter to LONG_MIN. Wider or smaller characters need to use a
945  * specific value here.
946  *
947  * \param[in] name	The name (unicode number) of the glyph
948  * \param[in] ref	The corresponding shape
949  * \param[in] advance	The number of twips to the next character
950  *
951  * \return An error code or ErrorManager::ERROR_CODE_NONE
952  */
AddGlyph(sswf_ucs4_t name,const TagBase * ref,long advance)953 ErrorManager::error_code_t TagFont::AddGlyph(sswf_ucs4_t name, const TagBase *ref, long advance)
954 {
955 	font_glyph_t	*glyph;
956 	font_info_t	info;
957 
958 	if(ref == 0 || strcmp(ref->Name(), "shape") != 0) {
959 		return OnError(ErrorManager::ERROR_CODE_MISSING_SHAPE, "a glyph reference must be of type TagShape and it has to exist");
960 	}
961 
962 	info.f_glyph = name;
963 	if(FindGlyph(info)) {
964 		// the user has the right to redefine the space as an
965 		// empty character!
966 		if(info.f_index != SSWF_FONT_SPACE_INDEX) {
967 			return OnError(ErrorManager::ERROR_CODE_GLYPH_DEFINED_TWICE, "glyph 'u%ld' defined twice. Second instance ignored.", (long) name);
968 		}
969 	}
970 
971 	glyph = new font_glyph_t;
972 	MemAttach(glyph, sizeof(font_glyph_t), "TagFont::AddGlyph() -- glyph of font");
973 	glyph->f_name = name;
974 	glyph->f_shape = dynamic_cast<const TagShape *>(ref);
975 	glyph->f_advance = advance;	// if LONG_MIN, use the default
976 	glyph->f_in_use = false;	// if true, must be saved
977 
978 	// Glyphs MUST be sorted for Macromedia players
979 	// This allow for binary searches which are very effective
980 	// and since we searched for the character with the FindGlyph()
981 	// we already know where we need to insert this new glyph
982 	f_glyphs.Insert(info.f_position, glyph);
983 
984 	return ErrorManager::ERROR_CODE_NONE;
985 }
986 
987 
988 /** \brief Add a special kern between two glyphs.
989  *
990  * Defines two glyphs and the space to add when they are encountered
991  * in that specific order in a word.
992  *
993  * For instance, a capital W followed by a lower case I need to be
994  * closer to each others than what the default advance of the W
995  * character implies.
996  *
997  * This advance is added to the normal advance (cumulative) this it
998  * often ends up being negative.
999  *
1000  * \todo
1001  * We would need to make sure that all kerns are distinct.
1002  *
1003  * \param[in] code0	The first glyph
1004  * \param[in] code1	The second glyph
1005  * \param[in] advance	The advance to add when these two glyphs are found in a string
1006  */
AddKern(sswf_ucs4_t code0,sswf_ucs4_t code1,long advance)1007 void TagFont::AddKern(sswf_ucs4_t code0, sswf_ucs4_t code1, long advance)
1008 {
1009 	font_kern_t	*kern;
1010 
1011 	kern = new font_kern_t;
1012 	MemAttach(kern, sizeof(font_kern_t), "TagFont::AddKern() -- font kern");
1013 	kern->f_code[0] = code0;
1014 	kern->f_code[1] = code1;
1015 	kern->f_advance = advance;
1016 	f_kerns.Set(-1, kern);
1017 }
1018 
1019 
1020 /** \brief Gets the name of the font.
1021  *
1022  * This function returns the current name of the font.
1023  *
1024  * \return The name of the font.
1025  */
FontName(void) const1026 const char *TagFont::FontName(void) const
1027 {
1028 	return f_font_name;
1029 }
1030 
1031 
1032 /** \brief Retrieve the information (advance, etc.) of the specified glyph.
1033  *
1034  * For this function, define info.f_index with the glyph information
1035  * you want to retrieve. Call the function, and if the glyph exists,
1036  * the information for that glyph will be saved in the other fields
1037  * of the structure.
1038  *
1039  * It is an error to put a glyph index larger than the number of glyphs
1040  * available.
1041  *
1042  * Note that the index represents the index in the array of glyphs, not
1043  * the glyph Unicode number. Use the FindGlyph() function instead to
1044  * find a glyph using its glyph Unicode number.
1045  *
1046  * \param[in,out] info	A glyph information structure with it's f_index
1047  *			properly defined; returned with the other glyph
1048  *			information
1049  *
1050  * \return An error code or ErrorManager::ERROR_CODE_NONE
1051  *
1052  * \sa sswf::TagFont::FindGlyph(font_info_t& info, bool mark_empty_in_use) const
1053  */
GlyphInfo(font_info_t & info) const1054 ErrorManager::error_code_t TagFont::GlyphInfo(font_info_t& info) const
1055 {
1056 	font_glyph_t	*glyph;
1057 
1058 	if(info.f_index >= static_cast<unsigned long>(f_glyphs.Count())) {
1059 		return OnError(ErrorManager::ERROR_CODE_INVALID_GLYPH, "invalid index for a GlyphInfo request");
1060 	}
1061 
1062 	glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(info.f_index));
1063 	info.f_glyph = glyph->f_name;
1064 	info.f_saved_index = glyph->f_index;
1065 	if(glyph->f_advance == LONG_MIN) {
1066 		info.f_advance = f_default_advance;
1067 	}
1068 	else {
1069 		info.f_advance = glyph->f_advance;
1070 	}
1071 	info.f_is_empty = glyph->f_shape->IsEmpty();
1072 
1073 	return ErrorManager::ERROR_CODE_NONE;
1074 }
1075 
1076 
1077 /** \brief Check whether the font has glyphs.
1078  *
1079  * This function returns true if the font defins one or more glyphs.
1080  * This can be used to know whether the font is an embedded or a
1081  * ssytem font.
1082  *
1083  * \return true when the font has glyphs
1084  */
HasGlyph(void) const1085 bool TagFont::HasGlyph(void) const
1086 {
1087 	return f_glyphs.Count() != 0;
1088 }
1089 
1090 
1091 /** \brief Retrieve the information (advance, etc.) of the specified glyph.
1092  *
1093  * For this function, define info.f_glyph with the glyph Unicode number
1094  * you want to retrieve. Call the function, and if the glyph exists,
1095  * the information for that glyph will be saved in the other fields
1096  * of the structure.
1097  *
1098  * The glyph is searched with a binary search so it is fast.
1099  *
1100  * When the fonction does not find the glyph, it is not considered an
1101  * error. It returns the structure with f_index set to the location
1102  * where the glyph defined in f_glyph can be inserted (this is used
1103  * internally whenever a new glyph is added to the TagFont.)
1104  *
1105  * \param[in,out] info	A glyph information structure with its f_glyph
1106  *			properly defined; returned with the other glyph
1107  *			information
1108  * \param[in] mark_empty_in_use	Whether to mark empty glyphs in use or not
1109  *
1110  * \return true when the glyph was found
1111  *
1112  * \sa sswf::TagFont::GlyphInfo(font_info_t& info) const
1113  */
FindGlyph(font_info_t & info,bool mark_empty_in_use) const1114 bool TagFont::FindGlyph(font_info_t& info, bool mark_empty_in_use) const
1115 {
1116 	font_glyph_t	*glyph;
1117 	int		i, j, p;
1118 	bool		found;
1119 
1120 	// avoid warnings -- also crashes better if an error occurs
1121 	glyph = 0;
1122 
1123 	/*
1124 	 * search the list of available glyphs and
1125 	 * determine the index which represents the character 'c'
1126 	 * note that the glyphs are always ordered
1127 	 */
1128 	p = 0;		// necessary for empty lists!
1129 	found = false;
1130 	j = f_glyphs.Count();
1131 	if(j < 4) {
1132 		/* ugly bubble search when not enough entries yet */
1133 		while(j > 0) {
1134 			j--;
1135 			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(j));
1136 			if(glyph->f_name == info.f_glyph) {
1137 				p = j;
1138 				found = true;
1139 				break;
1140 			}
1141 			if(glyph->f_name < info.f_glyph) {
1142 				// user glyph larger than any of the glyphs
1143 				// in out list
1144 				p = j + 1;
1145 				break;
1146 			}
1147 		}
1148 	}
1149 	else {
1150 		// binary search -- you can't go faster
1151 		i = 0;
1152 		while(i < j) {
1153 			// get the center position of the current range
1154 			p = i + (j - i) / 2;
1155 			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(p));
1156 			if(glyph->f_name == info.f_glyph) {
1157 				found = true;
1158 				break;
1159 			}
1160 			if(glyph->f_name < info.f_glyph) {
1161 				p++;
1162 				i = p;
1163 			}
1164 			else {
1165 				j = p;
1166 			}
1167 		}
1168 	}
1169 
1170 	if(found) {
1171 		info.f_index = info.f_position = p;
1172 		info.f_saved_index = glyph->f_index;
1173 		if(glyph->f_advance == LONG_MIN) {
1174 			info.f_advance = f_default_advance;
1175 		}
1176 		else {
1177 			info.f_advance = glyph->f_advance;
1178 		}
1179 		info.f_is_empty = glyph->f_shape->IsEmpty();
1180 		glyph->f_in_use = info.f_is_empty ? mark_empty_in_use : true;
1181 		return true;
1182 	}
1183 
1184 	if(info.f_glyph == ' ' && f_space_advance != LONG_MIN) {
1185 		info.f_advance = f_space_advance;
1186 		info.f_index = SSWF_FONT_SPACE_INDEX;
1187 		info.f_position = p;
1188 		info.f_saved_index = 0;		// this one shouldn't be used
1189 		info.f_is_empty = true;
1190 		return true;
1191 	}
1192 
1193 	// Ooops doesn't exist!
1194 	// 'p' is the closest position (i.e. if we are adding a new
1195 	// glyph that's where we want it!)
1196 	info.f_index = (unsigned short) (info.f_position = p);
1197 	info.f_saved_index = (unsigned short) info.f_glyph;
1198 
1199 	return false;
1200 }
1201 
1202 
1203 
1204 /** \brief Returns the default ascent.
1205  *
1206  * This function returns the value representing the default ascent for
1207  * an SWF font. It is recommanded to use that value for your font
1208  * ascent if possible.
1209  *
1210  * \return The default ascent.
1211  */
DefaultAscent(void) const1212 long TagFont::DefaultAscent(void) const
1213 {
1214 	return 750;
1215 }
1216 
1217 
1218 /** \brief Returns the default descent.
1219  *
1220  * This function returns the value representing the default descent for
1221  * an SWF font. It is recommanded to use that value for your font
1222  * descent if possible.
1223  *
1224  * \return The default descent.
1225  */
DefaultDescent(void) const1226 long TagFont::DefaultDescent(void) const
1227 {
1228 	return 1024 - DefaultAscent();
1229 }
1230 
1231 
1232 /** \brief Returns the default leading height.
1233  *
1234  * This function returns the value representing the default leading
1235  * height for an SWF font. It is recommanded that you use that value
1236  * for your own fonts if possible.
1237  *
1238  * \return The default leading height
1239  */
DefaultLeadingHeight(void) const1240 long TagFont::DefaultLeadingHeight(void) const
1241 {
1242 	return 0;
1243 }
1244 
1245 
1246 /** \brief Defines the name of the font.
1247  *
1248  * This function defines the name of the font.
1249  *
1250  * A font name starting with an underscore is taken as a "direct font name"
1251  * and requires V6.x. The currently supported names are:
1252  *
1253  * \code
1254  *	_sans
1255  *	_serif
1256  *	_typewriter
1257  *	5F E3 82 B4 E3 82 B7 E3 83 83 E3 82 AF (Gothic&mdash;Japanese)
1258  *	5F E7 AD 89 E5 B9 85 (Tohaba, Gothic Mono&mdash;Japanese)
1259  *	5F E6 98 8E E6 9C 9D (Mincho&mdash;Japanese)
1260  * \endcode
1261  *
1262  * We use that mechanism rather than checking for special names so additional
1263  * names added by Macromedia/Adobe are automatically supported.
1264  *
1265  * This function overwrites the previous name if one existed.
1266  *
1267  * \param[in] font_name The new name of the font.
1268  */
SetName(const char * font_name)1269 void TagFont::SetName(const char *font_name)
1270 {
1271 	MemFree(f_font_name);
1272 	f_font_name = StrDup(font_name);
1273 }
1274 
1275 
1276 /** \brief Defines the display name of the font.
1277  *
1278  * This function can be used to define the display name of the font
1279  * opposed to the exact system name.
1280  *
1281  * For instance, a font can be called "ArialBld" and the display name
1282  * would then be "Arial Bold"
1283  *
1284  * \param[in] display_name The name of the font as we want to show it to an end user
1285  */
SetDisplayName(const char * display_name)1286 void TagFont::SetDisplayName(const char *display_name)
1287 {
1288 	MemFree(f_display_name);
1289 	f_display_name = StrDup(display_name);
1290 }
1291 
1292 
1293 /** \brief Defines a copyright or license for the font.
1294  *
1295  * This function defines a copyright string to save along the font.
1296  * This can include any information such as how the font can be
1297  * used.
1298  *
1299  * \param[in] copyright The copyright or license for the embedded font
1300  */
SetCopyright(const char * copyright)1301 void TagFont::SetCopyright(const char *copyright)
1302 {
1303 	MemFree(f_copyright);
1304 	f_copyright = StrDup(copyright);
1305 }
1306 
1307 
1308 /** \brief Set the font layout
1309  *
1310  * This function sets the ascent, descent and leading height of the font.
1311  *
1312  * The ascent represents the distance from the base to the top of the font.
1313  *
1314  * The descent represents the distance from the base to the bottom of the font.
1315  *
1316  * The leading height is added the ascent and the descent to move to the
1317  * next of text. The default is zero assuming that the ascent and descent
1318  * include enough space to separate two lines of text.
1319  *
1320  * \param[in] ascent		The ascent of the font.
1321  * \param[in] descent		The descent of the font.
1322  * \param[in] leading_height	The leading height of the font.
1323  */
SetLayout(long ascent,long descent,long leading_height)1324 void TagFont::SetLayout(long ascent, long descent, long leading_height)
1325 {
1326 	f_ascent = ascent;
1327 	f_descent = descent;
1328 	f_leading_height = leading_height;
1329 }
1330 
1331 
1332 /** \brief Set the default advance.
1333  *
1334  * This function can be used to define the default advance of
1335  * a glyph. This is useful to avoid having to define the
1336  * advance parameter each time a new glyph is added.
1337  *
1338  * By default this value is set to zero: not advance.
1339  *
1340  * \param[in] advance	The amount to advance to go where the next glyph should be rendered
1341  */
SetDefaultAdvance(long advance)1342 void TagFont::SetDefaultAdvance(long advance)
1343 {
1344 	f_default_advance = advance;
1345 }
1346 
1347 
1348 /** \brief Set the width of the regular space glyph.
1349  *
1350  * This function can be used to define the width of the space
1351  * glyph. This is the glyph with Unicde number 0x20 (32).
1352  * That glyph is never included in the final font.
1353  *
1354  * \param[in] advance The size of one space character
1355  */
SetSpaceAdvance(long advance)1356 void TagFont::SetSpaceAdvance(long advance)
1357 {
1358 	f_space_advance = advance;
1359 }
1360 
1361 
1362 /** \brief Set the type of font.
1363  *
1364  * The type of font to use with the TagFont.
1365  *
1366  * This applies to SWF version 5 and earlier. Since version 6,
1367  * the font type is automatically Unicode, which encompass all
1368  * the other possible fonts.
1369  *
1370  * The available types are:
1371  *
1372  * \code
1373  *	TagFont::FONT_TYPE_BEST
1374  *	TagFont::FONT_TYPE_ASCII
1375  *	TagFont::FONT_TYPE_UNICODE
1376  *	TagFont::FONT_TYPE_SHIFTJIS
1377  * \endcode
1378  *
1379  * \param[in] type The font type.
1380  */
SetType(font_type_t type)1381 void TagFont::SetType(font_type_t type)
1382 {
1383 	f_type = type;
1384 }
1385 
1386 
1387 /** \brief Set the language corresponding to this font.
1388  *
1389  * This function sets the language corresponding to this font.
1390  * This is not very useful since version 6 since all fonts use
1391  * Unicode which include all possible languages today (and tomorrow
1392  * once we have Klingon in Unicode.)
1393  *
1394  * You can use the TagFont::StringToLanguage(const char *language)
1395  * to transform a string to a language code as required by this
1396  * function.
1397  *
1398  * The available languages are defined here:
1399  *
1400  * \code
1401  *	FONT_LANGUAGE_UNKNOWN
1402  *	FONT_LANGUAGE_LOCALE
1403  *	FONT_LANGUAGE_LATIN
1404  *	FONT_LANGUAGE_JAPANESE
1405  *	FONT_LANGUAGE_KOREAN
1406  *	FONT_LANGUAGE_SIMPLIFIED_CHINESE
1407  *	FONT_LANGUAGE_TRADITIONAL_CHINESE
1408  * \endcode
1409  *
1410  * Unknown is used to mark a font as language-less.
1411  *
1412  * \param[in] language		The language code
1413  *
1414  * \sa sswf::TagFont::StringToLanguage(const char *language)
1415  */
SetLanguage(font_language_t language)1416 void TagFont::SetLanguage(font_language_t language)
1417 {
1418 	f_language = language < 0 || language >= FONT_LANGUAGE_max
1419 				? FONT_LANGUAGE_UNKNOWN : language;
1420 }
1421 
1422 
1423 /** \brief Mark the font as representing a bold style.
1424  *
1425  * Set this flag if your font represents a bold version of the
1426  * font. If you want to use a system font, use this flag so
1427  * the bold version of the font is used.
1428  *
1429  * \param[in] bold	true if the font is bold
1430  */
SetBold(bool bold)1431 void TagFont::SetBold(bool bold)
1432 {
1433 	f_bold = bold;
1434 }
1435 
1436 
1437 /** \brief Mark the font as representing an italic style.
1438  *
1439  * Set this flag if your font represents an italic version of the
1440  * font. If you want to use a system font, use this flag so
1441  * the italic version of the font is used.
1442  *
1443  * \param[in] italic	true if the font is italic
1444  */
SetItalic(bool italic)1445 void TagFont::SetItalic(bool italic)
1446 {
1447 	f_italic = italic;
1448 }
1449 
1450 
1451 /** \brief Mark the font as being a small text font.
1452  *
1453  * Set this flag to true as a hint to the Flash Player that the font
1454  * will be used to draw small text.
1455  *
1456  * \param[in] small_text	true to mark the font as used for small text
1457  */
SetSmallText(bool small_text)1458 void TagFont::SetSmallText(bool small_text)
1459 {
1460 	f_small_text = small_text;
1461 }
1462 
1463 
1464 /** \brief Define the thickness of the font.
1465  *
1466  * This value is set to Unknown by default meaning that the
1467  * thickness is not specified.
1468  *
1469  * It can be set to Thin, Medium or Thick:
1470  *
1471  * \code
1472  *	FONT_THICKNESS_THIN
1473  *	FONT_THICKNESS_MEDIUM
1474  *	FONT_THICKNESS_THICK
1475  * \endcode
1476  *
1477  * The thickness will not be saved in the font if the EM square
1478  * is not also marked as large and all glyphs got an align zone
1479  * defined.
1480  *
1481  * \param[in] thickness The new thickness
1482  *
1483  * \sa TagFont::SetEMSize(font_em_size_t font_em_size)
1484  */
SetThickness(font_thickness_t thickness)1485 void TagFont::SetThickness(font_thickness_t thickness)
1486 {
1487 	f_thickness = thickness;
1488 }
1489 
1490 
1491 /** \brief Define the size of the EM square of the font.
1492  *
1493  * This function is used to define the size of the EM square
1494  * used to draw the glyphs. This could be done automatically
1495  * by checking the size of the glyphs, but that's not done
1496  * yet and it would not automatically work in all cases.
1497  *
1498  * The EM square can be small or large:
1499  *
1500  * \code
1501  *	FONT_EM_SMALL
1502  *	FONT_EM_LARGE
1503  * \endcode
1504  *
1505  * \param[in] font_em_size The new size of the EM square
1506  */
SetEMSize(font_em_size_t font_em_size)1507 void TagFont::SetEMSize(font_em_size_t font_em_size)
1508 {
1509 	f_font_em_size = font_em_size;
1510 }
1511 
1512 
1513 /** \brief Mark the font as a Unicode font.
1514  *
1515  * This flag is ignored in SWF version 6 and over. In that case, all fonts must
1516  * be defined an Unicode (wide).
1517  *
1518  * Otherwise, use this flag to mark whether you want to use the 256 glyphs
1519  * font or the 65536 glyphs font.
1520  *
1521  * \param[in] wide	true to make the font Unicode
1522  */
SetWide(bool wide)1523 void TagFont::SetWide(bool wide)
1524 {
1525 	f_wide = wide;
1526 }
1527 
1528 
1529 
1530 /** \brief Set which glyphs are used.
1531  *
1532  * This function can be used to define the glyphs that other tags use.
1533  *
1534  * \param[in] used_glyphs	A string representing the glyphs in use or NULL
1535  * \param[in] mark_empty_in_use	Whether empty glyphs should be marked in use
1536  *
1537  * \return An error code or ErrorManager::ERROR_CODE_NONE
1538  *
1539  * \sa TagFont::SetUsedGlyphs(const sswf_ucs4_t *used_glyphs, bool mark_empty_in_use)
1540  */
SetUsedGlyphs(const char * used_glyphs,bool mark_empty_in_use)1541 ErrorManager::error_code_t TagFont::SetUsedGlyphs(const char *used_glyphs, bool mark_empty_in_use)
1542 {
1543 	ErrorManager::error_code_t	ec;
1544 	sswf_ucs4_t			*wc_used_glyphs, *d;
1545 	size_t				l, sz;
1546 
1547 	if(used_glyphs == 0 || (used_glyphs[0] == '*' && used_glyphs[1] == '\0')) {
1548 		return SetUsedGlyphs(static_cast<const sswf_ucs4_t *>(0), mark_empty_in_use);
1549 	}
1550 	l = strlen(used_glyphs);
1551 	sz = l * sizeof(sswf_ucs4_t);
1552 	wc_used_glyphs = new sswf_ucs4_t[l + 1];
1553 	d = wc_used_glyphs;
1554 	mbtowc(used_glyphs, l, d, sz);
1555 	*d = (sswf_ucs4_t) '\0';	// mbtowc() doesn't terminate the strings
1556 	ec = SetUsedGlyphs(wc_used_glyphs, true);
1557 	delete [] wc_used_glyphs;
1558 
1559 	return ec;
1560 }
1561 
1562 
1563 /** \brief Set which glyphs are used.
1564  *
1565  * This function can be used to define the glyphs that other tags use.
1566  *
1567  * This is the official function which accepts a Unicode string as input.
1568  *
1569  * The special strings "*" and NULL can be used in the used_glyphs parameter
1570  * to mark all the glyphs in used at once.
1571  *
1572  * The string can otherwise be defined with a range defined by two glyphs
1573  * separated by a dash (-). For instance, to include all the ASCII upper case
1574  * characters, one can use "A-Z". Several ranges can be included in the same
1575  * string and the dash (-) can be included at the very beginning or the end
1576  * of the string to be included as a glyph in use. The code accepts ranges
1577  * which are written backward; so "9-0" is taken as "0-9".
1578  *
1579  * \param[in] used_glyphs	A string representing the glyphs in use or NULL
1580  * \param[in] mark_empty_in_use	Whether empty glyphs should be marked in use
1581  *
1582  * \return An error code or ErrorManager::ERROR_CODE_NONE
1583  *
1584  * \sa TagFont::SetUsedGlyphs(const char *used_glyphs, bool mark_empty_in_use)
1585  */
SetUsedGlyphs(const sswf_ucs4_t * used_glyphs,bool mark_empty_in_use)1586 ErrorManager::error_code_t TagFont::SetUsedGlyphs(const sswf_ucs4_t *used_glyphs, bool mark_empty_in_use)
1587 {
1588 	font_info_t			info;
1589 	int				a, b, max, idx;
1590 	ErrorManager::error_code_t	err_code;
1591 
1592 	// if no glyph, just forget it altogether in this case
1593 	max = f_glyphs.Count();
1594 	if(max == 0) {
1595 		return ErrorManager::ERROR_CODE_NONE;
1596 	}
1597 
1598 	if(used_glyphs == 0 || (used_glyphs[0] == '*' && used_glyphs[1] == '\0')) {
1599 		// all the characters need to be marked in use
1600 		for(idx = 0; idx < max; idx++) {
1601 			dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx))->f_in_use = true;
1602 		}
1603 		return ErrorManager::ERROR_CODE_NONE;
1604 	}
1605 
1606 	err_code = ErrorManager::ERROR_CODE_NONE;
1607 
1608 	while(*used_glyphs != '\0') {
1609 		a = used_glyphs[0];
1610 		if(used_glyphs[1] == '-' && used_glyphs[2] != '\0') {
1611 			b = used_glyphs[2];
1612 			if(a > b) {
1613 				b = a;
1614 				a = used_glyphs[2];
1615 			}
1616 			used_glyphs += 3;
1617 		}
1618 		else {
1619 			b = a;
1620 			used_glyphs++;
1621 		}
1622 		while(a <= b) {
1623 			info.f_glyph = a;
1624 			if(!FindGlyph(info, mark_empty_in_use)) {
1625 				char buf[16];
1626 				err_code = OnError(ErrorManager::ERROR_CODE_NO_SUCH_GLYPH, "TagEditText: the character %s (%d) does not exist in the font named \"%s\". (2)\n", wcname(a, buf), a, f_font_name);
1627 			}
1628 			a++;
1629 		}
1630 	}
1631 
1632 	return err_code;
1633 }
1634 
1635 
1636 /** \brief Defines whether the font is used by a TagEditText box
1637  *
1638  * A TagEditText cannot use a DefineFont. Thus it is important to know whether the
1639  * font will be used by an Edit Text box. At times it is not possible to infer such
1640  * a thing until the movie runs. For this reason, this flag is included to force the
1641  * font to be saved in DefineFont2 or DefineFont3.
1642  *
1643  * \param[in] used	True if the font is used in a TagEditText
1644  */
SetUsedByEditText(bool used)1645 void TagFont::SetUsedByEditText(bool used)
1646 {
1647 	f_used_by_edit_text = used;
1648 }
1649 
1650 
1651 
1652 
1653 
1654 
1655 
1656 /* The following options fold the documentation; use 'zi' to turn on and off
1657  *
1658  * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
1659  */
1660