What is in flash.swc?

In this part of our ongoing series about cross-compiling ActionScript to JavaScript I will talk about flash.swc, which is the last of the three FlashRT SWCs of my  “dreamed up” Flex SDK for JavaScript:

  • frameworks/libs/browser/browserglobal.swc
  • frameworks/libs/browser.swc
  • frameworks/libs/flash.swc

The FlashRuntime API has about 450 classes and flash.swc has about 200 of those classes covered. Some of the APIs for i.e. accessing the camera will probably never make it into flash.swc, because browsers don’t support those APIs. One important thing to point out right from the start is that I recommend implementing the FlashRuntime API in ActionScript in terms of browser.swc and browserglobal.swc like I did in my previous post with the implementation of trace().

There is no way I can cover all 200 classes of flash.swc. Instead I would like to focus on a few classes that were particularly hard. Those are:

  • Proxy
  • Dictionary
  • XML, XMLList
  • EventDispatcher
  • DisplayObject
  • BitmapData
  • ByteArray
  • MovieClip
  • Stage

Let’s get started!

 

Proxy

You might recall that I explained Proxy in a previous post in December. It can be done, but supporting Proxy requires a lot of work on the cross-compiler.

 

Dictionary

I have also talked in detail about Dictionary in a previous post. To summarize, Dictionaries can be implemented as a class derived from Proxy. The only ActionScript feature that we cannot support is weak references. For that reason it is probably a good idea to throw an error if somebody passes true for useWeakKeys when creating a Dictionary:

// ActionScript:
public dynamic class Dictionary extends Proxy
{
    public function Dictionary( useWeakKeys : Boolean = false )
    {
        if( useWeakKeys )
            throw new Error("Weak references are not supported!");
    }
}

XML, XMLList

ActionScript support built-in XML (E4X) but no browser except for Firefox supports E4x and even Mozilla hinted that they might drop support for E4X. In a previous post I suggested for that reason dropping support for E4X. But in practice you’ll find a lot of projects that do use XML and E4X. Over time I realized that we probably need to offer some sort of compromise and I created two classes AS3XML and AS3XMLList that emulate a subset of XML features on top of DOM Element and NodeList.

The details are pretty boring except for maybe the part where the constructor parses a string to an Element:

package flash.xml
{
  import adobe;
  import org.w3c.dom.DOMParser;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  ...
  // E4X definitions. based on ECMA-357
  public final dynamic class AS3XML extends Object
  {
    public function AS3XML(value:Object=null)
    {
      if( adobe.jsInstanceOf(value, Node) )
      {
        const valueAsNode : Node = value as Node;
        setNode(valueAsNode);
      }
      else if( typeof(value) == "string" )
      {
        const str:String= value as String;
        setNode( parseFromString(str) );
      }
      else
      {
        throw new Error("XML: incorrect parameter");
      }
   }
   public static function parseFromString( str : String ) : Element
   {
     if( !str )
       return null;

     const parser : DOMParser = new DOMParser();
     const elem : Element = parser.parseFromString(str, "text/xml") as Element;
     return elem;
   }
   public function getNode() : Node
   {
     return m_node;
   }
   private function setNode( val : Node ) : void
   {
     m_node = val;
   }
   ...
 }
}

 

EventDispatcher

In the Flash Runtime dispatching and observing events is probably one of the most important mechanism used for communicating between instances. The browser’s DOM does support event propagation, too. But some features like event bubbling are either different, or missing. You could roll your own event model like Google did in its Closure Library. If you do so you would run the risk of  missing out on some optimizations that only the native browser code offers. I went back and forth on this topic until I decided to base flash.events.EventDispatcher on jQuery’s event implementation. My hope was that I might get the good parts of both worlds. Later I abstracted the event model core in IFramework in order to allow other framework implementations including Google’s Closure Library.

 

DisplayObject

“Do you use SVG, or Canvas?” That’s what people ask me all the time. My answer has always been: “Both”. But my flash.swc has a bias towards SVG. DisplayObject uses an SVGLocatableElement. Here is an example:

public function set alpha(value:Number):void
{
  m_alpha = value;
  m_element.setAttribute( "opacity", value.toString() );
}

 

BitmapData

As far as I remember BitmapData is the only class that uses Canvas within flash.swc. But how do I integrate Canvas elements with the rest of my SVG tree? Well, SVG has this fantastic feature called ForeignObjectElement. You can mix Canvas into SVG, but not the other way around. If you are interested in more details on how you can use Canvas in SVG, please read this article.

 

ByteArray

I probably spent more than a week on ByteArray alone. These were the painful areas:

  • read/writeFloat
  • read/writeDouble
  • read/writeObject
  • compress/uncompress, deflate/inflate

read/writeFloat is about  serializing IEEE 754 single-precision (32-bit) floating-point numbers while read/writeDouble is about  IEEE 754 double-precision (64-bit) floating-point number serialization. You might think that by now there should be tons of libraries and examples out there that serialize according to IEEE 754. That is indeed the case, but I could only find one implementation that worked. The rest all had bugs which I found with the fantastic IEEE-754 Analyzer.

In order to support read/writeObject I had to implement Action Message Format serialization. I did that by manually converting BlazeDS’s Java code to ActionScript. The compress/uncompress, deflate/inflate require zip compression code, which I implemented using the old FZlib, that is still floating around on the Web.

The code for AMF and FZLib is so large that I moved it into amf.swc and fzlib.swc. The current implementation of ByteArray doesn’t require amf.swc and fzlib.swc and will assert if you use i.e. read/writeObject without linking amf.swc:

public function readObject():*
{
  // s_defaultDeserializer is implemented by amf.swc
  if( s_defaultDeserializer )
    return s_defaultDeserializer.readObject(this);
  throw new Error( "ByteArray: no default deserializer. " +
                   "Did you forget to link amf.swc?" );
}

 

MovieClip

As a Flex developer you rarely see or use MovieClip. But if you come from the Flash Pro world you constantly deal with MovieClips. The biggest pain about MovieClip is that it is a read-only interface. As a developer you are supposed to only play a MovieClip but never programatically add any frames to it. When I started working more seriously with MovieClip I quickly realized that the API is pretty much useless if you want to for example cross-compile a game like Pew Pew.

A MovieClip is conceptually a Sprite with a Timeline. So here is how MovieClip looks like in flash.swc (and in my opinion that is how MovieClip should have been designed):

public dynamic class MovieClip extends Sprite
{
  protected var m_timeline : ITimeline = null;
  public function MovieClip(tl:ITimeline = null, element : SVGLocatableElement=null)
  {
    super(null,element);
    if(tl)
      m_timeline = tl;
    else
      m_timeline = new Timeline();

    ...
 }
 ...
}

The ITimeline interface allows you to add frames and retrieve TimelineObjects from the timeline. This change allowed me to cross-compile ActionScript code that integrates with Adobe Edge‘s runtime.

 

Stage

There is really only one Stage per SWF. For that reason I made Stage a singleton:

public static function instance() : Stage
{
  if( !s_instance )
  {
    ...
    s_instance = createStage(w,h,null,bgcolor);
    ...
  }
  return s_instance;
}

 

What is next?

We finally made it through the long lost of painful flash.swc classes!

So what’s next? These are the topics that I have in mind:

  • debugging
  • testing
  • optimizing
Please let me know if there are any topics you would like me to talk about.