PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/!src/com/greensock12/loading/core/DisplayObjectLoader.as

https://github.com/tluczyns/tluczyns-as3-base
ActionScript | 318 lines | 233 code | 27 blank | 58 comment | 66 complexity | 966b31d43abb0793166e93abff251793 MD5 | raw file
  1. /**
  2. * VERSION: 1.935
  3. * DATE: 2013-03-18
  4. * AS3
  5. * UPDATES AND DOCS AT: http://www.greensock.com/loadermax/
  6. **/
  7. package com.greensock.loading.core {
  8. import com.greensock.events.LoaderEvent;
  9. import com.greensock.loading.LoaderMax;
  10. import com.greensock.loading.LoaderStatus;
  11. import com.greensock.loading.display.ContentDisplay;
  12. import flash.display.DisplayObject;
  13. import flash.display.Loader;
  14. import flash.display.Sprite;
  15. import flash.events.ErrorEvent;
  16. import flash.events.Event;
  17. import flash.events.ProgressEvent;
  18. import flash.net.LocalConnection;
  19. import flash.net.URLRequest;
  20. import flash.system.ApplicationDomain;
  21. import flash.system.Capabilities;
  22. import flash.system.LoaderContext;
  23. import flash.system.Security;
  24. import flash.system.SecurityDomain;
  25. /**
  26. * Serves as the base class for SWFLoader and ImageLoader. There is no reason to use this class on its own.
  27. * Please refer to the documentation for the other classes.
  28. *
  29. * <p><strong>Copyright 2013, GreenSock. All rights reserved.</strong> This work is subject to the terms in <a href="http://www.greensock.com/terms_of_use.html">http://www.greensock.com/terms_of_use.html</a> or for <a href="http://www.greensock.com/club/">Club GreenSock</a> members, the software agreement that was issued with the membership.</p>
  30. *
  31. * @author Jack Doyle, jack@greensock.com
  32. */
  33. public class DisplayObjectLoader extends LoaderItem {
  34. /** By default, LoaderMax will automatically attempt to force garbage collection when a SWFLoader or ImageLoader is unloaded or cancelled but if you prefer to skip this measure, set defaultAutoForceGC to <code>false</code>. If garbage collection isn't forced, sometimes Flash doesn't completely unload swfs/images properly, particularly if there is audio embedded in the root timeline. **/
  35. public static var defaultAutoForceGC:Boolean = true;
  36. /** @private the Sprite to which the EVENT_LISTENER was attached for forcing garbage collection after 1 frame (improves performance especially when multiple loaders are disposed at one time). **/
  37. protected static var _gcDispatcher:Sprite;
  38. /** @private **/
  39. protected static var _gcCycles:uint = 0;
  40. /** @private **/
  41. protected var _loader:Loader;
  42. /** @private **/
  43. protected var _sprite:Sprite;
  44. /** @private **/
  45. protected var _context:LoaderContext;
  46. /** @private **/
  47. protected var _initted:Boolean;
  48. /** @private used by SWFLoader when the loader is canceled before the SWF ever had a chance to init which causes garbage collection issues. We slip into stealthMode at that point, wait for it to init, and then cancel the _loader's loading.**/
  49. protected var _stealthMode:Boolean;
  50. /** @private allows us to apply a LoaderContext to the file size audit (only if necessary - URLStream is better/faster/smaller and works great unless we run into security errors because of a missing crossdomain.xml file) **/
  51. protected var _fallbackAudit:Loader;
  52. /**
  53. * Constructor
  54. *
  55. * @param urlOrRequest The url (<code>String</code>) or <code>URLRequest</code> from which the loader should get its content
  56. * @param vars An object containing optional parameters like <code>estimatedBytes, name, autoDispose, onComplete, onProgress, onError</code>, etc. For example, <code>{estimatedBytes:2400, name:"myImage1", onComplete:completeHandler}</code>.
  57. */
  58. public function DisplayObjectLoader(urlOrRequest:*, vars:Object=null) {
  59. super(urlOrRequest, vars);
  60. _refreshLoader(false);
  61. if (LoaderMax.contentDisplayClass is Class) {
  62. _sprite = new LoaderMax.contentDisplayClass(this);
  63. if (!_sprite.hasOwnProperty("rawContent")) {
  64. throw new Error("LoaderMax.contentDisplayClass must be set to a class with a 'rawContent' property, like com.greensock.loading.display.ContentDisplay");
  65. }
  66. } else {
  67. _sprite = new ContentDisplay(this);
  68. }
  69. }
  70. /** @private Set inside ContentDisplay's or FlexContentDisplay's "loader" setter. **/
  71. public function setContentDisplay(contentDisplay:Sprite):void {
  72. _sprite = contentDisplay;
  73. }
  74. /** @private **/
  75. override protected function _load():void {
  76. _prepRequest();
  77. if (this.vars.context is LoaderContext) {
  78. _context = this.vars.context;
  79. } else if (_context == null) {
  80. if (LoaderMax.defaultContext != null) {
  81. _context = LoaderMax.defaultContext;
  82. if (_isLocal) {
  83. _context.securityDomain = null;
  84. }
  85. } else if (!_isLocal) {
  86. _context = new LoaderContext(true, new ApplicationDomain(ApplicationDomain.currentDomain), SecurityDomain.currentDomain); //avoids some security sandbox headaches that plague many users.
  87. }
  88. }
  89. if (Capabilities.playerType != "Desktop") { //AIR apps will choke on Security.allowDomain()
  90. Security.allowDomain(_url);
  91. }
  92. _loader.load(_request, _context);
  93. }
  94. /** @inheritDoc **/
  95. override public function auditSize():void {
  96. if (Capabilities.playerType != "Desktop") { //AIR apps will choke on Security.allowDomain()
  97. Security.allowDomain(_url);
  98. }
  99. super.auditSize();
  100. }
  101. override protected function _closeStream():void {
  102. _closeFallbackAudit();
  103. super._closeStream();
  104. }
  105. protected function _closeFallbackAudit():void {
  106. if (_fallbackAudit != null) {
  107. _fallbackAudit.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _auditStreamHandler, false, 0, true);
  108. _fallbackAudit.contentLoaderInfo.addEventListener(Event.COMPLETE, _auditStreamHandler, false, 0, true);
  109. _fallbackAudit.contentLoaderInfo.addEventListener("ioError", _auditStreamHandler, false, 0, true);
  110. _fallbackAudit.contentLoaderInfo.addEventListener("securityError", _auditStreamHandler, false, 0, true);
  111. try {
  112. _fallbackAudit.close();
  113. } catch (error:Error) {
  114. }
  115. _fallbackAudit = null;
  116. }
  117. }
  118. /** @private **/
  119. override protected function _auditStreamHandler(event:Event):void {
  120. //If a security error is thrown because of a missing crossdomain.xml file for example and the user didn't define a specific LoaderContext, we'll try again without checking the policy file, accepting the restrictions that come along with it because typically people would rather have the content show up on the screen rather than just error out (and they can always check the scriptAccessDenied property if they need to figure out whether it's safe to do BitmapData stuff on it, etc.)
  121. if (event.type == "securityError") {
  122. if (_fallbackAudit == null) {
  123. _context = new LoaderContext(false);
  124. _scriptAccessDenied = true;
  125. dispatchEvent(new LoaderEvent(LoaderEvent.SCRIPT_ACCESS_DENIED, this, ErrorEvent(event).text));
  126. _errorHandler(event);
  127. _fallbackAudit = new Loader(); //so that we can apply a LoaderContext. We don't want to use a Loader initially because they are more memory-intensive than URLStream and they can tend to have more problems with garbage collection.
  128. _fallbackAudit.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _auditStreamHandler, false, 0, true);
  129. _fallbackAudit.contentLoaderInfo.addEventListener(Event.COMPLETE, _auditStreamHandler, false, 0, true);
  130. _fallbackAudit.contentLoaderInfo.addEventListener("ioError", _auditStreamHandler, false, 0, true);
  131. _fallbackAudit.contentLoaderInfo.addEventListener("securityError", _auditStreamHandler, false, 0, true);
  132. var request:URLRequest = new URLRequest();
  133. request.data = _request.data;
  134. request.method = _request.method;
  135. _setRequestURL(request, _url, (!_isLocal || _url.substr(0, 4) == "http") ? "gsCacheBusterID=" + (_cacheID++) + "&purpose=audit" : "");
  136. if (Capabilities.playerType != "Desktop") { //AIR apps will choke on Security.allowDomain()
  137. Security.allowDomain(_url);
  138. }
  139. _fallbackAudit.load(request, _context);
  140. return;
  141. } else {
  142. _closeFallbackAudit();
  143. }
  144. }
  145. super._auditStreamHandler(event);
  146. }
  147. /** @private **/
  148. protected function _refreshLoader(unloadContent:Boolean=true):void {
  149. if (_loader != null) {
  150. //to avoid gc issues and get around a bug in Flash that incorrectly reports progress values on Loaders that were closed before completing, we must force gc and recreate the Loader altogether...
  151. if (_status == LoaderStatus.LOADING) {
  152. try {
  153. _loader.close();
  154. } catch (error:Error) {
  155. }
  156. }
  157. _loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, _progressHandler);
  158. _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, _completeHandler);
  159. _loader.contentLoaderInfo.removeEventListener("ioError", _failHandler);
  160. _loader.contentLoaderInfo.removeEventListener("securityError", _securityErrorHandler);
  161. _loader.contentLoaderInfo.removeEventListener("httpStatus", _httpStatusHandler);
  162. _loader.contentLoaderInfo.removeEventListener("httpResponseStatus", _httpStatusHandler);
  163. _loader.contentLoaderInfo.removeEventListener(Event.INIT, _initHandler);
  164. if (_loader.hasOwnProperty("uncaughtErrorEvents")) { //not available when published to FP9, so we reference things this way to avoid compiler errors
  165. Object(_loader).uncaughtErrorEvents.removeEventListener("uncaughtError", _errorHandler);
  166. }
  167. if (unloadContent) {
  168. try {
  169. if (_loader.parent == null && _sprite != null) {
  170. _sprite.addChild(_loader); //adding the _loader to the display list BEFORE calling unloadAndStop() and then removing it will greatly improve its ability to gc correctly if event listeners were added to the stage from within a subloaded swf without specifying "true" for the weak parameter of addEventListener(). The order here is critical.
  171. }
  172. if (_loader.hasOwnProperty("unloadAndStop")) { //Flash Player 10 and later only
  173. (_loader as Object).unloadAndStop();
  174. } else {
  175. _loader.unload();
  176. }
  177. } catch (error:Error) {
  178. }
  179. if (_loader.parent) {
  180. _loader.parent.removeChild(_loader);
  181. }
  182. if (("autoForceGC" in this.vars) ? this.vars.autoForceGC : defaultAutoForceGC) {
  183. forceGC((this.hasOwnProperty("getClass")) ? 3 : 1);
  184. }
  185. }
  186. }
  187. _initted = false;
  188. _loader = new Loader();
  189. _loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _progressHandler, false, 0, true);
  190. _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _completeHandler, false, 0, true);
  191. _loader.contentLoaderInfo.addEventListener("ioError", _failHandler, false, 0, true);
  192. _loader.contentLoaderInfo.addEventListener("securityError", _securityErrorHandler, false, 0, true);
  193. _loader.contentLoaderInfo.addEventListener("httpStatus", _httpStatusHandler, false, 0, true);
  194. _loader.contentLoaderInfo.addEventListener("httpResponseStatus", _httpStatusHandler, false, 0, true);
  195. _loader.contentLoaderInfo.addEventListener(Event.INIT, _initHandler, false, 0, true);
  196. if (_loader.hasOwnProperty("uncaughtErrorEvents")) { //not available when published to FP9, so we reference things this way to avoid compiler errors
  197. Object(_loader).uncaughtErrorEvents.addEventListener("uncaughtError", _errorHandler, false, 0, true);
  198. }
  199. }
  200. /** @private works around bug in Flash Player that prevents SWFs from properly being garbage collected after being unloaded - for certain types of objects like swfs, this needs to be run more than once (spread out over several frames) to force Flash to properly garbage collect everything. **/
  201. public static function forceGC(cycles:uint=1):void {
  202. if (_gcCycles < cycles) {
  203. _gcCycles = cycles;
  204. if (_gcDispatcher == null) {
  205. _gcDispatcher = new Sprite();
  206. _gcDispatcher.addEventListener(Event.ENTER_FRAME, _forceGCHandler, false, 0, true);
  207. }
  208. }
  209. }
  210. /** @private **/
  211. protected static function _forceGCHandler(event:Event):void {
  212. if (--_gcCycles <= 0) {
  213. _gcDispatcher.removeEventListener(Event.ENTER_FRAME, _forceGCHandler);
  214. _gcDispatcher = null;
  215. }
  216. try {
  217. new LocalConnection().connect("FORCE_GC");
  218. new LocalConnection().connect("FORCE_GC");
  219. } catch (error:Error) {
  220. }
  221. }
  222. /** @private scrubLevel: 0 = cancel, 1 = unload, 2 = dispose, 3 = flush **/
  223. override protected function _dump(scrubLevel:int=0, newStatus:int=LoaderStatus.READY, suppressEvents:Boolean=false):void {
  224. if (!_stealthMode) {
  225. _refreshLoader(Boolean(scrubLevel != 2));
  226. }
  227. if (scrubLevel == 1) { //unload
  228. (_sprite as Object).rawContent = null;
  229. } else if (scrubLevel == 2) { //dispose
  230. (_sprite as Object).loader = null;
  231. } else if (scrubLevel == 3) { //unload and dispose
  232. (_sprite as Object).dispose(false, false); //makes sure the ContentDisplay is removed from its parent as well.
  233. }
  234. super._dump(scrubLevel, newStatus, suppressEvents);
  235. }
  236. /** @private **/
  237. protected function _determineScriptAccess():void {
  238. if (!_scriptAccessDenied) {
  239. if (!_loader.contentLoaderInfo.childAllowsParent) {
  240. _scriptAccessDenied = true;
  241. dispatchEvent(new LoaderEvent(LoaderEvent.SCRIPT_ACCESS_DENIED, this, "Error #2123: Security sandbox violation: " + this + ". No policy files granted access."));
  242. }
  243. }
  244. }
  245. //---- EVENT HANDLERS ------------------------------------------------------------------------------------
  246. /** @private **/
  247. protected function _securityErrorHandler(event:ErrorEvent):void {
  248. //If a security error is thrown because of a missing crossdomain.xml file for example and the user didn't define a specific LoaderContext, we'll try again without checking the policy file, accepting the restrictions that come along with it because typically people would rather have the content show up on the screen rather than just error out (and they can always check the scriptAccessDenied property if they need to figure out whether it's safe to do BitmapData stuff on it, etc.)
  249. if (_context != null && _context.checkPolicyFile && !(this.vars.context is LoaderContext)) {
  250. _context = new LoaderContext(false);
  251. _scriptAccessDenied = true;
  252. dispatchEvent(new LoaderEvent(LoaderEvent.SCRIPT_ACCESS_DENIED, this, event.text));
  253. _errorHandler(event);
  254. _load();
  255. } else {
  256. _failHandler(event);
  257. }
  258. }
  259. /** @private **/
  260. protected function _initHandler(event:Event):void {
  261. if (!_initted) {
  262. _initted = true;
  263. if (_content == null) { //_content is set in ImageLoader or SWFLoader (subclasses), but we put this here just in case someone wants to use DisplayObjectLoader on its own as a lighter weight alternative without the bells & whistles of SWFLoader/ImageLoader.
  264. _content = (_scriptAccessDenied) ? _loader : _loader.content;
  265. }
  266. (_sprite as Object).rawContent = (_content as DisplayObject);
  267. dispatchEvent(new LoaderEvent(LoaderEvent.INIT, this));
  268. }
  269. }
  270. //---- GETTERS / SETTERS -------------------------------------------------------------------------
  271. /** A ContentDisplay object (a Sprite) that will contain the remote content as soon as the <code>INIT</code> event has been dispatched. This ContentDisplay can be accessed immediately; you do not need to wait for the content to load. **/
  272. override public function get content():* {
  273. return _sprite;
  274. }
  275. /**
  276. * The raw content that was successfully loaded <strong>into</strong> the <code>content</code> ContentDisplay
  277. * Sprite which varies depending on the type of loader and whether or not script access was denied while
  278. * attempting to load the file:
  279. *
  280. * <ul>
  281. * <li>ImageLoader with script access granted: <code>flash.display.Bitmap</code></li>
  282. * <li>ImageLoader with script access denied: <code>flash.display.Loader</code></li>
  283. * <li>SWFLoader with script access granted: <code>flash.display.DisplayObject</code> (the swf's <code>root</code>)</li>
  284. * <li>SWFLoader with script access denied: <code>flash.display.Loader</code> (the swf's <code>root</code> cannot be accessed because it would generate a security error)</li>
  285. * </ul>
  286. **/
  287. public function get rawContent():* {
  288. return _content;
  289. }
  290. }
  291. }