[Laszlo-checkins] r12995 - openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9

bargull@openlaszlo.org bargull at openlaszlo.org
Sat Feb 21 16:45:52 PST 2009


Author: bargull
Date: 2009-02-21 16:45:48 -0800 (Sat, 21 Feb 2009)
New Revision: 12995

Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
Log:
Change 20090220-bargull-Y8a by bargull at dell--p4--2-53 on 2009-02-20 00:53:38
    in /home/Admin/src/svn/openlaszlo/trunk
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: loadratio for swf9 and change for security check

New Features:

Bugs Fixed: LPP-7709, LPP-7716

Technical Reviewer: max
QA Reviewer: promanik
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:
Renamed sound playback related methods:
- "startPlay" to "startSoundPlay"
- "stopPlay" to "stopSoundPlay"
- "updatePlay" to "updateSoundPlay"
Removed "frames", "source", "lastreswidth", "lastresheight", "skiponload", "baseurl". All of them were either no longer needed or left-overs from the original dhtml kernel based sprite implementation.
Moved loadurl computation in "setSource" in a separate method ("getLoadURL").
Removed null-pointer check in "applyStretchResource" because it was done twice.
Moved framenumber computation and setting from "stop()" and "play()" into a separate method ("updateResourcePlay").

LPP-7709:
Add all loader-events immediately after constructing the Loader, even though the comment at "loaderInitHandler" says that it won't work (which is a lie). See event description for "init" (flash.display.LoaderInfo):
"Dispatched when the properties and methods of a loaded SWF file are accessible and ready for use."
So the "init"-event is dispatched far too late and therefore no "progress"-events were detected and therefore no "onloadratio"-events for users.
LPP-7716:
Don't use "parentAllowsChild"/"childAllowsParent" to avoid security exceptions, instead use a simple try-catch block when accessing the loaded content. Also moved the playback warning from "loaderEventHandler" to "stop"/"play", because otherwise these warnings did appear when loading a simple application in debug-mode (triggered by avm1movie assets for the debugger). 
 

    

Tests:
testcase from LPP-7709, note that "onloadratio" events are generated
amazon-demo in swf9



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as	2009-02-21 23:47:00 UTC (rev 12994)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as	2009-02-22 00:45:48 UTC (rev 12995)
@@ -30,7 +30,6 @@
   import flash.media.SoundTransform;
   import flash.media.SoundLoaderContext;
   import flash.media.ID3Info;
-
 }#
 
 #passthrough  {
@@ -48,18 +47,12 @@
       public var clickbutton:SimpleButton = null;
       public var clickregion:Shape = null;
       public var masksprite:Sprite = null;
-      public var frames:int = 1;
       public var resource:String = null;
-      public var source:String = null;
       public var clip:Boolean = false;
       public var resourcewidth:Number = 0;
       public var resourceheight:Number = 0;
       public var isroot:Boolean = false;
       public static var rootSprite:LzSprite = null;
-      var lastreswidth:Number = 0;
-      var lastresheight:Number = 0;
-      var skiponload = false;
-      var baseurl;
 
       // Used for workaround for contextmenu bug; use as a null hitArea for sprites that
       // we don't want to get mouse events.
@@ -84,7 +77,7 @@
       /* private */ var sound:Sound = null;
       /* private */ var soundChannel:SoundChannel = null;
       /* private */ var soundLoading:Boolean = false;
-      
+
       //@field Boolean _setrescwidth: If true, the view does not set its
       //resource to the width given in a call to
       //<method>setAttribute</method>. By default, views do not scale their
@@ -219,7 +212,6 @@
       public function setResource (r:String):void {
           if (this.resource == r) return;
           if (r.indexOf('http:') == 0 || r.indexOf('https:') == 0) {
-              this.skiponload = false;
               this.setSource( r );
               return;
           }
@@ -240,7 +232,7 @@
               }
               return;
           }
-          
+
           if (LzAsset.isBitmapAsset(r) 
                 || LzAsset.isMovieClipAsset(r) 
                 || LzAsset.isMovieClipLoaderAsset(r)) {
@@ -258,7 +250,7 @@
                   // clear resource cache
                   this.resourceCache = null;
               }
-              
+
               this.__isinternalresource = true;
               this.resource = r;
               // instantiate resource at frame 1
@@ -270,13 +262,13 @@
               this.unload();
               this.__isinternalresource = true;
               this.resource = r;
-              
+
               this.sound = new res['assetclass']() as Sound;
               this.totalframes = Math.floor(this.getTotalTime() * MP3_FPS);
 
               // TODO: add condition on this
-              this.startPlay()
-              
+              this.startSoundPlay()
+
               // send events, but skip onload
               this.sendResourceLoad(true);
           } else if ($debug) {
@@ -287,7 +279,8 @@
 
       public var imgLoader:Loader;
       public var loaderMC:MovieClip;
-      private var IMGDEPTH:int = 0;
+      private const IMGDEPTH:int = 0;
+      private static const MIME_SWF:String = "application/x-shockwave-flash";
 
       /** setSource( String:url )
           o Loads and displays media from the specified url
@@ -297,36 +290,7 @@
           if (url == null || url == 'null') {
               return;
           }
-          var loadurl = url;
-          var proxied = this.owner.__LZcheckProxyPolicy( url );
-          var proxyurl = this.owner.getProxyURL(url);
-          if (proxied) {
-              var params:Object = {serverproxyargs: {},
-                                   timeout: canvas.medialoadtimeout,
-                                   proxyurl: proxyurl,
-                                   url: url,
-                                   httpmethod: 'GET',
-                                   service: 'media'
-              };
-              if (headers != null) {
-                  params.headers = headers;
-              }
-              if (cache == "none") {
-                  params.cache = false;
-                  params.ccache = false;
-              } else if (cache == "clientonly") {
-                  params.cache = false;
-                  params.ccache = true;
-              } else if (cache == "serveronly") {
-                  params.cache = true;
-                  params.ccache = false;
-              } else {
-                  params.cache = true;
-                  params.ccache = true;
-              }
-              loadurl = lz.Browser.makeProxiedURL(params);
-          }
-
+          var loadurl:String = getLoadURL(url, cache, headers);
           if (getFileType(url, filetype) == "mp3") {
               // unload previous image-resource and sound-resource
               this.unload();
@@ -338,7 +302,7 @@
                   // unload previous sound-resource
                   this.unloadSound();
               }
-            
+
               if (! imgLoader) {
                   if (this.resourceContainer) {
                       // unload previous internal image-resource
@@ -349,9 +313,7 @@
                   imgLoader.mouseChildren = false;
                   this.resourceContainer = imgLoader;
                   this.addChildAt(imgLoader, IMGDEPTH);
-                  var info:LoaderInfo = imgLoader.contentLoaderInfo;
-                  info.addEventListener(Event.INIT, loaderInitHandler);
-                  info.addEventListener(IOErrorEvent.IO_ERROR, loaderEventHandler);
+                  this.attachLoaderEvents(imgLoader.contentLoaderInfo);
               } else {
                   //TODO [20080911 anba] cancel current load?
                   // imgLoader.close();
@@ -367,8 +329,40 @@
           }
       }
 
-      
-      private function getFileType (url:String, filetype:String = null) :String {
+      private function getLoadURL (url:String, cache:String, headers:String) :String {
+          var loadurl:String = url;
+          var proxied:* = this.owner.__LZcheckProxyPolicy( url );
+          if (proxied) {
+              var proxyurl:String = this.owner.getProxyURL(url);
+              var params:Object = {serverproxyargs: {},
+                                   timeout: canvas.medialoadtimeout,
+                                   proxyurl: proxyurl,
+                                   url: url,
+                                   httpmethod: 'GET',
+                                   service: 'media'
+              };
+              if (headers != null) {
+                  params.headers = headers;
+              }
+              if (cache == "none") {
+                  params.cache = false;
+                  params.ccache = false;
+              } else if (cache == "clientonly") {
+                  params.cache = false;
+                  params.ccache = true;
+              } else if (cache == "serveronly") {
+                  params.cache = true;
+                  params.ccache = false;
+              } else {
+                  params.cache = true;
+                  params.ccache = true;
+              }
+              loadurl = lz.Browser.makeProxiedURL(params);
+          }
+          return loadurl;
+      }
+
+      private function getFileType (url:String, filetype:String) :String {
           if (filetype != null) {
               return filetype.toLowerCase();
           } else {
@@ -377,16 +371,14 @@
           }
       }
 
-      public function loaderInitHandler(event:Event):void {
-          // These progress event listeners can only be installed after the init event
-          // has been received. You get an error if you try to add them before this.
-          var loader:Loader = Loader(event.target.loader);
-          var info:LoaderInfo = LoaderInfo(loader.contentLoaderInfo);
+      private function attachLoaderEvents (info:LoaderInfo) :void {
           info.addEventListener(ProgressEvent.PROGRESS, loaderEventHandler);
           info.addEventListener(Event.OPEN, loaderEventHandler);
-          info.addEventListener(Event.UNLOAD, loaderEventHandler); 
+          // info.addEventListener(Event.UNLOAD, loaderEventHandler);
+          // info.addEventListener(Event.INIT, loaderEventHandler);
           info.addEventListener(Event.COMPLETE, loaderEventHandler);
           info.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderEventHandler);
+          info.addEventListener(IOErrorEvent.IO_ERROR, loaderEventHandler);
           // @devnote: From the HTTPStatusEvent reference page:
           // > Some Flash Player environments may be unable to detect HTTP status codes; 
           // > a status code of 0 is always reported in these cases.
@@ -394,7 +386,6 @@
           //info.addEventListener(HTTPStatusEvent.HTTP_STATUS, loaderEventHandler);
       }
 
-
       public function loaderEventHandler(event:Event):void {
           try {
               //@devnote: accessing the Loader through "event.target.loader" may 
@@ -411,29 +402,34 @@
                   }
 
                   var info:LoaderInfo = event.target as LoaderInfo;
-                  // avoid security exceptions
-                  if (info.parentAllowsChild) {
-                      if (info.content is AVM1Movie) {
-                          if ($debug) {
-                              Debug.warn("Playback control will not work for the resource.  Please update or recompile the resource for Flash 9.", this.resource);
-                          }
-                      } else if (info.content is MovieClip) {
+                  try {
+                      // accessing LoaderInfo.content may throw security exceptions
+                      var content:DisplayObject = info.content;
+                      if (content is AVM1Movie) {
+                          // no playback control
+                      } else if (content is MovieClip) {
                           // store a reference for playback control
-                          this.loaderMC = MovieClip(info.content);  
+                          this.loaderMC = MovieClip(content);  
                           this.totalframes = this.loaderMC.totalFrames;
                           this.loaderMC.addEventListener(Event.ENTER_FRAME, updateFrames);
                           this.owner.resourceevent('play', null, true);
                           this.playing = this.owner.playing = true;
-                      } else if (info.content is Bitmap) {
-                          (info.content as Bitmap).smoothing = true;
+                      } else if (content is Bitmap) {
+                          (content as Bitmap).smoothing = true;
                       }
+                  } catch (error:SecurityError) {
+                      // ignore for now
                   }
 
                   try {
-                      var loader:Loader = Loader(event.target.loader);
+                      // accessing LoaderInfo.loader may throw security exceptions
+                      // TODO [20090203 anba] why can't we use LoaderInfo.width/height,
+                      // which won't generate security exceptions?
+                      var loader:Loader = Loader(info.loader);
                       this.resourcewidth = loader.width;
                       this.resourceheight = loader.height;
-                  } catch (e) {
+                  } catch (error:SecurityError) {
+                      // TODO [20090203 anba] install default values?
                   }
                   // Apply stretch if needed, now that we know the asset dimensions.
                   this.applyStretchResource();
@@ -444,8 +440,8 @@
                          event.type == SecurityErrorEvent.SECURITY_ERROR) {
                   //TODO [20080911 anba] how can "owner" become null here?
                   if (this.owner != null) {
-                      // IOErrorEvent/SecurityErrorEvent -> ErrorEvent -> TextEvent
-                      this.owner.resourceloaderror( (event as TextEvent).text );
+                      // IOErrorEvent/SecurityErrorEvent -> ErrorEvent
+                      this.owner.resourceloaderror( (event as ErrorEvent).text );
                   }
               } else if (event.type == ProgressEvent.PROGRESS) {
                   var ev:ProgressEvent = event as ProgressEvent;
@@ -488,20 +484,20 @@
           this.sound.addEventListener(Event.COMPLETE, soundLoadHandler);
           this.sound.addEventListener(ProgressEvent.PROGRESS, soundLoadHandler);
           this.sound.addEventListener(IOErrorEvent.IO_ERROR, soundLoadHandler);
-          
+
           this.sound.load(new URLRequest(url), LzSprite.soundLoaderContext);
-          
+
           // TODO: add condition on this
-          this.startPlay();
+          this.startSoundPlay();
       }
-      
+
       /** 
         * Stop current playback and unload sound
         */
       private function unloadSound () :void {
           if (this.playing) {
               // stop playing
-              this.stopPlay();
+              this.stopSoundPlay();
           }
           if (this.sound) {
               if (this.soundLoading) {
@@ -512,15 +508,15 @@
               this.sound = null;
           }
       }
-      
+
       /** 
         * Start sound playback and tracking
         * @param Number frame: frame/secs to start at playing
         * @param Boolean isFrame: if set to false, treat 'frame' as seconds
         */
-      private function startPlay (frame:Number = 0, isFrame:Boolean = true) :void {
+      private function startSoundPlay (frame:Number = 0, isFrame:Boolean = true) :void {
           var pos:Number = (isFrame ? (frame / MP3_FPS) : frame) * 1000;
-          
+
           this.playing = this.owner.playing = true;
           this.soundChannel = this.sound.play(pos, 0, this.soundTransform);
           this.addEventListener(Event.ENTER_FRAME, soundFrameHandler);
@@ -531,31 +527,31 @@
         * Stop sound playback and tracking
         * @return Number: the current frame when playback was stopped
         */
-      private function stopPlay () :Number {
+      private function stopSoundPlay () :Number {
           var frame:Number = Math.floor(this.soundChannel.position * 0.001 * MP3_FPS);
-          
+
           this.playing = this.owner.playing = false;
           this.removeEventListener(Event.ENTER_FRAME, soundFrameHandler);
           this.soundChannel.stop();
           this.soundChannel = null;
-          
+
           return frame;
       }
-      
+
       /** 
         * Update sound play status
         */
-      private function updatePlay (play:Boolean, framenumber:*, rel:Boolean) :void {
+      private function updateSoundPlay (play:Boolean, framenumber:*, rel:Boolean) :void {
           var fr:Number;
           if (this.playing) {
               // stop previous playback
-              fr = this.stopPlay();
+              fr = this.stopSoundPlay();
           } else {
               // TODO: this.frame is initialized with 1, which
               // means we currently skip 33ms at the beginning
               fr = this.frame;
           }
-          
+
           if (framenumber != null) {
               framenumber += rel ? fr : 0;
           } else if (play) {
@@ -565,14 +561,14 @@
           } else {
               framenumber = fr;
           }
-          
+
           if (play) {
-              this.startPlay(framenumber);
+              this.startSoundPlay(framenumber);
           } else {
               this.frame = framenumber;
           }
       }
-      
+
       /** 
         * Progress sound loading
         */
@@ -600,10 +596,10 @@
                   this.owner.resourceloaderror( (event as IOErrorEvent).text );
               }
           } catch (error:Error) {
-              trace(event.type + " " + error);
+              if ($debug) Debug.warn(event.type + " " + error);
           }
       }
-      
+
       /** 
         * Track playback
         */
@@ -619,7 +615,7 @@
       private function soundCompleteHandler (event:Event) :void {
           // Event.SOUND_COMPLETE
           if (this.playing) {
-              this.stopPlay();
+              this.stopSoundPlay();
               this.frame = this.totalframes;
 
               // SoundChannel.position does not stop exactly at Sound.length, 
@@ -629,7 +625,7 @@
               this.owner.resourceevent('lastframe', null, true);
           }
       }
-      
+
       //// Mouse event trampoline
       public function attachMouseEvents(dobj:DisplayObject) :void {
           dobj.addEventListener(MouseEvent.CLICK, __mouseEvent, false);
@@ -963,24 +959,20 @@
       public function play (framenumber:* = null, rel:Boolean = false) :void {
           if (this.isaudio) {
               // audio-resource is attached
-              this.updatePlay(true, framenumber, rel);
-              
+              this.updateSoundPlay(true, framenumber, rel);
+
               this.owner.resourceevent('play', null, true);
           } else if (this.__isinternalresource) {
               stop(framenumber, rel);
           } else if (this.loaderMC) {
               this.owner.resourceevent('play', null, true);
-              this.playing = this.owner.playing = true;
-              if (framenumber == null) {
-                  this.loaderMC.play();
-              } else {
-                  if (rel) framenumber += this.frame;
-                  if (framenumber > this.totalframes) {
-                      framenumber = this.totalframes;
-                  } else if (framenumber < 1) {
-                      framenumber = 1;
+              this.updateResourcePlay(true, framenumber, rel);
+          } else if (this.imgLoader) {
+              if ($debug) {
+                  var info:LoaderInfo = this.imgLoader.contentLoaderInfo;
+                  if (info.contentType == LzSprite.MIME_SWF && info.swfVersion < SWFVersion.FLASH9) {    
+                      Debug.warn("Playback control will not work for the resource. Please update or recompile the resource for Flash 9.", this.resource);
                   }
-                  this.loaderMC.gotoAndPlay(framenumber);
               }
           } else {
               //Debug.write('unhandled play', framenumber, rel);
@@ -996,15 +988,15 @@
           if (this.isaudio) {
               // audio-resource is attached
               var p:Boolean = this.playing;
-              this.updatePlay(false, fn, rel);
-              
+              this.updateSoundPlay(false, fn, rel);
+
               if (p) this.owner.resourceevent('stop', null, true);
           } else if (this.__isinternalresource) {
               var resinfo:Object = LzResourceLibrary[this.resource];
 
               // Frames are one based not zero based
               var frames:Array = resinfo.frames;
-              var origfn = fn;
+              var origfn:* = fn;
               if (fn == null || fn < 1) {
                   origfn = fn = 1;
               } else if (fn > frames.length) {
@@ -1030,7 +1022,7 @@
                   if (asset == null) {
                       //Debug.write('CACHE MISS, new ',assetclass);
                       asset = new assetclass();
-                      asset.scaleX = 1.0
+                      asset.scaleX = 1.0;
                       asset.scaleY = 1.0;
                       this.resourceCache[framenumber] = asset;
                   }
@@ -1043,7 +1035,7 @@
                       LzIdleKernel.addCallback(this, '__resetframe');
                       return;
                   }
-                    
+
                   if (this.resourceContainer != null) {
                       this.removeChild(this.resourceContainer);
                   }
@@ -1052,7 +1044,7 @@
                   if (asset is DisplayObjectContainer) DisplayObjectContainer(asset).mouseChildren = false;
 
                   this.resourceContainer = asset;
-                  this.addChildAt(asset,IMGDEPTH);
+                  this.addChildAt(asset, IMGDEPTH);
 
                   this.applyStretchResource();
 
@@ -1078,17 +1070,13 @@
               }
           } else if (this.loaderMC) {
               if ( this.playing ) this.owner.resourceevent('stop', null, true);
-              this.playing = this.owner.playing = false;
-              if (fn == null) {
-                  this.loaderMC.stop();
-              } else {
-                  if (rel) fn += this.frame;
-                  if (fn > this.totalframes) {
-                      fn = this.totalframes;
-                  } else if (fn < 1) {
-                      fn = 1;
+              this.updateResourcePlay(false, fn, rel);
+          } else if (this.imgLoader) {
+              if ($debug) {
+                  var info:LoaderInfo = this.imgLoader.contentLoaderInfo;
+                  if (info.contentType == LzSprite.MIME_SWF && info.swfVersion < SWFVersion.FLASH9) {
+                      Debug.warn("Playback control will not work for the resource. Please update or recompile the resource for Flash 9.", this.resource);
                   }
-                  this.loaderMC.gotoAndStop(fn);
               }
           } else {
               // This shouldn't happen - but it does, on roll over 
@@ -1096,6 +1084,30 @@
           }
       }
 
+      private function updateResourcePlay (play:Boolean, framenumber:*, rel:Boolean) :void {
+          this.playing = this.owner.playing = play;
+
+          if (framenumber == null) {
+              if (play) {
+                  this.loaderMC.play();
+              } else {
+                  this.loaderMC.stop();
+              }
+          } else {
+              if (rel) framenumber += this.frame;
+              if (framenumber > this.totalframes) {
+                  framenumber = this.totalframes;
+              } else if (framenumber < 1) {
+                  framenumber = 1;
+              }
+              if (play) {
+                  this.loaderMC.gotoAndPlay(framenumber);
+              } else {
+                  this.loaderMC.gotoAndStop(framenumber);
+              }
+          }
+      }
+
       /** Callback resets resources after they have loaded and displayed */
       public function __resetframe(ignore=null):void {
           LzIdleKernel.removeCallback(this, '__resetframe');
@@ -1168,10 +1180,6 @@
       }
 
       public function applyStretchResource():void {
-          if (this.resourceContainer == null) {
-              return;
-          }
-
           var res = this.resourceContainer;
 
           // Don't try to do anything while an image is loading
@@ -1335,7 +1343,7 @@
         }
         if (this.isaudio) this.unloadSound();
         // clear out cached values
-        this.lastreswidth = this.lastresheight = this.resourcewidth = this.resourceheight = 0;
+        this.resourcewidth = this.resourceheight = 0;
         this.resource = null;
         this.__isinternalresource = null;
         if (this.loaderMC) {
@@ -1468,7 +1476,7 @@
       function getPan () :Number {
           return LzAudioKernel.getPan(this);
       }
-      
+
       /** 
         * @param Number secs: 
         * @param Boolean playing: 
@@ -1482,16 +1490,16 @@
               if (pos > total) pos = total;
 
               if (this.playing) {
-                  this.stopPlay();
+                  this.stopSoundPlay();
               }
               if (doplay) {
-                  this.startPlay(pos, false);
+                  this.startSoundPlay(pos, false);
               } else {
                   this.frame = Math.floor(pos * MP3_FPS);
               }
           }
       }
-      
+
       /** 
         * @return Number: time elapsed (in seconds)
         */
@@ -1507,14 +1515,14 @@
               return 0;
           }
       }
-      
+
       /** 
         * @return Number: length of the current sound (in seconds)
         */
       function getTotalTime () :Number {
           return this.isaudio ? this.sound.length * 0.001 : 0;
       }
-      
+
       /** 
         * @return ID3Info: id3-info of the current sound
         */



More information about the Laszlo-checkins mailing list