gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r11125: Add an AS3 MovieClip interfa


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11125: Add an AS3 MovieClip interface. Move the AS functions into
Date: Tue, 16 Jun 2009 09:30:47 +0200
User-agent: Bazaar (1.13.1)

------------------------------------------------------------
revno: 11125
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Tue 2009-06-16 09:30:47 +0200
message:
  Add an AS3 MovieClip interface. Move the AS functions into 
  flash/display/MovieClip_as.cpp (I'm not sure this is a good idea, as
  MovieClip currently needs access to the interface objects).
  
  Make AVM2 call super constructors somehow (but not necessarily correctly).
  
  Don't return so much on AVM2 failure; break instead.
  
  Drop bogus global addChild functions.
modified:
  libcore/ClassHierarchy.cpp
  libcore/DisplayObject.cpp
  libcore/DisplayObjectContainer.h
  libcore/MovieClip.cpp
  libcore/MovieClip.h
  libcore/TextField.cpp
  libcore/as_object.cpp
  libcore/asobj/Global.cpp
  libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
  libcore/asobj/flash/display/DisplayObjectContainer_as.h
  libcore/asobj/flash/display/MovieClip_as.cpp
  libcore/asobj/flash/display/MovieClip_as.h
  libcore/asobj/flash/display/display.am
  libcore/vm/Machine.cpp
  libcore/vm/VM.h
  testsuite/as3/dejagnu.as
    ------------------------------------------------------------
    revno: 10995.2.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 07:33:47 +0200
    message:
      Make DisplayObjectContainer as_object interface available to other classes
      (for inheritance). Use DisplayObjectContainer class as implementation.
    modified:
      libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.h
    ------------------------------------------------------------
    revno: 10995.2.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 08:48:54 +0200
    message:
      Move the MovieClip AS interface to display/MovieClip_as.cpp, leaving the
      implementation where it is.
      
      Start splitting AS3 and AS2 interface.
    modified:
      libcore/ClassHierarchy.cpp
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/asobj/Global.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
      libcore/asobj/flash/display/MovieClip_as.cpp
      libcore/asobj/flash/display/MovieClip_as.h
      libcore/asobj/flash/display/display.am
      libcore/vm/VM.h
    ------------------------------------------------------------
    revno: 10995.2.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 08:53:55 +0200
    message:
      Use different ctors for AS2 and AS3 MovieClips.
    modified:
      libcore/asobj/flash/display/MovieClip_as.cpp
      libcore/asobj/flash/display/MovieClip_as.h
    ------------------------------------------------------------
    revno: 10995.2.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 09:14:23 +0200
    message:
      Silence irritating debugging.
    modified:
      libcore/DisplayObject.cpp
    ------------------------------------------------------------
    revno: 10995.2.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 09:14:33 +0200
    message:
      Add numChildren(), move addChild and addChildAt to where they should be.
    modified:
      libcore/DisplayObjectContainer.h
      libcore/asobj/Global.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
    ------------------------------------------------------------
    revno: 10995.2.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Thu 2009-06-04 13:51:18 +0200
    message:
      Minor fixes.
    modified:
      libcore/TextField.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
    ------------------------------------------------------------
    revno: 10995.2.7
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Mon 2009-06-15 11:01:54 +0200
    message:
      Logging.
    modified:
      libcore/abc_function.cpp
      libcore/as_object.cpp
      libcore/asobj/flash/display/MovieClip_as.cpp
    ------------------------------------------------------------
    revno: 11124.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 07:42:44 +0200
    message:
      Add AS3 interface for MovieClip and DisplayObjectContainer.
    modified:
      libcore/ClassHierarchy.cpp
      libcore/DisplayObject.cpp
      libcore/DisplayObjectContainer.h
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/TextField.cpp
      libcore/as_object.cpp
      libcore/asobj/Global.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.cpp
      libcore/asobj/flash/display/DisplayObjectContainer_as.h
      libcore/asobj/flash/display/MovieClip_as.cpp
      libcore/asobj/flash/display/MovieClip_as.h
      libcore/asobj/flash/display/display.am
      libcore/vm/Machine.cpp
      libcore/vm/VM.h
    ------------------------------------------------------------
    revno: 11124.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 07:45:41 +0200
    message:
      Silence debugging.
    modified:
      libcore/as_object.cpp
    ------------------------------------------------------------
    revno: 11124.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 08:35:15 +0200
    message:
      Minor fix.
    modified:
      testsuite/as3/dejagnu.as
    ------------------------------------------------------------
    revno: 11124.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 08:45:47 +0200
    message:
      Get the super class ctor called somehow.
    modified:
      libcore/vm/Machine.cpp
    ------------------------------------------------------------
    revno: 11124.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 08:51:59 +0200
    message:
      Useful debugging.
    modified:
      libcore/vm/Machine.cpp
    ------------------------------------------------------------
    revno: 11124.1.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Tue 2009-06-16 08:52:04 +0200
    message:
      Don't try creating a MovieClip for now, or it will crash.
    modified:
      libcore/asobj/flash/display/MovieClip_as.cpp
=== modified file 'libcore/ClassHierarchy.cpp'
--- a/libcore/ClassHierarchy.cpp        2009-06-12 19:37:55 +0000
+++ b/libcore/ClassHierarchy.cpp        2009-06-16 05:42:44 +0000
@@ -42,6 +42,7 @@
 #include "Math_as.h"
 #include "Namespace_as.h"
 #include "flash/ui/Mouse_as.h"
+#include "flash/display/MovieClip_as.h"
 #include "MovieClipLoader.h"
 #include "movie_definition.h"
 #include "NetConnection_as.h"

=== modified file 'libcore/DisplayObject.cpp'
--- a/libcore/DisplayObject.cpp 2009-06-03 16:05:40 +0000
+++ b/libcore/DisplayObject.cpp 2009-06-04 07:14:23 +0000
@@ -1297,8 +1297,8 @@
                                // must be an as-referenceable
                                // DisplayObject created using 'new'
                                // like, new MovieClip, new Video, new 
TextField...
-                               log_debug("DisplayObject %p (%s) doesn't have a 
parent and "
-                        "is not a Movie", ch, typeName(*ch));
+                               //log_debug("DisplayObject %p (%s) doesn't have 
a parent and "
+                //        "is not a Movie", ch, typeName(*ch));
                                ss << "<no parent, depth" << ch->get_depth() << 
">";
                                path.push_back(ss.str());
                        }

=== modified file 'libcore/DisplayObjectContainer.h'
--- a/libcore/DisplayObjectContainer.h  2009-06-03 13:34:35 +0000
+++ b/libcore/DisplayObjectContainer.h  2009-06-04 07:14:33 +0000
@@ -62,7 +62,7 @@
     //
     /// @param index    The depth from which to remove a DisplayObject.
     /// @return         The removed DisplayObject (reflects the AS return)
-    virtual DisplayObject* removeChildAt(int index);
+    DisplayObject* removeChildAt(int index);
     
     /// Remove the specified child DisplayObject.
     //
@@ -73,7 +73,7 @@
     //
     /// @param obj      The DisplayObject to remove.
     /// @return         The removed DisplayObject (reflects the AS return)
-    virtual DisplayObject* removeChild(DisplayObject* obj);
+    DisplayObject* removeChild(DisplayObject* obj);
     
     /// Add a child DisplayObject at the next suitable index (AS2: depth).
     //
@@ -84,7 +84,7 @@
     //
     /// @param obj      The DisplayObject to add.
     /// @return         The added DisplayObject (reflects the AS return)
-    virtual DisplayObject* addChild(DisplayObject* obj);
+    DisplayObject* addChild(DisplayObject* obj);
 
     /// Add a child DisplayObject at the specified index (AS2: depth).
     //
@@ -96,7 +96,11 @@
     /// @param obj      The DisplayObject to add.
     /// @param index    The index (depth) at which to add the DisplayObject.
     /// @return         The added DisplayObject (reflects the AS return)
-    virtual DisplayObject* addChildAt(DisplayObject* obj, int index);
+    DisplayObject* addChildAt(DisplayObject* obj, int index);
+
+    size_t numChildren() const {
+        return _displayList.size();
+    }
 
 #ifdef USE_SWFTREE
     // Override to append display list info, see dox in DisplayObject.h

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2009-06-15 14:53:11 +0000
+++ b/libcore/MovieClip.cpp     2009-06-16 05:42:44 +0000
@@ -64,6 +64,9 @@
 #include "InteractiveObject.h"
 #include "DisplayObjectContainer.h"
 
+// TODO: get rid of this include.
+#include "flash/display/MovieClip_as.h"
+
 #include <vector>
 #include <string>
 #include <algorithm> // for std::swap
@@ -90,73 +93,8 @@
 //
 //#define DEBUG_MOUSE_ENTITY_FINDING 1
 
-// Forward declarations
-namespace {
-    as_object* getMovieClipInterface();
-    void attachMovieClipInterface(as_object& o);
-    void attachMovieClipProperties(DisplayObject& o);
-
-    as_value movieclip_transform(const fn_call& fn);
-    as_value movieclip_scale9Grid(const fn_call& fn);
-    as_value movieclip_attachVideo(const fn_call& fn);
-    as_value movieclip_attachAudio(const fn_call& fn);
-    as_value movieclip_attachMovie(const fn_call& fn);
-    as_value movieclip_unloadMovie(const fn_call& fn);
-    as_value movieclip_loadMovie(const fn_call& fn);
-    as_value movieclip_getURL(const fn_call& fn);
-    as_value movieclip_ctor(const fn_call& fn);
-    as_value movieclip_attachBitmap(const fn_call& fn);
-    as_value movieclip_beginBitmapFill(const fn_call& fn);
-    as_value movieclip_createEmptyMovieClip(const fn_call& fn);
-    as_value movieclip_removeMovieClip(const fn_call& fn);
-    as_value movieclip_createTextField(const fn_call& fn);
-    as_value movieclip_curveTo(const fn_call& fn);
-    as_value movieclip_beginFill(const fn_call& fn);
-    as_value movieclip_prevFrame(const fn_call& fn);
-    as_value movieclip_nextFrame(const fn_call& fn);
-    as_value movieclip_endFill(const fn_call& fn);
-    as_value movieclip_clear(const fn_call& fn);
-    as_value movieclip_lineStyle(const fn_call& fn);
-    as_value movieclip_lineTo(const fn_call& fn);
-    as_value movieclip_moveTo(const fn_call& fn);
-    as_value movieclip_beginGradientFill(const fn_call& fn);
-    as_value movieclip_stopDrag(const fn_call& fn);
-    as_value movieclip_startDrag(const fn_call& fn);
-    as_value movieclip_removeMovieClip(const fn_call& fn);
-    as_value movieclip_gotoAndStop(const fn_call& fn);
-    as_value movieclip_duplicateMovieClip(const fn_call& fn);
-    as_value movieclip_gotoAndPlay(const fn_call& fn);
-    as_value movieclip_stop(const fn_call& fn);
-    as_value movieclip_play(const fn_call& fn);
-    as_value movieclip_setMask(const fn_call& fn);
-    as_value movieclip_getDepth(const fn_call& fn);
-    as_value movieclip_getBytesTotal(const fn_call& fn);
-    as_value movieclip_getBytesLoaded(const fn_call& fn);
-    as_value movieclip_getBounds(const fn_call& fn);
-    as_value movieclip_hitTest(const fn_call& fn);
-    as_value movieclip_globalToLocal(const fn_call& fn);
-    as_value movieclip_localToGlobal(const fn_call& fn);
-    as_value movieclip_swapDepths(const fn_call& fn);
-    as_value movieclip_scrollRect(const fn_call& fn);
-    as_value movieclip_getInstanceAtDepth(const fn_call& fn);
-    as_value movieclip_getNextHighestDepth(const fn_call& fn);
-    as_value movieclip_getTextSnapshot(const fn_call& fn);
-    as_value movieclip_tabIndex(const fn_call& fn);
-    as_value movieclip_opaqueBackground(const fn_call& fn);
-    as_value movieclip_filters(const fn_call& fn);
-    as_value movieclip_forceSmoothing(const fn_call& fn);
-    as_value movieclip_cacheAsBitmap(const fn_call& fn);
-    as_value movieclip_lineGradientStyle(const fn_call& fn);
-    as_value movieclip_getRect(const fn_call& fn);
-    as_value movieclip_meth(const fn_call& fn);
-    as_value movieclip_getSWFVersion(const fn_call& fn);
-    as_value movieclip_loadVariables(const fn_call& fn);
-
-}
-
 /// Anonymous namespace for module-private definitions
-namespace
-{
+namespace {
 
 /// ConstructEvent, used for queuing construction
 //
@@ -494,13 +432,16 @@
 {
     assert(_swf);
 
-    set_prototype(getMovieClipInterface());
+    if (!isAS3(getVM())) {
+        set_prototype(getMovieClipAS2Interface());
+        attachMovieClipAS2Properties(*this);
+    }
+    else {
+        set_prototype(getMovieClipAS3Interface());
+    }
             
     _environment.set_target(this);
 
-    // TODO: have the 'MovieClip' constructor take care of this !
-    attachMovieClipProperties(*this);
-
 }
 
 MovieClip::~MovieClip()
@@ -761,7 +702,8 @@
 }
 
 boost::intrusive_ptr<DisplayObject>
-MovieClip::add_textfield(const std::string& name, int depth, int x, int y, 
float width, float height)
+MovieClip::add_textfield(const std::string& name, int depth, int x, int y,
+        float width, float height)
 {
     
     // Set textfield bounds
@@ -777,7 +719,8 @@
     // Set _x and _y
     SWFMatrix txt_matrix;
     txt_matrix.set_translation(pixelsToTwips(x), pixelsToTwips(y));
-    txt_char->setMatrix(txt_matrix, true); // update caches (altought 
shouldn't be needed as we only set translation)
+    // update caches (although shouldn't be needed as we only set translation)
+    txt_char->setMatrix(txt_matrix, true); 
 
     // Here we add the DisplayObject to the displayList.    
     _displayList.placeDisplayObject(txt_char.get(), depth); 
@@ -808,9 +751,6 @@
 
     newmovieclip->setDynamic();
 
-    //if ( initObject ) newmovieclip->copyProperties(*initObject);
-    //else newmovieclip->copyProperties(*this);
-
     // Copy event handlers from movieclip
     // We should not copy 'm_action_buffer' since the 
     // 'm_method' already contains it
@@ -2703,2488 +2643,4 @@
     _playState = s;
 }
 
-
-void
-movieclip_class_init(as_object& global)
-{
-    // This is going to be the global MovieClip "class"/"function"
-    static boost::intrusive_ptr<builtin_function> cl=NULL;
-
-    if ( cl == NULL )
-    {
-        cl = new builtin_function(&movieclip_ctor, getMovieClipInterface());
-        global.getVM().addStatic(cl.get());
-    }
-
-    // Register _global.MovieClip
-    global.init_member("MovieClip", cl.get());
-}
-
-
-//---------------------
-//  MovieClip interface
-//---------------------
-
-namespace {
-
-/// Properties (and/or methods) *inherited* by MovieClip instances
-void
-attachMovieClipInterface(as_object& o)
-{
-        VM& vm = o.getVM();
-
-        o.init_member("attachMovie", vm.getNative(900, 0)); 
-        o.init_member("swapDepths", vm.getNative(900, 1));
-        o.init_member("localToGlobal", vm.getNative(900, 2));
-        o.init_member("globalToLocal", vm.getNative(900, 3));
-        o.init_member("hitTest", vm.getNative(900, 4));
-        o.init_member("getBounds", vm.getNative(900, 5));
-        o.init_member("getBytesTotal", vm.getNative(900, 6));
-        o.init_member("getBytesLoaded", vm.getNative(900, 7));
-        o.init_member("play", vm.getNative(900, 12));
-        o.init_member("stop", vm.getNative(900, 13));
-        o.init_member("nextFrame", vm.getNative(900, 14));
-        o.init_member("prevFrame", vm.getNative(900, 15));
-        o.init_member("gotoAndPlay", vm.getNative(900, 16));
-        o.init_member("gotoAndStop", vm.getNative(900, 17));
-        o.init_member("duplicateMovieClip", vm.getNative(900, 18));
-        o.init_member("removeMovieClip", vm.getNative(900, 19));
-        o.init_member("startDrag", vm.getNative(900, 20));
-        o.init_member("stopDrag", vm.getNative(900, 21));
-        o.init_member("loadMovie", new builtin_function(movieclip_loadMovie));
-        o.init_member("loadVariables", new builtin_function(
-                    movieclip_loadVariables));
-        o.init_member("unloadMovie", new builtin_function(
-                    movieclip_unloadMovie));
-        o.init_member("getURL", new builtin_function(movieclip_getURL));
-        o.init_member("getSWFVersion", new builtin_function(
-                    movieclip_getSWFVersion));
-        o.init_member("meth", new builtin_function(movieclip_meth));
-        o.init_member("enabled", true);
-        o.init_member("useHandCursor", true);
-        o.init_property("_lockroot", &MovieClip::lockroot_getset,
-              &MovieClip::lockroot_getset);
-        o.init_member("beginBitmapFill", new builtin_function(
-                    movieclip_beginBitmapFill));
-        o.init_member("getRect", new builtin_function(
-                    movieclip_getRect));
-        o.init_member("lineGradientStyle", new builtin_function(
-                    movieclip_lineGradientStyle));
-        o.init_member("attachBitmap", new builtin_function(
-                    movieclip_attachBitmap));
-        o.init_property("blendMode", &DisplayObject::blendMode,
-                &DisplayObject::blendMode);
-        o.init_property("cacheAsBitmap", &movieclip_cacheAsBitmap, 
-                &movieclip_cacheAsBitmap);
-        o.init_property("filters", &movieclip_filters, &movieclip_filters);
-        o.init_property("forceSmoothing", &movieclip_forceSmoothing,
-                &movieclip_forceSmoothing);
-        o.init_property("opaqueBackground", &movieclip_opaqueBackground,
-                &movieclip_opaqueBackground);
-        o.init_property("scale9Grid", &movieclip_scale9Grid,
-                movieclip_scale9Grid);
-        o.init_property("scrollRect", &movieclip_scrollRect,
-                       &movieclip_scrollRect);
-        o.init_property("tabIndex", &movieclip_tabIndex, &movieclip_tabIndex);
-        o.init_property("transform", &movieclip_transform, 
-                &movieclip_transform);
-
-        const int swf6Flags = as_prop_flags::dontDelete |
-                    as_prop_flags::dontEnum |
-                    as_prop_flags::onlySWF6Up;
-
-        o.init_member("attachAudio", vm.getNative(900, 8), swf6Flags);
-        o.init_member("attachVideo", vm.getNative(900, 9), swf6Flags);
-        o.init_member("getDepth", vm.getNative(900, 10), swf6Flags);
-        o.init_member("setMask", vm.getNative(900, 11), swf6Flags);
-        o.init_member("createEmptyMovieClip", vm.getNative(901, 0), swf6Flags);
-        o.init_member("beginFill", vm.getNative(901, 1), swf6Flags);
-        o.init_member("beginGradientFill", vm.getNative(901, 2), swf6Flags);
-        o.init_member("moveTo", vm.getNative(901, 3), swf6Flags);
-        o.init_member("lineTo", vm.getNative(901, 4), swf6Flags);
-        o.init_member("curveTo", vm.getNative(901, 5), swf6Flags);
-        o.init_member("lineStyle", vm.getNative(901, 6), swf6Flags);
-        o.init_member("endFill", vm.getNative(901, 7), swf6Flags);
-        o.init_member("clear", vm.getNative(901, 8), swf6Flags);
-        o.init_member("createTextField", vm.getNative(104, 200), swf6Flags);
-        o.init_member("getTextSnapshot", 
-                new builtin_function(movieclip_getTextSnapshot), swf6Flags);
-
-        const int swf7Flags = as_prop_flags::dontDelete |
-                    as_prop_flags::dontEnum |
-                    as_prop_flags::onlySWF7Up;
-
-        o.init_member("getNextHighestDepth", new builtin_function(
-                    movieclip_getNextHighestDepth), swf7Flags);
-        o.init_member("getInstanceAtDepth", new builtin_function(
-                    movieclip_getInstanceAtDepth), swf7Flags);
-
-}
-
-void
-registerNatives(VM& vm)
-{
-    // Natives are always here    (at least in swf5 I guess)
-    vm.registerNative(movieclip_attachMovie, 900, 0); 
-    // TODO: generalize to DisplayObject::swapDepths_method ?
-    vm.registerNative(movieclip_swapDepths, 900, 1); 
-    vm.registerNative(movieclip_localToGlobal, 900, 2);
-    vm.registerNative(movieclip_globalToLocal, 900, 3);
-    vm.registerNative(movieclip_hitTest, 900, 4);
-    vm.registerNative(movieclip_getBounds, 900, 5);
-    vm.registerNative(movieclip_getBytesTotal, 900, 6);
-    vm.registerNative(movieclip_getBytesLoaded, 900, 7);
-    vm.registerNative(movieclip_attachAudio, 900, 8);
-    vm.registerNative(movieclip_attachVideo, 900, 9);
-    // TODO: generalize to DisplayObject::getDepth_method ?
-    vm.registerNative(movieclip_getDepth, 900, 10);
-    vm.registerNative(movieclip_setMask, 900, 11); 
-    vm.registerNative(movieclip_play, 900, 12); 
-    vm.registerNative(movieclip_stop, 900, 13);
-    vm.registerNative(movieclip_nextFrame, 900, 14);
-    vm.registerNative(movieclip_prevFrame, 900, 15);
-    vm.registerNative(movieclip_gotoAndPlay, 900, 16);
-    vm.registerNative(movieclip_gotoAndStop, 900, 17);
-    vm.registerNative(movieclip_duplicateMovieClip, 900, 18);
-    vm.registerNative(movieclip_removeMovieClip, 900, 19);
-    vm.registerNative(movieclip_startDrag, 900, 20);
-    vm.registerNative(movieclip_stopDrag, 900, 21);
-    vm.registerNative(movieclip_createEmptyMovieClip, 901, 0);
-    vm.registerNative(movieclip_beginFill, 901, 1);
-    vm.registerNative(movieclip_beginGradientFill, 901, 2);
-    vm.registerNative(movieclip_moveTo, 901, 3);
-    vm.registerNative(movieclip_lineTo, 901, 4);
-    vm.registerNative(movieclip_curveTo, 901, 5);
-    vm.registerNative(movieclip_lineStyle, 901, 6);
-    vm.registerNative(movieclip_endFill, 901, 7);
-    vm.registerNative(movieclip_clear, 901, 8);
-
-    vm.registerNative(movieclip_createTextField, 104, 200);
-
-}
-
-as_value
-movieclip_play(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-
-    movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
-    return as_value();
-}
-
-as_value
-movieclip_stop(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-
-    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
-
-    return as_value();
-}
-
-
-//removeMovieClip() : Void
-as_value
-movieclip_removeMovieClip(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-    movieclip->removeMovieClip();
-    return as_value();
-}
-
-
-as_value
-movieclip_cacheAsBitmap(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE( log_unimpl(_("MovieClip.cacheAsBitmap()")) );
-    return as_value();
-}
-
-
-as_value
-movieclip_filters(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.filters()")));
-    return as_value();
-}
-
-
-as_value
-movieclip_forceSmoothing(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.forceSmoothing()")));
-    return as_value();
-}
-
-
-as_value
-movieclip_opaqueBackground(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.opaqueBackground()")));
-    return as_value();
-}
-
-    
-as_value
-movieclip_scale9Grid(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.scale9Grid()")));
-    return as_value();
-}
-
-
-as_value
-movieclip_scrollRect(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.scrollRect()")));
-    return as_value();
-}
-
-
-as_value
-movieclip_tabIndex(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-    LOG_ONCE(log_unimpl(_("MovieClip.tabIndex()")));
-    return as_value();
-}
-
-
-// attachMovie(idName:String, newName:String,
-//                         depth:Number [, initObject:Object]) : MovieClip
-as_value
-movieclip_attachMovie(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 3 || fn.nargs > 4)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("attachMovie called with wrong number of arguments"
-                " expected 3 to 4, got (%d) - returning undefined"), fn.nargs);
-        );
-        return as_value();
-    }
-
-    // Get exported resource 
-    const std::string& id_name = fn.arg(0).to_string();
-
-    boost::intrusive_ptr<ExportableResource> exported =
-        movieclip->get_root()->definition()->get_exported_resource(id_name);
-
-    if (!exported)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("attachMovie: '%s': no such exported resource - "
-            "returning undefined"), id_name);
-        );
-        return as_value(); 
-    }
-    
-    SWF::DefinitionTag* exported_movie =
-        dynamic_cast<SWF::DefinitionTag*>(exported.get());
-
-    if (!exported_movie)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("attachMovie: exported resource '%s' "
-            "is not a DisplayObject definition (%s) -- "
-            "returning undefined"), id_name,
-            typeid(*(exported.get())).name());
-        );
-        return as_value();
-    }
-
-    const std::string& newname = fn.arg(1).to_string();
-
-    // Movies should be attachable from -16384 to 2130690045, according to
-    // kirupa (http://www.kirupa.com/developer/actionscript/depths2.htm)
-    // Tests in misc-ming.all/DepthLimitsTest.c show that 2130690044 is the
-    // maximum valid depth.
-    const double depth = fn.arg(2).to_number();
-    
-    // This also checks for overflow, as both numbers are expressible as
-    // boost::int32_t.
-    if (depth < DisplayObject::lowerAccessibleBound ||
-            depth > DisplayObject::upperAccessibleBound)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("MovieClip.attachMovie: invalid depth %d "
-                    "passed; not attaching"), depth);
-        );
-        return as_value();
-    }
-    
-    boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
-
-    boost::intrusive_ptr<DisplayObject> newch =
-        exported_movie->createDisplayObject(movieclip.get(), 0);
-
-#ifndef GNASH_USE_GC
-    assert(newch->get_ref_count() > 0);
-#endif // ndef GNASH_USE_GC
-
-    newch->set_name(newname);
-    newch->setDynamic();
-
-    boost::intrusive_ptr<as_object> initObj;
-
-    if (fn.nargs > 3 ) {
-        initObj = fn.arg(3).to_object();
-        if (!initObj) {
-            // This is actually a valid thing to do,
-            // the documented behaviour is to just NOT
-            // initialize the properties in this
-            // case.
-            IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("Fourth argument of attachMovie doesn't cast to "
-                    "an object (%s), we'll act as if it wasn't given"),
-                    fn.arg(3));
-            );
-        }
-    }
-
-    // placeDisplayObject() will set depth on newch
-    if (!movieclip->attachCharacter(*newch, depthValue, initObj.get()))
-    {
-        log_error(_("Could not attach DisplayObject at depth %d"), depthValue);
-        return as_value();
-    }
-
-    return as_value(newch.get());
-}
-
-
-// attachAudio(id:Object) : Void
-as_value
-movieclip_attachAudio(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (!fn.nargs)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("MovieClip.attachAudio(): %s", _("missing arguments"));
-        );
-        return as_value();
-    }
-
-    as_object* obj = fn.arg(0).to_object().get();
-    if ( ! obj )
-    { 
-        std::stringstream ss; fn.dump_args(ss);
-        // TODO: find out what to do here
-        log_error("MovieClip.attachAudio(%s): first arg doesn't cast to "
-                "an object", ss.str());
-        return as_value();
-    }
-
-    NetStream_as* ns = dynamic_cast<NetStream_as*>(obj);
-    if ( ! ns )
-    { 
-        std::stringstream ss; fn.dump_args(ss);
-        // TODO: find out what to do here
-        log_error("MovieClip.attachAudio(%s): first arg doesn't cast to a "
-                "NetStream", ss.str());
-        return as_value();
-    }
-
-    ns->setAudioController(movieclip.get());
-
-    LOG_ONCE( log_unimpl("MovieClip.attachAudio() - TESTING") );
-    return as_value();
-}
-
-
-// MovieClip.attachVideo
-as_value
-movieclip_attachVideo(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(movieclip);
-
-    LOG_ONCE( log_unimpl("MovieClip.attachVideo()") );
-    return as_value();
-}
-
-
-//createEmptyMovieClip(name:String, depth:Number) : MovieClip
-as_value
-movieclip_createEmptyMovieClip(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs != 2)
-    {
-        if (fn.nargs < 2)
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("createEmptyMovieClip needs "
-                    "2 args, but %d given,"
-                    " returning undefined"),
-                    fn.nargs);
-            );
-            return as_value();
-        }
-        else
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("createEmptyMovieClip takes "
-                    "2 args, but %d given, discarding"
-                    " the excess"),
-                    fn.nargs);
-            )
-        }
-    }
-
-    // Unlike other MovieClip methods, the depth argument of an empty movie 
clip
-    // can be any number. All numbers are converted to an int32_t, and are 
valid
-    // depths even when outside the usual bounds.
-    DisplayObject* ch = movieclip->add_empty_movieclip(fn.arg(0).to_string(),
-            fn.arg(1).to_int());
-    return as_value(ch);
-}
-
-as_value
-movieclip_getDepth(const fn_call& fn)
-{
-    // TODO: make this a DisplayObject::getDepth_method function...
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    const int n = movieclip->get_depth();
-
-    return as_value(n);
-}
-
-//swapDepths(target:Object|target:Number)
-//
-// Returns void.
-as_value
-movieclip_swapDepths(const fn_call& fn)
-{
-
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-
-    const int this_depth = movieclip->get_depth();
-
-    if (fn.nargs < 1)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("%s.swapDepths() needs one arg"), 
movieclip->getTarget());
-        );
-        return as_value();
-    }
-
-    // Lower bound of source depth below which swapDepth has no effect
-    // (below Timeline/static zone)
-    if ( this_depth < DisplayObject::lowerAccessibleBound )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            std::stringstream ss;
-            fn.dump_args(ss);
-            log_aserror(_("%s.swapDepths(%s): won't swap a clip below "
-                    "depth %d (%d)"),
-            movieclip->getTarget(), ss.str(), 
DisplayObject::lowerAccessibleBound,
-                this_depth);
-        );
-        return as_value();
-    }
-
-    typedef boost::intrusive_ptr<DisplayObject> CharPtr;
-    typedef boost::intrusive_ptr<MovieClip> SpritePtr;
-
-    SpritePtr this_parent = dynamic_cast<MovieClip*>(
-            movieclip->get_parent());
-
-    //CharPtr target = NULL;
-    int target_depth = 0;
-
-    // movieclip.swapDepth(movieclip)
-    if ( SpritePtr target_movieclip = fn.arg(0).to_sprite() )
-    {
-        if ( movieclip == target_movieclip )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("%s.swapDepths(%s): invalid call, swapping to 
self?"),
-                movieclip->getTarget(), target_movieclip->getTarget());
-            );
-            return as_value();
-        }
-
-        SpritePtr target_parent =
-            dynamic_cast<MovieClip*>(movieclip->get_parent());
-        if ( this_parent != target_parent )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("%s.swapDepths(%s): invalid call, the two "
-                    "DisplayObjects don't have the same parent"),
-                movieclip->getTarget(), target_movieclip->getTarget());
-            );
-            return as_value();
-        }
-
-        target_depth = target_movieclip->get_depth();
-
-        // Check we're not swapping the our own depth so
-        // to avoid unecessary bounds invalidation and immunizing
-        // the instance from subsequent PlaceObject tags attempting
-        // to transform it.
-        if ( movieclip->get_depth() == target_depth )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                std::stringstream ss; fn.dump_args(ss);
-                log_aserror(_("%s.swapDepths(%s): ignored, source and "
-                    "target DisplayObjects have the same depth %d"),
-                    movieclip->getTarget(), ss.str(), target_depth);
-            );
-            return as_value();
-        }
-    }
-
-    // movieclip.swapDepth(depth)
-    else
-    {
-        double td = fn.arg(0).to_number();
-        if ( isNaN(td) )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            std::stringstream ss; fn.dump_args(ss);
-            log_aserror(_("%s.swapDepths(%s): first argument invalid "
-                "(neither a movieclip nor a number)"),
-                movieclip->getTarget(), ss.str());
-            );
-            return as_value();
-        }
-
-        target_depth = int(td);
-
-        // Check we're not swapping the our own depth so
-        // to avoid unecessary bounds invalidation and immunizing
-        // the instance from subsequent PlaceObjec tags attempting
-        // to transform it.
-        if ( movieclip->get_depth() == target_depth )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            std::stringstream ss; fn.dump_args(ss);
-            log_aserror(_("%s.swapDepths(%s): ignored, DisplayObject already "
-                    "at depth %d"),
-                movieclip->getTarget(), ss.str(), target_depth);
-            );
-            return as_value();
-        }
-
-
-        // TODO : check other kind of validities ?
-
-
-    }
-
-    if ( this_parent )
-    {
-        this_parent->swapDepths(movieclip.get(), target_depth);
-    }
-    else
-    {
-        movie_root& root = movieclip->getVM().getRoot();
-        root.swapLevels(movieclip, target_depth);
-        return as_value();
-    }
-
-    return as_value();
-
-}
-
-// TODO: wrap the functionality in a MovieClip method
-//             and invoke it from here, this should only be a wrapper
-//
-//duplicateMovieClip(name:String, depth:Number, [initObject:Object]) : 
MovieClip
-as_value
-movieclip_duplicateMovieClip(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-    
-    if (fn.nargs < 2)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.duplicateMovieClip() needs 2 or 3 args"));
-                );
-        return as_value();
-    }
-
-    const std::string& newname = fn.arg(0).to_string();
-
-    // Depth as in attachMovie
-    const double depth = fn.arg(1).to_number();
-    
-    // This also checks for overflow, as both numbers are expressible as
-    // boost::int32_t.
-    if (depth < DisplayObject::lowerAccessibleBound ||
-            depth > DisplayObject::upperAccessibleBound)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("MovieClip.duplicateMovieClip: "
-                        "invalid depth %d passed; not duplicating"), depth);
-        );    
-        return as_value();
-    }
-    
-    boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
-
-    boost::intrusive_ptr<MovieClip> ch;
-
-    // Copy members from initObject
-    if (fn.nargs == 3)
-    {
-        boost::intrusive_ptr<as_object> initObject = fn.arg(2).to_object();
-        ch = movieclip->duplicateMovieClip(newname, depthValue,
-                initObject.get());
-    }
-    else
-    {
-        ch = movieclip->duplicateMovieClip(newname, depthValue);
-    }
-
-    return as_value(ch.get());
-}
-
-as_value
-movieclip_gotoAndPlay(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 1)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("movieclip_goto_and_play needs one arg"));
-        );
-        return as_value();
-    }
-
-    size_t frame_number;
-    if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
-    {
-        // No dice.
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("movieclip_goto_and_play('%s') -- invalid frame"),
-                    fn.arg(0));
-        );
-        return as_value();
-    }
-
-    // Convert to 0-based
-    movieclip->goto_frame(frame_number);
-    movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
-    return as_value();
-}
-
-as_value movieclip_gotoAndStop(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 1)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("movieclip_goto_and_stop needs one arg"));
-        );
-        return as_value();
-    }
-
-    size_t frame_number;
-    if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
-    {
-        // No dice.
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("movieclip_goto_and_stop('%s') -- invalid frame"),
-                    fn.arg(0));
-        );
-        return as_value();
-    }
-
-    // Convert to 0-based
-    movieclip->goto_frame(frame_number);
-    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
-    return as_value();
-}
-
-as_value movieclip_nextFrame(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    const size_t frame_count = movieclip->get_frame_count();
-    const size_t current_frame = movieclip->get_current_frame();
-    if (current_frame < frame_count)
-    {
-        movieclip->goto_frame(current_frame + 1);
-    }
-    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
-    return as_value();
-}
-
-as_value
-movieclip_prevFrame(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    const size_t current_frame = movieclip->get_current_frame();
-    if (current_frame > 0)
-    {
-        movieclip->goto_frame(current_frame - 1);
-    }
-    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
-    return as_value();
-}
-
-as_value
-movieclip_getBytesLoaded(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(movieclip->get_bytes_loaded());
-}
-
-as_value
-movieclip_getBytesTotal(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    // @@ horrible uh ?
-    return as_value(movieclip->get_bytes_total());
-}
-
-// MovieClip.loadMovie(url:String [,variables:String]).
-//
-// Returns 1 for "get", 2 for "post", and otherwise 0. Case-insensitive.
-// This *always* calls MovieClip.meth.
-as_value
-movieclip_loadMovie(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    as_value val;
-    if (fn.nargs > 1) {
-        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
-    }
-    else val = movieclip->callMethod(NSV::PROP_METH);
-
-    if (fn.nargs < 1) // url
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.loadMovie() "
-            "expected 1 or 2 args, got %d - returning undefined"),
-            fn.nargs);
-        );
-        return as_value();
-    }
-
-    const std::string& urlstr = fn.arg(0).to_string();
-    if (urlstr.empty())
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("First argument of MovieClip.loadMovie(%s) "
-            "evaluates to an empty string - "
-            "returning undefined"),
-            ss.str());
-        );
-        return as_value();
-    }
-
-    movie_root& mr = movieclip->getVM().getRoot();
-    std::string target = movieclip->getTarget();
-
-    // TODO: if GET/POST should send variables of *this* movie,
-    // no matter if the target will be replaced by another movie !!
-    const MovieClip::VariablesMethod method =
-        static_cast<MovieClip::VariablesMethod>(val.to_int());
-
-    std::string data;
-
-    // This is just an optimization if we aren't going
-    // to send the data anyway. It might be wrong, though.
-    if (method != MovieClip::METHOD_NONE)
-    {
-        movieclip->getURLEncodedVars(data);
-    }
- 
-    mr.loadMovie(urlstr, target, data, method);
-
-    return as_value();
-}
-
-// my_mc.loadVariables(url:String [, variables:String]) : Void
-as_value
-movieclip_loadVariables(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    // This always calls MovieClip.meth, even when there are no
-    // arguments.
-    as_value val;
-    if (fn.nargs > 1)
-    {
-        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
-    }
-    else val = movieclip->callMethod(NSV::PROP_METH);
-
-    if (fn.nargs < 1) // url
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.loadVariables() "
-            "expected 1 or 2 args, got %d - returning undefined"),
-            fn.nargs);
-        );
-        return as_value();
-    }
-
-    const std::string& urlstr = fn.arg(0).to_string();
-    if (urlstr.empty())
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("First argument passed to MovieClip.loadVariables(%s) "
-            "evaluates to an empty string - "
-            "returning undefined"),
-            ss.str());
-        );
-        return as_value();
-    }
-
-    const MovieClip::VariablesMethod method =
-        static_cast<MovieClip::VariablesMethod>(val.to_int());
-
-    movieclip->loadVariables(urlstr, method);
-    log_debug("MovieClip.loadVariables(%s) - TESTING ", urlstr);
-
-    return as_value();
-}
-
-// my_mc.unloadMovie() : Void
-as_value
-movieclip_unloadMovie(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    movieclip->unloadMovie();
-
-    return as_value();
-}
-
-as_value
-movieclip_hitTest(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    switch (fn.nargs)
-    {
-        case 1: // target
-        {
-            const as_value& tgt_val = fn.arg(0);
-            DisplayObject* target = fn.env().find_target(tgt_val.to_string());
-            if ( ! target )
-            {
-                IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("Can't find hitTest target %s"),
-                    tgt_val);
-                );
-                return as_value();
-            }
-
-            rect thisbounds = movieclip->getBounds();
-            SWFMatrix thismat = movieclip->getWorldMatrix();
-            thismat.transform(thisbounds);
-
-            rect tgtbounds = target->getBounds();
-            SWFMatrix tgtmat = target->getWorldMatrix();
-            tgtmat.transform(tgtbounds);
-
-            return thisbounds.getRange().intersects(tgtbounds.getRange());
-
-            break;
-        }
-
-        case 2: // x, y
-        {
-            boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
-            boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
-
-            return movieclip->pointInBounds(x, y);
-        }
-
-        case 3: // x, y, shapeFlag
-        {
-             boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
-             boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
-             bool shapeFlag = fn.arg(2).to_bool();
-
-             if ( ! shapeFlag ) return movieclip->pointInBounds(x, y);
-             else return movieclip->pointInHitableShape(x, y);
-        }
-
-        default:
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("hitTest() called with %u args"),
-                    fn.nargs);
-            );
-            break;
-        }
-    }
-
-    return as_value();
-
-}
-
-as_value
-movieclip_createTextField(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 6) // name, depth, x, y, width, height
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField called with %d args, "
-            "expected 6 - returning undefined"), fn.nargs);
-        );
-        return as_value();
-    }
-
-    std::string txt_name = fn.arg(0).to_string();
-
-    int txt_depth = fn.arg(1).to_int();
-
-    int txt_x = fn.arg(2).to_int();
-
-    int txt_y = fn.arg(3).to_int();
-
-    int txt_width = fn.arg(4).to_int();
-    if ( txt_width < 0 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField: negative width (%d)"
-            " - reverting sign"), txt_width);
-        );
-        txt_width = -txt_width;
-    }
-
-    int txt_height = fn.arg(5).to_int();
-    if ( txt_height < 0 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("createTextField: negative height (%d)"
-            " - reverting sign"), txt_height);
-        );
-        txt_height = -txt_height;
-    }
-
-    boost::intrusive_ptr<DisplayObject> txt = 
movieclip->add_textfield(txt_name,
-            txt_depth, txt_x, txt_y, txt_width, txt_height);
-
-    // createTextField returns void, it seems
-    if ( movieclip->getVM().getSWFVersion() > 7 ) return as_value(txt.get());
-    else return as_value(); 
-}
-
-//getNextHighestDepth() : Number
-as_value
-movieclip_getNextHighestDepth(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    int nextdepth = movieclip->getNextHighestDepth();
-    return as_value(static_cast<double>(nextdepth));
-}
-
-//getInstanceAtDepth(depth:Number) : MovieClip
-as_value
-movieclip_getInstanceAtDepth(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> mc = ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 1)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("MovieClip.getInstanceAtDepth(): missing depth argument");
-        );
-        return as_value();
-    }
-
-    int depth = fn.arg(0).to_int();
-    boost::intrusive_ptr<DisplayObject> ch = 
mc->getDisplayObjectAtDepth(depth);
- 
-    // we want 'undefined', not 'null'
-    if (!ch) return as_value();
-    return as_value(ch.get());
-}
-
-/// MovieClip.getURL(url:String[, window:String[, method:String]])
-//
-/// Tested manually to function as a method of any as_object. Hard to
-/// test automatically as it doesn't return anything and only has external
-/// side-effects.
-/// Returns void.
-as_value
-movieclip_getURL(const fn_call& fn)
-{
-    boost::intrusive_ptr<as_object> movieclip =
-        ensureType<as_object>(fn.this_ptr);
-
-    std::string urlstr;
-    std::string target;
-
-    as_value val;
-    if (fn.nargs > 2)
-    {
-        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(2));
-    }
-    else val = movieclip->callMethod(NSV::PROP_METH);
-
-    switch (fn.nargs)
-    {
-        case 0:
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                log_aserror(_("No arguments passed to MovieClip.getURL()"));
-            );
-            return as_value();
-        }
-        default:
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-                std::ostringstream os;
-                fn.dump_args(os);
-                log_aserror(_("MovieClip.getURL(%s): extra arguments "
-                    "dropped"), os.str());
-            );
-        }
-        case 3:
-            // This argument has already been handled.
-        case 2:
-             target = fn.arg(1).to_string();
-        case 1:
-             urlstr = fn.arg(0).to_string();
-             break;
-    }
-
-
-    MovieClip::VariablesMethod method =
-        static_cast<MovieClip::VariablesMethod>(val.to_int());
-
-    std::string vars;
-
-    if (method != MovieClip::METHOD_NONE) {
-        // Get encoded vars.
-        movieclip->getURLEncodedVars(vars);
-    }
-
-    movie_root& m = movieclip->getVM().getRoot();
-    
-    m.getURL(urlstr, target, vars, method);
-
-    return as_value();
-}
-
-// getSWFVersion() : Number
-as_value
-movieclip_getSWFVersion(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(movieclip->getSWFVersion());
-}
-
-// MovieClip.meth(<string>) : Number
-//
-// Parses case-insensitive "get" and "post" into 1 and 2, 0 anything else
-// 
-as_value
-movieclip_meth(const fn_call& fn)
-{
-
-    if (!fn.nargs) return as_value(MovieClip::METHOD_NONE); 
-
-    const as_value& v = fn.arg(0);
-    boost::intrusive_ptr<as_object> o = v.to_object();
-    if ( ! o )
-    {
-        log_debug(_("meth(%s): first argument doesn't cast to object"), v);
-        return as_value(MovieClip::METHOD_NONE);
-    }
-
-    as_value lc = o->callMethod(NSV::PROP_TO_LOWER_CASE);
-
-    std::string s = lc.to_string();
-
-    if (s == "get") return as_value(MovieClip::METHOD_GET);
-    if (s == "post") return as_value(MovieClip::METHOD_POST);
-    return as_value(MovieClip::METHOD_NONE);
-}
-
-
-// getTextSnapshot() : TextSnapshot
-as_value
-movieclip_getTextSnapshot(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> obj = ensureType<MovieClip>(fn.this_ptr);
-
-    // If not found, construction fails.
-    as_value textSnapshot(fn.env().find_object("TextSnapshot"));
-
-    boost::intrusive_ptr<as_function> tsCtor = textSnapshot.to_as_function();
-
-    if (!tsCtor) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror("MovieClip.getTextSnapshot: failed to construct "
-                "TextSnapshot (object probably overridden)");
-        );
-        return as_value();
-    }
-
-    // Construct a flash.geom.Transform object with "this" as argument.
-    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
-    args->push_back(obj.get());
-
-    boost::intrusive_ptr<as_object> ts =
-        tsCtor->constructInstance(fn.env(), args);
-
-    return as_value(ts.get());
-}
-
-
-// getBounds(targetCoordinateSpace:Object) : Object
-as_value
-movieclip_getBounds(const fn_call& fn)
-{
-    boost::intrusive_ptr<DisplayObject> movieclip =
-        ensureType<DisplayObject>(fn.this_ptr);
-
-    rect bounds = movieclip->getBounds();
-
-    if ( fn.nargs > 0 )
-    {
-        DisplayObject* target = fn.arg(0).toDisplayObject();
-        if ( ! target )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("MovieClip.getBounds(%s): invalid call, first "
-                    "arg must be a DisplayObject"),
-                fn.arg(0));
-            );
-            return as_value();
-        }
-
-        SWFMatrix tgtwmat = target->getWorldMatrix();
-        SWFMatrix srcwmat = movieclip->getWorldMatrix();
-
-        srcwmat.transform(bounds);
-        tgtwmat.invert().transform(bounds);
-    }
-
-    // Magic numbers here... dunno why
-    double xMin = 6710886.35;
-    double yMin = 6710886.35;
-    double xMax = 6710886.35;
-    double yMax = 6710886.35;
-
-    if ( !bounds.is_null() )
-    {
-        // Round to the twip
-        xMin = twipsToPixels(bounds.get_x_min());
-        yMin = twipsToPixels(bounds.get_y_min());
-        xMax = twipsToPixels(bounds.get_x_max());
-        yMax = twipsToPixels(bounds.get_y_max());
-    }
-
-    boost::intrusive_ptr<as_object> bounds_obj(new as_object());
-    bounds_obj->init_member("xMin", as_value(xMin));
-    bounds_obj->init_member("yMin", as_value(yMin));
-    bounds_obj->init_member("xMax", as_value(xMax));
-    bounds_obj->init_member("yMax", as_value(yMax));
-
-    return as_value(bounds_obj.get());
-}
-
-as_value
-movieclip_globalToLocal(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    as_value ret;
-
-    if ( fn.nargs < 1 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.globalToLocal() takes one arg"));
-        );
-        return ret;
-    }
-
-    boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
-    if ( ! obj )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.globalToLocal(%s): "
-                "first argument doesn't cast to an object"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-
-    as_value tmp;
-    boost::int32_t    x = 0;
-    boost::int32_t    y = 0;
-
-    if ( ! obj->get_member(NSV::PROP_X, &tmp) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.globalToLocal(%s): "
-                "object parameter doesn't have an 'x' member"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-    x = pixelsToTwips(tmp.to_number());
-
-    if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.globalToLocal(%s): "
-                "object parameter doesn't have an 'y' member"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-    y = pixelsToTwips(tmp.to_number());
-
-    point    pt(x, y);
-    SWFMatrix world_mat = movieclip->getWorldMatrix();
-    world_mat.invert().transform(pt);
-
-    obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
-    obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
-
-    return ret;
-}
-
-as_value
-movieclip_localToGlobal(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    as_value ret;
-
-    if ( fn.nargs < 1 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.localToGlobal() takes one arg"));
-        );
-        return ret;
-    }
-
-    boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
-    if ( ! obj )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.localToGlobal(%s): "
-                "first argument doesn't cast to an object"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-
-    as_value tmp;
-    boost::int32_t    x = 0;
-    boost::int32_t    y = 0;
-
-    if ( ! obj->get_member(NSV::PROP_X, &tmp) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.localToGlobal(%s): "
-                "object parameter doesn't have an 'x' member"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-    x = pixelsToTwips(tmp.to_number());
-
-    if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("MovieClip.localToGlobal(%s): "
-                "object parameter doesn't have an 'y' member"),
-            fn.arg(0));
-        );
-        return ret;
-    }
-    y = pixelsToTwips(tmp.to_number());
-
-    point    pt(x, y);
-    SWFMatrix world_mat = movieclip->getWorldMatrix();
-    world_mat.transform(pt);
-
-    obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
-    obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
-    return ret;
-
-}
-
-as_value
-movieclip_setMask(const fn_call& fn)
-{
-    // swfdec/test/image/mask-textfield-6.swf shows that setMask should also
-    // work against TextFields, we have no tests for other DisplayObject types 
so
-    // we generalize it for any DisplayObject.
-    boost::intrusive_ptr<DisplayObject> maskee = 
-        ensureType<DisplayObject>(fn.this_ptr);
-
-    if ( ! fn.nargs )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("%s.setMask() : needs an argument"), 
maskee->getTarget());
-        );
-        return as_value();
-    }
-
-    const as_value& arg = fn.arg(0);
-    if ( arg.is_null() || arg.is_undefined() )
-    {
-        // disable mask
-        maskee->setMask(NULL);
-    }
-    else
-    {
-
-        boost::intrusive_ptr<as_object> obj ( arg.to_object() );
-        DisplayObject* mask = dynamic_cast<DisplayObject*>(obj.get());
-        if ( ! mask )
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("%s.setMask(%s) : first argument is not a 
DisplayObject"),
-                maskee->getTarget(), arg);
-            );
-            return as_value();
-        }
-
-        // ch is possibly NULL, which is intended
-        maskee->setMask(mask);
-    }
-
-    //log_debug("MovieClip.setMask() TESTING");
-
-    return as_value(true);
-}
-
-as_value
-movieclip_endFill(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.endFill(%s): args will be discarded"),
-            ss.str());
-    }
-    );
-#ifdef DEBUG_DRAWING_API
-    log_debug("%s.endFill();", movieclip->getTarget());
-#endif
-    movieclip->endFill();
-    return as_value();
-}
-
-as_value
-movieclip_lineTo(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    if ( fn.nargs < 2 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("MovieClip.lineTo() needs at least two arguments"));
-        );
-        return as_value();
-    }
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 2 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.lineTo(%s): args after the first two "
-                        "will be discarded"), ss.str());
-    }
-    );
-
-    double x = fn.arg(0).to_number();
-    double y = fn.arg(1).to_number();
-        
-    if (!isFinite(x) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.lineTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        x = 0;
-    }
-     
-    if (!isFinite(y) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.lineTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        y = 0;
-    }
-
-#ifdef DEBUG_DRAWING_API
-    log_debug("%s.lineTo(%g,%g);", movieclip->getTarget(), x, y);
-#endif
-    movieclip->lineTo(pixelsToTwips(x), pixelsToTwips(y));
-    return as_value();
-}
-
-as_value
-movieclip_moveTo(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if ( fn.nargs < 2 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("MovieClip.moveTo() takes two args"));
-        );
-        return as_value();
-    }
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 2 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.moveTo(%s): args after the first two will "
-                        "be discarded"), ss.str());
-    }
-    );
-
-    double x = fn.arg(0).to_number();
-    double y = fn.arg(1).to_number();
-     
-    if (!isFinite(x) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.moveTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        x = 0;
-    }
-     
-    if (!isFinite(y) )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.moveTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        y = 0;
-    }
-
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.moveTo(%g,%g);"), movieclip->getTarget(), x, y);
-#endif
-    movieclip->moveTo(pixelsToTwips(x), pixelsToTwips(y));
-    return as_value();
-}
-
-// SWF6,7: lineStyle(thickness:Number, rgb:Number, alpha:Number) : Void
-//
-//    SWF8+: lineStyle(thickness:Number, rgb:Number, alpha:Number,
-//                                     pixelHinting:Boolean, noScale:String,
-//                                     capsStyle:String, jointStyle:String,
-//                                     miterLimit:Number) : Void
-as_value
-movieclip_lineStyle(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    if ( ! fn.nargs )
-    {
-        movieclip->resetLineStyle();
-        return as_value();
-    }
-
-    boost::uint8_t r = 0;
-    boost::uint8_t g = 0;
-    boost::uint8_t b = 0;
-    boost::uint8_t a = 255;
-    boost::uint16_t thickness = 0;
-    bool scaleThicknessVertically = true;
-    bool scaleThicknessHorizontally = true;
-    bool pixelHinting = false;
-    bool noClose = false;
-    cap_style_e capStyle = CAP_ROUND;
-    join_style_e joinStyle = JOIN_ROUND;
-    float miterLimitFactor = 1.0f;
-
-    int arguments = fn.nargs;
-
-    const int swfVersion = movieclip->getVM().getSWFVersion();
-    if (swfVersion < 8 && fn.nargs > 3)
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            std::ostringstream ss;
-            fn.dump_args(ss);
-            log_aserror(_("MovieClip.lineStyle(%s): args after the "
-                          "first three will be discarded"), ss.str());
-            );
-        arguments = 3;
-    }
-
-    switch (arguments)
-    {
-        default:
-            IF_VERBOSE_ASCODING_ERRORS(
-                std::ostringstream ss;
-                fn.dump_args(ss);
-                log_aserror(_("MovieClip.lineStyle(%s): args after the "
-                              "first eight will be discarded"), ss.str());
-                );
-        case 8:
-            miterLimitFactor = clamp<int>(fn.arg(7).to_int(), 1, 255);
-        case 7:
-        {
-            std::string joinStyleStr = fn.arg(6).to_string();
-            if (joinStyleStr == "miter") joinStyle = JOIN_MITER;
-            else if (joinStyleStr == "round") joinStyle = JOIN_ROUND;
-            else if (joinStyleStr == "bevel") joinStyle = JOIN_BEVEL;
-            else
-            {
-                IF_VERBOSE_ASCODING_ERRORS(
-                    std::ostringstream ss;
-                    fn.dump_args(ss);
-                    log_aserror(_("MovieClip.lineStyle(%s): invalid joinStyle"
-                                "value '%s' (valid values: %s|%s|%s)"),
-                        ss.str(), joinStyleStr, "miter", "round", "bevel");
-                );
-            }
-        }
-        case 6:
-        {
-            const std::string capStyleStr = fn.arg(5).to_string();
-            if (capStyleStr == "none") capStyle = CAP_NONE;
-            else if (capStyleStr == "round") capStyle = CAP_ROUND;
-            else if (capStyleStr == "square") capStyle = CAP_SQUARE;
-            else
-            {
-                IF_VERBOSE_ASCODING_ERRORS(
-                    std::ostringstream ss;
-                    fn.dump_args(ss);
-                    log_aserror(_("MovieClip.lineStyle(%s): invalid capStyle "
-                               "value '%s' (valid values: none|round|square)"),
-                               ss.str(), capStyleStr);
-                );
-            }
-        }
-        case 5:
-        {
-            // Both values to be set here are true, so just set the
-            // appropriate values to false.
-            const std::string noScaleString = fn.arg(4).to_string();
-            if (noScaleString == "none")
-            {
-                scaleThicknessVertically = false;
-                scaleThicknessHorizontally = false;
-            }
-            else if (noScaleString == "vertical")
-            {
-                scaleThicknessVertically = false;
-            }
-            else if (noScaleString == "horizontal")
-            {
-                scaleThicknessHorizontally = false;
-            }
-            else if (noScaleString != "normal")
-            {
-                IF_VERBOSE_ASCODING_ERRORS(
-                    std::ostringstream ss;
-                    fn.dump_args(ss);
-                    log_aserror(_("MovieClip.lineStyle(%s): invalid "
-                                    "noScale value '%s' (valid values: "
-                                    "%s|%s|%s|%s)"),
-                                    ss.str(), noScaleString, "none",
-                                    "vertical", "horizontal", "normal");
-                );
-            }
-        }
-        case 4:
-            pixelHinting = fn.arg(3).to_bool();
-        case 3:
-        {
-            const float alphaval = clamp<float>(fn.arg(2).to_number(),
-                                     0, 100);
-            a = boost::uint8_t(255 * (alphaval / 100));
-        }
-        case 2:
-        {
-            // See pollock.swf for eventual regressions.
-            // It sets color to a random number from
-            // 0 to 160000000 (about 10 times more then the max).
-            boost::uint32_t rgbval = fn.arg(1).to_int();
-            r = boost::uint8_t((rgbval & 0xFF0000) >> 16);
-            g = boost::uint8_t((rgbval & 0x00FF00) >> 8);
-            b = boost::uint8_t((rgbval & 0x0000FF) );
-        }
-        case 1:
-            thickness = boost::uint16_t(pixelsToTwips(clamp<float>(
-                            fn.arg(0).to_number(), 0, 255)));
-            break;
-    }
-
-    rgba color(r, g, b, a);
-
-#ifdef DEBUG_DRAWING_API
-    log_debug("%s.lineStyle(%d,%d,%d,%d);", movieclip->getTarget(), thickness, 
r, g, b);
-#endif
-    movieclip->lineStyle(thickness, color,
-    scaleThicknessVertically, scaleThicknessHorizontally,
-    pixelHinting, noClose, capStyle, capStyle, joinStyle, miterLimitFactor);
-
-    return as_value();
-}
-
-as_value
-movieclip_curveTo(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-            ensureType<MovieClip>(fn.this_ptr);
-
-    if ( fn.nargs < 4 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("MovieClip.curveTo() takes four args"));
-        );
-        return as_value();
-    }
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 4 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.curveTo(%s): args after the first four "
-                "will be discarded"), ss.str());
-    }
-    );
-
-    double cx = fn.arg(0).to_number();
-    double cy = fn.arg(1).to_number();
-    double ax = fn.arg(2).to_number();
-    double ay = fn.arg(3).to_number();
-
-    if (!isFinite(cx))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite first argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        cx = 0;
-    }
-     
-    if (!isFinite(cy))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite second argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        cy = 0;
-    }
-
-    if (!isFinite(ax))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite third argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(0));
-        );
-        ax = 0;
-    }
-     
-    if (!isFinite(ay))
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.curveTo(%s) : non-finite fourth argument (%s), "
-            "converted to zero"), movieclip->getTarget(),
-            ss.str(), fn.arg(1));
-        );
-        ay = 0;
-    }
-
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.curveTo(%g,%g,%g,%g);"), movieclip->getTarget(),
-            cx, cy, ax, ay);
-#endif
-    movieclip->curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
-            pixelsToTwips(ax), pixelsToTwips(ay));
-
-    return as_value();
-}
-
-as_value
-movieclip_clear(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.clear(%s): args will be discarded"),
-            ss.str());
-    }
-    );
-
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.clear();"), movieclip->getTarget());
-#endif
-    movieclip->clear();
-
-    return as_value();
-}
-
-as_value
-movieclip_beginFill(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    boost::uint8_t r = 0;
-    boost::uint8_t g = 0;
-    boost::uint8_t b = 0;
-    boost::uint8_t a = 255;
-
-    if ( fn.nargs > 0 )
-    {
-        // 2^24 is the max here
-        boost::uint32_t rgbval = boost::uint32_t(
-                clamp<float>(fn.arg(0).to_number(), 0, 16777216));
-        r = boost::uint8_t( (rgbval&0xFF0000) >> 16);
-        g = boost::uint8_t( (rgbval&0x00FF00) >> 8);
-        b = boost::uint8_t( (rgbval&0x0000FF) );
-
-        if ( fn.nargs > 1 )
-        {
-            a = 255 * clamp<int>(fn.arg(1).to_int(), 0, 100) / 100;
-            IF_VERBOSE_ASCODING_ERRORS(
-            if ( fn.nargs > 2 )
-            {
-                std::stringstream ss; fn.dump_args(ss);
-                log_aserror(_("MovieClip.beginFill(%s): args after the "
-                        "first will be discarded"), ss.str());
-            }
-            );
-        }
-
-    }
-
-    rgba color(r, g, b, a);
-
-#ifdef DEBUG_DRAWING_API
-    log_debug(_("%s.beginFill(%d,%d,%d);"), movieclip->getTarget(), r, g, b);
-#endif
-    movieclip->beginFill(color);
-
-    return as_value();
-}
-
-as_value
-movieclip_beginGradientFill(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    if ( fn.nargs < 5 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.beginGradientFill(%s): invalid call: 5 arguments "
-                "needed"),
-            movieclip->getTarget(), ss.str());
-        );
-        return as_value();
-    }
-
-    IF_VERBOSE_ASCODING_ERRORS(
-    if ( fn.nargs > 5 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("MovieClip.beginGradientFill(%s): args after "
-                        "the first five will be discarded"), ss.str());
-    }
-    );
-
-    bool radial = false;
-    std::string typeStr = fn.arg(0).to_string();
-    // Case-sensitive comparison needed for this ...
-    if ( typeStr == "radial" ) radial = true;
-    else if ( typeStr == "linear" ) radial = false;
-    else
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.beginGradientFill(%s): first arg must be "
-            "'radial' or 'linear'"),
-            movieclip->getTarget(), ss.str());
-        );
-        return as_value();
-    }
-
-    typedef boost::intrusive_ptr<as_object> ObjPtr;
-
-    ObjPtr colors = fn.arg(1).to_object();
-    ObjPtr alphas = fn.arg(2).to_object();
-    ObjPtr ratios = fn.arg(3).to_object();
-    ObjPtr matrixArg = fn.arg(4).to_object();
-
-    if ( ! colors || ! alphas || ! ratios || ! matrixArg )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.beginGradientFill(%s): one or more of the "
-            " args from 2nd to 5th don't cast to objects"),
-            movieclip->getTarget(), ss.str());
-        );
-        return as_value();
-    }
-
-    // ----------------------------
-    // Parse SWFMatrix
-    // ----------------------------
-    
-    //
-    // TODO: fix the SWFMatrix build-up, it is NOT correct for
-    //             rotation.
-    //             For the "boxed" SWFMatrixType and radial fills this
-    //             is not a problem as this code just discards the
-    //             rotation (which doesn't make sense), but for
-    //             the explicit SWFMatrix type (a..i) it is a problem.
-    //             The whole code can likely be simplified by 
-    //             always transforming the gnash gradients to the
-    //             expected gradients and subsequently applying
-    //             user-specified SWFMatrix; for 'boxed' SWFMatrixType
-    //             this simplification would increas cost, but
-    //             it's too early to apply optimizations to the
-    //             code (correctness first!!).
-    //
-
-    SWFMatrix mat;
-    SWFMatrix input_matrix;
-
-    if ( matrixArg->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box" )
-    {
-        
-        boost::int32_t valX = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_X).to_number()); 
-        boost::int32_t valY = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_Y).to_number()); 
-        boost::int32_t valW = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_W).to_number()); 
-        boost::int32_t valH = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_H).to_number()); 
-        float valR = matrixArg->getMember(NSV::PROP_R).to_number(); 
-
-        if ( radial )
-        {
-            // Radial gradient is 64x64 twips.
-            input_matrix.set_scale(64.0/valW, 64.0/valH);
-
-            // For radial gradients, dunno why translation must be negative...
-            input_matrix.concatenate_translation( -valX, -valY );
-
-            // NOTE: rotation is intentionally discarded as it would
-            //             have no effect (theoretically origin of the radial
-            //             fill is at 0,0 making any rotation meaningless).
-
-        }
-        else
-        {
-            // Linear gradient is 256x1 twips.
-            //
-            // No idea why we should use the 256 value for Y scale, but 
-            // empirically seems to give closer results. Note that it only
-            // influences rotation, which is still not correct...
-            // TODO: fix it !
-            input_matrix.set_scale_rotation(256.0/valW, 256.0/valH, -valR);
-
-            // For linear gradients, dunno why translation must be negative...
-            input_matrix.concatenate_translation( -valX, -valY );
-        }
-
-        mat.concatenate(input_matrix);
-    }
-    else
-    {
-        float valA = matrixArg->getMember(NSV::PROP_A).to_number() ; // xx
-        float valB = matrixArg->getMember(NSV::PROP_B).to_number() ; // yx
-        float valD = matrixArg->getMember(NSV::PROP_D).to_number() ; // xy
-        float valE = matrixArg->getMember(NSV::PROP_E).to_number() ; // yy
-        boost::int32_t valG = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_G).to_number()); // x0
-        boost::int32_t valH = pixelsToTwips(
-                matrixArg->getMember(NSV::PROP_H).to_number()); // y0
-
-        input_matrix.sx    = valA * 65536; // sx
-        input_matrix.shx = valB * 65536; // shy
-        input_matrix.shy = valD * 65536; // shx
-        input_matrix.sy    = valE * 65536; // sy
-        input_matrix.tx = valG; // x0
-        input_matrix.ty = valH; // y0
-
-        // This is the SWFMatrix that would transform the gnash
-        // gradient to the expected flash gradient.
-        // Transformation is different for linear and radial
-        // gradient for Gnash (in flash they should be the same)
-        SWFMatrix gnashToFlash;
-
-        if ( radial )
-        {
-
-            // Gnash radial gradients are 64x64 with center at 32,32
-            // Should be 20x20 with center at 0,0
-            const double g2fs = 20.0/64.0; // gnash to flash scale
-            gnashToFlash.set_scale(g2fs, g2fs);
-            gnashToFlash.concatenate_translation(-32, -32);
-
-        }
-        else
-        {
-            // First define a SWFMatrix that would transform
-            // the gnash gradient to the expected flash gradient:
-            // this means translating our gradient to put the
-            // center of gradient at 0,0 and then scale it to
-            // have a size of 20x20 instead of 256x1 as it is
-            //
-            // Gnash linear gradients are 256x1 with center at 128,0
-            // Should be 20x20 with center at 0,0
-            gnashToFlash.set_scale(20.0/256.0, 20.0/1);
-            gnashToFlash.concatenate_translation(-128, 0);
-
-        }
-
-        // Apply gnash to flash SWFMatrix before user-defined one
-        input_matrix.concatenate(gnashToFlash);
-
-        // Finally, and don't know why, take
-        // the inverse of the resulting SWFMatrix as
-        // the one which would be used.
-        mat = input_matrix;
-        mat.invert();
-    }
-
-    // ----------------------------
-    // Create the gradients vector
-    // ----------------------------
-
-    size_t ngradients = colors->getMember(NSV::PROP_LENGTH).to_int();
-    // Check length compatibility of all args
-    if ( ngradients != (size_t)alphas->getMember(NSV::PROP_LENGTH).to_int() ||
-        ngradients != (size_t)ratios->getMember(NSV::PROP_LENGTH).to_int() )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror(_("%s.beginGradientFill(%s): colors, alphas and "
-            "ratios args don't have same length"),
-            movieclip->getTarget(), ss.str());
-        );
-        return as_value();
-    }
-
-    // TODO: limit ngradients to a max ?
-    if ( ngradients > 8 )
-    {
-        std::stringstream ss; fn.dump_args(ss);
-        log_debug(_("%s.beginGradientFill(%s) : too many array elements"
-            " for colors and ratios (%d), will trim to 8"), 
-            movieclip->getTarget(), ss.str(), ngradients); 
-        ngradients = 8;
-    }
-
-    VM& vm = movieclip->getVM();
-    string_table& st = vm.getStringTable();
-
-    std::vector<gradient_record> gradients;
-    gradients.reserve(ngradients);
-    for (size_t i=0; i<ngradients; ++i)
-    {
-
-        string_table::key key = st.find(boost::lexical_cast<std::string>(i));
-
-        as_value colVal = colors->getMember(key);
-        boost::uint32_t col = colVal.is_number() ? colVal.to_int() : 0;
-
-        as_value alpVal = alphas->getMember(key);
-        boost::uint8_t alp = alpVal.is_number() ? 
-            clamp<int>(alpVal.to_int(), 0, 255) : 0;
-
-        as_value ratVal = ratios->getMember(key);
-        boost::uint8_t rat = ratVal.is_number() ? 
-            clamp<int>(ratVal.to_int(), 0, 255) : 0;
-
-        rgba color;
-        color.parseRGB(col);
-        color.m_a = alp;
-
-        gradients.push_back(gradient_record(rat, color));
-    }
-
-    if ( radial )
-    {
-        movieclip->beginRadialGradientFill(gradients, mat);
-    }
-    else
-    {
-        movieclip->beginLinearGradientFill(gradients, mat);
-    }
-
-    LOG_ONCE( log_debug("MovieClip.beginGradientFill() TESTING") );
-    return as_value();
-}
-
-// startDrag([lockCenter:Boolean], [left:Number], [top:Number],
-//    [right:Number], [bottom:Number]) : Void`
-as_value
-movieclip_startDrag(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    drag_state st;
-    st.setCharacter( movieclip.get() );
-
-    // mark this DisplayObject is transformed.
-    movieclip->transformedByScript();
-
-    if ( fn.nargs )
-    {
-        st.setLockCentered( fn.arg(0).to_bool() );
-
-        if ( fn.nargs >= 5)
-        {
-            double x0 = fn.arg(1).to_number();
-            double y0 = fn.arg(2).to_number();
-            double x1 = fn.arg(3).to_number();
-            double y1 = fn.arg(4).to_number();
-
-            // check for infinite values
-            bool gotinf = false;
-            if (!isFinite(x0) ) { x0=0; gotinf=true; }
-            if (!isFinite(y0) ) { y0=0; gotinf=true; }
-            if (!isFinite(x1) ) { x1=0; gotinf=true; }
-            if (!isFinite(y1) ) { y1=0; gotinf=true; }
-
-            // check for swapped values
-            bool swapped = false;
-            if ( y1 < y0 )
-            {
-                std::swap(y1, y0);
-                swapped = true;
-            }
-
-            if ( x1 < x0 )
-            {
-                std::swap(x1, x0);
-                swapped = true;
-            }
-
-            IF_VERBOSE_ASCODING_ERRORS(
-                if ( gotinf || swapped ) {
-                    std::stringstream ss; fn.dump_args(ss);
-                    if ( swapped ) { 
-                        log_aserror(_("min/max bbox values in "
-                            "MovieClip.startDrag(%s) swapped, fixing"),
-                            ss.str());
-                    }
-                    if ( gotinf ) {
-                        log_aserror(_("non-finite bbox values in "
-                            "MovieClip.startDrag(%s), took as zero"),
-                            ss.str());
-                    }
-                }
-            );
-
-            rect bounds(pixelsToTwips(x0), pixelsToTwips(y0),
-                    pixelsToTwips(x1), pixelsToTwips(y1));
-            st.setBounds(bounds);
-        }
-    }
-
-    movieclip->getVM().getRoot().set_drag_state(st);
-
-    return as_value();
-}
-
-// stopDrag() : Void
-as_value
-movieclip_stopDrag(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    movieclip->getVM().getRoot().stop_drag();
-
-    return as_value();
-}
-
-
-as_value
-movieclip_beginBitmapFill(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-    LOG_ONCE( log_unimpl (__FUNCTION__) );
-    return as_value();
-}
-
-
-as_value
-movieclip_getRect(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-    LOG_ONCE( log_unimpl (__FUNCTION__) );
-    return as_value();
-}
-
-
-as_value
-movieclip_lineGradientStyle(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-    LOG_ONCE( log_unimpl (__FUNCTION__) );
-    return as_value();
-}
-
-
-as_value
-movieclip_attachBitmap(const fn_call& fn)
-{
-
-    GNASH_REPORT_FUNCTION;
-
-    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
-    if (fn.nargs < 2) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_debug("MovieClip.attachBitmap: expected 2 args, got %d",
-                fn.nargs);
-        );
-        return as_value();
-    }
-
-    as_object* obj = fn.arg(0).to_object().get();
-    boost::intrusive_ptr<BitmapData_as> bd = dynamic_cast<BitmapData_as*>(obj);
-
-    if (!bd) {
-        IF_VERBOSE_ASCODING_ERRORS(
-            log_debug("MovieClip.attachBitmap: first argument should be a "
-                "BitmapData", fn.arg(1));
-        );
-        return as_value();
-    }
-
-    int depth = fn.arg(1).to_int();
-
-    ptr->attachBitmap(bd, depth);
-
-    return as_value();
-}
-
-
-as_value
-movieclip_ctor(const fn_call& /* fn */)
-{
-    boost::intrusive_ptr<as_object> clip = 
-        new as_object(getMovieClipInterface());
-
-    return as_value(clip.get());
-}
-
-
-as_value
-movieclip_currentframe_get(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(std::min(ptr->get_loaded_frames(),
-                ptr->get_current_frame() + 1));
-}
-
-as_value
-movieclip_totalframes_get(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(ptr->get_frame_count());
-}
-
-as_value
-movieclip_framesloaded_get(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(ptr->get_loaded_frames());
-}
-
-as_value
-movieclip_droptarget_getset(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-
-    return ptr->getDropTarget();
-}
-
-as_value
-movieclip_url_getset(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
-    return as_value(ptr->get_root()->url());
-}
-
-// TODO: move this to DisplayObject class, _focusrect seems a generic property
-as_value
-movieclip_focusrect_getset(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        // Is a yellow rectangle visible around a focused movie clip (?)
-        // We don't support focuserct settings
-        return as_value(false);
-    }
-    else // setter
-    {
-        LOG_ONCE( log_unimpl("MovieClip._focusrect setting") );
-    }
-    return as_value();
-}
-
-as_value
-movieclip_soundbuftime_getset(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = 
-        ensureType<MovieClip>(fn.this_ptr);
-    UNUSED(ptr);
-
-    if ( fn.nargs == 0 ) // getter
-    {
-        // Number of seconds before sound starts to stream.
-        return as_value(0.0);
-    }
-    else // setter
-    {
-        LOG_ONCE( log_unimpl("MovieClip._soundbuftime setting") );
-    }
-    return as_value();
-}
-
-as_value
-movieclip_transform(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
-
-    // If not found, construction fails.
-    as_value transform(fn.env().find_object("flash.geom.Transform"));
-
-    boost::intrusive_ptr<as_function> transCtor = transform.to_as_function();
-
-    if (!transCtor) {
-        log_error("Failed to construct flash.geom.Transform!");
-        return as_value();
-    }
-
-    // Construct a flash.geom.Transform object with "this" as argument.
-    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
-    args->push_back(ptr.get());
-
-    boost::intrusive_ptr<as_object> newTrans =
-        transCtor->constructInstance(fn.env(), args);
-
-    return as_value(newTrans.get());
-}
-
-/// Properties (and/or methods) attached to every *instance* of a MovieClip 
-void
-attachMovieClipProperties(DisplayObject& o)
-{
-    //int target_version = o.getVM().getSWFVersion();
-
-    // This is a normal property, can be overridden, deleted and enumerated
-    // See swfdec/test/trace/movieclip-version-#.swf for why we only
-    // initialize this if we don't have a parent
-    if (!o.get_parent()) o.init_member("$version",
-            o.getVM().getPlayerVersion(), 0); 
-
-    as_c_function_ptr gettersetter;
-
-    gettersetter = DisplayObject::x_getset;
-    o.init_property(NSV::PROP_uX, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::y_getset;
-    o.init_property(NSV::PROP_uY, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::xscale_getset;
-    o.init_property(NSV::PROP_uXSCALE, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::yscale_getset;
-    o.init_property(NSV::PROP_uYSCALE, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::xmouse_get;
-    o.init_readonly_property(NSV::PROP_uXMOUSE, gettersetter);
-
-    gettersetter = DisplayObject::ymouse_get;
-    o.init_readonly_property(NSV::PROP_uYMOUSE, gettersetter);
-
-    gettersetter = DisplayObject::alpha_getset;
-    o.init_property(NSV::PROP_uALPHA, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::visible_getset;
-    o.init_property(NSV::PROP_uVISIBLE, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::width_getset;
-    o.init_property(NSV::PROP_uWIDTH, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::height_getset;
-    o.init_property(NSV::PROP_uHEIGHT, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::rotation_getset;
-    o.init_property(NSV::PROP_uROTATION, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::parent_getset;
-    o.init_property(NSV::PROP_uPARENT, gettersetter, gettersetter);
-
-    gettersetter = movieclip_currentframe_get;
-    o.init_property(NSV::PROP_uCURRENTFRAME, gettersetter, gettersetter);
-
-    gettersetter = movieclip_totalframes_get;
-    o.init_property(NSV::PROP_uTOTALFRAMES, gettersetter, gettersetter);
-
-    gettersetter = movieclip_framesloaded_get;
-    o.init_property(NSV::PROP_uFRAMESLOADED, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::target_getset;
-    o.init_property(NSV::PROP_uTARGET, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::name_getset;
-    o.init_property(NSV::PROP_uNAME, gettersetter, gettersetter);
-
-    gettersetter = movieclip_droptarget_getset;
-    o.init_property(NSV::PROP_uDROPTARGET, gettersetter, gettersetter);
-
-    gettersetter = movieclip_url_getset;
-    o.init_property(NSV::PROP_uURL, gettersetter, gettersetter);
-
-    gettersetter = DisplayObject::quality;
-    o.init_property(NSV::PROP_uQUALITY, gettersetter, gettersetter);
-    
-    gettersetter = DisplayObject::highquality;
-    o.init_property(NSV::PROP_uHIGHQUALITY, gettersetter, gettersetter);
-
-    gettersetter = movieclip_focusrect_getset;
-    o.init_property(NSV::PROP_uFOCUSRECT, gettersetter, gettersetter);
-
-    gettersetter = movieclip_soundbuftime_getset;
-    o.init_property(NSV::PROP_uSOUNDBUFTIME, gettersetter, gettersetter);
-
-}
-
-as_object*
-getMovieClipInterface()
-{
-    static boost::intrusive_ptr<as_object> proto;
-    if ( proto == NULL )
-    {
-        proto = new as_object(getObjectInterface());
-        VM& vm = VM::get();
-        vm.addStatic(proto.get());
-        registerNatives(vm);
-        attachMovieClipInterface(*proto);
-        //proto->init_member("constructor", new 
builtin_function(movieclip_ctor));
-    }
-    return proto.get();
-}
-
-} // anonymous namespace
-
-
-
 } // namespace gnash

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2009-06-09 07:59:09 +0000
+++ b/libcore/MovieClip.h       2009-06-16 05:42:44 +0000
@@ -988,9 +988,6 @@
     bool _lockroot;
 };
 
-/// Initialize the global MovieClip class
-void movieclip_class_init(as_object& global);
-
 } // end of namespace gnash
 
 #endif // GNASH_SPRITE_INSTANCE_H

=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp     2009-06-09 15:51:03 +0000
+++ b/libcore/TextField.cpp     2009-06-16 05:42:44 +0000
@@ -2700,8 +2700,7 @@
 
     as_object* obj = 0;
 
-    if ( vm.getSWFVersion() < 9 )
-    {
+    if (!isAS3(fn)) {
         // We should attach more properties to the prototype on first
         // instantiation.
         // TODO: this also attaches properties to the SWF5 prototype but makes
@@ -2710,8 +2709,7 @@
 
         obj = new as_object(proto);
     }
-    else
-    {
+    else {
         rect nullRect;
         obj = new TextField(0, nullRect);
     }

=== modified file 'libcore/as_object.cpp'
--- a/libcore/as_object.cpp     2009-06-03 16:05:40 +0000
+++ b/libcore/as_object.cpp     2009-06-16 05:45:41 +0000
@@ -380,8 +380,9 @@
                as_object* owner = 0;
                string_table& st = vm.getStringTable();
                string_table::key k = st.find(fname);
-               /*Property* p =*/ findProperty(k, 0, &owner);
-               if ( owner != this ) proto = owner; // should be 0 if 
findProperty returned 0
+               findProperty(k, 0, &owner);
+        // should be 0 if findProperty returned 0
+               if (owner != this) proto = owner; 
        }
 
        // proto's __proto__ is superProto 

=== modified file 'libcore/asobj/Global.cpp'
--- a/libcore/asobj/Global.cpp  2009-06-12 19:37:55 +0000
+++ b/libcore/asobj/Global.cpp  2009-06-16 05:42:44 +0000
@@ -47,6 +47,7 @@
 #include "flash/xml/XMLDocument_as.h"
 #include "flash/net/XMLSocket_as.h"
 #include "flash/ui/Mouse_as.h"
+#include "flash/display/MovieClip_as.h"
 #include "MovieClipLoader.h"
 #include "movie_definition.h"
 #include "NetConnection_as.h"
@@ -70,7 +71,6 @@
 #include "flash_pkg.h"
 
 #include "fn_call.h"
-#include "MovieClip.h"
 
 #include <limits> // for numeric_limits<double>::infinity
 #include <sstream>
@@ -111,8 +111,6 @@
     as_value global_clearTimeout(const fn_call& fn);
     as_value global_clearInterval(const fn_call& fn);
     as_value global_setInterval(const fn_call& fn);
-    as_value global_addChild(const fn_call& fn);
-    as_value global_addChildAt(const fn_call& fn);
     
     void registerNatives(as_object& global);
 }
@@ -170,8 +168,6 @@
         default:
             // Version 10 or above reported
         case 9:
-            init_member("addChild", new builtin_function(global_addChild));
-            init_member("addChildAt", new builtin_function(global_addChildAt));
         case 8:
 
         case 7:
@@ -595,114 +591,6 @@
     return as_value();
 }
 
-as_value
-global_addChild(const fn_call& fn)
-{
-    boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
-
-    as_value ret;
-
-    if ( ! fn.nargs )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("_global.addChild(): %s", _("missing arguments"));
-        );
-        return ret;
-    }
-
-    if ( fn.nargs > 1 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChild(%s): %s", ss.str(), _("ignoring args 
after the first"));
-        );
-    }
-
-    as_object* objArg = fn.arg(0).to_object().get();
-    if ( ! objArg )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChild(%s): first arg doesn't cast to an 
object", ss.str());
-        );
-        return ret;
-    }
-
-    DisplayObject* ch = objArg->toDisplayObject();
-    if ( ! ch )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChild(%s): first arg doesn't cast to a "
-            "DisplayObject", ss.str());
-        );
-        return ret;
-    }
-
-    VM& vm = ptr->getVM();
-    movie_root& stage = vm.getRoot();
-
-    stage.addChild(ch);
-
-    return as_value(ch);
-}
-
-as_value
-global_addChildAt(const fn_call& fn)
-{
-    boost::intrusive_ptr<as_object> ptr = ensureType<as_object>(fn.this_ptr);
-
-    as_value ret;
-
-    if ( fn.nargs < 2 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror("_global.addChildAt(): %s", _("missing arguments"));
-        );
-        return ret;
-    }
-
-    if ( fn.nargs > 2 )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChildAt(%s): %s", ss.str(), _("ignoring args 
after the second"));
-        );
-    }
-
-    as_object* objArg = fn.arg(0).to_object().get();
-    if ( ! objArg )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChildAt(%s): first arg doesn't cast to an 
object", ss.str());
-        );
-        return ret;
-    }
-
-    DisplayObject* ch = objArg->toDisplayObject();
-    if ( ! ch )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        std::stringstream ss; fn.dump_args(ss);
-        log_aserror("_global.addChildAt(%s): first arg doesn't cast to a "
-            "DisplayObject", ss.str());
-        );
-        return ret;
-    }
-
-    int depth = fn.arg(1).to_number();
-
-    VM& vm = ptr->getVM();
-    movie_root& stage = vm.getRoot();
-
-    std::stringstream ss; fn.dump_args(ss);
-    log_debug("TESTING: _global.addChildAt(%s)", ss.str());
-    
-    stage.addChildAt(ch, depth);
-
-    return as_value(ch);
-}
 
 as_value
 global_setInterval(const fn_call& fn)
@@ -885,6 +773,7 @@
     vm.registerNative(global_setInterval, 250, 0);
     vm.registerNative(global_clearInterval, 250, 1);
 
+    registerMovieClipNative(global);
     registerSelectionNative(global);
     registerColorNative(global);
     registerMathNative(global);

=== modified file 'libcore/asobj/flash/display/DisplayObjectContainer_as.cpp'
--- a/libcore/asobj/flash/display/DisplayObjectContainer_as.cpp 2009-05-28 
17:10:05 +0000
+++ b/libcore/asobj/flash/display/DisplayObjectContainer_as.cpp 2009-06-04 
11:51:18 +0000
@@ -1,4 +1,4 @@
-// DisplayObjectContainer_as.cpp:  ActionScript "DisplayObjectContainer" 
class, for Gnash.
+// DisplayObjectContainer_as.cpp:  ActionScript "DisplayObjectContainer" class.
 //
 //   Copyright (C) 2009 Free Software Foundation, Inc.
 //
@@ -21,19 +21,21 @@
 #include "gnashconfig.h"
 #endif
 
+#include "DisplayObjectContainer.h"
 #include "display/DisplayObjectContainer_as.h"
 #include "log.h"
 #include "fn_call.h"
-#include "smart_ptr.h" // for boost intrusive_ptr
-#include "builtin_function.h" // need builtin_function
-#include "GnashException.h" // for ActionException
+#include "smart_ptr.h" 
+#include "builtin_function.h" 
 
 namespace gnash {
 
 // Forward declarations
 namespace {
     as_value displayobjectcontainer_addChildAt(const fn_call& fn);
-    as_value displayobjectcontainer_areInaccessibleObjectsUnderPoint(const 
fn_call& fn);
+    as_value displayobjectcontainer_addChild(const fn_call& fn);
+    as_value displayobjectcontainer_areInaccessibleObjectsUnderPoint(
+            const fn_call& fn);
     as_value displayobjectcontainer_contains(const fn_call& fn);
     as_value displayobjectcontainer_getChildAt(const fn_call& fn);
     as_value displayobjectcontainer_getChildByName(const fn_call& fn);
@@ -44,61 +46,28 @@
     as_value displayobjectcontainer_setChildIndex(const fn_call& fn);
     as_value displayobjectcontainer_swapChildren(const fn_call& fn);
     as_value displayobjectcontainer_swapChildrenAt(const fn_call& fn);
+    as_value displayobjectcontainer_numChildren(const fn_call& fn);
     as_value displayobjectcontainer_ctor(const fn_call& fn);
     void attachDisplayObjectContainerInterface(as_object& o);
-    void attachDisplayObjectContainerStaticInterface(as_object& o);
-    as_object* getDisplayObjectContainerInterface();
-
 }
 
-class DisplayObjectContainer_as : public as_object
-{
-
-public:
-
-    DisplayObjectContainer_as()
-        :
-        as_object(getDisplayObjectContainerInterface())
-    {}
-};
-
 // extern (used by Global.cpp)
-void displayobjectcontainer_class_init(as_object& global)
+void
+displayobjectcontainer_class_init(as_object& where)
 {
+    
+    // This should never be called during AVM1 execution!
+    assert(isAS3(where.getVM()));
+
     static boost::intrusive_ptr<builtin_function> cl;
 
     if (!cl) {
-        cl = new builtin_function(&displayobjectcontainer_ctor, 
getDisplayObjectContainerInterface());
-        attachDisplayObjectContainerStaticInterface(*cl);
+        cl = new builtin_function(&displayobjectcontainer_ctor,
+                getDisplayObjectContainerInterface());
     }
 
     // Register _global.DisplayObjectContainer
-    global.init_member("DisplayObjectContainer", cl.get());
-}
-
-namespace {
-
-void
-attachDisplayObjectContainerInterface(as_object& o)
-{
-    o.init_member("addChildAt", new 
builtin_function(displayobjectcontainer_addChildAt));
-    o.init_member("areInaccessibleObjectsUnderPoint", new 
builtin_function(displayobjectcontainer_areInaccessibleObjectsUnderPoint));
-    o.init_member("contains", new 
builtin_function(displayobjectcontainer_contains));
-    o.init_member("getChildAt", new 
builtin_function(displayobjectcontainer_getChildAt));
-    o.init_member("getChildByName", new 
builtin_function(displayobjectcontainer_getChildByName));
-    o.init_member("getChildIndex", new 
builtin_function(displayobjectcontainer_getChildIndex));
-    o.init_member("getObjectsUnderPoint", new 
builtin_function(displayobjectcontainer_getObjectsUnderPoint));
-    o.init_member("removeChild", new 
builtin_function(displayobjectcontainer_removeChild));
-    o.init_member("removeChildAt", new 
builtin_function(displayobjectcontainer_removeChildAt));
-    o.init_member("setChildIndex", new 
builtin_function(displayobjectcontainer_setChildIndex));
-    o.init_member("swapChildren", new 
builtin_function(displayobjectcontainer_swapChildren));
-    o.init_member("swapChildrenAt", new 
builtin_function(displayobjectcontainer_swapChildrenAt));
-}
-
-void
-attachDisplayObjectContainerStaticInterface(as_object& o)
-{
-
+    where.init_member("DisplayObjectContainer", cl.get());
 }
 
 as_object*
@@ -112,21 +81,145 @@
     return o.get();
 }
 
+namespace {
+
+void
+attachDisplayObjectContainerInterface(as_object& o)
+{
+    o.init_member("addChildAt", new builtin_function(
+                displayobjectcontainer_addChildAt));
+    o.init_member("addChild", new builtin_function(
+                displayobjectcontainer_addChild));
+    o.init_member("areInaccessibleObjectsUnderPoint", new builtin_function(
+                displayobjectcontainer_areInaccessibleObjectsUnderPoint));
+    o.init_member("contains", new builtin_function(
+                displayobjectcontainer_contains));
+    o.init_member("getChildAt", new builtin_function(
+                displayobjectcontainer_getChildAt));
+    o.init_member("getChildByName", new builtin_function(
+                displayobjectcontainer_getChildByName));
+    o.init_member("getChildIndex", new builtin_function(
+                displayobjectcontainer_getChildIndex));
+    o.init_member("getObjectsUnderPoint", new builtin_function(
+                displayobjectcontainer_getObjectsUnderPoint));
+    o.init_member("removeChild", new builtin_function(
+                displayobjectcontainer_removeChild));
+    o.init_member("removeChildAt", new builtin_function(
+                displayobjectcontainer_removeChildAt));
+    o.init_member("setChildIndex", new builtin_function(
+                displayobjectcontainer_setChildIndex));
+    o.init_member("swapChildren", new builtin_function(
+                displayobjectcontainer_swapChildren));
+    o.init_member("swapChildrenAt", new builtin_function(
+                displayobjectcontainer_swapChildrenAt));
+    o.init_readonly_property("numChildren",
+            displayobjectcontainer_numChildren);
+}
+
+
+as_value
+displayobjectcontainer_addChild(const fn_call& fn)
+{
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
+
+    as_value ret;
+
+    if (!fn.nargs) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror("addChild(): %s", _("missing arguments"));
+        );
+        return ret;
+    }
+
+    if (fn.nargs > 1) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChild(%s): %s", ss.str(), _("ignoring args after "
+                "the first"));
+        );
+    }
+
+    as_object* objArg = fn.arg(0).to_object().get();
+    if (!objArg) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChild(%s): first arg doesn't cast to an object",
+            ss.str());
+        );
+        return ret;
+    }
+
+    DisplayObject* ch = objArg->toDisplayObject();
+    if (!ch) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChild(%s): first arg doesn't cast to a "
+            "DisplayObject", ss.str());
+        );
+        return ret;
+    }
+
+    return as_value(ptr->addChild(ch));
+}
+
 as_value
 displayobjectcontainer_addChildAt(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
+
+    as_value ret;
+
+    if (fn.nargs < 2) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror("addChildAt(): %s", _("missing arguments"));
+        );
+        return ret;
+    }
+
+    if (fn.nargs > 2) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChildAt(%s): %s", ss.str(), _("ignoring args after "
+                "the second"));
+        );
+    }
+
+    as_object* objArg = fn.arg(0).to_object().get();
+    if (!objArg) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChildAt(%s): first arg doesn't cast to an object",
+            ss.str());
+        );
+        return ret;
+    }
+
+    DisplayObject* ch = objArg->toDisplayObject();
+    if (!ch) {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror("addChildAt(%s): first arg doesn't cast to a "
+            "DisplayObject", ss.str());
+        );
+        return ret;
+    }
+
+    int depth = fn.arg(1).to_number();
+
+    std::stringstream ss; fn.dump_args(ss);
+    log_debug("TESTING: addChildAt(%s)", ss.str());
+    
+    return as_value(ptr->addChildAt(ch, depth));
+
 }
 
 as_value
 displayobjectcontainer_areInaccessibleObjectsUnderPoint(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -135,8 +228,8 @@
 as_value
 displayobjectcontainer_contains(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -145,8 +238,8 @@
 as_value
 displayobjectcontainer_getChildAt(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -155,18 +248,26 @@
 as_value
 displayobjectcontainer_getChildByName(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
 }
 
 as_value
+displayobjectcontainer_numChildren(const fn_call& fn)
+{
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
+    return as_value(ptr->numChildren());
+}
+
+as_value
 displayobjectcontainer_getChildIndex(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -175,8 +276,8 @@
 as_value
 displayobjectcontainer_getObjectsUnderPoint(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -185,8 +286,8 @@
 as_value
 displayobjectcontainer_removeChild(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -195,8 +296,8 @@
 as_value
 displayobjectcontainer_removeChildAt(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -205,8 +306,8 @@
 as_value
 displayobjectcontainer_setChildIndex(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -215,8 +316,8 @@
 as_value
 displayobjectcontainer_swapChildren(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -225,8 +326,8 @@
 as_value
 displayobjectcontainer_swapChildrenAt(const fn_call& fn)
 {
-    boost::intrusive_ptr<DisplayObjectContainer_as> ptr =
-        ensureType<DisplayObjectContainer_as>(fn.this_ptr);
+    boost::intrusive_ptr<DisplayObjectContainer> ptr =
+        ensureType<DisplayObjectContainer>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -235,9 +336,12 @@
 as_value
 displayobjectcontainer_ctor(const fn_call& fn)
 {
-    boost::intrusive_ptr<as_object> obj = new DisplayObjectContainer_as;
+    // This should never be called during AS2 execution!
+    assert(isAS3(fn));
 
-    return as_value(obj.get()); // will keep alive
+    log_unimpl("Attempt to construct a DisplayObjectContainer should throw"
+            "an exception!");
+    return as_value();
 }
 
 } // anonymous namespace 

=== modified file 'libcore/asobj/flash/display/DisplayObjectContainer_as.h'
--- a/libcore/asobj/flash/display/DisplayObjectContainer_as.h   2009-05-28 
17:29:17 +0000
+++ b/libcore/asobj/flash/display/DisplayObjectContainer_as.h   2009-06-04 
05:33:47 +0000
@@ -33,6 +33,9 @@
 /// Initialize the global DisplayObjectContainer class
 void displayobjectcontainer_class_init(as_object& global);
 
+/// Get an as_object with the DisplayObjectContainer interface.
+as_object* getDisplayObjectContainerInterface();
+
 } // gnash namespace
 
 // GNASH_ASOBJ3_DISPLAYOBJECTCONTAINER_H

=== modified file 'libcore/asobj/flash/display/MovieClip_as.cpp'
--- a/libcore/asobj/flash/display/MovieClip_as.cpp      2009-05-28 17:10:05 
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.cpp      2009-06-16 06:52:04 
+0000
@@ -21,60 +21,2628 @@
 #include "gnashconfig.h"
 #endif
 
+#include "MovieClip.h"
+#include "Movie.h"
 #include "display/MovieClip_as.h"
+#include "display/DisplayObjectContainer_as.h"
+#include "display/BitmapData_as.h"
+#include "NetStream_as.h"
+#include "movie_root.h"
+#include "GnashNumeric.h"
+#include "as_value.h"
+#include "Object.h"
 #include "log.h"
 #include "fn_call.h"
 #include "smart_ptr.h" // for boost intrusive_ptr
 #include "builtin_function.h" // need builtin_function
-#include "GnashException.h" // for ActionException
 
 namespace gnash {
 
 // Forward declarations
 namespace {
+
+    void attachMovieClipAS2Interface(as_object& o);
+
+    as_value movieclip_as2_ctor(const fn_call& fn);
+    as_value movieclip_transform(const fn_call& fn);
+    as_value movieclip_scale9Grid(const fn_call& fn);
+    as_value movieclip_attachVideo(const fn_call& fn);
+    as_value movieclip_attachAudio(const fn_call& fn);
+    as_value movieclip_attachMovie(const fn_call& fn);
+    as_value movieclip_unloadMovie(const fn_call& fn);
+    as_value movieclip_loadMovie(const fn_call& fn);
+    as_value movieclip_getURL(const fn_call& fn);
+    as_value movieclip_attachBitmap(const fn_call& fn);
+    as_value movieclip_beginBitmapFill(const fn_call& fn);
+    as_value movieclip_createEmptyMovieClip(const fn_call& fn);
+    as_value movieclip_removeMovieClip(const fn_call& fn);
+    as_value movieclip_createTextField(const fn_call& fn);
+    as_value movieclip_curveTo(const fn_call& fn);
+    as_value movieclip_beginFill(const fn_call& fn);
+    as_value movieclip_prevFrame(const fn_call& fn);
+    as_value movieclip_nextFrame(const fn_call& fn);
+    as_value movieclip_endFill(const fn_call& fn);
+    as_value movieclip_clear(const fn_call& fn);
+    as_value movieclip_lineStyle(const fn_call& fn);
+    as_value movieclip_lineTo(const fn_call& fn);
+    as_value movieclip_moveTo(const fn_call& fn);
+    as_value movieclip_beginGradientFill(const fn_call& fn);
+    as_value movieclip_stopDrag(const fn_call& fn);
+    as_value movieclip_startDrag(const fn_call& fn);
+    as_value movieclip_removeMovieClip(const fn_call& fn);
     as_value movieclip_gotoAndStop(const fn_call& fn);
-    as_value movieclip_nextFrame(const fn_call& fn);
+    as_value movieclip_duplicateMovieClip(const fn_call& fn);
+    as_value movieclip_gotoAndPlay(const fn_call& fn);
+    as_value movieclip_stop(const fn_call& fn);
+    as_value movieclip_play(const fn_call& fn);
+    as_value movieclip_setMask(const fn_call& fn);
+    as_value movieclip_getDepth(const fn_call& fn);
+    as_value movieclip_getBytesTotal(const fn_call& fn);
+    as_value movieclip_getBytesLoaded(const fn_call& fn);
+    as_value movieclip_getBounds(const fn_call& fn);
+    as_value movieclip_hitTest(const fn_call& fn);
+    as_value movieclip_globalToLocal(const fn_call& fn);
+    as_value movieclip_localToGlobal(const fn_call& fn);
+    as_value movieclip_swapDepths(const fn_call& fn);
+    as_value movieclip_scrollRect(const fn_call& fn);
+    as_value movieclip_getInstanceAtDepth(const fn_call& fn);
+    as_value movieclip_getNextHighestDepth(const fn_call& fn);
+    as_value movieclip_getTextSnapshot(const fn_call& fn);
+    as_value movieclip_tabIndex(const fn_call& fn);
+    as_value movieclip_opaqueBackground(const fn_call& fn);
+    as_value movieclip_filters(const fn_call& fn);
+    as_value movieclip_forceSmoothing(const fn_call& fn);
+    as_value movieclip_cacheAsBitmap(const fn_call& fn);
+    as_value movieclip_lineGradientStyle(const fn_call& fn);
+    as_value movieclip_getRect(const fn_call& fn);
+    as_value movieclip_meth(const fn_call& fn);
+    as_value movieclip_getSWFVersion(const fn_call& fn);
+    as_value movieclip_loadVariables(const fn_call& fn);
+    as_value movieclip_currentFrame(const fn_call& fn);
+    as_value movieclip_totalFrames(const fn_call& fn);
+    as_value movieclip_framesLoaded(const fn_call& fn);
+    as_value movieclip_dropTarget(const fn_call& fn);
+    as_value movieclip_url(const fn_call& fn);
+    as_value movieclip_focusRect(const fn_call& fn);
+    as_value movieclip_soundbuftime(const fn_call& fn);
+
+    // =============================================
+    // AS3 methods
+    // =============================================
+
+    void attachMovieClipAS3Interface(as_object& o);
+    as_value movieclip_as3_ctor(const fn_call& fn);
     as_value movieclip_nextScene(const fn_call& fn);
-    as_value movieclip_play(const fn_call& fn);
-    as_value movieclip_prevFrame(const fn_call& fn);
     as_value movieclip_prevScene(const fn_call& fn);
-    as_value movieclip_stop(const fn_call& fn);
-    as_value movieclip_ctor(const fn_call& fn);
-    void attachMovieClipInterface(as_object& o);
-    void attachMovieClipStaticInterface(as_object& o);
-    as_object* getMovieClipInterface();
 
 }
 
-class MovieClip_as : public as_object
-{
-
-public:
-
-    MovieClip_as()
-        :
-        as_object(getMovieClipInterface())
-    {}
-};
-
 // extern (used by Global.cpp)
-void movieclip_class_init(as_object& global)
+void
+movieclip_class_init(as_object& where)
 {
+    if (isAS3(where.getVM())) {
+
+        static boost::intrusive_ptr<builtin_function> cl;
+
+        if (!cl) {
+            cl = new builtin_function(&movieclip_as3_ctor,
+                    getMovieClipAS3Interface());
+
+            where.getVM().addStatic(cl.get());
+        }
+        
+        log_debug("AVM2 MovieClip, ctor %s", cl.get());
+
+        where.init_member("MovieClip", cl.get());
+        return;
+    }
+
     static boost::intrusive_ptr<builtin_function> cl;
 
     if (!cl) {
-        cl = new builtin_function(&movieclip_ctor, getMovieClipInterface());
-        attachMovieClipStaticInterface(*cl);
-    }
-
-    // Register _global.MovieClip
-    global.init_member("MovieClip", cl.get());
-}
+        cl = new builtin_function(&movieclip_as2_ctor,
+                getMovieClipAS2Interface());
+
+        where.getVM().addStatic(cl.get());
+    }
+
+    where.init_member("MovieClip", cl.get());
+}
+
+as_object*
+getMovieClipAS3Interface()
+{
+    static boost::intrusive_ptr<as_object> o;
+    if ( ! o ) {
+        o = getDisplayObjectContainerInterface();
+        attachMovieClipAS3Interface(*o);
+    }
+    return o.get();
+}
+
+void
+registerMovieClipNative(as_object& global)
+{
+    VM& vm = global.getVM();
+
+    // Natives are always here    (at least in swf5 I guess)
+    vm.registerNative(movieclip_attachMovie, 900, 0); 
+    // TODO: generalize to DisplayObject::swapDepths_method ?
+    vm.registerNative(movieclip_swapDepths, 900, 1); 
+    vm.registerNative(movieclip_localToGlobal, 900, 2);
+    vm.registerNative(movieclip_globalToLocal, 900, 3);
+    vm.registerNative(movieclip_hitTest, 900, 4);
+    vm.registerNative(movieclip_getBounds, 900, 5);
+    vm.registerNative(movieclip_getBytesTotal, 900, 6);
+    vm.registerNative(movieclip_getBytesLoaded, 900, 7);
+    vm.registerNative(movieclip_attachAudio, 900, 8);
+    vm.registerNative(movieclip_attachVideo, 900, 9);
+    // TODO: generalize to DisplayObject::getDepth_method ?
+    vm.registerNative(movieclip_getDepth, 900, 10);
+    vm.registerNative(movieclip_setMask, 900, 11); 
+    vm.registerNative(movieclip_play, 900, 12); 
+    vm.registerNative(movieclip_stop, 900, 13);
+    vm.registerNative(movieclip_nextFrame, 900, 14);
+    vm.registerNative(movieclip_prevFrame, 900, 15);
+    vm.registerNative(movieclip_gotoAndPlay, 900, 16);
+    vm.registerNative(movieclip_gotoAndStop, 900, 17);
+    vm.registerNative(movieclip_duplicateMovieClip, 900, 18);
+    vm.registerNative(movieclip_removeMovieClip, 900, 19);
+    vm.registerNative(movieclip_startDrag, 900, 20);
+    vm.registerNative(movieclip_stopDrag, 900, 21);
+    vm.registerNative(movieclip_createEmptyMovieClip, 901, 0);
+    vm.registerNative(movieclip_beginFill, 901, 1);
+    vm.registerNative(movieclip_beginGradientFill, 901, 2);
+    vm.registerNative(movieclip_moveTo, 901, 3);
+    vm.registerNative(movieclip_lineTo, 901, 4);
+    vm.registerNative(movieclip_curveTo, 901, 5);
+    vm.registerNative(movieclip_lineStyle, 901, 6);
+    vm.registerNative(movieclip_endFill, 901, 7);
+    vm.registerNative(movieclip_clear, 901, 8);
+
+    vm.registerNative(movieclip_createTextField, 104, 200);
+
+}
+
+/// Properties (and/or methods) attached to every *instance* of a MovieClip 
+void
+attachMovieClipAS2Properties(DisplayObject& o)
+{
+
+    // This is a normal property, can be overridden, deleted and enumerated
+    // See swfdec/test/trace/movieclip-version-#.swf for why we only
+    // initialize this if we don't have a parent
+    if (!o.get_parent()) o.init_member("$version",
+            o.getVM().getPlayerVersion(), 0); 
+
+    as_c_function_ptr gettersetter;
+
+    gettersetter = DisplayObject::x_getset;
+    o.init_property(NSV::PROP_uX, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::y_getset;
+    o.init_property(NSV::PROP_uY, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::xscale_getset;
+    o.init_property(NSV::PROP_uXSCALE, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::yscale_getset;
+    o.init_property(NSV::PROP_uYSCALE, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::xmouse_get;
+    o.init_readonly_property(NSV::PROP_uXMOUSE, gettersetter);
+
+    gettersetter = DisplayObject::ymouse_get;
+    o.init_readonly_property(NSV::PROP_uYMOUSE, gettersetter);
+
+    gettersetter = DisplayObject::alpha_getset;
+    o.init_property(NSV::PROP_uALPHA, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::visible_getset;
+    o.init_property(NSV::PROP_uVISIBLE, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::width_getset;
+    o.init_property(NSV::PROP_uWIDTH, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::height_getset;
+    o.init_property(NSV::PROP_uHEIGHT, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::rotation_getset;
+    o.init_property(NSV::PROP_uROTATION, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::parent_getset;
+    o.init_property(NSV::PROP_uPARENT, gettersetter, gettersetter);
+
+    gettersetter = movieclip_currentFrame;
+    o.init_property(NSV::PROP_uCURRENTFRAME, gettersetter, gettersetter);
+
+    gettersetter = movieclip_totalFrames;
+    o.init_property(NSV::PROP_uTOTALFRAMES, gettersetter, gettersetter);
+
+    gettersetter = movieclip_framesLoaded;
+    o.init_property(NSV::PROP_uFRAMESLOADED, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::target_getset;
+    o.init_property(NSV::PROP_uTARGET, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::name_getset;
+    o.init_property(NSV::PROP_uNAME, gettersetter, gettersetter);
+
+    gettersetter = movieclip_dropTarget;
+    o.init_property(NSV::PROP_uDROPTARGET, gettersetter, gettersetter);
+
+    gettersetter = movieclip_url;
+    o.init_property(NSV::PROP_uURL, gettersetter, gettersetter);
+
+    gettersetter = DisplayObject::quality;
+    o.init_property(NSV::PROP_uQUALITY, gettersetter, gettersetter);
+    
+    gettersetter = DisplayObject::highquality;
+    o.init_property(NSV::PROP_uHIGHQUALITY, gettersetter, gettersetter);
+
+    gettersetter = movieclip_focusRect;
+    o.init_property(NSV::PROP_uFOCUSRECT, gettersetter, gettersetter);
+
+    gettersetter = movieclip_soundbuftime;
+    o.init_property(NSV::PROP_uSOUNDBUFTIME, gettersetter, gettersetter);
+
+}
+
+as_object*
+getMovieClipAS2Interface()
+{
+    static boost::intrusive_ptr<as_object> proto;
+    if ( proto == NULL )
+    {
+        proto = new as_object(getObjectInterface());
+        VM& vm = VM::get();
+        vm.addStatic(proto.get());
+        attachMovieClipAS2Interface(*proto);
+    }
+    return proto.get();
+}
+
 
 namespace {
 
-void
-attachMovieClipInterface(as_object& o)
+// =======================
+// AS2 interface
+// =======================
+
+/// Properties (and/or methods) *inherited* by MovieClip instances
+void
+attachMovieClipAS2Interface(as_object& o)
+{
+        VM& vm = o.getVM();
+
+        o.init_member("attachMovie", vm.getNative(900, 0)); 
+        o.init_member("swapDepths", vm.getNative(900, 1));
+        o.init_member("localToGlobal", vm.getNative(900, 2));
+        o.init_member("globalToLocal", vm.getNative(900, 3));
+        o.init_member("hitTest", vm.getNative(900, 4));
+        o.init_member("getBounds", vm.getNative(900, 5));
+        o.init_member("getBytesTotal", vm.getNative(900, 6));
+        o.init_member("getBytesLoaded", vm.getNative(900, 7));
+        o.init_member("play", vm.getNative(900, 12));
+        o.init_member("stop", vm.getNative(900, 13));
+        o.init_member("nextFrame", vm.getNative(900, 14));
+        o.init_member("prevFrame", vm.getNative(900, 15));
+        o.init_member("gotoAndPlay", vm.getNative(900, 16));
+        o.init_member("gotoAndStop", vm.getNative(900, 17));
+        o.init_member("duplicateMovieClip", vm.getNative(900, 18));
+        o.init_member("removeMovieClip", vm.getNative(900, 19));
+        o.init_member("startDrag", vm.getNative(900, 20));
+        o.init_member("stopDrag", vm.getNative(900, 21));
+        o.init_member("loadMovie", new builtin_function(movieclip_loadMovie));
+        o.init_member("loadVariables", new builtin_function(
+                    movieclip_loadVariables));
+        o.init_member("unloadMovie", new builtin_function(
+                    movieclip_unloadMovie));
+        o.init_member("getURL", new builtin_function(movieclip_getURL));
+        o.init_member("getSWFVersion", new builtin_function(
+                    movieclip_getSWFVersion));
+        o.init_member("meth", new builtin_function(movieclip_meth));
+        o.init_member("enabled", true);
+        o.init_member("useHandCursor", true);
+        o.init_property("_lockroot", &MovieClip::lockroot_getset,
+              &MovieClip::lockroot_getset);
+        o.init_member("beginBitmapFill", new builtin_function(
+                    movieclip_beginBitmapFill));
+        o.init_member("getRect", new builtin_function(
+                    movieclip_getRect));
+        o.init_member("lineGradientStyle", new builtin_function(
+                    movieclip_lineGradientStyle));
+        o.init_member("attachBitmap", new builtin_function(
+                    movieclip_attachBitmap));
+        o.init_property("blendMode", &DisplayObject::blendMode,
+                &DisplayObject::blendMode);
+        o.init_property("cacheAsBitmap", &movieclip_cacheAsBitmap, 
+                &movieclip_cacheAsBitmap);
+        o.init_property("filters", &movieclip_filters, &movieclip_filters);
+        o.init_property("forceSmoothing", &movieclip_forceSmoothing,
+                &movieclip_forceSmoothing);
+        o.init_property("opaqueBackground", &movieclip_opaqueBackground,
+                &movieclip_opaqueBackground);
+        o.init_property("scale9Grid", &movieclip_scale9Grid,
+                movieclip_scale9Grid);
+        o.init_property("scrollRect", &movieclip_scrollRect,
+                       &movieclip_scrollRect);
+        o.init_property("tabIndex", &movieclip_tabIndex, &movieclip_tabIndex);
+        o.init_property("transform", &movieclip_transform, 
+                &movieclip_transform);
+
+        const int swf6Flags = as_prop_flags::dontDelete |
+                    as_prop_flags::dontEnum |
+                    as_prop_flags::onlySWF6Up;
+
+        o.init_member("attachAudio", vm.getNative(900, 8), swf6Flags);
+        o.init_member("attachVideo", vm.getNative(900, 9), swf6Flags);
+        o.init_member("getDepth", vm.getNative(900, 10), swf6Flags);
+        o.init_member("setMask", vm.getNative(900, 11), swf6Flags);
+        o.init_member("createEmptyMovieClip", vm.getNative(901, 0), swf6Flags);
+        o.init_member("beginFill", vm.getNative(901, 1), swf6Flags);
+        o.init_member("beginGradientFill", vm.getNative(901, 2), swf6Flags);
+        o.init_member("moveTo", vm.getNative(901, 3), swf6Flags);
+        o.init_member("lineTo", vm.getNative(901, 4), swf6Flags);
+        o.init_member("curveTo", vm.getNative(901, 5), swf6Flags);
+        o.init_member("lineStyle", vm.getNative(901, 6), swf6Flags);
+        o.init_member("endFill", vm.getNative(901, 7), swf6Flags);
+        o.init_member("clear", vm.getNative(901, 8), swf6Flags);
+        o.init_member("createTextField", vm.getNative(104, 200), swf6Flags);
+        o.init_member("getTextSnapshot", 
+                new builtin_function(movieclip_getTextSnapshot), swf6Flags);
+
+        const int swf7Flags = as_prop_flags::dontDelete |
+                    as_prop_flags::dontEnum |
+                    as_prop_flags::onlySWF7Up;
+
+        o.init_member("getNextHighestDepth", new builtin_function(
+                    movieclip_getNextHighestDepth), swf7Flags);
+        o.init_member("getInstanceAtDepth", new builtin_function(
+                    movieclip_getInstanceAtDepth), swf7Flags);
+
+}
+
+
+as_value
+movieclip_play(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+
+    movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
+    return as_value();
+}
+
+as_value
+movieclip_stop(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+
+    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+
+    return as_value();
+}
+
+
+//removeMovieClip() : Void
+as_value
+movieclip_removeMovieClip(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+    movieclip->removeMovieClip();
+    return as_value();
+}
+
+
+as_value
+movieclip_cacheAsBitmap(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE( log_unimpl(_("MovieClip.cacheAsBitmap()")) );
+    return as_value();
+}
+
+
+as_value
+movieclip_filters(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.filters()")));
+    return as_value();
+}
+
+
+as_value
+movieclip_forceSmoothing(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.forceSmoothing()")));
+    return as_value();
+}
+
+
+as_value
+movieclip_opaqueBackground(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.opaqueBackground()")));
+    return as_value();
+}
+
+    
+as_value
+movieclip_scale9Grid(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.scale9Grid()")));
+    return as_value();
+}
+
+
+as_value
+movieclip_scrollRect(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.scrollRect()")));
+    return as_value();
+}
+
+
+as_value
+movieclip_tabIndex(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+    LOG_ONCE(log_unimpl(_("MovieClip.tabIndex()")));
+    return as_value();
+}
+
+
+// attachMovie(idName:String, newName:String,
+//                         depth:Number [, initObject:Object]) : MovieClip
+as_value
+movieclip_attachMovie(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 3 || fn.nargs > 4)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("attachMovie called with wrong number of arguments"
+                " expected 3 to 4, got (%d) - returning undefined"), fn.nargs);
+        );
+        return as_value();
+    }
+
+    // Get exported resource 
+    const std::string& id_name = fn.arg(0).to_string();
+
+    boost::intrusive_ptr<ExportableResource> exported =
+        movieclip->get_root()->definition()->get_exported_resource(id_name);
+
+    if (!exported)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("attachMovie: '%s': no such exported resource - "
+            "returning undefined"), id_name);
+        );
+        return as_value(); 
+    }
+    
+    SWF::DefinitionTag* exported_movie =
+        dynamic_cast<SWF::DefinitionTag*>(exported.get());
+
+    if (!exported_movie)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("attachMovie: exported resource '%s' "
+            "is not a DisplayObject definition (%s) -- "
+            "returning undefined"), id_name,
+            typeid(*(exported.get())).name());
+        );
+        return as_value();
+    }
+
+    const std::string& newname = fn.arg(1).to_string();
+
+    // Movies should be attachable from -16384 to 2130690045, according to
+    // kirupa (http://www.kirupa.com/developer/actionscript/depths2.htm)
+    // Tests in misc-ming.all/DepthLimitsTest.c show that 2130690044 is the
+    // maximum valid depth.
+    const double depth = fn.arg(2).to_number();
+    
+    // This also checks for overflow, as both numbers are expressible as
+    // boost::int32_t.
+    if (depth < DisplayObject::lowerAccessibleBound ||
+            depth > DisplayObject::upperAccessibleBound)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("MovieClip.attachMovie: invalid depth %d "
+                    "passed; not attaching"), depth);
+        );
+        return as_value();
+    }
+    
+    boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
+
+    boost::intrusive_ptr<DisplayObject> newch =
+        exported_movie->createDisplayObject(movieclip.get(), 0);
+
+#ifndef GNASH_USE_GC
+    assert(newch->get_ref_count() > 0);
+#endif // ndef GNASH_USE_GC
+
+    newch->set_name(newname);
+    newch->setDynamic();
+
+    boost::intrusive_ptr<as_object> initObj;
+
+    if (fn.nargs > 3 ) {
+        initObj = fn.arg(3).to_object();
+        if (!initObj) {
+            // This is actually a valid thing to do,
+            // the documented behaviour is to just NOT
+            // initialize the properties in this
+            // case.
+            IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("Fourth argument of attachMovie doesn't cast to "
+                    "an object (%s), we'll act as if it wasn't given"),
+                    fn.arg(3));
+            );
+        }
+    }
+
+    // placeDisplayObject() will set depth on newch
+    if (!movieclip->attachCharacter(*newch, depthValue, initObj.get()))
+    {
+        log_error(_("Could not attach DisplayObject at depth %d"), depthValue);
+        return as_value();
+    }
+
+    return as_value(newch.get());
+}
+
+
+// attachAudio(id:Object) : Void
+as_value
+movieclip_attachAudio(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (!fn.nargs)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror("MovieClip.attachAudio(): %s", _("missing arguments"));
+        );
+        return as_value();
+    }
+
+    as_object* obj = fn.arg(0).to_object().get();
+    if ( ! obj )
+    { 
+        std::stringstream ss; fn.dump_args(ss);
+        // TODO: find out what to do here
+        log_error("MovieClip.attachAudio(%s): first arg doesn't cast to "
+                "an object", ss.str());
+        return as_value();
+    }
+
+    NetStream_as* ns = dynamic_cast<NetStream_as*>(obj);
+    if ( ! ns )
+    { 
+        std::stringstream ss; fn.dump_args(ss);
+        // TODO: find out what to do here
+        log_error("MovieClip.attachAudio(%s): first arg doesn't cast to a "
+                "NetStream", ss.str());
+        return as_value();
+    }
+
+    ns->setAudioController(movieclip.get());
+
+    LOG_ONCE( log_unimpl("MovieClip.attachAudio() - TESTING") );
+    return as_value();
+}
+
+
+// MovieClip.attachVideo
+as_value
+movieclip_attachVideo(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(movieclip);
+
+    LOG_ONCE( log_unimpl("MovieClip.attachVideo()") );
+    return as_value();
+}
+
+
+//createEmptyMovieClip(name:String, depth:Number) : MovieClip
+as_value
+movieclip_createEmptyMovieClip(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs != 2)
+    {
+        if (fn.nargs < 2)
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("createEmptyMovieClip needs "
+                    "2 args, but %d given,"
+                    " returning undefined"),
+                    fn.nargs);
+            );
+            return as_value();
+        }
+        else
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("createEmptyMovieClip takes "
+                    "2 args, but %d given, discarding"
+                    " the excess"),
+                    fn.nargs);
+            )
+        }
+    }
+
+    // Unlike other MovieClip methods, the depth argument of an empty movie 
clip
+    // can be any number. All numbers are converted to an int32_t, and are 
valid
+    // depths even when outside the usual bounds.
+    DisplayObject* ch = movieclip->add_empty_movieclip(fn.arg(0).to_string(),
+            fn.arg(1).to_int());
+    return as_value(ch);
+}
+
+as_value
+movieclip_getDepth(const fn_call& fn)
+{
+    // TODO: make this a DisplayObject::getDepth_method function...
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    const int n = movieclip->get_depth();
+
+    return as_value(n);
+}
+
+//swapDepths(target:Object|target:Number)
+//
+// Returns void.
+as_value
+movieclip_swapDepths(const fn_call& fn)
+{
+
+    boost::intrusive_ptr<MovieClip> movieclip =
+        ensureType<MovieClip>(fn.this_ptr);
+
+    const int this_depth = movieclip->get_depth();
+
+    if (fn.nargs < 1)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("%s.swapDepths() needs one arg"), 
movieclip->getTarget());
+        );
+        return as_value();
+    }
+
+    // Lower bound of source depth below which swapDepth has no effect
+    // (below Timeline/static zone)
+    if ( this_depth < DisplayObject::lowerAccessibleBound )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            std::stringstream ss;
+            fn.dump_args(ss);
+            log_aserror(_("%s.swapDepths(%s): won't swap a clip below "
+                    "depth %d (%d)"),
+            movieclip->getTarget(), ss.str(), 
DisplayObject::lowerAccessibleBound,
+                this_depth);
+        );
+        return as_value();
+    }
+
+    typedef boost::intrusive_ptr<DisplayObject> CharPtr;
+    typedef boost::intrusive_ptr<MovieClip> SpritePtr;
+
+    SpritePtr this_parent = dynamic_cast<MovieClip*>(
+            movieclip->get_parent());
+
+    //CharPtr target = NULL;
+    int target_depth = 0;
+
+    // movieclip.swapDepth(movieclip)
+    if ( SpritePtr target_movieclip = fn.arg(0).to_sprite() )
+    {
+        if ( movieclip == target_movieclip )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("%s.swapDepths(%s): invalid call, swapping to 
self?"),
+                movieclip->getTarget(), target_movieclip->getTarget());
+            );
+            return as_value();
+        }
+
+        SpritePtr target_parent =
+            dynamic_cast<MovieClip*>(movieclip->get_parent());
+        if ( this_parent != target_parent )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("%s.swapDepths(%s): invalid call, the two "
+                    "DisplayObjects don't have the same parent"),
+                movieclip->getTarget(), target_movieclip->getTarget());
+            );
+            return as_value();
+        }
+
+        target_depth = target_movieclip->get_depth();
+
+        // Check we're not swapping the our own depth so
+        // to avoid unecessary bounds invalidation and immunizing
+        // the instance from subsequent PlaceObject tags attempting
+        // to transform it.
+        if ( movieclip->get_depth() == target_depth )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                std::stringstream ss; fn.dump_args(ss);
+                log_aserror(_("%s.swapDepths(%s): ignored, source and "
+                    "target DisplayObjects have the same depth %d"),
+                    movieclip->getTarget(), ss.str(), target_depth);
+            );
+            return as_value();
+        }
+    }
+
+    // movieclip.swapDepth(depth)
+    else
+    {
+        double td = fn.arg(0).to_number();
+        if ( isNaN(td) )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            std::stringstream ss; fn.dump_args(ss);
+            log_aserror(_("%s.swapDepths(%s): first argument invalid "
+                "(neither a movieclip nor a number)"),
+                movieclip->getTarget(), ss.str());
+            );
+            return as_value();
+        }
+
+        target_depth = int(td);
+
+        // Check we're not swapping the our own depth so
+        // to avoid unecessary bounds invalidation and immunizing
+        // the instance from subsequent PlaceObjec tags attempting
+        // to transform it.
+        if ( movieclip->get_depth() == target_depth )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            std::stringstream ss; fn.dump_args(ss);
+            log_aserror(_("%s.swapDepths(%s): ignored, DisplayObject already "
+                    "at depth %d"),
+                movieclip->getTarget(), ss.str(), target_depth);
+            );
+            return as_value();
+        }
+
+
+        // TODO : check other kind of validities ?
+
+
+    }
+
+    if ( this_parent )
+    {
+        this_parent->swapDepths(movieclip.get(), target_depth);
+    }
+    else
+    {
+        movie_root& root = movieclip->getVM().getRoot();
+        root.swapLevels(movieclip, target_depth);
+        return as_value();
+    }
+
+    return as_value();
+
+}
+
+// TODO: wrap the functionality in a MovieClip method
+//             and invoke it from here, this should only be a wrapper
+//
+//duplicateMovieClip(name:String, depth:Number, [initObject:Object]) : 
MovieClip
+as_value
+movieclip_duplicateMovieClip(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+    
+    if (fn.nargs < 2)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.duplicateMovieClip() needs 2 or 3 args"));
+                );
+        return as_value();
+    }
+
+    const std::string& newname = fn.arg(0).to_string();
+
+    // Depth as in attachMovie
+    const double depth = fn.arg(1).to_number();
+    
+    // This also checks for overflow, as both numbers are expressible as
+    // boost::int32_t.
+    if (depth < DisplayObject::lowerAccessibleBound ||
+            depth > DisplayObject::upperAccessibleBound)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("MovieClip.duplicateMovieClip: "
+                        "invalid depth %d passed; not duplicating"), depth);
+        );    
+        return as_value();
+    }
+    
+    boost::int32_t depthValue = static_cast<boost::int32_t>(depth);
+
+    boost::intrusive_ptr<MovieClip> ch;
+
+    // Copy members from initObject
+    if (fn.nargs == 3)
+    {
+        boost::intrusive_ptr<as_object> initObject = fn.arg(2).to_object();
+        ch = movieclip->duplicateMovieClip(newname, depthValue,
+                initObject.get());
+    }
+    else
+    {
+        ch = movieclip->duplicateMovieClip(newname, depthValue);
+    }
+
+    return as_value(ch.get());
+}
+
+as_value
+movieclip_gotoAndPlay(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 1)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("movieclip_goto_and_play needs one arg"));
+        );
+        return as_value();
+    }
+
+    size_t frame_number;
+    if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
+    {
+        // No dice.
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("movieclip_goto_and_play('%s') -- invalid frame"),
+                    fn.arg(0));
+        );
+        return as_value();
+    }
+
+    // Convert to 0-based
+    movieclip->goto_frame(frame_number);
+    movieclip->setPlayState(MovieClip::PLAYSTATE_PLAY);
+    return as_value();
+}
+
+as_value movieclip_gotoAndStop(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 1)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("movieclip_goto_and_stop needs one arg"));
+        );
+        return as_value();
+    }
+
+    size_t frame_number;
+    if ( ! movieclip->get_frame_number(fn.arg(0), frame_number) )
+    {
+        // No dice.
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("movieclip_goto_and_stop('%s') -- invalid frame"),
+                    fn.arg(0));
+        );
+        return as_value();
+    }
+
+    // Convert to 0-based
+    movieclip->goto_frame(frame_number);
+    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+    return as_value();
+}
+
+as_value movieclip_nextFrame(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    const size_t frame_count = movieclip->get_frame_count();
+    const size_t current_frame = movieclip->get_current_frame();
+    if (current_frame < frame_count)
+    {
+        movieclip->goto_frame(current_frame + 1);
+    }
+    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+    return as_value();
+}
+
+as_value
+movieclip_prevFrame(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    const size_t current_frame = movieclip->get_current_frame();
+    if (current_frame > 0)
+    {
+        movieclip->goto_frame(current_frame - 1);
+    }
+    movieclip->setPlayState(MovieClip::PLAYSTATE_STOP);
+    return as_value();
+}
+
+as_value
+movieclip_getBytesLoaded(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(movieclip->get_bytes_loaded());
+}
+
+as_value
+movieclip_getBytesTotal(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    // @@ horrible uh ?
+    return as_value(movieclip->get_bytes_total());
+}
+
+// MovieClip.loadMovie(url:String [,variables:String]).
+//
+// Returns 1 for "get", 2 for "post", and otherwise 0. Case-insensitive.
+// This *always* calls MovieClip.meth.
+as_value
+movieclip_loadMovie(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    as_value val;
+    if (fn.nargs > 1) {
+        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
+    }
+    else val = movieclip->callMethod(NSV::PROP_METH);
+
+    if (fn.nargs < 1) // url
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.loadMovie() "
+            "expected 1 or 2 args, got %d - returning undefined"),
+            fn.nargs);
+        );
+        return as_value();
+    }
+
+    const std::string& urlstr = fn.arg(0).to_string();
+    if (urlstr.empty())
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("First argument of MovieClip.loadMovie(%s) "
+            "evaluates to an empty string - "
+            "returning undefined"),
+            ss.str());
+        );
+        return as_value();
+    }
+
+    movie_root& mr = movieclip->getVM().getRoot();
+    std::string target = movieclip->getTarget();
+
+    // TODO: if GET/POST should send variables of *this* movie,
+    // no matter if the target will be replaced by another movie !!
+    const MovieClip::VariablesMethod method =
+        static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+    std::string data;
+
+    // This is just an optimization if we aren't going
+    // to send the data anyway. It might be wrong, though.
+    if (method != MovieClip::METHOD_NONE)
+    {
+        movieclip->getURLEncodedVars(data);
+    }
+ 
+    mr.loadMovie(urlstr, target, data, method);
+
+    return as_value();
+}
+
+// my_mc.loadVariables(url:String [, variables:String]) : Void
+as_value
+movieclip_loadVariables(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    // This always calls MovieClip.meth, even when there are no
+    // arguments.
+    as_value val;
+    if (fn.nargs > 1)
+    {
+        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(1));
+    }
+    else val = movieclip->callMethod(NSV::PROP_METH);
+
+    if (fn.nargs < 1) // url
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.loadVariables() "
+            "expected 1 or 2 args, got %d - returning undefined"),
+            fn.nargs);
+        );
+        return as_value();
+    }
+
+    const std::string& urlstr = fn.arg(0).to_string();
+    if (urlstr.empty())
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("First argument passed to MovieClip.loadVariables(%s) "
+            "evaluates to an empty string - "
+            "returning undefined"),
+            ss.str());
+        );
+        return as_value();
+    }
+
+    const MovieClip::VariablesMethod method =
+        static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+    movieclip->loadVariables(urlstr, method);
+    log_debug("MovieClip.loadVariables(%s) - TESTING ", urlstr);
+
+    return as_value();
+}
+
+// my_mc.unloadMovie() : Void
+as_value
+movieclip_unloadMovie(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    movieclip->unloadMovie();
+
+    return as_value();
+}
+
+as_value
+movieclip_hitTest(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    switch (fn.nargs)
+    {
+        case 1: // target
+        {
+            const as_value& tgt_val = fn.arg(0);
+            DisplayObject* target = fn.env().find_target(tgt_val.to_string());
+            if ( ! target )
+            {
+                IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("Can't find hitTest target %s"),
+                    tgt_val);
+                );
+                return as_value();
+            }
+
+            rect thisbounds = movieclip->getBounds();
+            SWFMatrix thismat = movieclip->getWorldMatrix();
+            thismat.transform(thisbounds);
+
+            rect tgtbounds = target->getBounds();
+            SWFMatrix tgtmat = target->getWorldMatrix();
+            tgtmat.transform(tgtbounds);
+
+            return thisbounds.getRange().intersects(tgtbounds.getRange());
+
+            break;
+        }
+
+        case 2: // x, y
+        {
+            boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
+            boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
+
+            return movieclip->pointInBounds(x, y);
+        }
+
+        case 3: // x, y, shapeFlag
+        {
+             boost::int32_t x = pixelsToTwips(fn.arg(0).to_number());
+             boost::int32_t y = pixelsToTwips(fn.arg(1).to_number());
+             bool shapeFlag = fn.arg(2).to_bool();
+
+             if ( ! shapeFlag ) return movieclip->pointInBounds(x, y);
+             else return movieclip->pointInHitableShape(x, y);
+        }
+
+        default:
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("hitTest() called with %u args"),
+                    fn.nargs);
+            );
+            break;
+        }
+    }
+
+    return as_value();
+
+}
+
+as_value
+movieclip_createTextField(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 6) // name, depth, x, y, width, height
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField called with %d args, "
+            "expected 6 - returning undefined"), fn.nargs);
+        );
+        return as_value();
+    }
+
+    std::string txt_name = fn.arg(0).to_string();
+
+    int txt_depth = fn.arg(1).to_int();
+
+    int txt_x = fn.arg(2).to_int();
+
+    int txt_y = fn.arg(3).to_int();
+
+    int txt_width = fn.arg(4).to_int();
+    if ( txt_width < 0 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField: negative width (%d)"
+            " - reverting sign"), txt_width);
+        );
+        txt_width = -txt_width;
+    }
+
+    int txt_height = fn.arg(5).to_int();
+    if ( txt_height < 0 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("createTextField: negative height (%d)"
+            " - reverting sign"), txt_height);
+        );
+        txt_height = -txt_height;
+    }
+
+    boost::intrusive_ptr<DisplayObject> txt = 
movieclip->add_textfield(txt_name,
+            txt_depth, txt_x, txt_y, txt_width, txt_height);
+
+    // createTextField returns void, it seems
+    if ( movieclip->getVM().getSWFVersion() > 7 ) return as_value(txt.get());
+    else return as_value(); 
+}
+
+//getNextHighestDepth() : Number
+as_value
+movieclip_getNextHighestDepth(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    int nextdepth = movieclip->getNextHighestDepth();
+    return as_value(static_cast<double>(nextdepth));
+}
+
+//getInstanceAtDepth(depth:Number) : MovieClip
+as_value
+movieclip_getInstanceAtDepth(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> mc = ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 1)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror("MovieClip.getInstanceAtDepth(): missing depth argument");
+        );
+        return as_value();
+    }
+
+    int depth = fn.arg(0).to_int();
+    boost::intrusive_ptr<DisplayObject> ch = 
mc->getDisplayObjectAtDepth(depth);
+ 
+    // we want 'undefined', not 'null'
+    if (!ch) return as_value();
+    return as_value(ch.get());
+}
+
+/// MovieClip.getURL(url:String[, window:String[, method:String]])
+//
+/// Tested manually to function as a method of any as_object. Hard to
+/// test automatically as it doesn't return anything and only has external
+/// side-effects.
+/// Returns void.
+as_value
+movieclip_getURL(const fn_call& fn)
+{
+    boost::intrusive_ptr<as_object> movieclip =
+        ensureType<as_object>(fn.this_ptr);
+
+    std::string urlstr;
+    std::string target;
+
+    as_value val;
+    if (fn.nargs > 2)
+    {
+        val = movieclip->callMethod(NSV::PROP_METH, fn.arg(2));
+    }
+    else val = movieclip->callMethod(NSV::PROP_METH);
+
+    switch (fn.nargs)
+    {
+        case 0:
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                log_aserror(_("No arguments passed to MovieClip.getURL()"));
+            );
+            return as_value();
+        }
+        default:
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+                std::ostringstream os;
+                fn.dump_args(os);
+                log_aserror(_("MovieClip.getURL(%s): extra arguments "
+                    "dropped"), os.str());
+            );
+        }
+        case 3:
+            // This argument has already been handled.
+        case 2:
+             target = fn.arg(1).to_string();
+        case 1:
+             urlstr = fn.arg(0).to_string();
+             break;
+    }
+
+
+    MovieClip::VariablesMethod method =
+        static_cast<MovieClip::VariablesMethod>(val.to_int());
+
+    std::string vars;
+
+    if (method != MovieClip::METHOD_NONE) {
+        // Get encoded vars.
+        movieclip->getURLEncodedVars(vars);
+    }
+
+    movie_root& m = movieclip->getVM().getRoot();
+    
+    m.getURL(urlstr, target, vars, method);
+
+    return as_value();
+}
+
+// getSWFVersion() : Number
+as_value
+movieclip_getSWFVersion(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(movieclip->getSWFVersion());
+}
+
+// MovieClip.meth(<string>) : Number
+//
+// Parses case-insensitive "get" and "post" into 1 and 2, 0 anything else
+// 
+as_value
+movieclip_meth(const fn_call& fn)
+{
+
+    if (!fn.nargs) return as_value(MovieClip::METHOD_NONE); 
+
+    const as_value& v = fn.arg(0);
+    boost::intrusive_ptr<as_object> o = v.to_object();
+    if ( ! o )
+    {
+        log_debug(_("meth(%s): first argument doesn't cast to object"), v);
+        return as_value(MovieClip::METHOD_NONE);
+    }
+
+    as_value lc = o->callMethod(NSV::PROP_TO_LOWER_CASE);
+
+    std::string s = lc.to_string();
+
+    if (s == "get") return as_value(MovieClip::METHOD_GET);
+    if (s == "post") return as_value(MovieClip::METHOD_POST);
+    return as_value(MovieClip::METHOD_NONE);
+}
+
+
+// getTextSnapshot() : TextSnapshot
+as_value
+movieclip_getTextSnapshot(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> obj = ensureType<MovieClip>(fn.this_ptr);
+
+    // If not found, construction fails.
+    as_value textSnapshot(fn.env().find_object("TextSnapshot"));
+
+    boost::intrusive_ptr<as_function> tsCtor = textSnapshot.to_as_function();
+
+    if (!tsCtor) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror("MovieClip.getTextSnapshot: failed to construct "
+                "TextSnapshot (object probably overridden)");
+        );
+        return as_value();
+    }
+
+    // Construct a flash.geom.Transform object with "this" as argument.
+    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+    args->push_back(obj.get());
+
+    boost::intrusive_ptr<as_object> ts =
+        tsCtor->constructInstance(fn.env(), args);
+
+    return as_value(ts.get());
+}
+
+
+// getBounds(targetCoordinateSpace:Object) : Object
+as_value
+movieclip_getBounds(const fn_call& fn)
+{
+    boost::intrusive_ptr<DisplayObject> movieclip =
+        ensureType<DisplayObject>(fn.this_ptr);
+
+    rect bounds = movieclip->getBounds();
+
+    if ( fn.nargs > 0 )
+    {
+        DisplayObject* target = fn.arg(0).toDisplayObject();
+        if ( ! target )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("MovieClip.getBounds(%s): invalid call, first "
+                    "arg must be a DisplayObject"),
+                fn.arg(0));
+            );
+            return as_value();
+        }
+
+        SWFMatrix tgtwmat = target->getWorldMatrix();
+        SWFMatrix srcwmat = movieclip->getWorldMatrix();
+
+        srcwmat.transform(bounds);
+        tgtwmat.invert().transform(bounds);
+    }
+
+    // Magic numbers here... dunno why
+    double xMin = 6710886.35;
+    double yMin = 6710886.35;
+    double xMax = 6710886.35;
+    double yMax = 6710886.35;
+
+    if ( !bounds.is_null() )
+    {
+        // Round to the twip
+        xMin = twipsToPixels(bounds.get_x_min());
+        yMin = twipsToPixels(bounds.get_y_min());
+        xMax = twipsToPixels(bounds.get_x_max());
+        yMax = twipsToPixels(bounds.get_y_max());
+    }
+
+    boost::intrusive_ptr<as_object> bounds_obj(new as_object());
+    bounds_obj->init_member("xMin", as_value(xMin));
+    bounds_obj->init_member("yMin", as_value(yMin));
+    bounds_obj->init_member("xMax", as_value(xMax));
+    bounds_obj->init_member("yMax", as_value(yMax));
+
+    return as_value(bounds_obj.get());
+}
+
+as_value
+movieclip_globalToLocal(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    as_value ret;
+
+    if ( fn.nargs < 1 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.globalToLocal() takes one arg"));
+        );
+        return ret;
+    }
+
+    boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
+    if ( ! obj )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.globalToLocal(%s): "
+                "first argument doesn't cast to an object"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+
+    as_value tmp;
+    boost::int32_t    x = 0;
+    boost::int32_t    y = 0;
+
+    if ( ! obj->get_member(NSV::PROP_X, &tmp) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.globalToLocal(%s): "
+                "object parameter doesn't have an 'x' member"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+    x = pixelsToTwips(tmp.to_number());
+
+    if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.globalToLocal(%s): "
+                "object parameter doesn't have an 'y' member"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+    y = pixelsToTwips(tmp.to_number());
+
+    point    pt(x, y);
+    SWFMatrix world_mat = movieclip->getWorldMatrix();
+    world_mat.invert().transform(pt);
+
+    obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
+    obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
+
+    return ret;
+}
+
+as_value
+movieclip_localToGlobal(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    as_value ret;
+
+    if ( fn.nargs < 1 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.localToGlobal() takes one arg"));
+        );
+        return ret;
+    }
+
+    boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
+    if ( ! obj )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.localToGlobal(%s): "
+                "first argument doesn't cast to an object"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+
+    as_value tmp;
+    boost::int32_t    x = 0;
+    boost::int32_t    y = 0;
+
+    if ( ! obj->get_member(NSV::PROP_X, &tmp) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.localToGlobal(%s): "
+                "object parameter doesn't have an 'x' member"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+    x = pixelsToTwips(tmp.to_number());
+
+    if ( ! obj->get_member(NSV::PROP_Y, &tmp) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("MovieClip.localToGlobal(%s): "
+                "object parameter doesn't have an 'y' member"),
+            fn.arg(0));
+        );
+        return ret;
+    }
+    y = pixelsToTwips(tmp.to_number());
+
+    point    pt(x, y);
+    SWFMatrix world_mat = movieclip->getWorldMatrix();
+    world_mat.transform(pt);
+
+    obj->set_member(NSV::PROP_X, twipsToPixels(pt.x));
+    obj->set_member(NSV::PROP_Y, twipsToPixels(pt.y));
+    return ret;
+
+}
+
+as_value
+movieclip_setMask(const fn_call& fn)
+{
+    // swfdec/test/image/mask-textfield-6.swf shows that setMask should also
+    // work against TextFields, we have no tests for other DisplayObject types 
so
+    // we generalize it for any DisplayObject.
+    boost::intrusive_ptr<DisplayObject> maskee = 
+        ensureType<DisplayObject>(fn.this_ptr);
+
+    if ( ! fn.nargs )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        log_aserror(_("%s.setMask() : needs an argument"), 
maskee->getTarget());
+        );
+        return as_value();
+    }
+
+    const as_value& arg = fn.arg(0);
+    if ( arg.is_null() || arg.is_undefined() )
+    {
+        // disable mask
+        maskee->setMask(NULL);
+    }
+    else
+    {
+
+        boost::intrusive_ptr<as_object> obj ( arg.to_object() );
+        DisplayObject* mask = dynamic_cast<DisplayObject*>(obj.get());
+        if ( ! mask )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("%s.setMask(%s) : first argument is not a 
DisplayObject"),
+                maskee->getTarget(), arg);
+            );
+            return as_value();
+        }
+
+        // ch is possibly NULL, which is intended
+        maskee->setMask(mask);
+    }
+
+    //log_debug("MovieClip.setMask() TESTING");
+
+    return as_value(true);
+}
+
+as_value
+movieclip_endFill(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.endFill(%s): args will be discarded"),
+            ss.str());
+    }
+    );
+#ifdef DEBUG_DRAWING_API
+    log_debug("%s.endFill();", movieclip->getTarget());
+#endif
+    movieclip->endFill();
+    return as_value();
+}
+
+as_value
+movieclip_lineTo(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    if ( fn.nargs < 2 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("MovieClip.lineTo() needs at least two arguments"));
+        );
+        return as_value();
+    }
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs > 2 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.lineTo(%s): args after the first two "
+                        "will be discarded"), ss.str());
+    }
+    );
+
+    double x = fn.arg(0).to_number();
+    double y = fn.arg(1).to_number();
+        
+    if (!isFinite(x) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.lineTo(%s) : non-finite first argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(0));
+        );
+        x = 0;
+    }
+     
+    if (!isFinite(y) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.lineTo(%s) : non-finite second argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(1));
+        );
+        y = 0;
+    }
+
+#ifdef DEBUG_DRAWING_API
+    log_debug("%s.lineTo(%g,%g);", movieclip->getTarget(), x, y);
+#endif
+    movieclip->lineTo(pixelsToTwips(x), pixelsToTwips(y));
+    return as_value();
+}
+
+as_value
+movieclip_moveTo(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if ( fn.nargs < 2 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("MovieClip.moveTo() takes two args"));
+        );
+        return as_value();
+    }
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs > 2 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.moveTo(%s): args after the first two will "
+                        "be discarded"), ss.str());
+    }
+    );
+
+    double x = fn.arg(0).to_number();
+    double y = fn.arg(1).to_number();
+     
+    if (!isFinite(x) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.moveTo(%s) : non-finite first argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(0));
+        );
+        x = 0;
+    }
+     
+    if (!isFinite(y) )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.moveTo(%s) : non-finite second argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(1));
+        );
+        y = 0;
+    }
+
+#ifdef DEBUG_DRAWING_API
+    log_debug(_("%s.moveTo(%g,%g);"), movieclip->getTarget(), x, y);
+#endif
+    movieclip->moveTo(pixelsToTwips(x), pixelsToTwips(y));
+    return as_value();
+}
+
+// SWF6,7: lineStyle(thickness:Number, rgb:Number, alpha:Number) : Void
+//
+//    SWF8+: lineStyle(thickness:Number, rgb:Number, alpha:Number,
+//                                     pixelHinting:Boolean, noScale:String,
+//                                     capsStyle:String, jointStyle:String,
+//                                     miterLimit:Number) : Void
+as_value
+movieclip_lineStyle(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    if ( ! fn.nargs )
+    {
+        movieclip->resetLineStyle();
+        return as_value();
+    }
+
+    boost::uint8_t r = 0;
+    boost::uint8_t g = 0;
+    boost::uint8_t b = 0;
+    boost::uint8_t a = 255;
+    boost::uint16_t thickness = 0;
+    bool scaleThicknessVertically = true;
+    bool scaleThicknessHorizontally = true;
+    bool pixelHinting = false;
+    bool noClose = false;
+    cap_style_e capStyle = CAP_ROUND;
+    join_style_e joinStyle = JOIN_ROUND;
+    float miterLimitFactor = 1.0f;
+
+    int arguments = fn.nargs;
+
+    const int swfVersion = movieclip->getVM().getSWFVersion();
+    if (swfVersion < 8 && fn.nargs > 3)
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            std::ostringstream ss;
+            fn.dump_args(ss);
+            log_aserror(_("MovieClip.lineStyle(%s): args after the "
+                          "first three will be discarded"), ss.str());
+            );
+        arguments = 3;
+    }
+
+    switch (arguments)
+    {
+        default:
+            IF_VERBOSE_ASCODING_ERRORS(
+                std::ostringstream ss;
+                fn.dump_args(ss);
+                log_aserror(_("MovieClip.lineStyle(%s): args after the "
+                              "first eight will be discarded"), ss.str());
+                );
+        case 8:
+            miterLimitFactor = clamp<int>(fn.arg(7).to_int(), 1, 255);
+        case 7:
+        {
+            std::string joinStyleStr = fn.arg(6).to_string();
+            if (joinStyleStr == "miter") joinStyle = JOIN_MITER;
+            else if (joinStyleStr == "round") joinStyle = JOIN_ROUND;
+            else if (joinStyleStr == "bevel") joinStyle = JOIN_BEVEL;
+            else
+            {
+                IF_VERBOSE_ASCODING_ERRORS(
+                    std::ostringstream ss;
+                    fn.dump_args(ss);
+                    log_aserror(_("MovieClip.lineStyle(%s): invalid joinStyle"
+                                "value '%s' (valid values: %s|%s|%s)"),
+                        ss.str(), joinStyleStr, "miter", "round", "bevel");
+                );
+            }
+        }
+        case 6:
+        {
+            const std::string capStyleStr = fn.arg(5).to_string();
+            if (capStyleStr == "none") capStyle = CAP_NONE;
+            else if (capStyleStr == "round") capStyle = CAP_ROUND;
+            else if (capStyleStr == "square") capStyle = CAP_SQUARE;
+            else
+            {
+                IF_VERBOSE_ASCODING_ERRORS(
+                    std::ostringstream ss;
+                    fn.dump_args(ss);
+                    log_aserror(_("MovieClip.lineStyle(%s): invalid capStyle "
+                               "value '%s' (valid values: none|round|square)"),
+                               ss.str(), capStyleStr);
+                );
+            }
+        }
+        case 5:
+        {
+            // Both values to be set here are true, so just set the
+            // appropriate values to false.
+            const std::string noScaleString = fn.arg(4).to_string();
+            if (noScaleString == "none")
+            {
+                scaleThicknessVertically = false;
+                scaleThicknessHorizontally = false;
+            }
+            else if (noScaleString == "vertical")
+            {
+                scaleThicknessVertically = false;
+            }
+            else if (noScaleString == "horizontal")
+            {
+                scaleThicknessHorizontally = false;
+            }
+            else if (noScaleString != "normal")
+            {
+                IF_VERBOSE_ASCODING_ERRORS(
+                    std::ostringstream ss;
+                    fn.dump_args(ss);
+                    log_aserror(_("MovieClip.lineStyle(%s): invalid "
+                                    "noScale value '%s' (valid values: "
+                                    "%s|%s|%s|%s)"),
+                                    ss.str(), noScaleString, "none",
+                                    "vertical", "horizontal", "normal");
+                );
+            }
+        }
+        case 4:
+            pixelHinting = fn.arg(3).to_bool();
+        case 3:
+        {
+            const float alphaval = clamp<float>(fn.arg(2).to_number(),
+                                     0, 100);
+            a = boost::uint8_t(255 * (alphaval / 100));
+        }
+        case 2:
+        {
+            // See pollock.swf for eventual regressions.
+            // It sets color to a random number from
+            // 0 to 160000000 (about 10 times more then the max).
+            boost::uint32_t rgbval = fn.arg(1).to_int();
+            r = boost::uint8_t((rgbval & 0xFF0000) >> 16);
+            g = boost::uint8_t((rgbval & 0x00FF00) >> 8);
+            b = boost::uint8_t((rgbval & 0x0000FF) );
+        }
+        case 1:
+            thickness = boost::uint16_t(pixelsToTwips(clamp<float>(
+                            fn.arg(0).to_number(), 0, 255)));
+            break;
+    }
+
+    rgba color(r, g, b, a);
+
+#ifdef DEBUG_DRAWING_API
+    log_debug("%s.lineStyle(%d,%d,%d,%d);", movieclip->getTarget(), thickness, 
r, g, b);
+#endif
+    movieclip->lineStyle(thickness, color,
+    scaleThicknessVertically, scaleThicknessHorizontally,
+    pixelHinting, noClose, capStyle, capStyle, joinStyle, miterLimitFactor);
+
+    return as_value();
+}
+
+as_value
+movieclip_curveTo(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip =
+            ensureType<MovieClip>(fn.this_ptr);
+
+    if ( fn.nargs < 4 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("MovieClip.curveTo() takes four args"));
+        );
+        return as_value();
+    }
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs > 4 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.curveTo(%s): args after the first four "
+                "will be discarded"), ss.str());
+    }
+    );
+
+    double cx = fn.arg(0).to_number();
+    double cy = fn.arg(1).to_number();
+    double ax = fn.arg(2).to_number();
+    double ay = fn.arg(3).to_number();
+
+    if (!isFinite(cx))
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.curveTo(%s) : non-finite first argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(0));
+        );
+        cx = 0;
+    }
+     
+    if (!isFinite(cy))
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.curveTo(%s) : non-finite second argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(1));
+        );
+        cy = 0;
+    }
+
+    if (!isFinite(ax))
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.curveTo(%s) : non-finite third argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(0));
+        );
+        ax = 0;
+    }
+     
+    if (!isFinite(ay))
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.curveTo(%s) : non-finite fourth argument (%s), "
+            "converted to zero"), movieclip->getTarget(),
+            ss.str(), fn.arg(1));
+        );
+        ay = 0;
+    }
+
+#ifdef DEBUG_DRAWING_API
+    log_debug(_("%s.curveTo(%g,%g,%g,%g);"), movieclip->getTarget(),
+            cx, cy, ax, ay);
+#endif
+    movieclip->curveTo(pixelsToTwips(cx), pixelsToTwips(cy),
+            pixelsToTwips(ax), pixelsToTwips(ay));
+
+    return as_value();
+}
+
+as_value
+movieclip_clear(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.clear(%s): args will be discarded"),
+            ss.str());
+    }
+    );
+
+#ifdef DEBUG_DRAWING_API
+    log_debug(_("%s.clear();"), movieclip->getTarget());
+#endif
+    movieclip->clear();
+
+    return as_value();
+}
+
+as_value
+movieclip_beginFill(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    boost::uint8_t r = 0;
+    boost::uint8_t g = 0;
+    boost::uint8_t b = 0;
+    boost::uint8_t a = 255;
+
+    if ( fn.nargs > 0 )
+    {
+        // 2^24 is the max here
+        boost::uint32_t rgbval = boost::uint32_t(
+                clamp<float>(fn.arg(0).to_number(), 0, 16777216));
+        r = boost::uint8_t( (rgbval&0xFF0000) >> 16);
+        g = boost::uint8_t( (rgbval&0x00FF00) >> 8);
+        b = boost::uint8_t( (rgbval&0x0000FF) );
+
+        if ( fn.nargs > 1 )
+        {
+            a = 255 * clamp<int>(fn.arg(1).to_int(), 0, 100) / 100;
+            IF_VERBOSE_ASCODING_ERRORS(
+            if ( fn.nargs > 2 )
+            {
+                std::stringstream ss; fn.dump_args(ss);
+                log_aserror(_("MovieClip.beginFill(%s): args after the "
+                        "first will be discarded"), ss.str());
+            }
+            );
+        }
+
+    }
+
+    rgba color(r, g, b, a);
+
+#ifdef DEBUG_DRAWING_API
+    log_debug(_("%s.beginFill(%d,%d,%d);"), movieclip->getTarget(), r, g, b);
+#endif
+    movieclip->beginFill(color);
+
+    return as_value();
+}
+
+as_value
+movieclip_beginGradientFill(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    if ( fn.nargs < 5 )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.beginGradientFill(%s): invalid call: 5 arguments "
+                "needed"),
+            movieclip->getTarget(), ss.str());
+        );
+        return as_value();
+    }
+
+    IF_VERBOSE_ASCODING_ERRORS(
+    if ( fn.nargs > 5 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("MovieClip.beginGradientFill(%s): args after "
+                        "the first five will be discarded"), ss.str());
+    }
+    );
+
+    bool radial = false;
+    std::string typeStr = fn.arg(0).to_string();
+    // Case-sensitive comparison needed for this ...
+    if ( typeStr == "radial" ) radial = true;
+    else if ( typeStr == "linear" ) radial = false;
+    else
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.beginGradientFill(%s): first arg must be "
+            "'radial' or 'linear'"),
+            movieclip->getTarget(), ss.str());
+        );
+        return as_value();
+    }
+
+    typedef boost::intrusive_ptr<as_object> ObjPtr;
+
+    ObjPtr colors = fn.arg(1).to_object();
+    ObjPtr alphas = fn.arg(2).to_object();
+    ObjPtr ratios = fn.arg(3).to_object();
+    ObjPtr matrixArg = fn.arg(4).to_object();
+
+    if ( ! colors || ! alphas || ! ratios || ! matrixArg )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.beginGradientFill(%s): one or more of the "
+            " args from 2nd to 5th don't cast to objects"),
+            movieclip->getTarget(), ss.str());
+        );
+        return as_value();
+    }
+
+    // ----------------------------
+    // Parse SWFMatrix
+    // ----------------------------
+    
+    //
+    // TODO: fix the SWFMatrix build-up, it is NOT correct for
+    //             rotation.
+    //             For the "boxed" SWFMatrixType and radial fills this
+    //             is not a problem as this code just discards the
+    //             rotation (which doesn't make sense), but for
+    //             the explicit SWFMatrix type (a..i) it is a problem.
+    //             The whole code can likely be simplified by 
+    //             always transforming the gnash gradients to the
+    //             expected gradients and subsequently applying
+    //             user-specified SWFMatrix; for 'boxed' SWFMatrixType
+    //             this simplification would increas cost, but
+    //             it's too early to apply optimizations to the
+    //             code (correctness first!!).
+    //
+
+    SWFMatrix mat;
+    SWFMatrix input_matrix;
+
+    if ( matrixArg->getMember(NSV::PROP_MATRIX_TYPE).to_string() == "box" )
+    {
+        
+        boost::int32_t valX = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_X).to_number()); 
+        boost::int32_t valY = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_Y).to_number()); 
+        boost::int32_t valW = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_W).to_number()); 
+        boost::int32_t valH = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_H).to_number()); 
+        float valR = matrixArg->getMember(NSV::PROP_R).to_number(); 
+
+        if ( radial )
+        {
+            // Radial gradient is 64x64 twips.
+            input_matrix.set_scale(64.0/valW, 64.0/valH);
+
+            // For radial gradients, dunno why translation must be negative...
+            input_matrix.concatenate_translation( -valX, -valY );
+
+            // NOTE: rotation is intentionally discarded as it would
+            //             have no effect (theoretically origin of the radial
+            //             fill is at 0,0 making any rotation meaningless).
+
+        }
+        else
+        {
+            // Linear gradient is 256x1 twips.
+            //
+            // No idea why we should use the 256 value for Y scale, but 
+            // empirically seems to give closer results. Note that it only
+            // influences rotation, which is still not correct...
+            // TODO: fix it !
+            input_matrix.set_scale_rotation(256.0/valW, 256.0/valH, -valR);
+
+            // For linear gradients, dunno why translation must be negative...
+            input_matrix.concatenate_translation( -valX, -valY );
+        }
+
+        mat.concatenate(input_matrix);
+    }
+    else
+    {
+        float valA = matrixArg->getMember(NSV::PROP_A).to_number() ; // xx
+        float valB = matrixArg->getMember(NSV::PROP_B).to_number() ; // yx
+        float valD = matrixArg->getMember(NSV::PROP_D).to_number() ; // xy
+        float valE = matrixArg->getMember(NSV::PROP_E).to_number() ; // yy
+        boost::int32_t valG = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_G).to_number()); // x0
+        boost::int32_t valH = pixelsToTwips(
+                matrixArg->getMember(NSV::PROP_H).to_number()); // y0
+
+        input_matrix.sx    = valA * 65536; // sx
+        input_matrix.shx = valB * 65536; // shy
+        input_matrix.shy = valD * 65536; // shx
+        input_matrix.sy    = valE * 65536; // sy
+        input_matrix.tx = valG; // x0
+        input_matrix.ty = valH; // y0
+
+        // This is the SWFMatrix that would transform the gnash
+        // gradient to the expected flash gradient.
+        // Transformation is different for linear and radial
+        // gradient for Gnash (in flash they should be the same)
+        SWFMatrix gnashToFlash;
+
+        if ( radial )
+        {
+
+            // Gnash radial gradients are 64x64 with center at 32,32
+            // Should be 20x20 with center at 0,0
+            const double g2fs = 20.0/64.0; // gnash to flash scale
+            gnashToFlash.set_scale(g2fs, g2fs);
+            gnashToFlash.concatenate_translation(-32, -32);
+
+        }
+        else
+        {
+            // First define a SWFMatrix that would transform
+            // the gnash gradient to the expected flash gradient:
+            // this means translating our gradient to put the
+            // center of gradient at 0,0 and then scale it to
+            // have a size of 20x20 instead of 256x1 as it is
+            //
+            // Gnash linear gradients are 256x1 with center at 128,0
+            // Should be 20x20 with center at 0,0
+            gnashToFlash.set_scale(20.0/256.0, 20.0/1);
+            gnashToFlash.concatenate_translation(-128, 0);
+
+        }
+
+        // Apply gnash to flash SWFMatrix before user-defined one
+        input_matrix.concatenate(gnashToFlash);
+
+        // Finally, and don't know why, take
+        // the inverse of the resulting SWFMatrix as
+        // the one which would be used.
+        mat = input_matrix;
+        mat.invert();
+    }
+
+    // ----------------------------
+    // Create the gradients vector
+    // ----------------------------
+
+    size_t ngradients = colors->getMember(NSV::PROP_LENGTH).to_int();
+    // Check length compatibility of all args
+    if ( ngradients != (size_t)alphas->getMember(NSV::PROP_LENGTH).to_int() ||
+        ngradients != (size_t)ratios->getMember(NSV::PROP_LENGTH).to_int() )
+    {
+        IF_VERBOSE_ASCODING_ERRORS(
+        std::stringstream ss; fn.dump_args(ss);
+        log_aserror(_("%s.beginGradientFill(%s): colors, alphas and "
+            "ratios args don't have same length"),
+            movieclip->getTarget(), ss.str());
+        );
+        return as_value();
+    }
+
+    // TODO: limit ngradients to a max ?
+    if ( ngradients > 8 )
+    {
+        std::stringstream ss; fn.dump_args(ss);
+        log_debug(_("%s.beginGradientFill(%s) : too many array elements"
+            " for colors and ratios (%d), will trim to 8"), 
+            movieclip->getTarget(), ss.str(), ngradients); 
+        ngradients = 8;
+    }
+
+    VM& vm = movieclip->getVM();
+    string_table& st = vm.getStringTable();
+
+    std::vector<gradient_record> gradients;
+    gradients.reserve(ngradients);
+    for (size_t i=0; i<ngradients; ++i)
+    {
+
+        string_table::key key = st.find(boost::lexical_cast<std::string>(i));
+
+        as_value colVal = colors->getMember(key);
+        boost::uint32_t col = colVal.is_number() ? colVal.to_int() : 0;
+
+        as_value alpVal = alphas->getMember(key);
+        boost::uint8_t alp = alpVal.is_number() ? 
+            clamp<int>(alpVal.to_int(), 0, 255) : 0;
+
+        as_value ratVal = ratios->getMember(key);
+        boost::uint8_t rat = ratVal.is_number() ? 
+            clamp<int>(ratVal.to_int(), 0, 255) : 0;
+
+        rgba color;
+        color.parseRGB(col);
+        color.m_a = alp;
+
+        gradients.push_back(gradient_record(rat, color));
+    }
+
+    if ( radial )
+    {
+        movieclip->beginRadialGradientFill(gradients, mat);
+    }
+    else
+    {
+        movieclip->beginLinearGradientFill(gradients, mat);
+    }
+
+    LOG_ONCE( log_debug("MovieClip.beginGradientFill() TESTING") );
+    return as_value();
+}
+
+// startDrag([lockCenter:Boolean], [left:Number], [top:Number],
+//    [right:Number], [bottom:Number]) : Void`
+as_value
+movieclip_startDrag(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    drag_state st;
+    st.setCharacter( movieclip.get() );
+
+    // mark this DisplayObject is transformed.
+    movieclip->transformedByScript();
+
+    if ( fn.nargs )
+    {
+        st.setLockCentered( fn.arg(0).to_bool() );
+
+        if ( fn.nargs >= 5)
+        {
+            double x0 = fn.arg(1).to_number();
+            double y0 = fn.arg(2).to_number();
+            double x1 = fn.arg(3).to_number();
+            double y1 = fn.arg(4).to_number();
+
+            // check for infinite values
+            bool gotinf = false;
+            if (!isFinite(x0) ) { x0=0; gotinf=true; }
+            if (!isFinite(y0) ) { y0=0; gotinf=true; }
+            if (!isFinite(x1) ) { x1=0; gotinf=true; }
+            if (!isFinite(y1) ) { y1=0; gotinf=true; }
+
+            // check for swapped values
+            bool swapped = false;
+            if ( y1 < y0 )
+            {
+                std::swap(y1, y0);
+                swapped = true;
+            }
+
+            if ( x1 < x0 )
+            {
+                std::swap(x1, x0);
+                swapped = true;
+            }
+
+            IF_VERBOSE_ASCODING_ERRORS(
+                if ( gotinf || swapped ) {
+                    std::stringstream ss; fn.dump_args(ss);
+                    if ( swapped ) { 
+                        log_aserror(_("min/max bbox values in "
+                            "MovieClip.startDrag(%s) swapped, fixing"),
+                            ss.str());
+                    }
+                    if ( gotinf ) {
+                        log_aserror(_("non-finite bbox values in "
+                            "MovieClip.startDrag(%s), took as zero"),
+                            ss.str());
+                    }
+                }
+            );
+
+            rect bounds(pixelsToTwips(x0), pixelsToTwips(y0),
+                    pixelsToTwips(x1), pixelsToTwips(y1));
+            st.setBounds(bounds);
+        }
+    }
+
+    movieclip->getVM().getRoot().set_drag_state(st);
+
+    return as_value();
+}
+
+// stopDrag() : Void
+as_value
+movieclip_stopDrag(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> movieclip = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    movieclip->getVM().getRoot().stop_drag();
+
+    return as_value();
+}
+
+
+as_value
+movieclip_beginBitmapFill(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
+    return as_value();
+}
+
+
+as_value
+movieclip_getRect(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
+    return as_value();
+}
+
+
+as_value
+movieclip_lineGradientStyle(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+    LOG_ONCE( log_unimpl (__FUNCTION__) );
+    return as_value();
+}
+
+
+as_value
+movieclip_attachBitmap(const fn_call& fn)
+{
+
+    GNASH_REPORT_FUNCTION;
+
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+    if (fn.nargs < 2) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_debug("MovieClip.attachBitmap: expected 2 args, got %d",
+                fn.nargs);
+        );
+        return as_value();
+    }
+
+    as_object* obj = fn.arg(0).to_object().get();
+    boost::intrusive_ptr<BitmapData_as> bd = dynamic_cast<BitmapData_as*>(obj);
+
+    if (!bd) {
+        IF_VERBOSE_ASCODING_ERRORS(
+            log_debug("MovieClip.attachBitmap: first argument should be a "
+                "BitmapData", fn.arg(1));
+        );
+        return as_value();
+    }
+
+    int depth = fn.arg(1).to_int();
+
+    ptr->attachBitmap(bd, depth);
+
+    return as_value();
+}
+
+
+as_value
+movieclip_as2_ctor(const fn_call& fn)
+{
+
+    assert(!isAS3(fn));
+
+    boost::intrusive_ptr<as_object> clip = 
+        new as_object(getMovieClipAS2Interface());
+
+    return as_value(clip.get());
+}
+
+
+as_value
+movieclip_currentFrame(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(std::min(ptr->get_loaded_frames(),
+                ptr->get_current_frame() + 1));
+}
+
+as_value
+movieclip_totalFrames(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(ptr->get_frame_count());
+}
+
+as_value
+movieclip_framesLoaded(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(ptr->get_loaded_frames());
+}
+
+as_value
+movieclip_dropTarget(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+
+    return ptr->getDropTarget();
+}
+
+as_value
+movieclip_url(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+    return as_value(ptr->get_root()->url());
+}
+
+// TODO: move this to DisplayObject class, _focusrect seems a generic property
+as_value
+movieclip_focusRect(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        // Is a yellow rectangle visible around a focused movie clip (?)
+        // We don't support focuserct settings
+        return as_value(false);
+    }
+    else // setter
+    {
+        LOG_ONCE( log_unimpl("MovieClip._focusrect setting") );
+    }
+    return as_value();
+}
+
+as_value
+movieclip_soundbuftime(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = 
+        ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+
+    if ( fn.nargs == 0 ) // getter
+    {
+        // Number of seconds before sound starts to stream.
+        return as_value(0.0);
+    }
+    else // setter
+    {
+        LOG_ONCE( log_unimpl("MovieClip._soundbuftime setting") );
+    }
+    return as_value();
+}
+
+as_value
+movieclip_transform(const fn_call& fn)
+{
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+
+    // If not found, construction fails.
+    as_value transform(fn.env().find_object("flash.geom.Transform"));
+
+    boost::intrusive_ptr<as_function> transCtor = transform.to_as_function();
+
+    if (!transCtor) {
+        log_error("Failed to construct flash.geom.Transform!");
+        return as_value();
+    }
+
+    // Construct a flash.geom.Transform object with "this" as argument.
+    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+    args->push_back(ptr.get());
+
+    boost::intrusive_ptr<as_object> newTrans =
+        transCtor->constructInstance(fn.env(), args);
+
+    return as_value(newTrans.get());
+}
+
+// =======================
+// AS3 interface
+// =======================
+
+as_value
+movieclip_as3_ctor(const fn_call& fn)
+{
+    assert(isAS3(fn));
+
+    log_unimpl("AVM2 MovieClip ctor");
+
+    return as_value();
+}
+
+
+void
+attachMovieClipAS3Interface(as_object& o)
 {
     o.init_member("gotoAndStop", new builtin_function(movieclip_gotoAndStop));
     o.init_member("nextFrame", new builtin_function(movieclip_nextFrame));
@@ -85,68 +2653,10 @@
     o.init_member("stop", new builtin_function(movieclip_stop));
 }
 
-void
-attachMovieClipStaticInterface(as_object& o)
-{
-
-}
-
-as_object*
-getMovieClipInterface()
-{
-    static boost::intrusive_ptr<as_object> o;
-    if ( ! o ) {
-        o = new as_object();
-        attachMovieClipInterface(*o);
-    }
-    return o.get();
-}
-
-as_value
-movieclip_gotoAndStop(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-movieclip_nextFrame(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
 as_value
 movieclip_nextScene(const fn_call& fn)
 {
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-movieclip_play(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-movieclip_prevFrame(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
     UNUSED(ptr);
     log_unimpl (__FUNCTION__);
     return as_value();
@@ -155,29 +2665,10 @@
 as_value
 movieclip_prevScene(const fn_call& fn)
 {
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-movieclip_stop(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip_as> ptr =
-        ensureType<MovieClip_as>(fn.this_ptr);
-    UNUSED(ptr);
-    log_unimpl (__FUNCTION__);
-    return as_value();
-}
-
-as_value
-movieclip_ctor(const fn_call& fn)
-{
-    boost::intrusive_ptr<as_object> obj = new MovieClip_as;
-
-    return as_value(obj.get()); // will keep alive
+    boost::intrusive_ptr<MovieClip> ptr = ensureType<MovieClip>(fn.this_ptr);
+    UNUSED(ptr);
+    log_unimpl (__FUNCTION__);
+    return as_value();
 }
 
 } // anonymous namespace 

=== modified file 'libcore/asobj/flash/display/MovieClip_as.h'
--- a/libcore/asobj/flash/display/MovieClip_as.h        2009-05-28 17:29:17 
+0000
+++ b/libcore/asobj/flash/display/MovieClip_as.h        2009-06-04 06:53:55 
+0000
@@ -25,17 +25,29 @@
 #endif
 
 
+namespace gnash {
+
 // Forward declarations
 class as_object;
-
-namespace gnash {
+class DisplayObject;
 
 /// Initialize the global MovieClip class
 void movieclip_class_init(as_object& global);
 
+/// Get an as_object with the AS3 MovieClip interface.
+as_object* getMovieClipAS3Interface();
+
+/// Register ASNative MovieClip methods (AS2 only).
+void registerMovieClipNative(as_object& global);
+
+/// Used by MovieClip's ctor to attach properties to MovieClip instances.
+void attachMovieClipAS2Properties(DisplayObject& d);
+
+/// Get an as_object with the AS2 MovieClip interface.
+as_object* getMovieClipAS2Interface();
+
 } // gnash namespace
 
-// GNASH_ASOBJ3_MOVIECLIP_H
 #endif
 
 // local Variables:

=== modified file 'libcore/asobj/flash/display/display.am'
--- a/libcore/asobj/flash/display/display.am    2009-06-12 03:21:00 +0000
+++ b/libcore/asobj/flash/display/display.am    2009-06-16 05:42:44 +0000
@@ -123,10 +123,10 @@
 DISPLAY_HEADERS += asobj/flash/display/MorphShape_as.h
 endif
 
-# FIXME: already exists
-# DISPLAY_SOURCES += asobj/flash/display/MovieClip_as.cpp
+if BUILD_MOVIECLIP_AS3
+DISPLAY_SOURCES += asobj/flash/display/MovieClip_as.cpp
 DISPLAY_HEADERS += asobj/flash/display/MovieClip_as.h
-# endif
+endif
 
 if BUILD_PIXELSNAPPING_AS3
 DISPLAY_SOURCES += asobj/flash/display/PixelSnapping_as.cpp

=== modified file 'libcore/vm/Machine.cpp'
--- a/libcore/vm/Machine.cpp    2009-06-15 06:59:31 +0000
+++ b/libcore/vm/Machine.cpp    2009-06-16 06:51:59 +0000
@@ -269,30 +269,6 @@
 
 }
 
-Machine::Machine(VM& vm)
-        :
-        mStack(),
-        mRegisters(),
-        mScopeStack(),
-        mStream(0),
-        mST(vm.getStringTable()),
-        mDefaultXMLNamespace(0),
-        mCurrentScope(0),
-        mGlobalScope(0),
-        mDefaultThis(0),
-        mThis(0),
-        mGlobalObject(0),
-        mGlobalReturn(),
-        mIgnoreReturn(),
-        mIsAS3(false),
-        mExitWithReturn(false),
-        mPoolObject(0),
-        mCurrentFunction(0),
-        _vm(vm),
-        mCH(_vm.getClassHierarchy())
-{
-}
-
 void
 Machine::execute()
 {
@@ -363,8 +339,11 @@
                     mStack.drop(completeName(a));
                     // Get the target object.
                     ENSURE_OBJECT(mStack.top(0));
+                    
+                    // Use get_super?
                     as_object *super = mStack.top(0).to_object()->
                         get_prototype().get();
+                    
                     // If we don't have a super, throw.
                     if (!super) throw ASReferenceError();
                     Property *b = super->findProperty(a.getABCName(), 
@@ -392,6 +371,8 @@
                     mStack.drop(completeName(a));
 
                     ENSURE_OBJECT(mStack.top(0));
+                    
+                    // Use get_super?
                     as_object* super = mStack.pop().to_object()->
                         get_prototype().get();
                     if (!super) throw ASReferenceError();
@@ -1259,7 +1240,11 @@
                     int dropsize = completeName(a);
                     ENSURE_OBJECT(mStack.top(argc + dropsize));
                     mStack.drop(dropsize);
-                    as_object* super = 
mStack.top(argc).to_object()->get_super();
+
+                    // Why get_super() here and get_prototype everywhere else?
+                    as_object* super =
+                        mStack.top(argc).to_object()->get_super();
+
                     if (!super) throw ASReferenceError();
                     
                     Property* b = super->findProperty(a.getABCName(),
@@ -1301,10 +1286,11 @@
                     as_value result;
                     asName a = pool_name(mStream->read_V32(), mPoolObject);
                     boost::uint32_t argc = mStream->read_V32();
-                    std::auto_ptr<std::vector<as_value> > args = 
get_args(argc);
- 
+                    std::auto_ptr< std::vector<as_value> > args = 
get_args(argc);
+                    //TODO: If multiname is runtime also pop namespace and/or 
name values.
+                    
                     if (a.isRuntime()) {
-                        mStack.drop(completeName(a));
+                        log_unimpl("ABC_ACTION_CALL* with runtime multiname");
                     }
 
                     as_value object_val = pop_stack();
@@ -1312,31 +1298,31 @@
                     as_object *object = object_val.to_object().get();
                     if (!object) {
                         IF_VERBOSE_ASCODING_ERRORS(
-                        log_aserror(_("Can't call a method of a value that "
-                                "doesn't cast to an object (%s)."),
+                        log_aserror(_("Can't call a method of a value that 
doesn't "
+                                "cast to an object (%s)."),
                             object_val);
                         )
                     }
                     else {
 
-                        as_value property = object->getMember(
-                                a.getGlobalName(), 0);
+                        as_value property = 
object->getMember(a.getGlobalName(), 0);
                     
                         if (!property.is_undefined() && !property.is_null()) {
                             log_abc("Calling method %s on object %s",
-                                    property, object_val);
+                                    
property.toDebugString(),object_val.toDebugString());
                             as_environment env = as_environment(_vm);
                             result = call_method(property,env,object,args);
 
                         }
                         else {
                             IF_VERBOSE_ASCODING_ERRORS(
-                            log_aserror(_("Property '%s' of object '%s' is "
-                                    "'%s', cannot call as method"),
+                            log_aserror(_("Property '%s' of object '%s' is 
'%s', "
+                                    "cannot call as method"),
                                     mPoolObject->stringPoolAt(a.getABCName()),
                                     object_val, property);
                             )
                         }
+
                     }
                     
                     if (opcode == SWF::ABC_ACTION_CALLPROPERTY) {
@@ -1420,7 +1406,10 @@
                     get_args(argc);
                     
                     as_object* obj = mStack.top(argc).to_object().get();
-                    as_object* super = obj ? obj->get_super() : 0;
+
+                    // Using get_super() here fails; is it broken, or is
+                    // prototype what we want?
+                    as_object* super = obj ? obj->get_prototype().get() : 0;
                     log_abc("CONSTRUCTSUPER: object %s, super %s, args %s",
                             mStack.top(argc), super, argc);
 
@@ -1429,11 +1418,11 @@
                         throw ASException();
                     }
 
-                    as_function *func = super->get_constructor();
+                    as_function *func = super->to_function();
                     if (!func) {
                         log_abc("CONSTRUCTSUPER: %s has no constructor",
                                 super);
-                        return;
+                        break;
                     }
 
                     // 'obj' is the 'this' for the call, we ignore the
@@ -1563,14 +1552,15 @@
                     push_stack(as_value(mCurrentFunction));
                     break;
                 }
+
                 /// 0x58 ABC_ACTION_NEWCLASS
                 /// Stream: V32 'class_id'
                 /// Stack In:
                 ///  obj -- An object to be turned into a class. Its super
                 ///     is constructed.
                 /// Stack Out:
-                ///  class -- The newly made class, made from obj and the "
-                ///     "information at cinits_pool[class_id]
+                ///  class -- The newly made class, made from obj and the
+                ///     information at cinits_pool[class_id]
                 /// NB: This depends on scope and scope base (to determine
                 ///     lifetime(?))
                 case SWF::ABC_ACTION_NEWCLASS:
@@ -1595,19 +1585,14 @@
                     new_class->init_member(NSV::PROP_uuCONSTRUCTORuu,
                             as_value(static_constructor), 0);
                     
-                    as_function* constructor =
-                        c->getConstructor()->getPrototype();
-                    new_class->init_member(NSV::PROP_CONSTRUCTOR,
-                            constructor, 0);
-                    push_stack(new_class);
+                    as_function* constructor = 
c->getConstructor()->getPrototype();
+                    new_class->init_member(NSV::PROP_CONSTRUCTOR, 
as_value(constructor), 0);
+                    push_stack(as_value(new_class));
 
-                    // Call the class's static constructor (which may be 
-                    // undefined).
+                    // Call the class's static constructor (which may be 
undefined).
                     as_environment env = as_environment(_vm);
-                    as_value property = new_class->getMember(
-                            NSV::PROP_uuCONSTRUCTORuu, 0);
-                    as_value value = call_method(property, env, new_class,
-                            get_args(0));
+                    as_value property = 
new_class->getMember(NSV::PROP_uuCONSTRUCTORuu, 0);
+                    as_value value = call_method(property, env, new_class, 
get_args(0));
 
                     break;
                 }
@@ -1700,8 +1685,6 @@
                 {
                     asName a = pool_name(mStream->read_V32(), mPoolObject);
                 
-                    // This pushes a value onto the stack, but it seems
-                    // we don't need it.
                     as_value val = find_prop_strict(a);
 
                     log_abc("GETLEX: found value %s", val);
@@ -1834,13 +1817,10 @@
 
                     as_value object_val = pop_stack();
                     as_object* object = object_val.to_object().get();
-                   
-                    log_abc(_("ABC_ACTION_GETPROPERTY: Looking for property "
-                            "%s of object %s"), mST.value(name), object_val);
-
+                    
                     if (!object) {
-                        log_abc(_("ABC_ACTION_GETPROPERTY: expecting "
-                                    "object on stack, got %s."), object_val);
+                        log_abc(_("GETPROPERTY: expecting object on "
+                                    "stack, got %s."), object_val);
                         push_stack(as_value());
                         break;
                     }
@@ -1934,6 +1914,11 @@
                     as_value val;
                     boost::uint32_t sindex = mStream->read_V32();
                     as_object* object = pop_stack().to_object().get();
+                    if (!object) {
+                        log_abc("GETSLOT: Did not find expected object on "
+                                "stack");
+                        break;
+                    } 
 
                     object->get_member_slot(sindex + 1, &val);
 
@@ -2574,9 +2559,10 @@
                     if (!valueObject || !typeObject) {
                         // TODO: what here!?
                         // This should eventually be a malformed SWF error.
-                        log_error("ACTION_ISTYPELATE: require two objects on 
stack, got "
-                               "obj: %s, type: %s.", value, type);
-                        return;
+                        log_error("ACTION_ISTYPELATE: require two objects "
+                                "on stack, got obj: %s, type: %s.",
+                                value, type);
+                        break;
                     }
                     const bool truth = valueObject->instanceOf(typeObject);
                     push_stack(truth);
@@ -3062,16 +3048,41 @@
     // is to be constructed. Setting it to global as before seems to be wrong.
        mRegisters[0] = cl->getPrototype();
        executeCodeblock(ctor->getBody());
-
     log_debug("Finished instantiating class %s", className);
 }
 
+Machine::Machine(VM& vm)
+        :
+        mStack(),
+        mRegisters(),
+        mScopeStack(),
+        mStream(0),
+        mST(vm.getStringTable()),
+        mDefaultXMLNamespace(0),
+        mCurrentScope(0),
+        mGlobalScope(0),
+        mDefaultThis(0),
+        mThis(0),
+        mGlobalObject(0),
+        mGlobalReturn(),
+        mIgnoreReturn(),
+        mIsAS3(false),
+        mExitWithReturn(false),
+        mPoolObject(0),
+        mCurrentFunction(0),
+        _vm(vm),
+        mCH(_vm.getClassHierarchy())
+{
+       //Local registers should be initialized at the beginning of each 
function call, but
+       //we don't currently parse the number of local registers for each 
function.
+//     mRegisters.resize(16);
+//     mST = new string_table();
+//     mST = ST;
+}
+
 as_value
-Machine::find_prop_strict(asName multiname)
-{
-    
-    log_abc("Looking for property %s", mST.value(multiname.getGlobalName()));
-
+Machine::find_prop_strict(asName multiname) {
+       
        as_value val;
        mScopeStack.push(mGlobalObject);
        for (size_t i = 0; i < mScopeStack.size(); ++i)
@@ -3091,17 +3102,16 @@
                }
        }
 
-       as_object* target = 0;
+       log_abc("Cannot find property in scope stack.  Trying again using "
+            "as_environment.");
+       as_object *target = NULL;
        as_environment env = as_environment(_vm);
        std::string name = mPoolObject->stringPoolAt(multiname.getABCName());
        std::string ns = mPoolObject->stringPoolAt(
             multiname.getNamespace()->getAbcURI());
        std::string path = ns.empty() ? name : ns + "." + name;
-       
-    log_abc("Failed to find property in scope stack. Looking for %s in "
-            "as_environment", path);
 
-    std::auto_ptr<as_environment::ScopeStack> envStack (getScopeStack());
+    std::auto_ptr<as_environment::ScopeStack> envStack ( getScopeStack() );
        val = env.get_variable(path, *envStack, &target);
 
        push_stack(target);     

=== modified file 'libcore/vm/VM.h'
--- a/libcore/vm/VM.h   2009-06-03 16:05:40 +0000
+++ b/libcore/vm/VM.h   2009-06-04 06:48:54 +0000
@@ -352,6 +352,13 @@
 
 };
 
+/// Return true if the VM is executing AS3 (ABC bytecode).
+inline bool
+isAS3(VM& vm)
+{
+    return vm.getAVMVersion() == VM::AVM2;
+}
+
 } // namespace gnash
 
 #endif // GNASH_VM_H

=== modified file 'testsuite/as3/dejagnu.as'
--- a/testsuite/as3/dejagnu.as  2009-06-15 16:42:47 +0000
+++ b/testsuite/as3/dejagnu.as  2009-06-16 06:35:15 +0000
@@ -19,9 +19,8 @@
 package dejagnu {
 
     import flash.text.*;
-    import flash.display.Sprite;
 
-    public class Dejagnu extends Sprite {
+    public class Dejagnu {
 
         private static var passed = 0;
         private static var failed = 0;


reply via email to

[Prev in Thread] Current Thread [Next in Thread]