From f5a10e15002bf6bef73ddd9a21b155e07582f4d3 Mon Sep 17 00:00:00 2001 From: darl2ng Date: Tue, 1 Oct 2013 15:07:50 +0200 Subject: [PATCH] use SafeLoader instead of Loader to be able to load swf with tlf text field --- src/fl/display/SafeLoader.as | 169 +++++++++++++++++ src/fl/display/SafeLoaderInfo.as | 174 ++++++++++++++++++ .../loaders/DisplayObjectLoader.as | 28 +-- src/org/assetloader/loaders/SWFLoader.as | 20 +- 4 files changed, 370 insertions(+), 21 deletions(-) create mode 100644 src/fl/display/SafeLoader.as create mode 100644 src/fl/display/SafeLoaderInfo.as diff --git a/src/fl/display/SafeLoader.as b/src/fl/display/SafeLoader.as new file mode 100644 index 0000000..3a56032 --- /dev/null +++ b/src/fl/display/SafeLoader.as @@ -0,0 +1,169 @@ +package fl.display { + + import flash.display.DisplayObject; + import flash.display.Loader; + import flash.display.LoaderInfo; + import flash.display.Sprite; + import flash.net.URLRequest; + import flash.system.LoaderContext; + import flash.utils.ByteArray; + + /** + * This class is provided as sample code. Loading a SWF with the SafeLoader instead of + * flash.display.Loader allows you to load a SWF that uses TLF and the default RSL + * preloading options and be able to script the loaded content normally. When you use + * the SafeLoader, you will not get the Event.INIT or Event.COMPLETE events until the + * RSL preloading is completed and the real content is available and when you access + * the content property, you will be accessing the real content. This will allow you + * to write script that calls between the loaded SWF that uses TLF and the loading SWF + * as you normally would. + * + *

Note that SafeLoader is NOT a subclass of flash.display.Loader, so you will need + * to change all type references to be SafeLoader instead of Loader.

+ */ + + public class SafeLoader extends Sprite + { + private var _cli:SafeLoaderInfo; + private var _loader:Loader; + private var _content:DisplayObject; + private var _loading:Boolean; + + public function SafeLoader() + { + _loading = false; + _content = null; + _loader = new Loader(); + _loader.visible = false; + super.addChild(_loader); + _cli = new SafeLoaderInfo(this, loadDoneCallback); + } + + // called by SafeLoaderInfo when the content is ready and before the events + // are dispatched. Returns false if load was cancelled + private function loadDoneCallback(d:DisplayObject):Boolean + { + if (!_loading) { + _loader.unload(); + return false; + } + _loading = false; + _content = d; + if (d != null) { + super.addChild(d); + super.removeChild(_loader); + } + return true; + } + + /** + * get access to the flash.display.Loader being used by the SafeLoader to do all the work. + */ + public function get realLoader():Loader { return _loader; } + + /** + * mimic Loader API + */ + public function get content():DisplayObject { + return _content; + } + + /** + * mimic Loader API. Important difference is contentLoaderInfo returns a SafeLoaderInfo, + * which is NOT a subclass of LoaderInfo. + */ + public function get contentLoaderInfo():SafeLoaderInfo { + return _cli; + } + + /** + * mimic Loader API + */ + public function close():void { + if (_loading) { + _loading = false; + // we may be still acting as though the load is incomplete to allow RSL preloading + // to finish, so catch any errors + try { _loader.close(); } catch (e:Error) { } + } else { + _loader.close(); + } + } + + /** + * mimic Loader API + */ + public function load(request:URLRequest, context:LoaderContext=null):void { + _loading = true; + if (_content != null && _content.parent == this) super.removeChild(_content); + _content = null; + _loader.load(request, context); + } + + /** + * mimic Loader API + */ + public function loadBytes(bytes:ByteArray, context:LoaderContext=null):void { + _loading = true; + if (_content != null && _content.parent == this) super.removeChild(_content); + _content = null; + _loader.loadBytes(bytes, context); + } + + /** + * mimic Loader API + */ + public function unload():void { + if (_content != null && _content.parent == this) super.removeChild(_content); + _content = null; + _loader.unload(); + } + + /** + * mimic Loader API. This API only available player 10, AIR 1.5 or higher. + */ + public function unloadAndStop(gc:Boolean=true):void { + if (_content != null && _content.parent == this) super.removeChild(_content); + _content = null; + _loader["unloadAndStop"](gc); + } + + /** + * mimic the way flash.display.Loader disallows children to be added, removed + * @private + */ + public override function addChild(c:DisplayObject):DisplayObject { + throw new Error("Error #2069: The SafeLoader class does not implement this method."); + } + /** + * mimic the way flash.display.Loader disallows children to be added, removed + * @private + */ + public override function addChildAt(c:DisplayObject, i:int):DisplayObject { + throw new Error("Error #2069: The SafeLoader class does not implement this method."); + } + /** + * mimic the way flash.display.Loader disallows children to be added, removed + * @private + */ + public override function removeChild(c:DisplayObject):DisplayObject { + throw new Error("Error #2069: The SafeLoader class does not implement this method."); + } + /** + * mimic the way flash.display.Loader disallows children to be added, removed + * @private + */ + public override function removeChildAt(i:int):DisplayObject { + throw new Error("Error #2069: The SafeLoader class does not implement this method."); + } + /** + * mimic the way flash.display.Loader disallows children to be added, removed + * @private + */ + public override function setChildIndex(c:DisplayObject, i:int):void { + throw new Error("Error #2069: The SafeLoader class does not implement this method."); + } + + } +} + diff --git a/src/fl/display/SafeLoaderInfo.as b/src/fl/display/SafeLoaderInfo.as new file mode 100644 index 0000000..8de2555 --- /dev/null +++ b/src/fl/display/SafeLoaderInfo.as @@ -0,0 +1,174 @@ +package fl.display { + + import flash.display.DisplayObject; + import flash.display.DisplayObjectContainer; + import flash.display.InteractiveObject; + import flash.display.Loader; + import flash.display.LoaderInfo; + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.HTTPStatusEvent; + import flash.events.IOErrorEvent; + import flash.events.ProgressEvent; + import flash.system.ApplicationDomain; + import flash.utils.ByteArray; + import flash.utils.getQualifiedClassName; + + /** + * This class is provided as example code. Used by SafeLoader to do the bulk of the + * heavy lifting of the safe loading of SWF files using TLF with default RSL preloading + * settings. This class has been developed to be compatible with Flash Player 10, but + * if you are using AIR and you need access to the childSandboxBridge or parentSandboxBridge + * properties, you can uncomment them in the code below. + */ + + public class SafeLoaderInfo extends EventDispatcher{ + + private var _safeLoader:SafeLoader; + private var _loadDoneCallback:Function; + private var _realLI:LoaderInfo; + + private var _rslPreloaderLoaded:Boolean; + private var _numAdded:int; + + /** + * it is never useful to create a SafeLoaderInfo directly. It should always + * be created by the SafeLoader and accessed via the contentLoaderInfo property. + */ + public function SafeLoaderInfo(l:SafeLoader, c:Function) + { + _rslPreloaderLoaded = false; + _numAdded = 0; + + _safeLoader = l; + _loadDoneCallback = c; + _realLI = l.realLoader.contentLoaderInfo; + + _realLI.addEventListener(Event.COMPLETE, handleLoaderInfoEvent); + _realLI.addEventListener(HTTPStatusEvent.HTTP_STATUS, handleLoaderInfoEvent); + _realLI.addEventListener(Event.INIT, handleLoaderInfoEvent); + _realLI.addEventListener(IOErrorEvent.IO_ERROR, handleLoaderInfoEvent); + _realLI.addEventListener(Event.OPEN, handleLoaderInfoEvent); + _realLI.addEventListener(ProgressEvent.PROGRESS, handleProgressEvent); + _realLI.addEventListener(Event.UNLOAD, handleLoaderInfoEvent); + } + + public function get actionScriptVersion():uint { return _realLI.actionScriptVersion; } + public function get applicationDomain():ApplicationDomain { return _realLI.applicationDomain; } + public function get bytes():ByteArray { return _realLI.bytes; } + + /** + * prevent bytesLoaded from equalling bytesTotal until we are certain that everything + * is loaded completely correctly. Users should not rely on this to assume that everything + * is ready, they should be using the init and complete events, but just in case. + */ + public function get bytesLoaded():uint { + if (_realLI.bytesLoaded >= _realLI.bytesTotal && _safeLoader.content == null) { + return _realLI.bytesTotal - 1; + } + return _realLI.bytesLoaded; + } + + public function get bytesTotal():uint { return _realLI.bytesTotal; } + public function get childAllowsParent():Boolean { return _realLI.childAllowsParent; } + + // only for AIR apps. + public function get childSandboxBridge():Object { return _realLI["childSandboxBridge"]; } + + public function get content():DisplayObject { return _safeLoader.content; } + + public function get contentType():String { return _realLI.contentType; } + public function get frameRate():Number { return _realLI.frameRate; } + public function get height():int { return _realLI.height; } + public function get loader():SafeLoader { return _safeLoader; } + public function get loaderURL():String { return _realLI.loaderURL; } + public function get parameters():Object { return _realLI.parameters; } + public function get parentAllowsChild():Boolean { return _realLI.parentAllowsChild; } + + // only for AIR apps. + public function get parentSandboxBridge():Object { return _realLI["parentSandboxBridge"]; } + + public function get sameDomain():Boolean { return _realLI.sameDomain; } + public function get sharedEvents():EventDispatcher { return _realLI.sharedEvents; } + public function get swfVersion():uint { return _realLI.swfVersion; } + public function get url():String { return _realLI.url; } + public function get width():int { return _realLI.width; } + + private function handleLoaderInfoEvent(e:Event):void + { + switch (e.type) { + case HTTPStatusEvent.HTTP_STATUS: + case IOErrorEvent.IO_ERROR: + case Event.OPEN: + case Event.UNLOAD: + // just forward these events + dispatchEvent(e); + break; + case Event.INIT: + // check if we have loaded an RSL preloader SWF + _rslPreloaderLoaded = false; + var theContent:DisplayObject = _realLI.content; + try { + var theName:String = getQualifiedClassName(theContent); + if (theName.substr(-13) == "__Preloader__") { + var rslPreloader:Object = theContent["__rslPreloader"]; + if (rslPreloader != null) { + theName = getQualifiedClassName(rslPreloader); + if (theName == "fl.rsl::RSLPreloader") { + _rslPreloaderLoaded = true; + _numAdded = 0; + theContent.addEventListener(Event.ADDED, handleAddedEvent); + } + } + } + } catch (e:Error) { + _rslPreloaderLoaded = false; + } + if (!_rslPreloaderLoaded) { + _loadDoneCallback(theContent); + if (_realLI.bytesLoaded >= _realLI.bytesTotal) { + dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _realLI.bytesLoaded, _realLI.bytesTotal)); + } + dispatchEvent(e); + } + break; + case Event.COMPLETE: + if (!_rslPreloaderLoaded) dispatchEvent(e); + break; + } + } + + private function handleProgressEvent(e:ProgressEvent):void + { + // don't dispatch event with progress at 100% completion until + // we have determined whether we need to stall for the RSL preload + // to complete + if (e.bytesLoaded < e.bytesTotal || _safeLoader.content != null) { + dispatchEvent(e); + } + } + + private function handleAddedEvent(e:Event):void + { + // check to ensure this was actually something added to the Loader.content + var c:DisplayObject = e.target as DisplayObject; + var p:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer; + if (c != null && p != null && c.parent == p) { + _numAdded++; + } + // the first thing added will be the loader animation swf, so ignore that + if (_numAdded > 1) { + e.currentTarget.removeEventListener(Event.ADDED, handleAddedEvent); + // if the load was cancelled, then _loadDoneCallback() will return false + if (_loadDoneCallback(c)) { + if (_realLI.bytesLoaded >= _realLI.bytesTotal) { + dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _realLI.bytesLoaded, _realLI.bytesTotal)); + } + dispatchEvent(new Event(Event.INIT, false, false)); + dispatchEvent(new Event(Event.COMPLETE, false, false)); + } + } + } + + } +} \ No newline at end of file diff --git a/src/org/assetloader/loaders/DisplayObjectLoader.as b/src/org/assetloader/loaders/DisplayObjectLoader.as index acd3719..7dfbc07 100644 --- a/src/org/assetloader/loaders/DisplayObjectLoader.as +++ b/src/org/assetloader/loaders/DisplayObjectLoader.as @@ -1,18 +1,18 @@ package org.assetloader.loaders { - import flash.display.LoaderInfo; - import org.assetloader.base.AssetType; - import org.assetloader.base.Param; - import org.assetloader.signals.LoaderSignal; - import flash.display.DisplayObject; - import flash.display.Loader; - import flash.display.LoaderInfo; import flash.events.ErrorEvent; import flash.events.Event; import flash.events.IEventDispatcher; import flash.net.URLRequest; + import fl.display.SafeLoader; + import fl.display.SafeLoaderInfo; + + import org.assetloader.base.AssetType; + import org.assetloader.base.Param; + import org.assetloader.signals.LoaderSignal; + /** * @author Matan Uberstein */ @@ -26,7 +26,7 @@ package org.assetloader.loaders /** * @private */ - protected var _loader : Loader; + protected var _loader : SafeLoader; public function DisplayObjectLoader(request : URLRequest, id : String = null) { @@ -47,7 +47,7 @@ package org.assetloader.loaders */ override protected function constructLoader() : IEventDispatcher { - _loader = new Loader(); + _loader = new SafeLoader(); return _loader.contentLoaderInfo; } @@ -107,7 +107,7 @@ package org.assetloader.loaders /** * @private - * + * * @return Error message, empty String if no error occured. */ protected function testData(data : DisplayObject) : String @@ -117,7 +117,7 @@ package org.assetloader.loaders /** * Gets the resulting DisplayObject after loading is complete. - * + * * @return DisplayObject */ public function get displayObject() : DisplayObject @@ -127,12 +127,14 @@ package org.assetloader.loaders /** * Gets the current content's LoaderInfo. - * + * * @return LoaderInfo */ - public function get contentLoaderInfo() : LoaderInfo + public function get contentLoaderInfo() : SafeLoaderInfo { return _loader ? _loader.contentLoaderInfo : null; } } } + + diff --git a/src/org/assetloader/loaders/SWFLoader.as b/src/org/assetloader/loaders/SWFLoader.as index c98773b..93b0fdd 100644 --- a/src/org/assetloader/loaders/SWFLoader.as +++ b/src/org/assetloader/loaders/SWFLoader.as @@ -1,13 +1,15 @@ package org.assetloader.loaders { - import org.assetloader.base.AssetType; - import org.assetloader.signals.LoaderSignal; - import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.Event; import flash.events.IEventDispatcher; import flash.net.URLRequest; + import flash.utils.getDefinitionByName; + import avmplus.getQualifiedClassName; + + import org.assetloader.base.AssetType; + import org.assetloader.signals.LoaderSignal; /** * @author Matan Uberstein @@ -78,7 +80,7 @@ package org.assetloader.loaders /** * @private - * + * * @inheritDoc */ override protected function testData(data : DisplayObject) : String @@ -97,7 +99,7 @@ package org.assetloader.loaders /** * Gets the resulting Sprite after loading is complete. - * + * * @return Sprite */ public function get swf() : Sprite @@ -108,7 +110,7 @@ package org.assetloader.loaders /** * Gets the resulting Sprite class after loading is complete. * Allows multiple instanciation of this SWF content. - * + * * @return Class */ public function get swfClass() : Class @@ -120,12 +122,12 @@ package org.assetloader.loaders /** * Dispatched when the properties and methods of a loaded SWF file are accessible and ready for use. - * + * *

HANDLER ARGUMENTS: (signal:LoaderSignal)

* - * + * * @see org.assetloader.signals.LoaderSignal */ public function get onInit() : LoaderSignal @@ -134,3 +136,5 @@ package org.assetloader.loaders } } } + +