Dynamic Font Loading in Flash 9
June 18th, 2008 by RobOne of the biggest headaches in localizing Flash sites is setting up to dynamically load and easily use embedded fonts. Recently, in order to build a site that will need localization for an as-yet-undecided number of countries, I finally decided to dive in and solve this problem once and for all.
There are several problems with creating loadable font modules for Flash:
- If you embed fonts in a TextField, there’s no way to access the Font instance or class from the swf.
- If you create a font library symbol, there’s no way to alter the character set, other than changing your machine’s locale.
- If you set the same font in a library symbol and a TextField, the charset in the symbol will actually override that in the TextField, and an incomplete charset will be baked into the swf (whaa?)
So, how do you create an accessible font in an swf? FLEX!
Flex allows you to specify specific charsets for embedded fonts, and requires that you define a class for the embedded font. The font can easily be retrieved from the swf after loading. Here’s a usage example.
function loadFont(fontURL:String):void{
var loader : Loader = new Loader();
loader .contentLoaderInfo.addEventListener(Event.INIT,fontLoaded);
loader .load(new URLRequest(fontURL));
}
// when the swf is loaded…
function fontLoaded(evt:Event):void{
// get the loader
var loader : Loader = (evt.target as LoaderInfo).loader;
// remove events
loader .contentLoaderInfo.removeEventListener(Event.INIT,fontLoaded);
// cast the loader content to the IFontSource type. IFontSource defines a getFont() method that
// we can use to retrieve the font. DO NOT use the swf’s actual main class here. if the main class
// is referenced anywhere in the current swf, things will break down (a subject for another lecture…)
var fontSource : IFontSource = (loader.content as IFontSource);
// retrieve the font class from the swf.
var font : Class = fontSource.getFont();
// register the loaded font with the fonts list.
Font.registerFont(font);
}
The font is now registered in the current swf and ready for use.
Now you can do this:
function fillTextField(text:String,font:String):void{
// prepare a new text field
var textField : TextField = new TextField();
textField.width = 200;
textField.height = 25;
// create and assign a TextFormat using the submitted font name
textField.defaultTextFormat = new TextFormat(font,12,0);
// embed the font
textField.embedFonts = true;
// etc…
textField.text = text;
addChild(textField);
}
There’s only one catch here. You have to be careful what font name you use. It must be the font’s internal name. Fortunately, there’s an easy way to retrieve it:
var font : Font = new MySpecialFont();
// retrieve the font’s internal name
var fontName : String = font.fontName;
You can use fontName in the TextFormat object.
Now, some code:
Create an interface that your target movie will use to retrieve fonts.
function getFont():Class;
}
Now make an abstract class for the font swfs. This will be a base class for the MXML application. You can use an interface in the application’s default declaration, but if you inherit from Sprite, you can drop some baggage.
public function getFont():Class{
// not implemented yet…
return null;
}
}
Now, create an mxml file that implements everything. The application inherits from FontSource.
<font:FontSource
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:font="*">
<mx:Script>
<![CDATA[
[Embed(systemFont="Bwhebb",fontName="hebrew",mimeType="application/x-font",unicodeRange="Hebrew")]
public var hebrew : Class;
public override function getFont():Class{
return hebrew;
}
]]>
</mx:Script>
</font:FontSource>
The new swf contains the font class (with glyphs) and a mechanism to retrieve it.
In order to publish the font swf, you have to edit your [flex sdk]/frameworks/flex-config.xml file so that it contains the appropriate character ranges. Some charsets are already provided in the [flex sdk]/frameworks/flash-unicode-table.xml file. You simply copy and paste elements from this file (or create your own) and paste them into flex-config.xml.
In flash-unicode-table.xml, you’ll copy the language-range element (in this case, all uppercase latin characters):
<language-range>
<lang>Uppercase</lang>
<range>U+0020,U+0041-U+005A</range>
</language-range>
</flash-unicode-table>
Paste the copied element into flex-config.xml:
<languages>
<language-range>
<lang>Uppercase</lang>
<range>U+0020,U+0041-U+005A</range>
</language-range>
</languages>
</flex-config>