Flex and Embedded Fonts

Flex tries to provide you with the most flexible way of using embedded fonts in your applications. If your application consists of just one SWF and you embed fonts in that SWF, everything should just work, but once there are multiple SWFs involved, while it should work most of the time, if it doesn’t, you may need the following information to figure out why. With Flex 4 defaulting to using RSLs, your default configuration now involves multiple SWFs and many more of you are suddenly using multiple-SWF applications because each RSL counts as a SWF.
The principle rule is that there are two places that the Flash Player will look to find an embedded font to use to display text in a TextField or TextLine. It will look in the global table where fonts are registered via Font.registerFont, and it will look in the SWF whose code instantiated the TextField or TextLine.
Font.registerFont has a couple of limitations. One is that, if two SWFs try to register the same font, the last one in wins. That is normally ok until you start embedding font subsets (only certain characters in the font) which you might want to do when optimizing for SWF size, especially with large Asian fonts. If SWF A has only upper case characters and SWF B has only lower case characters, for example, then SWF A won’t be able to display its characters if SWF B loads later and registers its font of lower case characters.
The second limitation is that there is no Font.unregisterFont call so registering a Font pins the SWF with the font in memory.
For those reasons, Flex never tries to call Font.registerFont. Instead it has an infrastructure that tries to make sure that all TextFields and TextLines are created by code in the SWF that contains the embedded font. We use the term “SWF context” to mean the SWF whose code created the TextField or TextLine. And because a TextField or TextLine can have only one SWF context, it means that all fonts displayed in a TextField or TextLine must be embedded in the same SWF. If you must mix, you will have to register the font and deal with the fact that the SWFs containing the fonts may never unload.
Making sure the right code instantiates TextField is a bit trickier than it first seems. You can’t just put calls to “new TextField” or “TextBlock.createTextLine()” in a single factory class and link that class into every SWF. The ApplicationDomain rules may cause the class in a SWF to be ignored (see the modules presentation on the blog for details).
For example, suppose I create a TextLineFactory class and link it into SWF A and SWF B. If SWF A loads SWF B, when B calls TextLineFactory, it will be calling the one in SWF A and thus the TextLine will be created in a different SWF context than B expected and the embedded fonts won’t show up. Or suppose the TextLineFactory class is in an RSL. Then it is not in SWF A or SWF B so those SWFs won’t be able to display text using fonts embedded in those SWFs.
In order to solve this, Flex adds code to a uniquely named class in every SWF it generates for RSLs and Applications and Modules. That way there are no ApplicationDomain class collisions. Flex does that by adding that code to the main class of every SWF and names it after the SWF. For example, if you have A.SWF with mx:Application, Flex wraps the mx:Application with a SystemManager subclass called something like A_SystemManager and adds factory APIs to that subclass.
For TextField, Flex uses the ISystemManager.create() method. For TextLine, Flex uses the ISWFContext.callInContext API. If you are writing your own text-based components, it would be a good idea to subclass the Flex components so you can inherit the embedded font infrastructure that makes those calls and also figures out the next hard part: given an embedded font, which SWF do you reference to call these APIs? Again, because of ApplicationDomain rules, any class you write may be running in a different SWF context from the caller.
Flex tracks all fonts it embeds in SWFs and each SWF registers its embedded fonts in the EmbeddedFontRegistry on load. (Yes, we do it in a way that allows the SWF to unload). When a Flex text component is about to display text, it looks up the fontFamily, fontStyle and fontWeight and sees if there is an embedded font in the registry that matches, biasing the search to the current SWF so that colliding subsets will work. The EmbeddedFontRegistry returns the best SWF context for that font and the component uses that SWF context to create the TextField or TextLines. That means that even simple components like Label will destroy and create a new children if the font styles change since the style change could require the use of a different SWF context.
How can Flex always know which SWF is the current SWF given the ApplicationDomain rules? This is done in Flex by conditionally propagating the moduleFactory property to child components. All top-level components in a SWF have their moduleFactory set to the SWF’s IModuleFactory and propagate it to children unless the child already has a moduleFactory set.
Note that even though SystemManager is an IModuleFactory, not all ISystemManagers are IModuleFactory like AIR’s WindowedSystemManager so code should not assume that you can determine your SWF context from the systemManager property.
There are lots of implications from having this infrastructure. If you can’t control the code that creates the TextLine or TextField because the instances are created via mx.core.IFactory (itemRenderers and Chart visuals), you may need to use ContextualClassFactory or code up something similar. It also means you can’t cache a single TextField for measuring text; you may have to cache a TextField in each SWF context. It means that SystemManager.isFontEmbedded and Font.enumerateFonts may not know about every font that has been loaded and return inaccurate results.
And, it turns out that other font-related APIs must also be called in the correct SWF context. If you call ElementFormat.getFontMetrics(), you must also call that via ISWFContext if you are using embedded fonts in a multi-SWF configuration. Getting this wrong an result in really subtle bugs like having the position of strikethrough and underline being off by a pixel or two, or having baselinePosition be off by a pixel or two.
The Flex team has put a lot of work into making all of this transparent to developers, so hopefully you won’t ever need to know all of this, but folks definitely get tripped up by this now and then. And now, if you do, I hope you can use the information in this post to solve your problem.

24 Responses to Flex and Embedded Fonts

  1. dave says:

    I just upgraded to flash builder 4 from the beta version. I imported my project
    and now my datagrid is acting funny. I have data paging enabled. The one thing I
    tweaked was on this part:
    http://sujitreddyg.files.wordpress.com/2009/06/165.png
    Instead of setting the “Count operation” to “count()”, I’ve set it to “None”. I
    have a large amount of data and setting it to “None” makes the thumb larger so
    that users can use it. It also disables the ability to “jump” pages (which uses
    a lot of memory if you have a datagrid).
    Everything worked fine in the beta version of flash builder but in the non-beta
    version I came across a problem: I can initially page (with my mouse wheel) a
    few times and then it just stops for no reason. I try to keep scrolling w/ the
    mouse wheel and nothing. However, if I click on a row, then it will get another
    page. I have to continue to click on the rows in order to get another page.
    Annoying, to say the least.
    Anyone notice this? I didn’t change anything so figured it must be the updated
    version. (You can see for yourself w/ your own project…just change the Count
    operation to “none” and then try to page through the datagrid)…..any
    suggestions?

  2. I might have a related problem. My project shows embedded fonts if frame work is Merged into code, but not if I choose RSL.
    Texts is placed in TLF textFlows in classes extending UIComponent. The wierd thing is that if I create a TextBlock in the same context, with the same font, it shows even if the TLF textFlow is rendered in Times.
    The font is embedded one place and no swfs are embedded containing the same font.

  3. Alex Harui says:

    That doesn’t seem related to this post. You might want to ask on the forums. Mucking with the count can probably affect the paging behavior though.

  4. Alex Harui says:

    If you don’t use merged-into-code, the text components are in different SWF contexts so you have to get TLF to use the correct ISWFContext. In the Flex components you can set fontFamily to one of the fonts in the SWF containing the embedded fonts.

  5. Sorry, this confuses me. I’ve tried to set
    _myTextFlow.fontFamily = HelvNeueStdLight.NAME;
    where HelvNeueStdLight is the font that is embedded, but not shown when using RSL.
    This doesn’t work either.
    I’ve tried to debug by looking at what happens internally in TLF, right down to the calls to the underlying TextEngine. While interesting to see what happens behind the scenes, I haven’t been able to solve the problem.
    I assume that the ISWFContext interface holds a solution. Is the cause of the problem that the TLF framework is loaded as an external SWF and thus is in another context? How is this handled by the Spark classes using TLF?
    Right now I’m struggling with another odd issue. I’ve got several textflows instantiated. All but one shows selection graphics when I do a selection – thought selection events are fired and start and end of selection are correct.
    Any help and pointers would be appreciated.
    BTW. the Captcha check seems broken – I can’t submit directly – I have to do a preview first for the captcha string to be accepted.

  6. Update. I got embedded fonts to work with RSL now, much thanks to your post and reply. Thanks!
    The solution was to explicitly set the SWFContext using the UIComponent.getFontContext method. It’s in the mx_internal namespace.
    Example that works even in non-UIComponent descendants (HelvNeueStdLight is just one random font that’s embedded. All fonts are embedded in the same context for this project).
    var uic:UIComponent = UIComponent(FlexGlobals.topLevelApplication);
    _textFlow.flowComposer.swfContext = ISWFContext(uic.getFontContext(HelvNeueStdLight.NAME, false, false, true));

    • Magesh says:

      Hi – We are in the same situation where in embedded fonts are not working for TLF. Can you pls share your example. We embed the fonts in the css file wih embedAsCFF as false. It shows the fonts fine in the mx combobox component but not in TLF. We tried to do a AS way of embeding font as below in the initial mxml, so that it gets available when textregion is created dynamically.
      [Embed(source=”/assets/fonts/font1.ttf”, mimeType=”application/x-font-truetype”, fontName=”CrownRoman”,
      embedAsCFF=”true”)]
      public static const font1:Class;

      and Font.registerFont(font1);

      But this is not helping either. Fonts are not getting embedded.

      I tried to use your uic.getFontContext as explained above, but it gives me complier error “Attempted access of inaccessible method getFontContext through a reference with static type mx.core:UIComponent”

      Pls help me in solving this. Its very critical. Any help is appreciated. Let me know if you need more details.

  7. Nagarjuna says:

    Hi Alex…
    I want to add tickmark for the context menu item when it is selected and removes when deselect.please help me….

  8. vasanth says:

    The information which u gave is useful for me, while im using the same to .png image i face some problem.
    i give some codes.
    [Bindable]
    private var _url:String=””;
    public function set url(value:String):void{
    _url=value;
    }
    public function get url():String{
    return _url;
    }
    var butt:Button=new Button();
    but.label=”my Button”;
    but.setStyle(“icon”,url)—-> Is this possible how can i use this in dynamically

  9. Todd Kneib says:

    So, is Flex calling Font.registerFont under hood when I load a SWF that was compiled from a CSS that contains a font?
    styleManager.loadStyleDeclarations(swfName, true, false, ApplicationDomain.currentDomain, null);
    I ask, because when I call styleManager.unloadStyleDeclarations, the styling effects go away, but if you call Font.enumerateFonts(false), the font is still there, and I can still assign it to labels, textareas, etc.
    The app I’m working on will have upwards of 30 different fonts, each in its own swf file, that I only load when the user picks its name from a dropdownlist. The issue I am running into is that after about 15-17 different font swf files get loaded using loadStyleDeclarations, the browser crashes (both IE and FF), So I want to unload the unused ones, but after calling unloadStyleDeclarations, there is no change in memory usage, and I can still use the font.
    Any ideas?
    Todd
    ps.I have made a real simple (all 137K zipped) FlashBuilder 4 project that shows the font staying in memory if you want to see it.

  10. Alex Harui says:

    You could have a regular context menu item open a regular Menu.

  11. Alex Harui says:

    Please post questions relevant to the topic. Button does not load external images.

  12. Alex Harui says:

    Yeah, CSS registers the fonts. If you embed your fonts in a regular module they will unload

  13. Sam says:

    Alex, what license are your code bits published under? Am I allowed to redistribute libraries in which I use bits of code that I find on your blogs?

  14. Jeff Battershall says:

    With the release of Flash Builder 4.01, suddenly I’m getting a lot of runtime warnings about the need to set embedAsCff=true in my modular application, even though this is already set in the CSS file that embeds the font. What could I be doing wrong?

  15. Vic says:

    Can we get strongly typed (casted) object via loader (loading swf) in pure as?

    tia,
    .V

  16. Lyndon says:

    Hi Alex Why do mx Components cause this conflict with runtime warnings about the need to set embedAsCff=true and mixing spark and mx components ofteen produces mx components that do not diplay properly whats the logic behind it??

    • Alex Harui says:

      By default MX components use TextField for text display and TextField cannot use cff fonts. TextField will show blanks if it is told to use embedded fonts but there isn’t a font it can use or glyphs for that character in the font. Spark components use FTE and FTE requires cff fonts. Thus mixing the two is problematic. You could embed a font twice, both with cff true and false, but that’s not very efficient. In most cases if you use the MXFTEText.css file or check the box in the project properties, the MX components will switch to using FTE and cff fonts.

  17. Sergiy Zhyla says:

    Hi Alex!
    I get a problem with fonts loading. I load 2 different fonts from 2 different swf. Then I create textFlow object from HTML string. This HTML string use both of this fonts. After that I create RichText and set the textFlow property to my textFlow object. As a result I get the text with only one of fonts applyed (with the font which were last used in another RichText object using setStyle(‘FontFamily’, fontName) function). So the question is how can I apply this 2 fonts to the one RichText?
    And the secont problem appear when I try to use RichEditebleText in the same way. In this case no one font applyed at all. So the second question: How can I proceed with this situation.
    regards

  18. For Flex3 you can also try Antialiaser, a new tool for designers that helps you to embed & fine-tune your fonts for Flex and AIR applications.

    http://www.cycle-it.com/antialiaser/