/* libsswf_tag_font.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2008 */

/*

Copyright (c) 2002-2008 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

/** \file
 *
 * \brief The implementation of the sswf::TagFont class
 *
 * This file declares the body of the functions which are not
 * inline. It is part of the SSWF library.
 */

#include	"sswf/libsswf.h"

using namespace sswf;



/////////////////////////////////////////// TagFont


/** \class sswf::TagFont
 *
 * \brief Define a system or embedded font.
 *
 * This tag is used to define a font.
 *
 * Embedded fonts include definitions for each glyph as required.
 *
 * System fonts just define the name of the system font.
 *
 * \sa sswf::TagShape
 * \sa <a href="../SWFalexref.html#tag_definefont">SWF Alexis' Reference&mdash;Define Font</a>
 * \sa <a href="../SWFalexref.html#tag_definefont2">SWF Alexis' Reference&mdash;Define Font2</a>
 * \sa <a href="../SWFalexref.html#tag_definefont3">SWF Alexis' Reference&mdash;Define Font3</a>
 * \sa <a href="../SWFalexref.html#tag_definefontinfo">SWF Alexis' Reference&mdash;Define Font Info</a>
 * \sa <a href="../SWFalexref.html#tag_definefontinfo2">SWF Alexis' Reference&mdash;Define Font Info2</a>
 * \sa <a href="../SWFalexref.html#tag_definefontname">SWF Alexis' Reference&mdash;Define Font Name</a>
 * \sa <a href="../SWFalexref.html#tag_definefontalignzones">SWF Alexis' Reference&mdash;Define Font Align Zones</a>
 * \sa <a href="../SWFalexref.html#tag_defineshape">SWF Alexis' Reference&mdash;Define Shape</a>
 * \sa <a href="../SWFalexref.html#swf_tag">SWF Alexis' Reference&mdash;swf_tag</a>
 */



/** \enum sswf::TagFont::font_type_t
 *
 * \brief The list of font types.
 *
 * This enumeration defines the different types of fonts available.
 */

/** \var sswf::TagFont::FONT_TYPE_BEST
 *
 * \brief Selects the best type which can be used.
 *
 * Use this type to let the font choose what it wants to make it all
 * work properly.
 */

/** \var sswf::TagFont::FONT_TYPE_ASCII
 *
 * \brief Select the type ASCII.
 *
 * This type represents a font with at most 256 characters.
 */

/** \var sswf::TagFont::FONT_TYPE_UNICODE
 *
 * \brief Select the type UNICODE
 *
 * This type represents any font in all languages. It supports
 * 65536 characters all together. The character numbers are defined
 * by the Unicode consortium: http://www.unicode.org
 *
 * This is the prefered type since version 6.
 */

/** \var sswf::TagFont::FONT_TYPE_SHIFTJIS
 *
 * \brief Select the type SHIFTJIS
 *
 * This type represents Japanese. I'm not too sure how this was
 * used. Now, Japanese as well as Chinese, Korean, and any other
 * language character set is defined using Unicode.
 */

/** \enum sswf::TagFont::font_language_t
 *
 * \brief Language definition for a font.
 *
 * Before version 6, many strange things appeared in Flash including
 * a language definition for a font. There is really no need for it.
 * Just use Unicode.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_UNKNOWN
 *
 * \brief This value is used to mark a font as not having a language.
 *
 * This is the default value for a font.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_LOCALE
 *
 * \brief This value is used so the player uses the current locale.
 *
 * I'm not too sure what this was for. How can a font be defined by
 * a changing locale?
 */

/** \var sswf::TagFont::FONT_LANGUAGE_LATIN
 *
 * \brief Latin-1 languages.
 *
 * This value was for fonts representing the Latin-1 character set.
 * (code page 0x00 in Unicode.)
 */

/** \var sswf::TagFont::FONT_LANGUAGE_JAPANESE
 *
 * \brief Japanese language.
 *
 * This value was for fonts representing a set of Japanese glyphs.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_KOREAN
 *
 * \brief Korean language.
 *
 * This value was for fonts representing a set of Korean glyphs.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_SIMPLIFIED_CHINESE
 *
 * \brief Chinese language.
 *
 * This value was for fonts representing a set of simplified Chinese glyphs.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_TRADITIONAL_CHINESE
 *
 * \brief Chinese language.
 *
 * This value was for fonts representing a set of traditional Chinese glyphs.
 */

/** \var sswf::TagFont::FONT_LANGUAGE_max
 *
 * \brief This represents the largest possible language code
 *
 * This can be used as a limit boundary.
 */


/** \enum sswf::TagFont::font_thickness_t
 *
 * \brief Defines the thickness of the font.
 *
 * The Flash player will by default determine the thickness of a font
 * using a lookup table. If the font isn't found in that table, then
 * it uses the thickness defined in the SWF file.
 */

/** \var sswf::TagFont::FONT_THICKNESS_UNKNOWN
 *
 * \brief The default: the thickness is not specified.
 *
 * The thickness is a feature of the fonts since SWF version 8. By
 * default the thickness is not specified.
 */

/** \var sswf::TagFont::FONT_THICKNESS_THIN
 *
 * \brief Defines the thickness of the font as thin.
 *
 * This is a thin font. This means thinner than normal (light).
 */

/** \var sswf::TagFont::FONT_THICKNESS_MEDIUM
 *
 * \brief Defines the thickness of the font as medium.
 *
 * This is a medium font. This means a mostly normal font.
 */

/** \var sswf::TagFont::FONT_THICKNESS_THICK
 *
 * \brief Defines the thickness of the font as thick.
 *
 * This is a thick font. This means thicker than normal (bold).
 */







/** \brief Initializes the font object.
 *
 * This function sets the font object to defaults.
 *
 * By default a font has no name, no display name, no copyrigth,
 * no predefined language, no type, no specific style, no
 * glyph, etc.
 *
 * \param[in] parent The TagHeader where the TagFont is included.
 */
TagFont::TagFont(TagBase *parent)
	: TagBaseID("font", parent)
{
	f_font_name = 0;
	f_display_name = 0;
	f_copyright = 0;
	f_language = FONT_LANGUAGE_UNKNOWN;
	f_type = FONT_TYPE_BEST;
	f_bold = false;
	f_italic = false;
	f_small_text = false;
	f_wide = false;
	f_has_wide_char = false;		// defined in PreSave2ndPass() and used in Save()
	f_has_wide_offsets = false;		// defined in PreSave2ndPass() and used in Save()
	f_has_layout = false;			// defined in PreSave2ndPass() and used in Save()
	f_used_by_edit_text = false;
	f_define_font2 = false;			// defined in PreSave2ndPass() and used in Save()
	f_thickness = FONT_THICKNESS_UNKNOWN;
	f_font_em_size = FONT_EM_SMALL;
	f_ascent = DefaultAscent();
	f_descent = DefaultDescent();
	f_leading_height = DefaultLeadingHeight();
	f_default_advance = 0;
	f_space_advance = LONG_MIN;
	f_offsets_max = 0;			// defined in PreSave2ndPass() and used in Save()
	f_offsets = 0;				// defined in PreSave2ndPass() and used in Save()
	f_count = 0;
	//f_save_glyphs = ...
	//f_glyphs = ...
	//f_kerns = ...
}



/** \brief The flags defining a font.
 *
 * A font is a definition and it has an identifier.
 *
 * \return SWF_TYPE_DEFINE and SWF_TYPE_HAS_ID
 */
TagBase::swf_type_t TagFont::TypeFlags(void) const
{
	return SWF_TYPE_DEFINE | SWF_TYPE_HAS_ID;
}


/** \brief Prepare the font for saving.
 *
 * This function ensures that the font will properly be saved (as
 * obtimized as possible.)
 *
 * The main action of this function is to clear the
 * \em in \em use flag of all the glyphs to \em false.
 * This means no glyphs will be saved in that font. The
 * next step is for the other tags to mark exactly which
 * glyphs are necessary for them. For instance, an edit text
 * box could ask for all capital letters (A-Z) and another
 * ask for digits (0-9).
 *
 * In order to complete the preparations before the Save()
 * function is called, the PreSave2ndPass() will be called.
 * That's at that time that the font can determine the index
 * of each glyph since now it knows which glyph will be saved
 * in the final font.
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 */
ErrorManager::error_code_t TagFont::PreSave(void)
{
	long		idx;

	// reset the IN USE flag of each glyph
	idx = f_glyphs.Count();
	while(idx > 0) {
		idx--;
		dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx))->f_in_use = false;
	}

	f_used_by_edit_text = false;

	// if not unknown it was defined by the user
	// if not locale, then we need v6.x
	if(f_language != FONT_LANGUAGE_UNKNOWN
	&& f_language != FONT_LANGUAGE_LOCALE) {
		MinimumVersion(6);
	}

	// a font name with an underscore as the first
	// character is taken as a "direct font name"
	// and thus we need V6.x -- this way we avoid
	// testing specific names and not be forward
	// compatible at a later date when Macromedia
	// decides to add new names.
	if(f_font_name != 0 && *f_font_name == '_') {
		MinimumVersion(6);
	}

	// the small text font hint appeared in version 7
	if(f_small_text) {
		MinimumVersion(7);
	}

	// with a proper thickness, we need a V8 and the DefineFontAlignZone
	// for kerns to be useful, we need a V8 Flash animation
	if(f_font_em_size == FONT_EM_LARGE
	|| f_kerns.Count() > 0) {
		MinimumVersion(8);
	}

	// license info; display name defaults to font name
	// if there is a copyright and no display name
	if(f_display_name != 0 || f_copyright != 0) {
		MinimumVersion(9);
	}

	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Finilize the font preparations for saving.
 *
 * This function is called after all the other objects PreSave()
 * was called giving them a chance to define which of the embedded
 * glyphs they use.
 *
 * At this point we also know whether the font must be defined
 * with a DefineFont2 and using Unicode (wide) characters.
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 */
ErrorManager::error_code_t TagFont::PreSave2ndPass(void)
{
	font_glyph_t	*glyph;
	int		idx, rmax;
	unsigned long	extra;
	unsigned short	*short_offsets;
#if DEBUG
	sswf_ucs4_t	previous;
#endif

	// Now we know what character is used and whether an
	// edit text is referencing this font - from the
	// Macromedia documents, we have to have a DefineFont2
	// if an edit text references a font
	// Also, if anything said to use v6.x then the fonts
	// must be saved in Unicode (no choice!)
	//
	// WARNING: it is not possible to change from prior
	//	    version 6 to version 6 or more in the
	//	    2nd pass

	f_define_font2 = false;

	// by default we use the user defined f_wide flag
	// which is forced to true if one or more glyph has
	// an ID of 256 or more or we are using v6+
	f_has_wide_char = f_wide || Version() >= 6;

	// to know the size of the glyphs we need to compute it
	// and that means creating the actual buffer of all the
	// glyphs
	rmax = f_glyphs.Count();

	// the default layout flag value is set to true if some
	// of the layout parameters are defined -- note that having
	// a layout in a font doesn't mean we will use them (we do
	// only if a DefineTextField -- an edit text -- references
	// the font)
	f_has_layout = f_ascent != DefaultAscent()
		|| f_descent != DefaultDescent()
		|| f_leading_height != DefaultLeadingHeight()
		|| f_kerns.Count() != 0;
		/* Note: Macromedia says they are not currently taking
		 * the kerning in account... what about other players?
		 * -- Update: this has changed since version 8 -- now
		 * Macromedia has its own font renderer which takes
		 * the kernel in account.
		 */

	// try to avoid re-allocating the offsets buffer if possible
	if(f_offsets != 0) {
		if(f_offsets_max < rmax + 1) {
			MemClean(&f_offsets);
		}
	}
	if(f_offsets == 0) {
		f_offsets = (unsigned long *) MemAlloc((rmax + 1) * sizeof(unsigned long), "offsets to the glyphs");
		f_offsets_max = rmax + 1;
	}
	// by default we have no glyphs (use only the DefineFontInfo[2]
	// if no edit text references this font!)
#if DEBUG
	previous = -1;
#endif
	f_count = 0;
	f_save_glyphs.Empty();
	for(idx = 0; idx < rmax; idx++) {
		glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));

#if DEBUG
		// ensure that the glyphs are ordered properly
		assert((long) glyph->f_name > (long) previous,
			"TagFont::PreSave2ndPass() found unordered glyphs (%ld >= %ld)",
				(long) previous, (long) glyph->f_name);
		previous = glyph->f_name;
#endif

//printf("Glyph [%c] %s\n", glyph->f_name, glyph->f_in_use ? "in use" : "never referenced");

		if(!glyph->f_in_use) {
			// unused, just skip it
			continue;
		}
		if(glyph->f_name > 255) {
			f_has_wide_char = true;
		}
		/*
		 * Note: Macromedia says they don't use the per char
		 *       bounding boxes -- what about other players?
		 */
		if(glyph->f_shape->HasBounds()) {
			f_has_layout = true;
		}
		glyph->f_index = (unsigned short) f_count;		// index at which the glyph is being saved
		f_offsets[f_count] = f_save_glyphs.ByteSize();
		(const_cast<TagShape *>(glyph->f_shape))->SaveWithoutStyles(f_save_glyphs);
		f_save_glyphs.Align();
		f_count++;
	}
	// save the total size in the last offset entry
	f_offsets[f_count] = f_save_glyphs.ByteSize();
	f_count++;
	// got to include this last entry here to make sure we don't
	// overflow anything

	// if an EditText tag references this font
	// if the EM square of the font is large
	//
	//	then we need a DefineFont2
	//
	//	otherwise it depends on whether we need large
	//		offsets to access the glyphs
	if(f_used_by_edit_text
	|| f_font_em_size == FONT_EM_LARGE) {
		// NOTE: the MinimumVersion(3) is useless since the
		//	 TagEditText forces v4.x already!
		//MinimumVersion(3);
		f_define_font2 = true;
	}
	else {
		// we don't want any layout if we don't have
		// an edit text (would be unused!)
		f_has_layout = false;
	}

	// compute the size of the offset table
	extra = (f_count - 1) * 2 + (f_define_font2 ? 2 : 0);
	f_has_wide_offsets = f_offsets[f_count - 1] + extra > USHRT_MAX;
	if(f_has_wide_offsets) {
		MinimumVersion(3);

		// only DefineFont2 accepts large offsets
		if(!f_define_font2) {
			f_define_font2 = true;
			extra += 2;
		}

		// wide offsets! we need to add 2 x extra because
		// that's the actual size of the table! Also include
		// the offset to the map
		extra *= 2;
		for(idx = 0; (unsigned int) idx < f_count; idx++) {
#if BYTE_ORDER == BIG_ENDIAN
			f_offsets[idx] = swap_int(f_offsets[idx] + extra);
#else
			f_offsets[idx] += extra;
#endif
		}
	}
	else {
		short_offsets = reinterpret_cast<unsigned short *>(f_offsets);
		for(idx = 0; (unsigned int) idx < f_count; idx++) {
#if BYTE_ORDER == BIG_ENDIAN
			short_offsets[idx] = swap_short((unsigned short) (f_offsets[idx] + extra));
#else
			short_offsets[idx] = (unsigned short) (f_offsets[idx] + extra);
#endif
		}
	}

	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Save the TagFont in the specified Data buffer
 *
 * This function saves the font in the specified Data buffer.
 *
 * It will save the glyphs in the DefineFont or DefineFont2 tag.
 * And some extraneous information in a DefineFontInfo or
 * DefineFontInfo2 tag. And it saves the name and license in a
 * DefineFontName tag.
 *
 * To save the glyphs, the TagFont calls the
 * sswf::TagShape::SaveWithoutStyles(Data& data) function.
 *
 * \param[in] data The Data buffer where the font tags are saved
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 *
 * \sa sswf::TagShape::SaveWithoutStyles(Data& data)
 */
ErrorManager::error_code_t TagFont::Save(Data& data)
{
	Data			sub_data, kern_data;
	font_glyph_t		*glyph;
	font_kern_t		*kern;
	const char		*name, *license;
	int			idx, max, rmax, cnt, used, l1, l2;
	bool			has_align_zones;

	rmax = f_glyphs.Count();

// if the f_font_define2 is set, then we save that type of a
// font, otherwise save a define font + define font info if
// required
	if(f_define_font2) {
		SaveID(sub_data);
		sub_data.WriteBits(f_has_layout, 1);

		// by default we assume that we have alignment zones
		// unless there are no glyphs
		has_align_zones = rmax != 0;

		// can types be all set? it isn't clear in any doc.
		if(Version() <= 5) {
			switch(f_type) {
			case FONT_TYPE_BEST:
				sub_data.WriteBits(0, 3);		/* not specific */
				break;

			case FONT_TYPE_ASCII:
				sub_data.WriteBits(1, 3);
				break;

			/*
			 * this is now defined as always zero in v6.x doc.
			 * it was properly defined as the Unicode flag
			 * before and is perfectly valid in prior v6.x
			 * movies!
			 */
			case FONT_TYPE_UNICODE:
				sub_data.WriteBits(2, 3);
				break;

			case FONT_TYPE_SHIFTJIS:
				sub_data.WriteBits(4, 3);
				break;

			}
		}
		else {
			sub_data.WriteBits(0, 1);
			sub_data.WriteBits(f_small_text, 1);
			sub_data.WriteBits(0, 1);
		}

		// determine whether we need to use wide offsets
		sub_data.WriteBits(f_has_wide_offsets, 1);

		sub_data.WriteBits(f_has_wide_char, 1);

		sub_data.WriteBits(f_italic, 1);
		sub_data.WriteBits(f_bold, 1);

		// language in v6.x, 0 otherwise
		if(Version() <= 5) {
			sub_data.PutByte(0);
		}
		else {
			sub_data.PutByte(f_language);
		}

		cnt = f_font_name == 0 ? 0 : strlen(f_font_name);
		if(cnt > 255) {
			OnError(ErrorManager::ERROR_CODE_NAME_TOO_LONG, "a font name cannot be more than 255 characters long, change \"%s\"", f_font_name);
			cnt = 255;
		}
		sub_data.PutByte(cnt);		/* this one is a Pstring, why is that, dunno... */
		sub_data.Write(f_font_name, cnt);

		// save the number of glyphs
		// we MUST have one extra "offset" that actually represents the size of the
		// table so one can skip all the glyphs at once
		sub_data.PutShort((short) (f_count - 1));

		// save the array of offsets
		sub_data.Write(f_offsets, f_count * (f_has_wide_offsets ? 4 : 2));

		// save the shapes
		sub_data.Append(f_save_glyphs);

		// save the mapping between the shapes and characters
		for(idx = 0; idx < rmax; idx++) {
			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
			if(!glyph->f_in_use) {
				// unused, just skip it
				continue;
			}
			if(f_has_wide_char) {
				sub_data.PutShort((unsigned short) glyph->f_name);
			}
			else {
				sub_data.PutByte((unsigned char) glyph->f_name);
			}
			if(!glyph->f_shape->HasAlignZone()) {
				has_align_zones = false;
			}
		}

		if(f_has_layout) {
			sub_data.PutShort((short) f_ascent);
			sub_data.PutShort((short) f_descent);
			sub_data.PutShort((short) f_leading_height);
			for(idx = 0; idx < rmax; idx++) {
				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
				if(!glyph->f_in_use) {
					// unused, just skip it
					continue;
				}
				if(glyph->f_advance != LONG_MIN) {
					sub_data.PutShort((short) glyph->f_advance);
				}
				else {
					// if not specific to a character, use the default
					sub_data.PutShort((short) f_default_advance);
				}
			}
			for(idx = 0; idx < rmax; idx++) {
				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
				if(!glyph->f_in_use) {
					// unused, just skip it
					continue;
				}
				glyph->f_shape->Bounds(0).Save(sub_data);
				sub_data.Align();		// <- is this correct? shouldn't it be in the rectangle Save() function?
			}
			// New max (i.e. the # of kerning entries)
			max = f_kerns.Count();
			for(idx = 0, cnt = 0; idx < max; idx++) {
				kern = dynamic_cast<font_kern_t *>(f_kerns.Get(idx));
				/*
				 * before to save a kern we want to make sure it's not
				 * useless; we go through the list of glyph and ensures
				 * that BOTH the glyphs are defined in the font; if not
				 * then this kerning can't even happen so we don't need
				 * it and thus don't save it.
				 */
				for(idx = 0, used = 0; idx < rmax && used != 3; idx++) {
					glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
					if(glyph->f_name == kern->f_code[0]) {
						if(!glyph->f_in_use) {
							break;
						}
						used |= 1;
					}
					// don't put an 'else' here since code0 == code1
					// is possible! (though probably really rare?)
					if(glyph->f_name == kern->f_code[1]) {
						if(!glyph->f_in_use) {
							break;
						}
						used |= 2;
					}
				}
				if(used == 3) {
					if(f_has_wide_char) {
						kern_data.PutShort((unsigned short) kern->f_code[0]);
						kern_data.PutShort((unsigned short) kern->f_code[1]);
					}
					else {
						kern_data.PutByte((unsigned char) kern->f_code[0]);
						kern_data.PutByte((unsigned char) kern->f_code[1]);
					}
					kern_data.PutShort((short) kern->f_advance);
					cnt++;
				}
			}
			// now we can save the kerning tables
			sub_data.PutShort(cnt);
			sub_data.Append(kern_data);
		}
		SaveTag(data, f_font_em_size == FONT_EM_LARGE ? SWF_TAG_DEFINE_FONT3 : SWF_TAG_DEFINE_FONT2, sub_data.ByteSize());
		data.Append(sub_data);

		// if we had zones, then we save them now
		if(has_align_zones) {
			if(f_font_em_size == FONT_EM_LARGE) {
				// There is no compression for this tag so we can compute the
				// size at once and avoid saving things in an intermediate buffer
				SaveTag(data, SWF_TAG_DEFINE_FONT_ALIGN_ZONES, 5 + (f_count - 1) * 8);
				data.PutShort(Identification());
				if(f_thickness == FONT_THICKNESS_UNKNOWN) {
					data.WriteBits(FONT_THICKNESS_MEDIUM, 2);
				}
				else {
					data.WriteBits(f_thickness, 2);
				}
				data.WriteBits(0, 6);
				data.PutByte(2);		// 2 entries per zone
				for(idx = 0; idx < rmax; idx++) {
					glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
					if(!glyph->f_in_use) {
						// unused, just skip it
						continue;
					}
					glyph->f_shape->SaveAlignZone(data);
				}
				data.WriteBits(1, 1);	// zone_x
				data.WriteBits(1, 1);	// zone_y
				data.WriteBits(0, 6);	// reserver
			}
			else {
				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");
			}
		}
	}
	else {
		// if there isn't any glyph we still need a DefineFont tag
		SaveID(sub_data);
		sub_data.Write(f_offsets, f_count == 1 ? 2 : (f_count - 1) * 2);
		sub_data.Append(f_save_glyphs);
		SaveTag(data, SWF_TAG_DEFINE_FONT, sub_data.ByteSize());
		data.Append(sub_data);

		// in some cases we also want to save a DefineFontInfo
		if((f_font_name != 0 && *f_font_name != '\0')
		|| f_bold || f_italic
		|| (f_language != FONT_LANGUAGE_UNKNOWN && f_language != FONT_LANGUAGE_LOCALE)
		|| f_count == 1) {
			sub_data.Empty();
			SaveID(sub_data);	// same ID as the font

			cnt = f_font_name == 0 ? 0 : strlen(f_font_name);
			if(cnt > 255) {
				OnError(ErrorManager::ERROR_CODE_NAME_TOO_LONG, "a font name cannot be more than 255 characters long, change \"%s\"", f_font_name);
				cnt = 255;
			}
			sub_data.PutByte(cnt);		/* this one is a Pstring, why is that, dunno... */
			sub_data.Write(f_font_name, cnt);

			sub_data.WriteBits(0, 2);
			if(Version() >= 6) {
				sub_data.WriteBits(f_small_text, 1);
				sub_data.WriteBits(0, 2);
			}
			else {
				switch(f_type) {
				case FONT_TYPE_BEST:
					sub_data.WriteBits(0, 3);		/* not specific */
					break;

				case FONT_TYPE_ASCII:
					sub_data.WriteBits(1, 3);
					break;

				case FONT_TYPE_SHIFTJIS:
					sub_data.WriteBits(2, 3);
					break;

				/*
				 * this is now defined as always zero in v6.x doc.
				 * it was properly defined as the Unicode flag
				 * before and is perfectly valid in prior v6.x
				 * movies!
				 */
				case FONT_TYPE_UNICODE:
					sub_data.WriteBits(4, 3);
					break;

				}
			}
			sub_data.WriteBits(f_italic, 1);
			sub_data.WriteBits(f_bold, 1);

			// here we know that f_has_wide_char is
			// already 1 when Version() >= 6
			sub_data.WriteBits(f_has_wide_char, 1);

			if(Version() >= 6) {
				sub_data.PutByte(f_language);
			}

			// save the mapping between the shapes and characters
			for(idx = 0; idx < rmax; idx++) {
				glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx));
				if(!glyph->f_in_use) {
					// unused, just skip it
					continue;
				}
				if(f_has_wide_char) {
					sub_data.PutShort((unsigned short) glyph->f_name);
				}
				else {
					sub_data.PutByte((unsigned char) glyph->f_name);
				}
			}

			SaveTag(data, Version() >= 6 ? SWF_TAG_DEFINE_FONT_INFO2 : SWF_TAG_DEFINE_FONT_INFO, sub_data.ByteSize());
			data.Append(sub_data);
		}
	}

	// Add another tag when there is a display name and/or copyright
	if(f_display_name != 0 || f_copyright != 0) {
		name = f_display_name;
		if(name == 0) {
			// default to the other name if it exists
			name = f_font_name;
			if(name == 0) {
				// otherwise nothing
				name = "";
			}
		}
		l1 = strlen(name) + 1;
		license = f_copyright;
		if(license == 0) {
			// make sure we don't crash with strlen() + Write()
			license = "";
		}
		l2 = strlen(license) + 1;
		SaveTag(data, SWF_TAG_DEFINE_FONT_NAME, 2 + l1 + l2);
		SaveID(data);
		data.Write(name, l1);
		data.Write(license, l2);
	}

	return ErrorManager::ERROR_CODE_NONE;
}


const char *	TagFont::g_font_language_name[FONT_LANGUAGE_max] = {
	"LOCALE",
	"LATIN",
	"JAPANESE",
	"KOREAN",
	"SIMPLIFIED_CHINESE",
	"TRADITIONAL_CHINESE"
};


/** \brief Defines the language number from its name.
 *
 * This function searches for a language by name and return the corresponding
 * language code.
 *
 * \code
 *	LOCALE
 *	LATIN
 *	JAPANESE
 *	KOREAN
 *	SIMPLIFIED_CHINESE
 *	TRADITIONAL_CHINESE
 * \endcode
 *
 * \param[in] language The name of the language this font is for
 */
TagFont::font_language_t TagFont::StringToLanguage(const char *language)
{
	font_language_t		idx;

	for(idx = FONT_LANGUAGE_LOCALE; idx < FONT_LANGUAGE_max; idx = (font_language_t) ((int) idx + 1)) {
		if(strcasecmp(g_font_language_name[(int) idx], language) == 0) {
			return idx;
		}
	}

	return FONT_LANGUAGE_UNKNOWN;
}


/** \brief Transform a language index to the corresponding name.
 *
 * This function transform a language index in a corresponding string.
 *
 * \param[in] language The language index to convert to a string.
 *
 * \return A constant string with the language name or "invalid".
 */
const char *TagFont::LanguageToString(font_language_t language)
{
	if(language < 0 || language >= FONT_LANGUAGE_max) {
		return "invalid";
	}

	return g_font_language_name[language];
}


/** \brief Add a glyph to an embedded font.
 *
 * This function adds the ref shape as the character defined with the code
 * defined in the name parameter.
 *
 * If you want to use the normal advance for a character, set the advance
 * paramter to LONG_MIN. Wider or smaller characters need to use a
 * specific value here.
 *
 * \param[in] name	The name (unicode number) of the glyph
 * \param[in] ref	The corresponding shape
 * \param[in] advance	The number of twips to the next character
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 */
ErrorManager::error_code_t TagFont::AddGlyph(sswf_ucs4_t name, const TagBase *ref, long advance)
{
	font_glyph_t	*glyph;
	font_info_t	info;

	if(ref == 0 || strcmp(ref->Name(), "shape") != 0) {
		return OnError(ErrorManager::ERROR_CODE_MISSING_SHAPE, "a glyph reference must be of type TagShape and it has to exist");
	}

	info.f_glyph = name;
	if(FindGlyph(info)) {
		// the user has the right to redefine the space as an
		// empty character!
		if(info.f_index != SSWF_FONT_SPACE_INDEX) {
			return OnError(ErrorManager::ERROR_CODE_GLYPH_DEFINED_TWICE, "glyph 'u%ld' defined twice. Second instance ignored.", (long) name);
		}
	}

	glyph = new font_glyph_t;
	MemAttach(glyph, sizeof(font_glyph_t), "TagFont::AddGlyph() -- glyph of font");
	glyph->f_name = name;
	glyph->f_shape = dynamic_cast<const TagShape *>(ref);
	glyph->f_advance = advance;	// if LONG_MIN, use the default
	glyph->f_in_use = false;	// if true, must be saved

	// Glyphs MUST be sorted for Macromedia players
	// This allow for binary searches which are very effective
	// and since we searched for the character with the FindGlyph()
	// we already know where we need to insert this new glyph
	f_glyphs.Insert(info.f_position, glyph);

	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Add a special kern between two glyphs.
 *
 * Defines two glyphs and the space to add when they are encountered
 * in that specific order in a word.
 *
 * For instance, a capital W followed by a lower case I need to be
 * closer to each others than what the default advance of the W
 * character implies.
 *
 * This advance is added to the normal advance (cumulative) this it
 * often ends up being negative.
 *
 * \todo
 * We would need to make sure that all kerns are distinct.
 *
 * \param[in] code0	The first glyph
 * \param[in] code1	The second glyph
 * \param[in] advance	The advance to add when these two glyphs are found in a string
 */
void TagFont::AddKern(sswf_ucs4_t code0, sswf_ucs4_t code1, long advance)
{
	font_kern_t	*kern;

	kern = new font_kern_t;
	MemAttach(kern, sizeof(font_kern_t), "TagFont::AddKern() -- font kern");
	kern->f_code[0] = code0;
	kern->f_code[1] = code1;
	kern->f_advance = advance;
	f_kerns.Set(-1, kern);
}


/** \brief Gets the name of the font.
 *
 * This function returns the current name of the font.
 *
 * \return The name of the font.
 */
const char *TagFont::FontName(void) const
{
	return f_font_name;
}


/** \brief Retrieve the information (advance, etc.) of the specified glyph.
 *
 * For this function, define info.f_index with the glyph information
 * you want to retrieve. Call the function, and if the glyph exists,
 * the information for that glyph will be saved in the other fields
 * of the structure.
 *
 * It is an error to put a glyph index larger than the number of glyphs
 * available.
 *
 * Note that the index represents the index in the array of glyphs, not
 * the glyph Unicode number. Use the FindGlyph() function instead to
 * find a glyph using its glyph Unicode number.
 *
 * \param[in,out] info	A glyph information structure with it's f_index
 *			properly defined; returned with the other glyph
 *			information
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 *
 * \sa sswf::TagFont::FindGlyph(font_info_t& info, bool mark_empty_in_use) const
 */
ErrorManager::error_code_t TagFont::GlyphInfo(font_info_t& info) const
{
	font_glyph_t	*glyph;

	if(info.f_index >= static_cast<unsigned long>(f_glyphs.Count())) {
		return OnError(ErrorManager::ERROR_CODE_INVALID_GLYPH, "invalid index for a GlyphInfo request");
	}

	glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(info.f_index));
	info.f_glyph = glyph->f_name;
	info.f_saved_index = glyph->f_index;
	if(glyph->f_advance == LONG_MIN) {
		info.f_advance = f_default_advance;
	}
	else {
		info.f_advance = glyph->f_advance;
	}
	info.f_is_empty = glyph->f_shape->IsEmpty();

	return ErrorManager::ERROR_CODE_NONE;
}


/** \brief Check whether the font has glyphs.
 *
 * This function returns true if the font defins one or more glyphs.
 * This can be used to know whether the font is an embedded or a
 * ssytem font.
 *
 * \return true when the font has glyphs
 */
bool TagFont::HasGlyph(void) const
{
	return f_glyphs.Count() != 0;
}


/** \brief Retrieve the information (advance, etc.) of the specified glyph.
 *
 * For this function, define info.f_glyph with the glyph Unicode number
 * you want to retrieve. Call the function, and if the glyph exists,
 * the information for that glyph will be saved in the other fields
 * of the structure.
 *
 * The glyph is searched with a binary search so it is fast.
 *
 * When the fonction does not find the glyph, it is not considered an
 * error. It returns the structure with f_index set to the location
 * where the glyph defined in f_glyph can be inserted (this is used
 * internally whenever a new glyph is added to the TagFont.)
 *
 * \param[in,out] info	A glyph information structure with its f_glyph
 *			properly defined; returned with the other glyph
 *			information
 * \param[in] mark_empty_in_use	Whether to mark empty glyphs in use or not
 *
 * \return true when the glyph was found
 *
 * \sa sswf::TagFont::GlyphInfo(font_info_t& info) const
 */
bool TagFont::FindGlyph(font_info_t& info, bool mark_empty_in_use) const
{
	font_glyph_t	*glyph;
	int		i, j, p;
	bool		found;

	// avoid warnings -- also crashes better if an error occurs
	glyph = 0;

	/*
	 * search the list of available glyphs and
	 * determine the index which represents the character 'c'
	 * note that the glyphs are always ordered
	 */
	p = 0;		// necessary for empty lists!
	found = false;
	j = f_glyphs.Count();
	if(j < 4) {
		/* ugly bubble search when not enough entries yet */
		while(j > 0) {
			j--;
			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(j));
			if(glyph->f_name == info.f_glyph) {
				p = j;
				found = true;
				break;
			}
			if(glyph->f_name < info.f_glyph) {
				// user glyph larger than any of the glyphs
				// in out list
				p = j + 1;
				break;
			}
		}
	}
	else {
		// binary search -- you can't go faster
		i = 0;
		while(i < j) {
			// get the center position of the current range
			p = i + (j - i) / 2;
			glyph = dynamic_cast<font_glyph_t *>(f_glyphs.Get(p));
			if(glyph->f_name == info.f_glyph) {
				found = true;
				break;
			}
			if(glyph->f_name < info.f_glyph) {
				p++;
				i = p;
			}
			else {
				j = p;
			}
		}
	}

	if(found) {
		info.f_index = info.f_position = p;
		info.f_saved_index = glyph->f_index;
		if(glyph->f_advance == LONG_MIN) {
			info.f_advance = f_default_advance;
		}
		else {
			info.f_advance = glyph->f_advance;
		}
		info.f_is_empty = glyph->f_shape->IsEmpty();
		glyph->f_in_use = info.f_is_empty ? mark_empty_in_use : true;
		return true;
	}

	if(info.f_glyph == ' ' && f_space_advance != LONG_MIN) {
		info.f_advance = f_space_advance;
		info.f_index = SSWF_FONT_SPACE_INDEX;
		info.f_position = p;
		info.f_saved_index = 0;		// this one shouldn't be used
		info.f_is_empty = true;
		return true;
	}

	// Ooops doesn't exist!
	// 'p' is the closest position (i.e. if we are adding a new
	// glyph that's where we want it!)
	info.f_index = (unsigned short) (info.f_position = p);
	info.f_saved_index = (unsigned short) info.f_glyph;

	return false;
}



/** \brief Returns the default ascent.
 *
 * This function returns the value representing the default ascent for
 * an SWF font. It is recommanded to use that value for your font
 * ascent if possible.
 *
 * \return The default ascent.
 */
long TagFont::DefaultAscent(void) const
{
	return 750;
}


/** \brief Returns the default descent.
 *
 * This function returns the value representing the default descent for
 * an SWF font. It is recommanded to use that value for your font
 * descent if possible.
 *
 * \return The default descent.
 */
long TagFont::DefaultDescent(void) const
{
	return 1024 - DefaultAscent();
}


/** \brief Returns the default leading height.
 *
 * This function returns the value representing the default leading
 * height for an SWF font. It is recommanded that you use that value
 * for your own fonts if possible.
 *
 * \return The default leading height
 */
long TagFont::DefaultLeadingHeight(void) const
{
	return 0;
}


/** \brief Defines the name of the font.
 *
 * This function defines the name of the font.
 *
 * A font name starting with an underscore is taken as a "direct font name"
 * and requires V6.x. The currently supported names are:
 *
 * \code
 *	_sans
 *	_serif
 *	_typewriter
 *	5F E3 82 B4 E3 82 B7 E3 83 83 E3 82 AF (Gothic&mdash;Japanese)
 *	5F E7 AD 89 E5 B9 85 (Tohaba, Gothic Mono&mdash;Japanese)
 *	5F E6 98 8E E6 9C 9D (Mincho&mdash;Japanese)
 * \endcode
 *
 * We use that mechanism rather than checking for special names so additional
 * names added by Macromedia/Adobe are automatically supported.
 *
 * This function overwrites the previous name if one existed.
 *
 * \param[in] font_name The new name of the font.
 */
void TagFont::SetName(const char *font_name)
{
	MemFree(f_font_name);
	f_font_name = StrDup(font_name);
}


/** \brief Defines the display name of the font.
 *
 * This function can be used to define the display name of the font
 * opposed to the exact system name.
 *
 * For instance, a font can be called "ArialBld" and the display name
 * would then be "Arial Bold"
 *
 * \param[in] display_name The name of the font as we want to show it to an end user
 */
void TagFont::SetDisplayName(const char *display_name)
{
	MemFree(f_display_name);
	f_display_name = StrDup(display_name);
}


/** \brief Defines a copyright or license for the font.
 *
 * This function defines a copyright string to save along the font.
 * This can include any information such as how the font can be
 * used.
 *
 * \param[in] copyright The copyright or license for the embedded font
 */
void TagFont::SetCopyright(const char *copyright)
{
	MemFree(f_copyright);
	f_copyright = StrDup(copyright);
}


/** \brief Set the font layout
 *
 * This function sets the ascent, descent and leading height of the font.
 *
 * The ascent represents the distance from the base to the top of the font.
 *
 * The descent represents the distance from the base to the bottom of the font.
 *
 * The leading height is added the ascent and the descent to move to the
 * next of text. The default is zero assuming that the ascent and descent
 * include enough space to separate two lines of text.
 *
 * \param[in] ascent		The ascent of the font.
 * \param[in] descent		The descent of the font.
 * \param[in] leading_height	The leading height of the font.
 */
void TagFont::SetLayout(long ascent, long descent, long leading_height)
{
	f_ascent = ascent;
	f_descent = descent;
	f_leading_height = leading_height;
}


/** \brief Set the default advance.
 *
 * This function can be used to define the default advance of
 * a glyph. This is useful to avoid having to define the
 * advance parameter each time a new glyph is added.
 *
 * By default this value is set to zero: not advance.
 *
 * \param[in] advance	The amount to advance to go where the next glyph should be rendered
 */
void TagFont::SetDefaultAdvance(long advance)
{
	f_default_advance = advance;
}


/** \brief Set the width of the regular space glyph.
 *
 * This function can be used to define the width of the space
 * glyph. This is the glyph with Unicde number 0x20 (32).
 * That glyph is never included in the final font.
 *
 * \param[in] advance The size of one space character
 */
void TagFont::SetSpaceAdvance(long advance)
{
	f_space_advance = advance;
}


/** \brief Set the type of font.
 *
 * The type of font to use with the TagFont.
 *
 * This applies to SWF version 5 and earlier. Since version 6,
 * the font type is automatically Unicode, which encompass all
 * the other possible fonts.
 *
 * The available types are:
 *
 * \code
 *	TagFont::FONT_TYPE_BEST
 *	TagFont::FONT_TYPE_ASCII
 *	TagFont::FONT_TYPE_UNICODE
 *	TagFont::FONT_TYPE_SHIFTJIS
 * \endcode
 *
 * \param[in] type The font type.
 */
void TagFont::SetType(font_type_t type)
{
	f_type = type;
}


/** \brief Set the language corresponding to this font.
 *
 * This function sets the language corresponding to this font.
 * This is not very useful since version 6 since all fonts use
 * Unicode which include all possible languages today (and tomorrow
 * once we have Klingon in Unicode.)
 *
 * You can use the TagFont::StringToLanguage(const char *language)
 * to transform a string to a language code as required by this
 * function.
 *
 * The available languages are defined here:
 *
 * \code
 *	FONT_LANGUAGE_UNKNOWN
 *	FONT_LANGUAGE_LOCALE
 *	FONT_LANGUAGE_LATIN
 *	FONT_LANGUAGE_JAPANESE
 *	FONT_LANGUAGE_KOREAN
 *	FONT_LANGUAGE_SIMPLIFIED_CHINESE
 *	FONT_LANGUAGE_TRADITIONAL_CHINESE
 * \endcode
 *
 * Unknown is used to mark a font as language-less.
 *
 * \param[in] language		The language code
 *
 * \sa sswf::TagFont::StringToLanguage(const char *language)
 */
void TagFont::SetLanguage(font_language_t language)
{
	f_language = language < 0 || language >= FONT_LANGUAGE_max
				? FONT_LANGUAGE_UNKNOWN : language;
}


/** \brief Mark the font as representing a bold style.
 *
 * Set this flag if your font represents a bold version of the
 * font. If you want to use a system font, use this flag so
 * the bold version of the font is used.
 *
 * \param[in] bold	true if the font is bold
 */
void TagFont::SetBold(bool bold)
{
	f_bold = bold;
}


/** \brief Mark the font as representing an italic style.
 *
 * Set this flag if your font represents an italic version of the
 * font. If you want to use a system font, use this flag so
 * the italic version of the font is used.
 *
 * \param[in] italic	true if the font is italic
 */
void TagFont::SetItalic(bool italic)
{
	f_italic = italic;
}


/** \brief Mark the font as being a small text font.
 *
 * Set this flag to true as a hint to the Flash Player that the font
 * will be used to draw small text.
 *
 * \param[in] small_text	true to mark the font as used for small text
 */
void TagFont::SetSmallText(bool small_text)
{
	f_small_text = small_text;
}


/** \brief Define the thickness of the font.
 *
 * This value is set to Unknown by default meaning that the
 * thickness is not specified.
 *
 * It can be set to Thin, Medium or Thick:
 *
 * \code
 *	FONT_THICKNESS_THIN
 *	FONT_THICKNESS_MEDIUM
 *	FONT_THICKNESS_THICK
 * \endcode
 *
 * The thickness will not be saved in the font if the EM square
 * is not also marked as large and all glyphs got an align zone
 * defined.
 *
 * \param[in] thickness The new thickness
 *
 * \sa TagFont::SetEMSize(font_em_size_t font_em_size)
 */
void TagFont::SetThickness(font_thickness_t thickness)
{
	f_thickness = thickness;
}


/** \brief Define the size of the EM square of the font.
 *
 * This function is used to define the size of the EM square
 * used to draw the glyphs. This could be done automatically
 * by checking the size of the glyphs, but that's not done
 * yet and it would not automatically work in all cases.
 *
 * The EM square can be small or large:
 *
 * \code
 *	FONT_EM_SMALL
 *	FONT_EM_LARGE
 * \endcode
 *
 * \param[in] font_em_size The new size of the EM square
 */
void TagFont::SetEMSize(font_em_size_t font_em_size)
{
	f_font_em_size = font_em_size;
}


/** \brief Mark the font as a Unicode font.
 *
 * This flag is ignored in SWF version 6 and over. In that case, all fonts must
 * be defined an Unicode (wide).
 *
 * Otherwise, use this flag to mark whether you want to use the 256 glyphs
 * font or the 65536 glyphs font.
 *
 * \param[in] wide	true to make the font Unicode
 */
void TagFont::SetWide(bool wide)
{
	f_wide = wide;
}



/** \brief Set which glyphs are used.
 *
 * This function can be used to define the glyphs that other tags use.
 *
 * \param[in] used_glyphs	A string representing the glyphs in use or NULL
 * \param[in] mark_empty_in_use	Whether empty glyphs should be marked in use
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 *
 * \sa TagFont::SetUsedGlyphs(const sswf_ucs4_t *used_glyphs, bool mark_empty_in_use)
 */
ErrorManager::error_code_t TagFont::SetUsedGlyphs(const char *used_glyphs, bool mark_empty_in_use)
{
	ErrorManager::error_code_t	ec;
	sswf_ucs4_t			*wc_used_glyphs, *d;
	size_t				l, sz;

	if(used_glyphs == 0 || (used_glyphs[0] == '*' && used_glyphs[1] == '\0')) {
		return SetUsedGlyphs(static_cast<const sswf_ucs4_t *>(0), mark_empty_in_use);
	}
	l = strlen(used_glyphs);
	sz = l * sizeof(sswf_ucs4_t);
	wc_used_glyphs = new sswf_ucs4_t[l + 1];
	d = wc_used_glyphs;
	mbtowc(used_glyphs, l, d, sz);
	*d = (sswf_ucs4_t) '\0';	// mbtowc() doesn't terminate the strings
	ec = SetUsedGlyphs(wc_used_glyphs, true);
	delete [] wc_used_glyphs;

	return ec;
}


/** \brief Set which glyphs are used.
 *
 * This function can be used to define the glyphs that other tags use.
 *
 * This is the official function which accepts a Unicode string as input.
 *
 * The special strings "*" and NULL can be used in the used_glyphs parameter
 * to mark all the glyphs in used at once.
 *
 * The string can otherwise be defined with a range defined by two glyphs
 * separated by a dash (-). For instance, to include all the ASCII upper case
 * characters, one can use "A-Z". Several ranges can be included in the same
 * string and the dash (-) can be included at the very beginning or the end
 * of the string to be included as a glyph in use. The code accepts ranges
 * which are written backward; so "9-0" is taken as "0-9".
 *
 * \param[in] used_glyphs	A string representing the glyphs in use or NULL
 * \param[in] mark_empty_in_use	Whether empty glyphs should be marked in use
 *
 * \return An error code or ErrorManager::ERROR_CODE_NONE
 *
 * \sa TagFont::SetUsedGlyphs(const char *used_glyphs, bool mark_empty_in_use)
 */
ErrorManager::error_code_t TagFont::SetUsedGlyphs(const sswf_ucs4_t *used_glyphs, bool mark_empty_in_use)
{
	font_info_t			info;
	int				a, b, max, idx;
	ErrorManager::error_code_t	err_code;

	// if no glyph, just forget it altogether in this case
	max = f_glyphs.Count();
	if(max == 0) {
		return ErrorManager::ERROR_CODE_NONE;
	}

	if(used_glyphs == 0 || (used_glyphs[0] == '*' && used_glyphs[1] == '\0')) {
		// all the characters need to be marked in use
		for(idx = 0; idx < max; idx++) {
			dynamic_cast<font_glyph_t *>(f_glyphs.Get(idx))->f_in_use = true;
		}
		return ErrorManager::ERROR_CODE_NONE;
	}

	err_code = ErrorManager::ERROR_CODE_NONE;

	while(*used_glyphs != '\0') {
		a = used_glyphs[0];
		if(used_glyphs[1] == '-' && used_glyphs[2] != '\0') {
			b = used_glyphs[2];
			if(a > b) {
				b = a;
				a = used_glyphs[2];
			}
			used_glyphs += 3;
		}
		else {
			b = a;
			used_glyphs++;
		}
		while(a <= b) {
			info.f_glyph = a;
			if(!FindGlyph(info, mark_empty_in_use)) {
				char buf[16];
				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);
			}
			a++;
		}
	}

	return err_code;
}


/** \brief Defines whether the font is used by a TagEditText box
 *
 * A TagEditText cannot use a DefineFont. Thus it is important to know whether the
 * font will be used by an Edit Text box. At times it is not possible to infer such
 * a thing until the movie runs. For this reason, this flag is included to force the
 * font to be saved in DefineFont2 or DefineFont3.
 *
 * \param[in] used	True if the font is used in a TagEditText
 */
void TagFont::SetUsedByEditText(bool used)
{
	f_used_by_edit_text = used;
}







/* The following options fold the documentation; use 'zi' to turn on and off
 *
 * vim: foldexpr=getline(v\:lnum)!~'^/\\*\\*'&&getline(v\:lnum)!~'^\ \\*'?0\:1 foldcolumn=2 foldmethod=expr
 */
