Posts in Category "Advanced Topics"

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.

Custom Preloader DownloadProgressBar

The DownloadProgressBar is the thing you see while the SWF is being downloaded. It also shows a progress bar while the application is being initialized. The one we ship is pretty vanilla and boring to watch if you have a large SWF that takes a long time to download or initialize.
You can create custom ProgressBars by implements IPreloaderDisplay on a Sprite and doing whatever you want in it. The trick is that you can’t use Flex classes since they haven’t been downloaded or initialized yet, and you can’t probably don’t want to do asynchronous things like load images since you’re already in the process of getting the SWF over the network.
I’ve posted two different prototypes of custom DownloadProgressBars. Remember, these are prototypes so they probably have bugs and were only tested on FIreFox on the Mac but the I just want to give you an idea of things that are possible.
The first one displays a set of “slides” the user can read while the application is starting up. The ones in the demo are ugly, but are there to give you an idea of what capabilities I was able to code up in as little code as possible. You can’t use embedded fonts since that will take too long to download. You probably don’t want to use bitmaps either because of their size. But you can draw filled shapes and add text and format that text to some degree. Yeah, you could try to mimic as much of FXG or SVG as possible, but again, that will probably take too much code.
An interesting feature of the SlideShow preloader is that it gets its slide data from the HTML wrapper. That way the slide data isn’t baked into a SWF and you don’t have to make an additional network call to get the slide data. If you add some server logic, you can generate different slide data in the wrapper based on any other knowledge you have of the user without having to change the SWF.
I haven’t gotten the SlideShow demo to work on Safari. I’m not sure if it is because Safari doesn’t handle XML or because there is something I haven’t configured in Safari. I could re-write the wrapper to use appended strings instead of XML if I really wanted to make sure it worked on Safari.
Run SlideShow Demo
Download Source
The second one displays a screen capture taken just before the application was last shut down. It leverages the onBeforeUnload in a custom HTML wrapper. As the application shuts down, it saves its state and a screen snapshot in a local SharedObject. On startup, the custom ProgressBar grabs the snapshot and displays it right away so it appears the app is up quickly. In the demo, I purposely blur the snapshot so the user knows not to try to interact, but you don’t have to do that if you don’t want to. Then as the application finishes up, it restores the UI widgets to their last state based on the data stored in the SharedObject and then the application can be used again. You will need to run the demo twice (or refresh the page after making some changes) to see the snapshot in use.
Run SnapShot Demo
Download Source

Constrained Drag and Drop

I’ve seen a few questions about how to restrict drag and drop so you can’t just drag something anywhere. I had some spare cycles so I put this together. There are probably several ways to do this, but I chose to delay the mouseMove handler to run after the DragManager has done its work, and reposition the dragImage and cursor in the mouseMove handler.
Download Source
Run Demo
You should be able to create variants that only allow vertical movement or don’t allow the dragImage outside of a certain rectangle.
Usual caveats apply. And yes, it isn’t a real game and doesn’t handle overlaying tiles.

Tree and Lazy or Paged Data

The Flex Tree control (mx.controls.Tree) is the subject of many complaints. It’s pretty finicky if you don’t use a dataProvider where the data is “all there”. Any attempts to lazily load in nodes must be coded carefully. If you don’t tweak the DataDescriptor properly it won’t work.
Tree does have one major flaw, and that is that it can’t handle a dataProvider that throws ItemPendingErrors as data sets that come from LiveCycle DataServices do. Tree uses an undocumented pair of classes to effectively linearize the current set of open nodes into a dataProvider that its base class (List) can handle. The code for that was scrambled together at the last minute and wasn’t deemed sufficient enough for the AdvancedDataGrid, so our AdvancedDataGrid team developed their own HierarchicalCollectionView classes and beefed them up to handle ItemPendingErrors. Due to various scheduling and logistical issues, Tree was left by the side of the road, stuck with its undocumented HierarchicalCollection classes that can’t handle ItemPendingErrors.
At the tail end of Flex 3, several customers were in need of a Tree that could handle ItemPendingErrors. THe shortest route to such a thing was to create a subclass of Tree that could handle the AdvancedDataGrid’s HierarchicalCollectionView. Example and source code are below. You’ll see the acronym “DMV” throughout because the AdvancedDataGrid and HierarchicalCollectionView are part of the Data Management and Visualization package (which requires the Professional versions and/or more money) so those of you trying to go the cheap route won’t be able to leverage this code. Also, you won’t need this unless your data source throws ItemPendingErrors when an attempt is made to fetch data that hasn’t been paged in yet, and unless you developed your own, you are using one of our data services which also cost you some money.
The example comes with a test tool we wrote that throws lots of ItemPendingErrors so we can try to find all the code paths that are sensitive to it. Unlike most of the posts on my blog, this one actually got some QA time, but the usual caveats apply.
Run Example
Download Source

Flex 3.x Versioning and Portals

While most of my colleagues are busy working on Flex 4, a few of us have been working on something we’re calling the “Marshall Plan”. Most of you won’t ever need it, but some really important customers do. If you want to make a Flex Portal, or have the kind of application where it is impractical to update all of the SWFs that make up the application to the latest version, or if you just have a lot of time on your hands, then the following link might be of interest to you.
The Marshall Plan