I have discovered an issue with Flash CS5 and a TLF TextField in a loaded swf.

If you use TLF Engine in a loaded swf, you cannot call a public function of a document class (runtime error function doesn't exist), you cannot cast the swf as its document class or cast it as an interface the document class implements (both cause a coercion error).

It's an extremely common use case to need one swf to load another swf and need that other swf to have TLF TextFields in it, and also need to call public functions on the swf, or cast the loader.content as the document class or interface.

You can download a trivial example here:
TLF_Fail.zip

In the zip, there are two .fla files, main.fla and other.fla, each with a document class. The other.fla has a TLF TextField on its stage and its document class has a public function customFunc() that traces that it was called. The Main document class creates a loader, loads the other.fla and when the COMPLETE event fires, it tries to call the public function or tries to cast the document class as the document class or cast the document class as its interface. Each of these causes an error.

Main.as

package
{
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	public class Main extends MovieClip
	{
		private var loader:Loader;
		
		public function Main()
		{
			super();
			init();
		}
		private function init():void
		{
			addChild(loader = new Loader());
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
			loader.load(new URLRequest("other.swf"));
		}
		private function onLoadComplete(event:Event):void 
		{
			// this says that there's no such function on the __Preloader__
			MovieClip(loader.content).customFunc();
			
			// this causes a coercion error
			//Other(loader.content);
			
			// this causes a coercion error
			//ICustom(loader.content).customFunc();
		}
	}
}



Other.as

package
{
	import flash.display.MovieClip;
	import fl.text.TLFTextField;
	
	public class Other extends MovieClip implements ICustom
	{
		public var TLF_Foo:TLFTextField;
		
		public function Other()
		{
			super();
		}
		public function customFunc():void
		{
			trace("custom func called");
		}
	}
}



ICustom.as

package
{
	public interface ICustom
	{
		function customFunc():void;
	}
}



Here are the error messages:

MovieClip(loader.content).customFunc();

ReferenceError: Error #1069: Property customFunc not found on Other__Preloader__ and there is no default value.
	at Main/onLoadComplete()



Other(loader.content);

TypeError: Error #1034: Type Coercion failed: cannot convert Other__Preloader__@23c88121 to Other.
	at Main/onLoadComplete()
ReferenceError: Error #1056: Cannot create property __rslLoaders on Other.
	at fl.rsl::RSLPreloader/contentComplete()



ICustom(loader.content);

TypeError: Error #1034: Type Coercion failed: cannot convert Other__Preloader__@23c98121 to ICustom.
	at Main/onLoadComplete()


There are tens of thousands of developers worldwide who have a big stake in this issue being resolved because the Gaia Framework casts all of its pages as interfaces and calls functions on them and this bug makes it so developers cannot use the Gaia Framework with the TLF Engine.

Adobe, please fix this issue.

UPDATE 1
I decided to run a test to see how long before the loader.content is my swf and not Adobe's TLF Preloader. It never happens.

private var count:int;

private function onLoadComplete(event:Event):void 
{
	addEventListener(Event.ENTER_FRAME, onFrame);
}
private function onFrame(event:Event):void
{
	trace(++count + ": " + loader.content);
}


Here's the output:

1: [object Other__Preloader__]
2: [object Other__Preloader__]
3: [object Other__Preloader__]
4: [object Other__Preloader__]
5: [object Other__Preloader__]
...
89: [object Other__Preloader__]
90: [object Other__Preloader__]
91: [object Other__Preloader__]



When you load a swf that has TLF inside it, the loader.content is never your swf.



UPDATE 2
If you go into the Actionscript settings of the swf using the TLF Engine and changed the Runtime Shared Library Settings Default linkage to "Merged into code" the errors go away. But, the problem with this workaround is that the swf increases in size by 125k.

This means that for enterprise sites that use multiple swfs, every swf that uses TLF has to increase by 125k. I can imagine that this will dissuade enterprise customers like Disney, HBO, Ford and other big companies who serve millions of visitors daily from using the TLF engine on their sites.



UPDATE 3
I've done some more investigating. I trace the parent stack when ADDED_TO_STAGE is fired inside the loaded swf. The ADDED_TO_STAGE event fires twice. Here's what happens.

When you use Loader to load a swf that has an RSL (which, in this case, is the TLF engine), and you load that swf, Adobe's Preloader is what it actually loads. Then, Adobe's Preloader creates a Loader and adds that Loader to its display stack, alongside a Shape that is the visual part of their preloader. Adobe's Preloader then tells its Loader to load your swf.

Once your swf loads, it's already on the stage, so ADDED_TO_STAGE is fired. Then, Adobe's Preloader calls removeChild() on the Loader and the Shape, and then calls addChild(loader.content), which triggers another ADDED_TO_STAGE event. After that, your loaded swf's parent is their Preloader, not their Preloader's Loader.

Now here's where it gets complicated. The Preloader attempts to add a property called __rslLoaders to your document class. If you reference the document class of the loaded swf in your Main document class before you load your swf (such as you write code that casts the loaded swf as your document class, i.e. Other(loader.content) you get a runtime error:
ReferenceError: Error #1056: Cannot create property __rslLoaders on Other.
at fl.rsl::RSLPreloader/contentComplete()

The Loader you use to load your swf fires its COMPLETE event before Adobe's Preloader is finished loading your swf. You cannot listen to Adobe's preloader to know when your swf has actually been loaded and is available, and, as far as I can tell, Adobe's Preloader provides no way to target your swf.

The unfortunate side effect of this is that using TLF makes it difficult to target the timeline of a loaded swf without jumping through some hoops.

Because you cannot bubble events from within the other.swf through the Loader that loaded it to the Main class, your loading class has no way of knowing when your loaded swf is actually available unless you do an ENTER_FRAME listener and loop through the children of MovieClip(loader.content) and look for your interface class (as mentioned above, you cannot cast as the document class or you get a runtime reference error, and you cannot change the ApplicationDomain or the SecurityDomain of Adobe's Preloader's Loader). Then, you need to store a reference to your swf to be able to access it, which means you have to be sure to clear that reference when unloading.

private var otherSWF:ICustom;

private function onLoadComplete(event:Event):void 
{
	addEventListener(Event.ENTER_FRAME, onFrame);
}
private function onFrame(event:Event):void 
{
	var i:int = MovieClip(loader.content).numChildren;
	while (i--)
	{
		if (MovieClip(loader.content).getChildAt(i) as ICustom != null)
		{
			otherSWF = MovieClip(loader.content).getChildAt(i) as ICustom;
			removeEventListener(Event.ENTER_FRAME, onFrame);
			break;
		}
	}
}



In my trivial example running on my local machine, it takes 5 frames before my loaded swf is available.

 

47 Responses to Flash CS5 TLF Engine Causes Errors With Loaded SWFs

  1. Richard says:

    I hope you went to Adobe's site and filed this as a bug either in their bug system, or sent them an email.

  2. Henke37 says:

    Here is a tip: just decompile the output from Flash and stop doing blackbox experiments.

  3. Benny says:

    Hi Steven,

    Please report your findings also on the TLF forum: http://forums.adobe.com/community/opensource/tlf

    The TLF team is very responsive there and may they will be able to explain things and give advise how to work around the problem, well at least I hope so.

  4. Andrew says:

    When I changed to TLF text fields it increased my .swf file by 400k. Isn't it just compiling all the TLF code in the .swf so it works in flash player 10. When 10.1 comes out it will be in the player?

  5. Zo says:

    I ran into the same issue doing a very simple runtime shared library test, which basically just uses Loader to load an external swf.

    It looks like TLF's arent going to be a valuable option until they work out these issues.

    Thanks for looking into it and posting details.

  6. fixedmachine says:

    Hey,
    thanks for your article.

    I found that solutions from this technote from Adobe:
    http://kb2.adobe.com/cps/838/cpsid_83812.html
    will do the trick. I've tested first one with setting "Custom preloader loop" and moving everything to frame #2 – it's working.

    Anyway, all that stuff its like a BIG joke…

  7. Alan Stearns says:

    Please let us (Adobe) know if the SafeLoader class from the tech note works for you.

    Andrew – we don't currently have a plan to put TLF into the Player. The intent is to have the separate RSL for most uses of TLF. The RSL is downloaded once per machine, so you wouldn't gain much by adding it to the Player – you either make the Player a little larger for the initial install or defer the download until the first time you encounter TLF content.

    Making TLF separate from the Player gives people the option to change and recompile the code for their own uses (see http://code.google.com/p/tlfx/).

  8. fixedmachine says:

    I've tested SafeLoader with Gaia and it's working fine too.

    I just replaced Loader with SafeLoader in DisplayObjectAsset and IDisplayObject.

    In Gaia it's not a big deal because everything is well written and loading assets is centralized so there are only few lines which should be changed. But in other scenarios this might be a problem.

    Adobe should fix this bug by patching Loader class instead of creating a new one.

  9. DZ says:

    If you dont need TLF just go to Publish Options, then in Flash, ActionScript 3 Configuration, then in the Lib Path delete the TLF libpath. For the preload, under that select Embed to code.

  10. Alan Stearns says:

    For what it's worth (and I realize it's not much) this problem is limited to Flash Authoring. Flex does not have this issue, and it's not something that TLF can fix. If you want to put pressure on the Flash Authoring team to fix this you can

    1. Post on their forums: http://forums.adobe.com/community/flash
    2. Log a bug: https://www.adobe.com/cfusion/mmform/index.cfm?name=wishform (select Flash Authoring)

  11. Guilherme says:

    Much much thanks! Very useful!
    I got this error one minute later!

  12. Jeff Kamerer says:

    The tech note is actually a little confusing and misleading. I hope to get it altered a bit, but in the mean time i made a blog post that explains the SafeLoader work around and other work arounds in more detail. http://jeffkamerer.com/blog/2010/06/09/problems-loading-child-swfs-that-use-tlf-text/

  13. Alan Owen says:

    Excellent information for what is likely a common issue in the professional field. Merging TLF into code works in my case, so a cheap fix that you've led me to straight away. Thanks indeed :)

  14. Ellen VandenKerckhove says:

    I have done a lot of tests with that SafeLoader class and found out that it works fine in most of the cases.
    But if you want to communicate between parent and child swf, you get problems…
    In my child swf, I place following code, and that doesn’t work :

    if(this.parent.parent != null){
    var parentObj:Object = this.parent.parent as Object;
    parentObj.someFunction();
    }

    In fact, it works fine if I play my movie on a computer where the program Flash CS is installed, but not an another computer where I have only a Flash Player. Strange…

    If someone knows about this problem, please let me know…
    It would be a very good help to me!
    Thanks!!!

  15. Jeff Kamerer says:

    I had published an answer to Ellen's question on my blog (she posted it there as well) and just now realized the same question is here, so i will post the same answer.

    I think i know what your problem is Ellen. The SafeLoader manages to fix things so that the parent doesn’t get the init and complete events until the child is set up correctly and has the correct parent (which is the SafeLoader). HOWEVER, when the child content starts running, this is not the case. What you are trying to do will work on frame 2, but if you try that code on frame 1 it is too soon.

    What you can do on frame one (and it hurts me just to type this, but it is what it is) is you could do parent.parent.parent.parent.parent. That is right, go through five parents! The first is a Loader, the second is the RSL preloader, the third is another loader, the fourth is the SafeLoader and finally you get to the loading main timeline.

    But i would recommend just waiting until frame 2 if you can, as the five parent traversal thing is nasty, and it is the sort of thing we would like to fix in the future, and if we do fix it in a future release and you republish with the fix, then the five parent traversal trick would then be the WRONG thing to do.

  16. Steven Sacks says:

    This is where you, as the author of said code, needs to override get parent and return the loader.

    YOU are the one injecting your hidden private undocumented code in between the expected behavior and the actual behavior.

    YOU need to override parent so it returns parent.parent.parent (or whatever the path is to the loader) so the API stays consistent.

    YOU broke it. YOU fix it.

    Nobody opted in for your solution, they aren't given a choice. It is up to YOU to solve the problem. Do not ask developers to do your job for you.

  17. Toka says:

    Thank you for this post, helped me a LOT!

  18. Adrian Parr says:

    I have just had a similar problem loading in FlashVars. Basically, the usual AS3 code for reading FlashVars doesn't work when there is a Flash CS5 TLFTextField in your movie.

    Googling for a solution brought me here, but you don't mention any issue with FlashVars, only loaded SWFs.

    After posting my issue to the Adobe Forums for TLF (http://forums.adobe.com/community/opensource/tlf?view=discussions&start=0) I recieved a speedy reply from Alan Stearns.

    He pointed me to the following thread and solution …

    http://forums.adobe.com/message/2859307#2859307

    I was accessing my FlashVars from an external document class (not the first frame on the timeline) and so you need to listen for the ADDED_TO_STAGE event before trying to access them.

    For example …

    package
    {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.display.LoaderInfo;

    public class Main extends Sprite
    {

    public function Main():void
    {
    if (stage) init();
    else addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(evt:Event = null):void
    {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    var params:Object = loaderInfo.parameters;
    if (parent != null && parent.parent != null) {
    params = parent.parent.loaderInfo.parameters;
    }
    // You can now loop through the params to access your FlashVars
    }

    }
    }

    I hope that helps someone else!

    Adrian

  19. Andrey says:

    Any progress on this? I still get it, even I couldn't find TLF text into my movie..

    I don't have time today, but what if you simply link a movie from your library with some class, and then simply create an instance of that class? I mean, use library linkage instead of document class.

    Library linkage content should be exported on first frame?

  20. Ivan Reese says:

    Steven Sacks, you are my hero.

    This whole affair reeks either of laziness, sloppiness, or tardiness. The reasons this SWC/RSL business isn't built-in to the Flash Player don't make any sense to me. Every reason I've heard seems paper-thin:

    • Deferring the download until later? Come on, it's 150k, and the Flash Player is 8mb!

    • Allowing for individual updates to the RSL? How hard would it be to combine those with FP and Flash Authoring updates? How often will the RSL be updated? What what what!?

    • "Making TLF separate from the Player gives people the option to change and recompile the code for their own uses" — That makes all this trouble worthwhile. Totally. Yep. Great.

    So, instead of addressing this issue while CS5 was in development, and instead of providing a "fix" in an update, we get a mishmash of half-fixes that the developer is required to implement, with no notice provided to them that these fixes exist until they encounter the problems and manage to find the related articles on the internet. You have no idea how many hours it took me to not only figure out what was going on, but find the solution. Maybe I'm slow, but even if it takes the average Flash dev 30 minutes to route out, research and overcome this issue.. that's a LOT of wasted developer time. And I bet it takes more than 30 minutes, on average.

    Now, I get to spend part of this week explaining to my designers why we don't get carte blanche on the awesome TLF features, and why they have to tolerate all these SWZ files.

  21. Ivan Reese says:

    When I said SWC, I mean't SWZ. Sorry.

  22. Brian says:

    Thank you Steven for saving my project, you rock!

  23. one giant says:

    Well, I've been doing flash actionscript development for about 13 years now, and I have to say this is definitely one of the top 5 bogus things adobe has done to release new features, making development even harder. Is it not enough that we've cast designers away with a stricter OOP actionscript? Now we have to get all types of proprietary with this TLF crap inserting additional loader instances out of nowhere? It doesn't even look that much better than classic text :-x . Now we're supposed to jump through hoops to get old code working with updated text? This is BS. It's called backwards compatibility, and any developer can appreciate the importance. Who's running this TLF project anyway, a band of corporate monkeys? FIX THIS PLEASE ADOBE, DON'T MAKE US DO IT. And this time, NO CHANGING THE DISPLAY STACK to your own liking without backwards compatibility, that's just selfish, short sighted, and general bad practice no matter what you're doing. Christ this ruins the framework for pretty much every component based app I've made that references external SWF functions… ARRRRGH… Maybe I should check into SilverLight after all… 8-x

  24. Eskil says:

    Sweet, Steven, but stupidest implementation in Flash ever. Even worse than the infamous "level 9999" bug in AS2. I cannot beleive Adobe did this…

  25. John says:

    Not that Flash Pro's TLF implementation couldn't get any worse, I found a big memory leak with TLF in Flash Pro. I've posted about it on Adobe's forums : http://forums.adobe.com/thread/750341?tstart=0 but basically TLF TextField in a Movieclip that is created/destroyed via the timeline will leak memory in a bad way. I think until Adobe releases an update to address TLF in Flash Pro, I'm advising others to stay away from TLF in Flash Pro all together. IMO, the Flash Pro team fubar'd a good technology.

  26. Thanks for posting this, probably saved me a couple of hours of headscratching …

    I was embedding a CS5 made swf in Flash Builder 4, then did some changed in the swf, and suddently I wasn't able to call a function in the swf anymore .. get "Property getTeamBlob not found on symbols_fla.MainTimeline__Preloader__ and there is no default value."

    Turned out I had set some textfield as TLF (and then removed it again)..

    anyway, thanks again!

  27. liloo says:

    i've tiring myself for 1 hour before find your "solution" …

    thanks a lot

    Liloo

  28. Stef says:

    I have cried myself to sleep many times over this bug.

    I still haven't found a 100% solution that doesn't give me headaches to get around this.

  29. HRickH says:

    Thank you Steven and all the others. I don't know if others came across this issue, but when using the SafeLoader fix from Adobe, the solution didn't work with loaded SWF's UNLESS the fonts were embedded. The fonts on the loaded SWFs were jacked, unless all the fonts on the loading swf were embedded.

    Another thing that is easy to miss, not knowing better, is the new .swz file. But what newbies like me might misdiagnose as "it doesn't work on other computers – I thought it was situation where it worked on my mac but not on a pc"(and I had two 10 year veterans stuck on this too when I sent them my swfs) is what I call the five dots of death. This is what happens when you send the swf without the swz files that are "surprise" automatically created. I only put this in just in case someone googles "five dots of death" like I did. ;) Yes, I know now that that is a default loader.

  30. jpmorin says:

    I don't think that TLF is the problem, your are simply loading the "other.swf" in another Domain. That is why you can't access it's methods and can't cast it.

    Try this line to load "other.swf"

    loader.load(new URLRequest("other.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));

    All you cast operation should work now.

    -JP

  31. [...] Once I figured out what was causing the issue, I did some Googling and found this: Flash CS5 TLF Engine Causes Errors With Loaded SWFs. [...]

  32. Dela says:

    SACKS!!! I LOVE YOU!!! Dude, so funny to find you posted this life saving post. Fuck man… what a stupid bug.

    DONT USE TLF TEXT!!! That's what it should say on the box when you buy the new version of Flash. Worthless feature. I prefer using the existing shitty text built into Flash. I got no problem keeping my text on pixel thank you very much.

    As a note to other readers I went into my ActionScript Settings selected the Library Tab and deleted the textLayout.swc – with this file deleted the offending SWF would throw many TLF related errors until I had deleted/converted all of my TLF text fields. Once they were all gone no more errors – and thus no more TLF. Now my SWF loads correctly into the parent ApplicationDomain. Whew.

    As another side note – when you import PSD's into your FLA all text fields in the PSD will be converted into TLF textfields.

    Sacks THANK YOU again man.

  33. Matt says:

    Thank you so much for posting this.

    It took me over half a day of time wasted debugging my application before I found your post. I was looking at it from the wrong end, assuming the error was in the code I used to load the swf. I was seeing that the loader.content only had 2 frames and the objects contained within it were a shape and a loader. Now I understand what the heck was going on there. For now I'm eliminating TLF from my project.

  34. Peter says:

    "As another side note – when you import PSD's into your FLA all text fields in the PSD will be converted into TLF textfields."

    I would like to avoid using TLF textfields in Flash CS5 but if all the textfields in a PSD are imported automatically as TLF it is very difficult to convert them back to Classic textfield… Very annoying.

  35. Al Lemieux says:

    Peter,

    You can avoid using TLF from imported PSD and AI files by changing your Publish settings to AS2, import the necessary files, then change the publish settings back to AS3. All text fields will be Classic in AS2.

  36. Steven Sacks says:

    @Al – Best. Tip. Ever.

  37. yeahdixon says:

    http://kb2.adobe.com/cps/838/cpsid_83812.html

    here is a class adobe released for loading tlf with swfs

    safeloaderclass

  38. [...] in conjunction with external classes or with loading SWF files doesn't work (as chronicled here), until now. The problem really wasn't with the TLF engine, it was Flash's Loader class [...]

  39. Luis Alberto says:

    The SafeLoader class works perfect, thanks!

    http://kb2.adobe.com/cps/838/cpsid_83812.html

  40. Kawika says:

    TLF sucks! I don't use it in any of my projects.

  41. Robert LaMarca says:

    Yes, just wasted 5 hours of my life debugging and then finally removing all the tlf fields. All I wanted was a native device to vertically center text! It added 60k.

    Looking at this just illustrates everything that is wrong with the flash platform.
    1 AS3 emulates the most difficult languages. Of all the languages I know save Java, this requires the most keystrokes to do the mundane things.

    2 A text field should not greatly increase the file size of something that is 90+% used for small ads.

    It is a pity that Apple is killing flash an open platform terms, but Adobe set themselves up years ago.

  42. Mofeed says:

    I have a similar issue that I couldn't solve for a long time.
    Could you please review my post at the following link and help me to solve it.

    http://stackoverflow.com/questions/10370979/sqlite-database-and-tlf-text-in-flash-cs5

    Thanks

  43. Resolved – Flash CS5 TLF Engine Causes Errors With Loaded SWFs
    I only played with the advanced action script setting options of the fla of the loaded swf in Flash CS5.
    What I did, just by chance: set opttion: default linkage to merged into code, and set option preloader to none.

    It worked but the swf compiling gets slwo.

    May be you experts can explain what happend, that was just a beginners luck.

  44. Thank you for this post. I have just wasted 2 hours trying to work out why a child swf using TLF could not communicate with the parent swf.

    Also, tracing the loaded object returned : childSWF__Preloader__ . That was my first clue that something was wrong with the Loader.

    Will Adobe fix the Loader class. They absolutely should!

  45. There is another Loader for the files generated by Flash Professional. His name is ProLoader http://help.adobe.com/es_ES/FlashPlatform/reference/actionscript/3/fl/display/ProLoader.html

    Using it you can get all the content of the swf. Including the TLF text. Get events, get the text clicked, go to the next line… The class of each one is TextLine.

    It works perfectly on android, desktop.. if you built your swf with merged code in settings. But the problem is in iOS, Apple does not allow to load extern swfs with code. And the text in a release app is not shown. I think that it is because TLF text loads extern code. But I'm not sure. Really this is a problem… if you have all the text in TLF. And this would allow made searchs and everything…

  46. Laiza says:

    Thanks, you helped me a lot! ;-)

Leave a Reply

Set your Twitter account name in your settings to use the TwitterBar Section.