gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash/server MovieClipLoader.cpp Sprite.cpp Spr...


From: strk
Subject: [Gnash-commit] gnash/server MovieClipLoader.cpp Sprite.cpp Spr...
Date: Fri, 27 Jan 2006 00:54:38 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Branch:         
Changes by:     strk <address@hidden>   06/01/27 00:54:38

Modified files:
        server         : MovieClipLoader.cpp Sprite.cpp Sprite.h 
                         action.cpp action.h gnash.h impl.cpp impl.h 
                         sound.cpp text.cpp 

Log message:
        More separation in Sprite.{cpp,h}.
        General Doxygen dox (it's a long way...)

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/MovieClipLoader.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Sprite.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/Sprite.h.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/action.cpp.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/action.h.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/gnash.h.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/impl.cpp.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/impl.h.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/sound.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/gnash/gnash/server/text.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text

Patches:
Index: gnash/server/MovieClipLoader.cpp
diff -u gnash/server/MovieClipLoader.cpp:1.1 
gnash/server/MovieClipLoader.cpp:1.2
--- gnash/server/MovieClipLoader.cpp:1.1        Tue Jan 24 10:12:00 2006
+++ gnash/server/MovieClipLoader.cpp    Fri Jan 27 00:54:38 2006
@@ -21,6 +21,7 @@
 #include "tu_config.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <typeinfo> 
 
 #ifdef HAVE_LIBXML
 // TODO: http and sockets and such ought to be factored out into an
@@ -202,12 +203,36 @@
 
   moviecliploader_as_object*   ptr = (moviecliploader_as_object*) (as_object*) 
fn.this_ptr;
   
-  tu_string url = fn.arg(0).to_string(); 
-  as_object *target = (as_object *)fn.arg(1).to_object();
+       tu_string url = fn.arg(0).to_string(); 
+       as_object *target = (as_object *)fn.arg(1).to_object();
 
-  log_msg("load clip: %s, target is: %p\n", url.c_str(), target);
+       log_msg("load clip: %s, target is: %p (%s)\n", url.c_str(),
+               target, typeid(*target).name());
+
+       //
+       // Extract root movie URL 
+       // @@ could be cached somewhere...
+       //
+       as_value target_url;
+       if ( ! target->get_member("_url", &target_url) )
+       {
+               log_msg("FIXME: no _url member in target!");
+       }
+
+       log_msg(" target._url: %s\n", target_url.to_string());
+
+#if 0
+       as_value root_url;
+       if ( ! target->get_member("_url", &root_url) )
+       {
+               log_msg("FIXME: no _url member in target!");
+       }
 
-  xmlNanoHTTPInit();            // This doesn't do much for now, but in the
+       log_msg(" root._url: type:%d to_string:%s rtty:%s\n",
+               root_url.m_type, root_url.to_string(), typeid(root_url).name());
+#endif
+
+       xmlNanoHTTPInit();      // This doesn't do much for now, but in the
                                 // future it might, so here it is...
 
        if (target == NULL)
@@ -217,19 +242,18 @@
                return;    
        }
 
+       //
+       // Resolve relative urls
+       // @@ todo
+       
+
        // local file path
        // this is either fetched from http or local in origin
        tu_string filespec;
-       bool filespec_copied = true;
+       bool filespec_copied = false;
 
-       if (url.utf8_substring(0, 7) == "file://")
+       if (url.utf8_substring(0, 7) == "http://";)
        {
-               filespec = url.utf8_substring(7, url.length());
-               filespec_copied = false;
-       }
-       else
-       {
-
                // Grab the filename off the end of the URL, and use the same 
name
                // as the disk file when something is fetched. Store files in 
/tmp/.
                // If the file exists, libxml properly replaces it.
@@ -242,8 +266,19 @@
                xmlNanoHTTPCleanup();
 
                // FIXME: check for success or failure
+               filespec_copied = true;
 
        }
+       else if (url.utf8_substring(0, 7) == "file://")
+       {
+               filespec = url.utf8_substring(7, url.length());
+       }
+       else
+       {
+               // @@ should never happen if we resolve relative urls
+               log_msg("FIXME: unresolved relative url\n");
+               filespec = url;
+       }
 
        // If the file doesn't exist, don't try to do anything.
        if (stat(filespec.c_str(), &stats) < 0)
Index: gnash/server/Sprite.cpp
diff -u gnash/server/Sprite.cpp:1.1 gnash/server/Sprite.cpp:1.2
--- gnash/server/Sprite.cpp:1.1 Wed Jan 25 18:03:25 2006
+++ gnash/server/Sprite.cpp     Fri Jan 27 00:54:38 2006
@@ -21,16 +21,17 @@
 #include "gnash.h"
 #include "Sprite.h"
 #include "MovieClipLoader.h" // @@ temp hack for loading tests
+#include <vector>
 
 namespace gnash {
 
        // Execute the actions in the action list, in the given
        // environment.
        static void
-       execute_actions(as_environment* env, const array<action_buffer*>&
-               action_list)
+       execute_actions(as_environment* env,
+                       const std::vector<action_buffer*>& action_list)
        {
-           for (int i = 0; i < action_list.size(); i++)
+               for (unsigned int i=0, n=action_list.size(); i<n; ++i)
                {
                    action_list[i]->execute(env);
                }
@@ -165,10 +166,20 @@
 
        static void sprite_load_movie(const fn_call& fn)
        {
-               log_error("Not implemented yet");
+               log_error("FIXME: %s not implemented yet", __PRETTY_FUNCTION__);
                //moviecliploader_loadclip(fn);
        }
 
+       static void sprite_create_text_field(const fn_call& fn)
+       {
+               log_error("FIXME: %s not implemented yet", __PRETTY_FUNCTION__);
+               //moviecliploader_loadclip(fn);
+       }
+
+       //------------------------------------------------
+       // sprite_instance
+       //------------------------------------------------
+
        //
        // Initialize the Sprite/MovieClip builtin class 
        //
@@ -187,6 +198,7 @@
                as_builtins.set_member("getBytesLoaded", 
&sprite_get_bytes_loaded);
                as_builtins.set_member("getBytesTotal", 
&sprite_get_bytes_total);
                as_builtins.set_member("loadMovie", &sprite_load_movie);
+               as_builtins.set_member("createTextField", 
&sprite_create_text_field);
 
                // @TODO
                //as_builtins.set_member("startDrag", &sprite_start_drag);
@@ -308,6 +320,8 @@
                    val->set_double(angle);
                    return true;
                }
+
+               /// FIXME: use a contextual 'target' member
                case M_TARGET:
                    //else if (name == "_target")
                {
@@ -335,6 +349,14 @@
                    val->set_string("/_root");
                    return true;
                }
+
+               ///
+               /// FIXME: add a valid 'url' member. Currently 
+               /// the verbatim "gnash" value is assigned to it.
+               /// The 'url' member should be inherited by
+               /// parent *unless* we loaded an external resource
+               /// into this movieclip.
+               ///
                case M_URL:
                    //else if (name == "_url")
                {
@@ -450,4 +472,934 @@
            m_action_list.resize(0);
        }
 
+       /// Execute the actions for the specified frame. 
+       //
+       /// The frame_spec could be an integer or a string.
+       ///
+       void sprite_instance::call_frame_actions(const as_value& frame_spec)
+       {
+               int     frame_number = -1;
+
+               // Figure out what frame to call.
+               if (frame_spec.get_type() == as_value::STRING)
+               {
+                       if (m_def->get_labeled_frame(frame_spec.to_string(), 
&frame_number) == false)
+                       {
+                               // Try converting to integer.
+                               frame_number = (int) frame_spec.to_number();
+                       }
+               }
+               else
+               {
+                       // convert from 1-based to 0-based
+                       frame_number = (int) frame_spec.to_number() - 1;
+               }
+
+               if (frame_number < 0 || frame_number >= 
m_def->get_frame_count())
+               {
+                           // No dice.
+                           log_error("error: call_frame('%s') -- unknown 
frame\n", frame_spec.to_string());
+                           return;
+               }
+
+               unsigned int top_action = m_action_list.size();
+
+               // Execute the execute_tag actions
+
+               const array<execute_tag*>&playlist = 
m_def->get_playlist(frame_number);
+               for (int i=0, n=playlist.size(); i<n; ++i)
+               {
+                       execute_tag*    e = playlist[i];
+                       if (e->is_action_tag())
+                       {
+                               e->execute(this);
+                       }
+               }
+
+               // Execute any new actions triggered by the tag,
+               // leaving existing actions to be executed.
+
+               while (m_action_list.size() > top_action)
+               {
+                       m_action_list[top_action]->execute(&m_as_environment);
+                       //m_action_list.remove(top_action);
+                       m_action_list.erase(m_action_list.begin()+top_action);
+               }
+
+               assert(m_action_list.size() == top_action);
+       }
+
+       void sprite_instance::clone_display_object(const tu_string& name,
+               const tu_string& newname, Uint16 depth)
+       {
+           character* ch = m_display_list.get_character_by_name(name);
+           if (ch)
+               {
+                   array<swf_event*>   dummy_event_handlers;
+
+                   add_display_object(
+                       ch->get_id(),
+                       newname.c_str(),
+                       dummy_event_handlers,
+                       depth,
+                       true,   // replace if depth is occupied
+                       ch->get_cxform(),
+                       ch->get_matrix(),
+                       ch->get_ratio(),
+                       ch->get_clip_depth());
+                   // @@ TODO need to duplicate ch's event handlers, and 
presumably other members?
+                   // Probably should make a character::clone() function to 
handle this.
+               }
+       }
+
+       void sprite_instance::remove_display_object(const tu_string& name)
+       {
+           character* ch = m_display_list.get_character_by_name(name);
+           if (ch)
+               {
+                   // @@ TODO: should only remove movies that were created via 
clone_display_object --
+                   // apparently original movies, placed by anim events, are 
immune to this.
+                   remove_display_object(ch->get_depth(), ch->get_id());
+               }
+       }
+
+       bool sprite_instance::on_event(event_id id)
+       {
+                   // Keep m_as_environment alive during any method calls!
+                   smart_ptr<as_object_interface>      this_ptr(this);
+
+                   bool called = false;
+                               
+                   // First, check for built-in event handler.
+                   {
+                       as_value        method;
+                       if (get_event_handler(id, &method))
+                           {
+                               // Dispatch.
+                               call_method0(method, &m_as_environment, this);
+
+                               called = true;
+                               // Fall through and call the function also, if 
it's defined!
+                               // (@@ Seems to be the behavior for mouse 
events; not tested & verified for
+                               // every event type.)
+                           }
+                   }
+
+                   // Check for member function.
+                   {
+                       // In ActionScript 2.0, event method names are CASE 
SENSITIVE.
+                       // In ActionScript 1.0, event method names are CASE 
INSENSITIVE.
+                       const tu_stringi&       method_name = 
id.get_function_name().to_tu_stringi();
+                       if (method_name.length() > 0)
+                           {
+                               as_value        method;
+                               if (get_member(method_name, &method))
+                                   {
+                                       call_method0(method, &m_as_environment, 
this);
+                                       called = true;
+                                   }
+                           }
+                   }
+
+                   return called;
+       }
+
+       movie* sprite_instance::get_relative_target(const tu_string& name)
+       {
+           if (name == "." || name == "this")
+               {
+                   return this;
+               }
+           else if (name == "..")
+               {
+                   return get_parent();
+               }
+           else if (name == "_level0"
+                    || name == "_root")
+               {
+                   return m_root->m_movie.get_ptr();
+               }
+
+           // See if we have a match on the display list.
+           return m_display_list.get_character_by_name(name);
+       }
+
+       void sprite_instance::set_member(const tu_stringi& name,
+                       const as_value& val)
+       {
+                   as_standard_member  std_member = get_standard_member(name);
+                   switch (std_member)
+                       {
+                       default:
+                       case M_INVALID_MEMBER:
+                           break;
+                       case M_X:
+                           //if (name == "_x")
+                       {
+                           matrix      m = get_matrix();
+                           m.m_[0][2] = (float) 
PIXELS_TO_TWIPS(val.to_number());
+                           set_matrix(m);
+
+                           m_accept_anim_moves = false;
+
+                           return;
+                       }
+                       case M_Y:
+                           //else if (name == "_y")
+                       {
+                           matrix      m = get_matrix();
+                           m.m_[1][2] = (float) 
PIXELS_TO_TWIPS(val.to_number());
+                           set_matrix(m);
+
+                           m_accept_anim_moves = false;
+
+                           return;
+                       }
+                       case M_XSCALE:
+                           //else if (name == "_xscale")
+                       {
+                           matrix      m = get_matrix();
+
+                           // Decompose matrix and insert the desired value.
+                           float       x_scale = (float) val.to_number() / 
100.f;      // input is in percent
+                           float       y_scale = m.get_y_scale();
+                           float       rotation = m.get_rotation();
+                           m.set_scale_rotation(x_scale, y_scale, rotation);
+
+                           set_matrix(m);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_YSCALE:
+                           //else if (name == "_yscale")
+                       {
+                           matrix      m = get_matrix();
+
+                           // Decompose matrix and insert the desired value.
+                           float       x_scale = m.get_x_scale();
+                           float       y_scale = (float) val.to_number() / 
100.f;      // input is in percent
+                           float       rotation = m.get_rotation();
+                           m.set_scale_rotation(x_scale, y_scale, rotation);
+
+                           set_matrix(m);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_ALPHA:
+                           //else if (name == "_alpha")
+                       {
+                           // Set alpha modulate, in percent.
+                           cxform      cx = get_cxform();
+                           cx.m_[3][0] = float(val.to_number()) / 100.f;
+                           set_cxform(cx);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_VISIBLE:
+                           //else if (name == "_visible")
+                       {
+                           set_visible(val.to_bool());
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_WIDTH:
+                           //else if (name == "_width")
+                       {
+                           // @@ tulrich: is parameter in world-coords or 
local-coords?
+                           matrix      m = get_matrix();
+                           m.m_[0][0] = 
float(PIXELS_TO_TWIPS(val.to_number()));
+                           float w = get_width();
+                           if (fabsf(w) > 1e-6f)
+                               {
+                                   m.m_[0][0] /= w;
+                               }
+                           set_matrix(m);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_HEIGHT:
+                           //else if (name == "_height")
+                       {
+                           // @@ tulrich: is parameter in world-coords or 
local-coords?
+                           matrix      m = get_matrix();
+                           m.m_[1][1] = 
float(PIXELS_TO_TWIPS(val.to_number()));
+                           float h = get_width();
+                           if (fabsf(h) > 1e-6f)
+                               {
+                                   m.m_[1][1] /= h;
+                               }
+                           set_matrix(m);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_ROTATION:
+                           //else if (name == "_rotation")
+                       {
+                           matrix      m = get_matrix();
+
+                           // Decompose matrix and insert the desired value.
+                           float       x_scale = m.get_x_scale();
+                           float       y_scale = m.get_y_scale();
+                           float       rotation = (float) val.to_number() * 
float(M_PI) / 180.f;       // input is in degrees
+                           m.set_scale_rotation(x_scale, y_scale, rotation);
+
+                           set_matrix(m);
+                           m_accept_anim_moves = false;
+                           return;
+                       }
+                       case M_HIGHQUALITY:
+                           //else if (name == "_highquality")
+                       {
+                           // @@ global { 0, 1, 2 }
+       //                              // Whether we're in high quality mode 
or not.
+       //                              val->set(true);
+                           return;
+                       }
+                       case M_FOCUSRECT:
+                           //else if (name == "_focusrect")
+                       {
+       //                              // Is a yellow rectangle visible around 
a focused movie clip (?)
+       //                              val->set(false);
+                           return;
+                       }
+                       case M_SOUNDBUFTIME:
+                           //else if (name == "_soundbuftime")
+                       {
+                           // @@ global
+       //                              // Number of seconds before sound 
starts to stream.
+       //                              val->set(0.0);
+                           return;
+                       }
+                       }       // end switch
+
+                               // Not a built-in property.  See if we have a
+                               // matching edit_text character in our display
+                               // list.
+                   bool        text_val = val.get_type() == as_value::STRING
+                       || val.get_type() == as_value::NUMBER;
+                   if (text_val)
+                       {
+                           bool        success = false;
+                           for (int i = 0, n = 
m_display_list.get_character_count(); i < n; i++)
+                               {
+                                   character*  ch = 
m_display_list.get_character(i);
+                                   // CASE INSENSITIVE compare.  In 
ActionScript 2.0, this
+                                   // changes to CASE SENSITIVE!!!
+                                   if (name == ch->get_text_name())
+                                       {
+                                           const char* text = val.to_string();
+                                           ch->set_text_value(text);
+                                           success = true;
+                                       }
+                               }
+                           if (success) return;
+                       }
+
+                   // If that didn't work, set a variable within this 
environment.
+                   m_as_environment.set_member(name, val);
+       }
+
+       const char* sprite_instance::get_variable(const char* path_to_var) const
+       {
+           assert(m_parent == NULL);   // should only be called on the root 
movie.
+
+           array<with_stack_entry>     empty_with_stack;
+           tu_string   path(path_to_var);
+
+           // NOTE: this is static so that the string
+           // value won't go away after we return!!!
+           // It'll go away during the next call to this
+           // function though!!!  NOT THREAD SAFE!
+           static as_value     val;
+
+           val = m_as_environment.get_variable(path, empty_with_stack);
+
+           return val.to_string();     // ack!
+       }
+
+       void sprite_instance::set_variable(const char* path_to_var,
+                       const wchar_t* new_value)
+       {
+               if (path_to_var == NULL)
+               {
+                       log_error("error: NULL path_to_var passed to 
set_variable()\n");
+                       return;
+               }
+               if (new_value == NULL)
+               {
+                       log_error("error: NULL passed to set_variable('%s',"
+                               " NULL)\n", path_to_var);
+                       return;
+               }
+
+               // should only be called on the root movie.
+               assert(m_parent == NULL);
+
+               array<with_stack_entry> empty_with_stack;
+               tu_string       path(path_to_var);
+               as_value        val(new_value);
+
+               m_as_environment.set_variable(path, val, empty_with_stack);
+       }
+
+       void sprite_instance::set_variable(const char* path_to_var,
+                       const char* new_value)
+       {
+                   assert(m_parent == NULL);   // should only be called on the 
root movie.
+
+                   if (path_to_var == NULL)
+                       {
+                           log_error("error: NULL path_to_var passed to 
set_variable()\n");
+                           return;
+                       }
+                   if (new_value == NULL)
+                       {
+                           log_error("error: NULL passed to set_variable('%s', 
NULL)\n", path_to_var);
+                           return;
+                       }
+
+                   array<with_stack_entry>     empty_with_stack;
+                   tu_string   path(path_to_var);
+                   as_value    val(new_value);
+
+                   m_as_environment.set_variable(path, val, empty_with_stack);
+       }
+
+       void sprite_instance::advance(float delta_time)
+       {
+       //      printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
+
+       // Keep this (particularly m_as_environment) alive during execution!
+               smart_ptr<as_object_interface>  this_ptr(this);
+
+               assert(m_def != NULL && m_root != NULL);
+
+               // Advance everything in the display list.
+               m_display_list.advance(delta_time);
+
+               // mouse drag.
+               character::do_mouse_drag();
+
+               m_time_remainder += delta_time;
+
+               const float     frame_time = 1.0f / m_root->get_frame_rate();   
// @@ cache this
+
+               // Check for the end of frame
+               if (m_time_remainder >= frame_time)
+               {
+                           m_time_remainder -= frame_time;
+
+                           // Update current and next frames.
+                           if (m_play_state == PLAY)
+                               {
+                                   int current_frame0 = m_current_frame;
+                                   increment_frame_and_check_for_loop();
+
+                                   // Execute the current frame's tags.
+                                   if (m_current_frame != current_frame0)
+                                       {
+                                           execute_frame_tags(m_current_frame);
+                                       }
+                               }
+
+                           // Dispatch onEnterFrame event.
+                           on_event(event_id::ENTER_FRAME);
+
+                           do_actions();
+
+                           // Clean up display list (remove dead objects).
+                           m_display_list.update();
+               }
+
+               // Skip excess time.  TODO root caller should
+               // loop to prevent this happening; probably
+               // only root should keep m_time_remainder, and
+               // advance(dt) should be a discrete tick()
+               // with no dt.
+               m_time_remainder = fmod(m_time_remainder, frame_time);
+       }
+
+       void sprite_instance::execute_frame_tags(int frame,
+               bool state_only)
+       {
+           // Keep this (particularly m_as_environment) alive during execution!
+           smart_ptr<as_object_interface>      this_ptr(this);
+
+           assert(frame >= 0);
+           assert(frame < m_def->get_frame_count());
+
+           // Execute this frame's init actions, if necessary.
+           if (m_init_actions_executed[frame] == false)
+               {
+                   const array<execute_tag*>*  init_actions = 
m_def->get_init_actions(frame);
+                   if (init_actions && init_actions->size() > 0)
+                       {
+                           // Need to execute these actions.
+                           for (int i= 0; i < init_actions->size(); i++)
+                               {
+                                   execute_tag*        e = (*init_actions)[i];
+                                   e->execute(this);
+                               }
+
+                           // Mark this frame done, so we never execute these 
init actions
+                           // again.
+                           m_init_actions_executed[frame] = true;
+                       }
+               }
+
+           const array<execute_tag*>&  playlist = m_def->get_playlist(frame);
+           for (int i = 0; i < playlist.size(); i++)
+               {
+                   execute_tag*        e = playlist[i];
+                   if (state_only)
+                       {
+                           e->execute_state(this);
+                       }
+                   else
+                       {
+                           e->execute(this);
+                       }
+               }
+       }
+
+       void sprite_instance::execute_frame_tags_reverse(int frame)
+       {
+           // Keep this (particularly m_as_environment) alive during execution!
+           smart_ptr<as_object_interface>      this_ptr(this);
+
+           assert(frame >= 0);
+           assert(frame < m_def->get_frame_count());
+
+           const array<execute_tag*>&  playlist = m_def->get_playlist(frame);
+           for (int i = 0; i < playlist.size(); i++)
+               {
+                   execute_tag*        e = playlist[i];
+                   e->execute_state_reverse(this, frame);
+               }
+       }
+
+       void sprite_instance::execute_remove_tags(int frame)
+       {
+                   assert(frame >= 0);
+                   assert(frame < m_def->get_frame_count());
+
+                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame);
+                   for (int i = 0; i < playlist.size(); i++)
+                       {
+                           execute_tag*        e = playlist[i];
+                           if (e->is_remove_tag())
+                               {
+                                   e->execute_state(this);
+                               }
+                       }
+       }
+
+       execute_tag*
+       sprite_instance::find_previous_replace_or_add_tag(int frame,
+                       int depth, int id)
+       {
+               uint32 depth_id = ((depth & 0x0FFFF) << 16) | (id & 0x0FFFF);
+
+               for (int f = frame - 1; f >= 0; f--)
+               {
+                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(f);
+                   for (int i = playlist.size() - 1; i >= 0; i--)
+                       {
+                           execute_tag*        e = playlist[i];
+                           if (e->get_depth_id_of_replace_or_add_tag() == 
depth_id)
+                               {
+                                   return e;
+                               }
+                       }
+               }
+
+           return NULL;
+       }
+
+       void
+       sprite_instance::goto_frame(int target_frame_number)
+       {
+       //                      
IF_VERBOSE_DEBUG(log_msg("sprite::goto_frame(%d)\n", 
target_frame_number));//xxxxx
+
+                   target_frame_number = iclamp(target_frame_number, 0, 
m_def->get_frame_count() - 1);
+
+                   if (target_frame_number < m_current_frame)
+                       {
+                           for (int f = m_current_frame; f > 
target_frame_number; f--)
+                               {
+                                   execute_frame_tags_reverse(f);
+                               }
+
+                           execute_frame_tags(target_frame_number, false);
+                           m_display_list.update();
+                       }
+                   else if (target_frame_number > m_current_frame)
+                       {
+                           for (int f = m_current_frame + 1; f < 
target_frame_number; f++)
+                               {
+                                   execute_frame_tags(f, true);
+                               }
+
+                           execute_frame_tags(target_frame_number, false);
+                           m_display_list.update();
+                       }
+
+                   m_current_frame = target_frame_number;      
+
+                   // goto_frame stops by default.
+                   m_play_state = STOP;
+       }
+
+       bool sprite_instance::goto_labeled_frame(const char* label)
+       {
+           int target_frame = -1;
+           if (m_def->get_labeled_frame(label, &target_frame))
+               {
+                   goto_frame(target_frame);
+                   return true;
+               }
+           else
+               {
+                   IF_VERBOSE_ACTION(
+                       log_error("error: movie_impl::goto_labeled_frame('%s') 
unknown label\n", label));
+                   return false;
+               }
+       }
+
+       void sprite_instance::display()
+       {
+           if (get_visible() == false)
+               {
+                   // We're invisible, so don't display!
+                   return;
+               }
+
+           m_display_list.display();
+
+           do_display_callback();
+       }
+
+       character*
+       sprite_instance::add_display_object(Uint16 character_id,
+                       const char* name,
+                       const array<swf_event*>& event_handlers,
+                       Uint16 depth, bool replace_if_depth_is_occupied,
+                       const cxform& color_transform, const matrix& matrix,
+                       float ratio, Uint16 clip_depth)
+       {
+                   assert(m_def != NULL);
+
+                   character_def*      cdef = 
m_def->get_character_def(character_id);
+                   if (cdef == NULL)
+                       {
+                           log_error("sprite::add_display_object(): unknown 
cid = %d\n", character_id);
+                           return NULL;
+                       }
+
+                   // If we already have this object on this
+                   // plane, then move it instead of replacing
+                   // it.
+                   character*  existing_char = 
m_display_list.get_character_at_depth(depth);
+                   if (existing_char
+                       && existing_char->get_id() == character_id
+                       && ((name == NULL && existing_char->get_name().length() 
== 0)
+                           || (name && existing_char->get_name() == name)))
+                       {
+       //                              IF_VERBOSE_DEBUG(log_msg("add changed 
to move on depth %d\n", depth));//xxxxxx
+                           move_display_object(depth, true, color_transform, 
true, matrix, ratio, clip_depth);
+                           return NULL;
+                       }
+                   //printf("%s: character %s, id is %d, count is %d\n", 
__FUNCTION__, existing_char->get_name(), 
character_id,m_display_list.get_character_count()); // FIXME:
+
+                   assert(cdef);
+                   smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
+                   assert(ch != NULL);
+                   if (name != NULL && name[0] != 0)
+                       {
+                           ch->set_name(name);
+                       }
+
+                   // Attach event handlers (if any).
+                   {for (int i = 0, n = event_handlers.size(); i < n; i++)
+                       {
+                           event_handlers[i]->attach_to(ch.get_ptr());
+                       }}
+
+                   m_display_list.add_display_object(
+                       ch.get_ptr(),
+                       depth,
+                       replace_if_depth_is_occupied,
+                       color_transform,
+                       matrix,
+                       ratio,
+                       clip_depth);
+
+                   assert(ch == NULL || ch->get_ref_count() > 1);
+                   return ch.get_ptr();
+       }
+
+       void
+       sprite_instance::replace_display_object(
+                       Uint16 character_id,
+                       const char* name,
+                       Uint16 depth,
+                       bool use_cxform,
+                       const cxform& color_transform,
+                       bool use_matrix,
+                       const matrix& mat,
+                       float ratio,
+                       Uint16 clip_depth)
+       {
+                   assert(m_def != NULL);
+                   // printf("%s: character %s, id is %d\n", __FUNCTION__, 
name, character_id); // FIXME: debugging crap
+
+                   character_def*      cdef = 
m_def->get_character_def(character_id);
+                   if (cdef == NULL)
+                       {
+                           log_error("sprite::replace_display_object(): 
unknown cid = %d\n", character_id);
+                           return;
+                       }
+                   assert(cdef);
+
+                   smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
+                   assert(ch != NULL);
+
+                   if (name != NULL && name[0] != 0)
+                       {
+                           ch->set_name(name);
+                       }
+
+                   m_display_list.replace_display_object(
+                       ch.get_ptr(),
+                       depth,
+                       use_cxform,
+                       color_transform,
+                       use_matrix,
+                       mat,
+                       ratio,
+                       clip_depth);
+       }
+
+       void sprite_instance::replace_display_object(
+                       character* ch,
+                       const char* name,
+                       Uint16 depth,
+                       bool use_cxform,
+                       const cxform& color_transform,
+                       bool use_matrix,
+                       const matrix& mat,
+                       float ratio,
+                       Uint16 clip_depth)
+       {
+           printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
ch->get_id()); // FIXME:
+
+           assert(ch != NULL);
+
+           if (name != NULL && name[0] != 0)
+               {
+                   ch->set_name(name);
+               }
+
+           m_display_list.replace_display_object(
+               ch,
+               depth,
+               use_cxform,
+               color_transform,
+               use_matrix,
+               mat,
+               ratio,
+               clip_depth);
+       }
+
+       int sprite_instance::get_id_at_depth(int depth)
+       {
+           int index = m_display_list.get_display_index(depth);
+           if (index == -1) return -1;
+
+           character*  ch = 
m_display_list.get_display_object(index).m_character.get_ptr();
+
+           return ch->get_id();
+       }
+
+       void sprite_instance::increment_frame_and_check_for_loop()
+       {
+           m_current_frame++;
+
+           int frame_count = m_def->get_frame_count();
+           if (m_current_frame >= frame_count)
+               {
+                   // Loop.
+                   m_current_frame = 0;
+                   m_has_looped = true;
+                   if (frame_count > 1)
+                       {
+                           m_display_list.reset();
+                       }
+               }
+       }
+
+       movie*
+       sprite_instance::get_topmost_mouse_entity(float x, float y)
+       {
+           if (get_visible() == false) {
+               return NULL;
+           }
+
+           matrix      m = get_matrix();
+           point       p;
+           m.transform_by_inverse(&p, point(x, y));
+
+           int i, n = m_display_list.get_character_count();
+           // Go backwards, to check higher objects first.
+           for (i = n - 1; i >= 0; i--)
+               {
+                   character* ch = m_display_list.get_character(i);
+                               
+                   if (ch != NULL && ch->get_visible())
+                       {
+                           movie*      te = 
ch->get_topmost_mouse_entity(p.m_x, p.m_y);
+                           if (te)
+                               {
+                                   // The containing entity that 1) is closest 
to root and 2) can
+                                   // handle mouse events takes precedence.
+                                   if (can_handle_mouse_event()) {
+                                       return this;
+                                   } else {
+                                       return te;
+                                   }
+                               }
+                       }
+               }
+
+           return NULL;
+       }
+
+       bool
+       sprite_instance::can_handle_mouse_event()
+       {
+           // We should cache this!
+           as_value dummy;
+
+           // Functions that qualify as mouse event handlers.
+           const char* FN_NAMES[] = {
+               "onKeyPress",
+               "onRelease",
+               "onDragOver",
+               "onDragOut",
+               "onPress",
+               "onReleaseOutside",
+               "onRollout",
+               "onRollover",
+           };
+           for (unsigned int i = 0; i < ARRAYSIZE(FN_NAMES); i++) {
+               if (get_member(FN_NAMES[i], &dummy)) {
+                   return true;
+               }
+           }
+
+           // Event handlers that qualify as mouse event handlers.
+           const event_id::id_code EH_IDS[] = {
+               event_id::PRESS,
+               event_id::RELEASE,
+               event_id::RELEASE_OUTSIDE,
+               event_id::ROLL_OVER,
+               event_id::ROLL_OUT,
+               event_id::DRAG_OVER,
+               event_id::DRAG_OUT,
+           };
+           {for (unsigned int i = 0; i < ARRAYSIZE(EH_IDS); i++) {
+               if (get_event_handler(EH_IDS[i], &dummy)) {
+                   return true;
+               }
+           }}
+
+           return false;
+       }
+                       
+       void sprite_instance::restart()
+       {
+           m_current_frame = 0;
+           m_time_remainder = 0;
+           m_update_frame = true;
+           m_has_looped = false;
+           m_play_state = PLAY;
+
+           execute_frame_tags(m_current_frame);
+           m_display_list.update();
+       }
+
+       float sprite_instance::get_height()
+       {
+           float       h = 0; 
+           int i, n = m_display_list.get_character_count();
+           character* ch;
+           for (i=0; i < n; i++)
+               {
+                   ch = m_display_list.get_character(i);
+                   if (ch != NULL)
+                       {
+                           float       ch_h = ch->get_height();
+                           if (ch_h > h)
+                               {
+                                   h = ch_h;
+                               }
+                       }
+               }
+           return h;
+       }
+
+       float sprite_instance::get_width()
+       {
+           float       w = 0;
+           int i, n = m_display_list.get_character_count();
+           character* ch;
+           for (i = 0; i < n; i++)
+               {
+                   ch = m_display_list.get_character(i);
+                   if (ch != NULL)
+                       {
+                           float ch_w = ch->get_width();
+                           if (ch_w > w)
+                               {
+                                   w = ch_w;
+                               }
+                       }
+               }
+
+           return w;
+       }
+
+       void sprite_instance::do_something(void *timer)
+       {
+           as_value    val;
+           as_object      *obj, *this_ptr;
+           as_environment *as_env;
+
+           //printf("FIXME: %s:\n", __FUNCTION__);
+           Timer *ptr = (Timer *)timer;
+           //log_msg("INTERVAL ID is %d\n", ptr->getIntervalID());
+
+           const as_value&     timer_method = ptr->getASFunction();
+           as_env = ptr->getASEnvironment();
+           this_ptr = ptr->getASObject();
+           obj = ptr->getObject();
+           //m_as_environment.push(obj);
+                       
+           as_c_function_ptr   cfunc = timer_method.to_c_function();
+           if (cfunc) {
+               // It's a C function. Call it.
+               //log_msg("Calling C function for interval timer\n");
+               //(*cfunc)(&val, obj, as_env, 0, 0);
+               (*cfunc)(fn_call(&val, obj, &m_as_environment, 0, 0));
+                               
+           } else if (as_as_function* as_func = timer_method.to_as_function()) 
{
+               // It's an ActionScript function. Call it.
+               as_value method;
+               //log_msg("Calling ActionScript function for interval timer\n");
+               (*as_func)(fn_call(&val, (as_object_interface *)this_ptr, 
as_env, 0, 0));
+               //(*as_func)(&val, (as_object_interface *)this_ptr, 
&m_as_environment, 1, 1);
+           } else {
+               log_error("error in call_method(): method is not a function\n");
+           }    
+       }       
 } // namespace gnash
Index: gnash/server/Sprite.h
diff -u gnash/server/Sprite.h:1.2 gnash/server/Sprite.h:1.3
--- gnash/server/Sprite.h:1.2   Thu Jan 26 00:15:57 2006
+++ gnash/server/Sprite.h       Fri Jan 27 00:54:38 2006
@@ -17,18 +17,24 @@
 
 // Implementation for ActionScript MovieClip object.
 
-// A sprite, or MovieClip, is a mini movie-within-a-movie. 
-// It doesn't define its own characters;
-// it uses the characters from the parent
-// movie, but it has its own frame counter, display list, etc.
-//
-// @@ are we sure it doesn't define its own chars ?
-//
-// The sprite implementation is divided into a
-// sprite_definition and a sprite_instance.  The _definition
-// holds the immutable data for a sprite, while the _instance
-// contains the state for a specific instance being updated
-// and displayed in the parent movie's display list.
+/// \page Sprite Sprites and MovieClips
+///
+/// A Sprite, or MovieClip, is a mini movie-within-a-movie. 
+///
+/// It doesn't define its own characters;
+/// it uses the characters from the parent
+/// movie, but it has its own frame counter, display list, etc.
+///
+/// @@ are we sure it doesn't define its own chars ?
+///
+/// The sprite implementation is divided into 
+/// gnash::sprite_definition and gnash::sprite_instance.
+///
+/// The _definition holds the immutable data for a sprite, while the _instance
+/// contains the state for a specific instance being updated
+/// and displayed in the parent movie's display list.
+///
+/// @@ QUESTION: why isn't sprite_definition a bunch of statics ?
 
 #ifndef GNASH_SPRITE_H
 #define GNASH_SPRITE_H
@@ -36,6 +42,7 @@
 #include "Movie.h"
 #include "dlist.h" // display_list 
 #include "stream.h"
+#include <vector>
 
 namespace gnash
 {
@@ -244,17 +251,16 @@
        };
 
 
-       /// Sprite instance
-       //
        /// Stateful Sprite object. Also known as a MovieClip.
-       ///
        struct sprite_instance : public character
        {
                smart_ptr<movie_definition_sub> m_def;
                movie_root*     m_root;
 
                display_list    m_display_list;
-               array<action_buffer*>   m_action_list;
+
+               //array<action_buffer*> m_action_list;
+               std::vector<action_buffer*>     m_action_list;
 
                play_state      m_play_state;
                int             m_current_frame;
@@ -286,17 +292,17 @@
 
                sprite_instance(movie_definition_sub* def,
                        movie_root* r, movie* parent, int id)
-               :
-               character(parent, id),
-               m_def(def),
-               m_root(r),
-               m_play_state(PLAY),
-               m_current_frame(0),
-               m_time_remainder(0),
-               m_update_frame(true),
-               m_has_looped(false),
-               m_accept_anim_moves(true),
-               m_mouse_state(UP)
+                       :
+                       character(parent, id),
+                       m_def(def),
+                       m_root(r),
+                       m_play_state(PLAY),
+                       m_current_frame(0),
+                       m_time_remainder(0),
+                       m_update_frame(true),
+                       m_has_looped(false),
+                       m_accept_anim_moves(true),
+                       m_mouse_state(UP)
                {
                        assert(m_def != NULL);
                        assert(m_root != NULL);
@@ -319,772 +325,262 @@
                    return m_root->add_interval_timer(timer);
                }
 
-           virtual void    clear_interval_timer(int x)
+               virtual void  clear_interval_timer(int x)
                {
                    // log_msg("FIXME: %s:\n", __FUNCTION__);
                    m_root->clear_interval_timer(x);
                }
                
 
-           /* sprite_instance */
-           virtual void    do_something(void *timer)
-               {
-                   as_value    val;
-                   as_object      *obj, *this_ptr;
-                   as_environment *as_env;
-
-                   //printf("FIXME: %s:\n", __FUNCTION__);
-                   Timer *ptr = (Timer *)timer;
-                   //log_msg("INTERVAL ID is %d\n", ptr->getIntervalID());
-
-                   const as_value&     timer_method = ptr->getASFunction();
-                   as_env = ptr->getASEnvironment();
-                   this_ptr = ptr->getASObject();
-                   obj = ptr->getObject();
-                   //m_as_environment.push(obj);
-                               
-                   as_c_function_ptr   cfunc = timer_method.to_c_function();
-                   if (cfunc) {
-                       // It's a C function. Call it.
-                       //log_msg("Calling C function for interval timer\n");
-                       //(*cfunc)(&val, obj, as_env, 0, 0);
-                       (*cfunc)(fn_call(&val, obj, &m_as_environment, 0, 0));
-                                       
-                   } else if (as_as_function* as_func = 
timer_method.to_as_function()) {
-                       // It's an ActionScript function. Call it.
-                       as_value method;
-                       //log_msg("Calling ActionScript function for interval 
timer\n");
-                       (*as_func)(fn_call(&val, (as_object_interface 
*)this_ptr, as_env, 0, 0));
-                       //(*as_func)(&val, (as_object_interface *)this_ptr, 
&m_as_environment, 1, 1);
-                   } else {
-                       log_error("error in call_method(): method is not a 
function\n");
-                   }    
-               }       
+               /// Interval timer timeout executor
+               virtual void    do_something(void *timer);
 
-           virtual ~sprite_instance()
+               virtual ~sprite_instance()
                {
                    m_display_list.clear();
                    //m_root->drop_ref();
                }
 
-           movie_interface*    get_root_interface() { return m_root; }
-           movie_root* get_root() { return m_root; }
-           movie*      get_root_movie() { return m_root->get_root_movie(); }
-
-           movie_definition*   get_movie_definition() { return 
m_def.get_ptr(); }
-
-           float       get_width()
-               {
-                   float       w = 0;
-                   int i, n = m_display_list.get_character_count();
-                   character* ch;
-                   for (i = 0; i < n; i++)
-                       {
-                           ch = m_display_list.get_character(i);
-                           if (ch != NULL)
-                               {
-                                   float ch_w = ch->get_width();
-                                   if (ch_w > w)
-                                       {
-                                           w = ch_w;
-                                       }
-                               }
-                       }
-
-                   return w;
+               movie_interface* get_root_interface() {
+                       return m_root;
                }
 
-
-           float       get_height()
-               {
-                   float       h = 0; 
-                   int i, n = m_display_list.get_character_count();
-                   character* ch;
-                   for (i=0; i < n; i++)
-                       {
-                           ch = m_display_list.get_character(i);
-                           if (ch != NULL)
-                               {
-                                   float       ch_h = ch->get_height();
-                                   if (ch_h > h)
-                                       {
-                                           h = ch_h;
-                                       }
-                               }
-                       }
-                   return h;
+               movie_root* get_root() {
+                       return m_root;
                }
 
-           int get_current_frame() const { return m_current_frame; }
-           int get_frame_count() const { return m_def->get_frame_count(); }
-
-           void        set_play_state(play_state s)
-               // Stop or play the sprite.
-               {
-                   if (m_play_state != s)
-                       {
-                           m_time_remainder = 0;
-                       }
-
-                   m_play_state = s;
+               movie*  get_root_movie() {
+                       return m_root->get_root_movie();
                }
-           play_state  get_play_state() const { return m_play_state; }
-
 
-           character*  get_character(int character_id)
-               {
-       //                      return m_def->get_character_def(character_id);
-                   // @@ TODO -- look through our dlist for a match
-                   return NULL;
+               movie_definition* get_movie_definition() {
+                       return m_def.get_ptr();
                }
 
-           float       get_background_alpha() const
-               {
-                   // @@ this doesn't seem right...
-                   return m_root->get_background_alpha();
-               }
+               float get_width();
 
-           float       get_pixel_scale() const { return 
m_root->get_pixel_scale(); }
+               float   get_height();
 
-           virtual void        get_mouse_state(int* x, int* y, int* buttons)
+               int get_current_frame() const
                {
-                   m_root->get_mouse_state(x, y, buttons);
+                       return m_current_frame;
                }
 
-           void        set_background_color(const rgba& color)
+               int get_frame_count() const
                {
-                   m_root->set_background_color(color);
+                       return m_def->get_frame_count();
                }
 
-           float       get_timer() const { return m_root->get_timer(); }
-
-           void        restart()
+               /// Stop or play the sprite.
+               void set_play_state(play_state s)
                {
-                   m_current_frame = 0;
-                   m_time_remainder = 0;
-                   m_update_frame = true;
-                   m_has_looped = false;
-                   m_play_state = PLAY;
-
-                   execute_frame_tags(m_current_frame);
-                   m_display_list.update();
+                   if (m_play_state != s) m_time_remainder = 0;
+                   m_play_state = s;
                }
 
+               play_state get_play_state() const { return m_play_state; }
 
-           virtual bool        has_looped() const { return m_has_looped; }
-
-           virtual bool        get_accept_anim_moves() const { return 
m_accept_anim_moves; }
-
-           inline int  transition(int a, int b) const
-               // Combine the flags to avoid a conditional. It would be faster 
with a macro.
+               character* get_character(int character_id)
                {
-                   return (a << 2) | b;
+                       //return m_def->get_character_def(character_id);
+                       // @@ TODO -- look through our dlist for a match
+                       log_msg("FIXME: %s doesn't even check for a char",
+                               __PRETTY_FUNCTION__);
+                       return NULL;
                }
 
-
-           bool can_handle_mouse_event()
-               // Return true if we have any mouse event handlers.
+               float   get_background_alpha() const
                {
-                   // We should cache this!
-                   as_value dummy;
-
-                   // Functions that qualify as mouse event handlers.
-                   const char* FN_NAMES[] = {
-                       "onKeyPress",
-                       "onRelease",
-                       "onDragOver",
-                       "onDragOut",
-                       "onPress",
-                       "onReleaseOutside",
-                       "onRollout",
-                       "onRollover",
-                   };
-                   for (unsigned int i = 0; i < ARRAYSIZE(FN_NAMES); i++) {
-                       if (get_member(FN_NAMES[i], &dummy)) {
-                           return true;
-                       }
-                   }
-
-                   // Event handlers that qualify as mouse event handlers.
-                   const event_id::id_code EH_IDS[] = {
-                       event_id::PRESS,
-                       event_id::RELEASE,
-                       event_id::RELEASE_OUTSIDE,
-                       event_id::ROLL_OVER,
-                       event_id::ROLL_OUT,
-                       event_id::DRAG_OVER,
-                       event_id::DRAG_OUT,
-                   };
-                   {for (unsigned int i = 0; i < ARRAYSIZE(EH_IDS); i++) {
-                       if (get_event_handler(EH_IDS[i], &dummy)) {
-                           return true;
-                       }
-                   }}
-
-                   return false;
+                   // @@ this doesn't seem right...
+                   return m_root->get_background_alpha();
                }
-                       
 
-           /* sprite_instance */
-           virtual movie*      get_topmost_mouse_entity(float x, float y)
-               // Return the topmost entity that the given point
-               // covers that can receive mouse events.  NULL if
-               // none.  Coords are in parent's frame.
+               float   get_pixel_scale() const
                {
-                   if (get_visible() == false) {
-                       return NULL;
-                   }
-
-                   matrix      m = get_matrix();
-                   point       p;
-                   m.transform_by_inverse(&p, point(x, y));
-
-                   int i, n = m_display_list.get_character_count();
-                   // Go backwards, to check higher objects first.
-                   for (i = n - 1; i >= 0; i--)
-                       {
-                           character* ch = m_display_list.get_character(i);
-                                       
-                           if (ch != NULL && ch->get_visible())
-                               {
-                                   movie*      te = 
ch->get_topmost_mouse_entity(p.m_x, p.m_y);
-                                   if (te)
-                                       {
-                                           // The containing entity that 1) is 
closest to root and 2) can
-                                           // handle mouse events takes 
precedence.
-                                           if (can_handle_mouse_event()) {
-                                               return this;
-                                           } else {
-                                               return te;
-                                           }
-                                       }
-                               }
-                       }
-
-                   return NULL;
+                       return m_root->get_pixel_scale();
                }
 
-
-           /* sprite_instance */
-           void        increment_frame_and_check_for_loop()
-               // Increment m_current_frame, and take care of looping.
+               virtual void    get_mouse_state(int* x, int* y, int* buttons)
                {
-                   m_current_frame++;
-
-                   int frame_count = m_def->get_frame_count();
-                   if (m_current_frame >= frame_count)
-                       {
-                           // Loop.
-                           m_current_frame = 0;
-                           m_has_looped = true;
-                           if (frame_count > 1)
-                               {
-                                   m_display_list.reset();
-                               }
-                       }
+                   m_root->get_mouse_state(x, y, buttons);
                }
 
-           /* sprite_instance */
-           virtual void        advance(float delta_time)
+               void    set_background_color(const rgba& color)
                {
-       //          printf("%s:\n", __PRETTY_FUNCTION__); // FIXME:
-
-                   // Keep this (particularly m_as_environment) alive during 
execution!
-                   smart_ptr<as_object_interface>      this_ptr(this);
-
-                   assert(m_def != NULL && m_root != NULL);
-
-                   // Advance everything in the display list.
-                   m_display_list.advance(delta_time);
-
-                   // mouse drag.
-                   character::do_mouse_drag();
-
-                   m_time_remainder += delta_time;
-
-                   const float frame_time = 1.0f / m_root->get_frame_rate();   
// @@ cache this
-
-                   // Check for the end of frame
-                   if (m_time_remainder >= frame_time)
-                       {
-                           m_time_remainder -= frame_time;
-
-                           // Update current and next frames.
-                           if (m_play_state == PLAY)
-                               {
-                                   int current_frame0 = m_current_frame;
-                                   increment_frame_and_check_for_loop();
-
-                                   // Execute the current frame's tags.
-                                   if (m_current_frame != current_frame0)
-                                       {
-                                           execute_frame_tags(m_current_frame);
-                                       }
-                               }
-
-                           // Dispatch onEnterFrame event.
-                           on_event(event_id::ENTER_FRAME);
-
-                           do_actions();
-
-                           // Clean up display list (remove dead objects).
-                           m_display_list.update();
-                       }
-
-                   // Skip excess time.  TODO root caller should
-                   // loop to prevent this happening; probably
-                   // only root should keep m_time_remainder, and
-                   // advance(dt) should be a discrete tick()
-                   // with no dt.
-                   m_time_remainder = fmod(m_time_remainder, frame_time);
+                   m_root->set_background_color(color);
                }
 
-           /*sprite_instance*/
-           void        execute_frame_tags(int frame, bool state_only = false)
-               // Execute the tags associated with the specified frame.
-               // frame is 0-based
-               {
-                   // Keep this (particularly m_as_environment) alive during 
execution!
-                   smart_ptr<as_object_interface>      this_ptr(this);
-
-                   assert(frame >= 0);
-                   assert(frame < m_def->get_frame_count());
-
-                   // Execute this frame's init actions, if necessary.
-                   if (m_init_actions_executed[frame] == false)
-                       {
-                           const array<execute_tag*>*  init_actions = 
m_def->get_init_actions(frame);
-                           if (init_actions && init_actions->size() > 0)
-                               {
-                                   // Need to execute these actions.
-                                   for (int i= 0; i < init_actions->size(); 
i++)
-                                       {
-                                           execute_tag*        e = 
(*init_actions)[i];
-                                           e->execute(this);
-                                       }
-
-                                   // Mark this frame done, so we never 
execute these init actions
-                                   // again.
-                                   m_init_actions_executed[frame] = true;
-                               }
-                       }
+               float   get_timer() const { return m_root->get_timer(); }
 
-                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame);
-                   for (int i = 0; i < playlist.size(); i++)
-                       {
-                           execute_tag*        e = playlist[i];
-                           if (state_only)
-                               {
-                                   e->execute_state(this);
-                               }
-                           else
-                               {
-                                   e->execute(this);
-                               }
-                       }
-               }
+               void    restart();
 
 
-           /*sprite_instance*/
-           void        execute_frame_tags_reverse(int frame)
-               // Execute the tags associated with the specified frame, IN 
REVERSE.
-               // I.e. if it's an "add" tag, then we do a "remove" instead.
-               // Only relevant to the display-list manipulation tags: add, 
move, remove, replace.
-               //
-               // frame is 0-based
+               virtual bool has_looped() const
                {
-                   // Keep this (particularly m_as_environment) alive during 
execution!
-                   smart_ptr<as_object_interface>      this_ptr(this);
-
-                   assert(frame >= 0);
-                   assert(frame < m_def->get_frame_count());
-
-                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame);
-                   for (int i = 0; i < playlist.size(); i++)
-                       {
-                           execute_tag*        e = playlist[i];
-                           e->execute_state_reverse(this, frame);
-                       }
+                       return m_has_looped;
                }
 
-                       
-           /*sprite_instance*/
-           execute_tag*        find_previous_replace_or_add_tag(int frame, int 
depth, int id)
+               virtual bool get_accept_anim_moves() const
                {
-                   uint32      depth_id = ((depth & 0x0FFFF) << 16) | (id & 
0x0FFFF);
-
-                   for (int f = frame - 1; f >= 0; f--)
-                       {
-                           const array<execute_tag*>&  playlist = 
m_def->get_playlist(f);
-                           for (int i = playlist.size() - 1; i >= 0; i--)
-                               {
-                                   execute_tag*        e = playlist[i];
-                                   if (e->get_depth_id_of_replace_or_add_tag() 
== depth_id)
-                                       {
-                                           return e;
-                                       }
-                               }
-                       }
-
-                   return NULL;
+                       return m_accept_anim_moves;
                }
 
-
-           /*sprite_instance*/
-           void        execute_remove_tags(int frame)
-               // Execute any remove-object tags associated with the specified 
frame.
-               // frame is 0-based
+               /// Combine the flags to avoid a conditional.
+               /// It would be faster with a macro.
+               inline int transition(int a, int b) const
                {
-                   assert(frame >= 0);
-                   assert(frame < m_def->get_frame_count());
-
-                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame);
-                   for (int i = 0; i < playlist.size(); i++)
-                       {
-                           execute_tag*        e = playlist[i];
-                           if (e->is_remove_tag())
-                               {
-                                   e->execute_state(this);
-                               }
-                       }
+                   return (a << 2) | b;
                }
 
 
-               // Take care of this frame's actions.
-               void do_actions();
-
-
-           /*sprite_instance*/
-           void        goto_frame(int target_frame_number)
-               // Set the sprite state at the specified frame number.
-               // 0-based frame numbers!!  (in contrast to ActionScript and 
Flash MX)
-               {
-       //                      
IF_VERBOSE_DEBUG(log_msg("sprite::goto_frame(%d)\n", 
target_frame_number));//xxxxx
-
-                   target_frame_number = iclamp(target_frame_number, 0, 
m_def->get_frame_count() - 1);
-
-                   if (target_frame_number < m_current_frame)
-                       {
-                           for (int f = m_current_frame; f > 
target_frame_number; f--)
-                               {
-                                   execute_frame_tags_reverse(f);
-                               }
-
-                           execute_frame_tags(target_frame_number, false);
-                           m_display_list.update();
-                       }
-                   else if (target_frame_number > m_current_frame)
-                       {
-                           for (int f = m_current_frame + 1; f < 
target_frame_number; f++)
-                               {
-                                   execute_frame_tags(f, true);
-                               }
-
-                           execute_frame_tags(target_frame_number, false);
-                           m_display_list.update();
-                       }
-
-                   m_current_frame = target_frame_number;      
-
-                   // goto_frame stops by default.
-                   m_play_state = STOP;
-               }
+               /// Return true if we have any mouse event handlers.
+               bool can_handle_mouse_event();
 
-
-           bool        goto_labeled_frame(const char* label)
-               // Look up the labeled frame, and jump to it.
-               {
-                   int target_frame = -1;
-                   if (m_def->get_labeled_frame(label, &target_frame))
-                       {
-                           goto_frame(target_frame);
-                           return true;
-                       }
-                   else
-                       {
-                           IF_VERBOSE_ACTION(
-                               log_error("error: 
movie_impl::goto_labeled_frame('%s') unknown label\n", label));
-                           return false;
-                       }
-               }
+               /// Return the topmost entity that the given point
+               /// covers that can receive mouse events.  NULL if
+               /// none.  Coords are in parent's frame.
+               virtual movie*  get_topmost_mouse_entity(float x, float y);
+
+               /// Increment m_current_frame, and take care of looping.
+               void    increment_frame_and_check_for_loop();
+
+               virtual void    advance(float delta_time);
+
+               /// Execute the tags associated with the specified frame.
+               /// frame is 0-based
+               void execute_frame_tags(int frame, bool state_only = false);
+
+
+               /// Execute the tags associated with the specified frame,
+               /// IN REVERSE.
+               /// I.e. if it's an "add" tag, then we do a "remove" instead.
+               /// Only relevant to the display-list manipulation tags:
+               /// add, move, remove, replace.
+               ///
+               /// frame is 0-based
+               void execute_frame_tags_reverse(int frame);
 
                        
-           /*sprite_instance*/
-           void        display()
-               {
-                   if (get_visible() == false)
-                       {
-                           // We're invisible, so don't display!
-                           return;
-                       }
+               execute_tag* find_previous_replace_or_add_tag(int frame,
+                       int depth, int id);
 
-                   m_display_list.display();
 
-                   do_display_callback();
-               }
+               /// Execute any remove-object tags associated with
+               /// the specified frame.
+               /// frame is 0-based
+               void    execute_remove_tags(int frame);
 
-           /*sprite_instance*/
-           character*  add_display_object(
-               Uint16 character_id,
-               const char* name,
-               const array<swf_event*>& event_handlers,
-               Uint16 depth,
-               bool replace_if_depth_is_occupied,
-               const cxform& color_transform,
-               const matrix& matrix,
-               float ratio,
-               Uint16 clip_depth)
-               // Add an object to the display list.
-               {
-                   assert(m_def != NULL);
 
-                   character_def*      cdef = 
m_def->get_character_def(character_id);
-                   if (cdef == NULL)
-                       {
-                           log_error("sprite::add_display_object(): unknown 
cid = %d\n", character_id);
-                           return NULL;
-                       }
+               /// Take care of this frame's actions.
+               void do_actions();
 
-                   // If we already have this object on this
-                   // plane, then move it instead of replacing
-                   // it.
-                   character*  existing_char = 
m_display_list.get_character_at_depth(depth);
-                   if (existing_char
-                       && existing_char->get_id() == character_id
-                       && ((name == NULL && existing_char->get_name().length() 
== 0)
-                           || (name && existing_char->get_name() == name)))
-                       {
-       //                              IF_VERBOSE_DEBUG(log_msg("add changed 
to move on depth %d\n", depth));//xxxxxx
-                           move_display_object(depth, true, color_transform, 
true, matrix, ratio, clip_depth);
-                           return NULL;
-                       }
-                   //printf("%s: character %s, id is %d, count is %d\n", 
__FUNCTION__, existing_char->get_name(), 
character_id,m_display_list.get_character_count()); // FIXME:
 
-                   assert(cdef);
-                   smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-                   assert(ch != NULL);
-                   if (name != NULL && name[0] != 0)
-                       {
-                           ch->set_name(name);
-                       }
+               /// Set the sprite state at the specified frame number.
+               //
+               /// 0-based frame numbers!! 
+               ///(in contrast to ActionScript and Flash MX)
+               ///
+               void    goto_frame(int target_frame_number);
 
-                   // Attach event handlers (if any).
-                   {for (int i = 0, n = event_handlers.size(); i < n; i++)
-                       {
-                           event_handlers[i]->attach_to(ch.get_ptr());
-                       }}
 
-                   m_display_list.add_display_object(
-                       ch.get_ptr(),
-                       depth,
-                       replace_if_depth_is_occupied,
-                       color_transform,
-                       matrix,
-                       ratio,
-                       clip_depth);
-
-                   assert(ch == NULL || ch->get_ref_count() > 1);
-                   return ch.get_ptr();
-               }
+               /// Look up the labeled frame, and jump to it.
+               bool goto_labeled_frame(const char* label);
 
+                       
+               /// Display (render?) this Sprite/MovieClip, unless invisible
+               void    display();
 
-           /*sprite_instance*/
-           void        move_display_object(
-               Uint16 depth,
-               bool use_cxform,
-               const cxform& color_xform,
-               bool use_matrix,
-               const matrix& mat,
-               float ratio,
-               Uint16 clip_depth)
-               // Updates the transform properties of the object at
-               // the specified depth.
+               /// Add an object to the DisplayList.
+               character*      add_display_object(
+                       Uint16 character_id,
+                       const char* name,
+                       const array<swf_event*>& event_handlers,
+                       Uint16 depth,
+                       bool replace_if_depth_is_occupied,
+                       const cxform& color_transform,
+                       const matrix& matrix,
+                       float ratio,
+                       Uint16 clip_depth);
+
+
+               /// Updates the transform properties of the object at
+               /// the specified depth.
+               void    move_display_object(
+                               Uint16 depth,
+                               bool use_cxform,
+                               const cxform& color_xform,
+                               bool use_matrix,
+                               const matrix& mat,
+                               float ratio,
+                               Uint16 clip_depth)
                {
                    m_display_list.move_display_object(depth, use_cxform, 
color_xform, use_matrix, mat, ratio, clip_depth);
                }
 
 
-           /*sprite_instance*/
-           void        replace_display_object(
-               Uint16 character_id,
-               const char* name,
-               Uint16 depth,
-               bool use_cxform,
-               const cxform& color_transform,
-               bool use_matrix,
-               const matrix& mat,
-               float ratio,
-               Uint16 clip_depth)
-               {
-                   assert(m_def != NULL);
-                   // printf("%s: character %s, id is %d\n", __FUNCTION__, 
name, character_id); // FIXME: debugging crap
-
-                   character_def*      cdef = 
m_def->get_character_def(character_id);
-                   if (cdef == NULL)
-                       {
-                           log_error("sprite::replace_display_object(): 
unknown cid = %d\n", character_id);
-                           return;
-                       }
-                   assert(cdef);
-
-                   smart_ptr<character>        ch = 
cdef->create_character_instance(this, character_id);
-                   assert(ch != NULL);
-
-                   if (name != NULL && name[0] != 0)
-                       {
-                           ch->set_name(name);
-                       }
-
-                   m_display_list.replace_display_object(
-                       ch.get_ptr(),
-                       depth,
-                       use_cxform,
-                       color_transform,
-                       use_matrix,
-                       mat,
-                       ratio,
-                       clip_depth);
-               }
-
-
-           /*sprite_instance*/
-           void        replace_display_object(
-               character* ch,
-               const char* name,
-               Uint16 depth,
-               bool use_cxform,
-               const cxform& color_transform,
-               bool use_matrix,
-               const matrix& mat,
-               float ratio,
-               Uint16 clip_depth)
-               {
-                   printf("%s: character %s, id is %d\n", __FUNCTION__, name, 
ch->get_id()); // FIXME:
-
-                   assert(ch != NULL);
-
-                   if (name != NULL && name[0] != 0)
-                       {
-                           ch->set_name(name);
-                       }
-
-                   m_display_list.replace_display_object(
-                       ch,
-                       depth,
-                       use_cxform,
-                       color_transform,
-                       use_matrix,
-                       mat,
-                       ratio,
-                       clip_depth);
-               }
-
-
-           /*sprite_instance*/
-           void        remove_display_object(Uint16 depth, int id)
-               // Remove the object at the specified depth.
-               // If id != -1, then only remove the object at depth with 
matching id.
+               void    replace_display_object(
+                               Uint16 character_id,
+                               const char* name,
+                               Uint16 depth,
+                               bool use_cxform,
+                               const cxform& color_transform,
+                               bool use_matrix,
+                               const matrix& mat,
+                               float ratio,
+                               Uint16 clip_depth);
+
+
+               void    replace_display_object(
+                               character* ch,
+                               const char* name,
+                               Uint16 depth,
+                               bool use_cxform,
+                               const cxform& color_transform,
+                               bool use_matrix,
+                               const matrix& mat,
+                               float ratio,
+                               Uint16 clip_depth);
+
+
+               /// Remove the object at the specified depth.
+               /// If id != -1, then only remove the object
+               /// at depth with matching id.
+               void    remove_display_object(Uint16 depth, int id)
                {
                    m_display_list.remove_display_object(depth, id);
                }
 
 
-           /*sprite_instance*/
-           void        add_action_buffer(action_buffer* a)
-               // Add the given action buffer to the list of action
-               // buffers to be processed at the end of the next
-               // frame advance.
+               /// Add the given action buffer to the list of action
+               /// buffers to be processed at the end of the next
+               /// frame advance.
+               void    add_action_buffer(action_buffer* a)
                {
                    m_action_list.push_back(a);
                }
 
 
-           /*sprite_instance*/
-           int get_id_at_depth(int depth)
-               // For debugging -- return the id of the character at the 
specified depth.
-               // Return -1 if nobody's home.
-               {
-                   int index = m_display_list.get_display_index(depth);
-                   if (index == -1)
-                       {
-                           return -1;
-                       }
-
-                   character*  ch = 
m_display_list.get_display_object(index).m_character.get_ptr();
-
-                   return ch->get_id();
-               }
-
-
-           //
-           // ActionScript support
-           //
-
-
-           /* sprite_instance */
-           virtual void        set_variable(const char* path_to_var, const 
char* new_value)
-               {
-                   assert(m_parent == NULL);   // should only be called on the 
root movie.
-
-                   if (path_to_var == NULL)
-                       {
-                           log_error("error: NULL path_to_var passed to 
set_variable()\n");
-                           return;
-                       }
-                   if (new_value == NULL)
-                       {
-                           log_error("error: NULL passed to set_variable('%s', 
NULL)\n", path_to_var);
-                           return;
-                       }
-
-                   array<with_stack_entry>     empty_with_stack;
-                   tu_string   path(path_to_var);
-                   as_value    val(new_value);
-
-                   m_as_environment.set_variable(path, val, empty_with_stack);
-               }
-
-           /* sprite_instance */
-           virtual void        set_variable(const char* path_to_var, const 
wchar_t* new_value)
-               {
-                   if (path_to_var == NULL)
-                       {
-                           log_error("error: NULL path_to_var passed to 
set_variable()\n");
-                           return;
-                       }
-                   if (new_value == NULL)
-                       {
-                           log_error("error: NULL passed to set_variable('%s', 
NULL)\n", path_to_var);
-                           return;
-                       }
-
-                   assert(m_parent == NULL);   // should only be called on the 
root movie.
-
-                   array<with_stack_entry>     empty_with_stack;
-                   tu_string   path(path_to_var);
-                   as_value    val(new_value);
+               /// For debugging -- return the id of the character
+               /// at the specified depth.
+               /// Return -1 if nobody's home.
+               int     get_id_at_depth(int depth);
 
-                   m_as_environment.set_variable(path, val, empty_with_stack);
-               }
-
-           /* sprite_instance */
-           virtual const char* get_variable(const char* path_to_var) const
-               {
-                   assert(m_parent == NULL);   // should only be called on the 
root movie.
 
-                   array<with_stack_entry>     empty_with_stack;
-                   tu_string   path(path_to_var);
+               //
+               // ActionScript support
+               //
 
-                   // NOTE: this is static so that the string
-                   // value won't go away after we return!!!
-                   // It'll go away during the next call to this
-                   // function though!!!  NOT THREAD SAFE!
-                   static as_value     val;
 
-                   val = m_as_environment.get_variable(path, empty_with_stack);
+               /// Set the named variable to the value
+               virtual void set_variable(const char* path_to_var,
+                       const char* new_value);
+
+               /// Set the named variable to the wide value
+               virtual void set_variable(const char* path_to_var,
+                       const wchar_t* new_value);
 
-                   return val.to_string();     // ack!
-               }
+               /// Returns address to static buffer. NOT THREAD SAFE!
+               virtual const char* get_variable(const char* path_to_var) const;
 
                // Set *val to the value of the named member and
                // return true, if we have the named member.
@@ -1092,438 +588,133 @@
                bool get_member(const tu_stringi& name, as_value* val);
 
                        
-           /* sprite_instance */
-           virtual void        set_member(const tu_stringi& name, const 
as_value& val)
-               // Set the named member to the value.  Return true if we have
-               // that member; false otherwise.
-               {
-                   as_standard_member  std_member = get_standard_member(name);
-                   switch (std_member)
-                       {
-                       default:
-                       case M_INVALID_MEMBER:
-                           break;
-                       case M_X:
-                           //if (name == "_x")
-                       {
-                           matrix      m = get_matrix();
-                           m.m_[0][2] = (float) 
PIXELS_TO_TWIPS(val.to_number());
-                           set_matrix(m);
-
-                           m_accept_anim_moves = false;
-
-                           return;
-                       }
-                       case M_Y:
-                           //else if (name == "_y")
-                       {
-                           matrix      m = get_matrix();
-                           m.m_[1][2] = (float) 
PIXELS_TO_TWIPS(val.to_number());
-                           set_matrix(m);
-
-                           m_accept_anim_moves = false;
-
-                           return;
-                       }
-                       case M_XSCALE:
-                           //else if (name == "_xscale")
-                       {
-                           matrix      m = get_matrix();
-
-                           // Decompose matrix and insert the desired value.
-                           float       x_scale = (float) val.to_number() / 
100.f;      // input is in percent
-                           float       y_scale = m.get_y_scale();
-                           float       rotation = m.get_rotation();
-                           m.set_scale_rotation(x_scale, y_scale, rotation);
-
-                           set_matrix(m);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_YSCALE:
-                           //else if (name == "_yscale")
-                       {
-                           matrix      m = get_matrix();
-
-                           // Decompose matrix and insert the desired value.
-                           float       x_scale = m.get_x_scale();
-                           float       y_scale = (float) val.to_number() / 
100.f;      // input is in percent
-                           float       rotation = m.get_rotation();
-                           m.set_scale_rotation(x_scale, y_scale, rotation);
-
-                           set_matrix(m);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_ALPHA:
-                           //else if (name == "_alpha")
-                       {
-                           // Set alpha modulate, in percent.
-                           cxform      cx = get_cxform();
-                           cx.m_[3][0] = float(val.to_number()) / 100.f;
-                           set_cxform(cx);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_VISIBLE:
-                           //else if (name == "_visible")
-                       {
-                           set_visible(val.to_bool());
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_WIDTH:
-                           //else if (name == "_width")
-                       {
-                           // @@ tulrich: is parameter in world-coords or 
local-coords?
-                           matrix      m = get_matrix();
-                           m.m_[0][0] = 
float(PIXELS_TO_TWIPS(val.to_number()));
-                           float w = get_width();
-                           if (fabsf(w) > 1e-6f)
-                               {
-                                   m.m_[0][0] /= w;
-                               }
-                           set_matrix(m);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_HEIGHT:
-                           //else if (name == "_height")
-                       {
-                           // @@ tulrich: is parameter in world-coords or 
local-coords?
-                           matrix      m = get_matrix();
-                           m.m_[1][1] = 
float(PIXELS_TO_TWIPS(val.to_number()));
-                           float h = get_width();
-                           if (fabsf(h) > 1e-6f)
-                               {
-                                   m.m_[1][1] /= h;
-                               }
-                           set_matrix(m);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_ROTATION:
-                           //else if (name == "_rotation")
-                       {
-                           matrix      m = get_matrix();
-
-                           // Decompose matrix and insert the desired value.
-                           float       x_scale = m.get_x_scale();
-                           float       y_scale = m.get_y_scale();
-                           float       rotation = (float) val.to_number() * 
float(M_PI) / 180.f;       // input is in degrees
-                           m.set_scale_rotation(x_scale, y_scale, rotation);
-
-                           set_matrix(m);
-                           m_accept_anim_moves = false;
-                           return;
-                       }
-                       case M_HIGHQUALITY:
-                           //else if (name == "_highquality")
-                       {
-                           // @@ global { 0, 1, 2 }
-       //                              // Whether we're in high quality mode 
or not.
-       //                              val->set(true);
-                           return;
-                       }
-                       case M_FOCUSRECT:
-                           //else if (name == "_focusrect")
-                       {
-       //                              // Is a yellow rectangle visible around 
a focused movie clip (?)
-       //                              val->set(false);
-                           return;
-                       }
-                       case M_SOUNDBUFTIME:
-                           //else if (name == "_soundbuftime")
-                       {
-                           // @@ global
-       //                              // Number of seconds before sound 
starts to stream.
-       //                              val->set(0.0);
-                           return;
-                       }
-                       }       // end switch
-
-                               // Not a built-in property.  See if we have a
-                               // matching edit_text character in our display
-                               // list.
-                   bool        text_val = val.get_type() == as_value::STRING
-                       || val.get_type() == as_value::NUMBER;
-                   if (text_val)
-                       {
-                           bool        success = false;
-                           for (int i = 0, n = 
m_display_list.get_character_count(); i < n; i++)
-                               {
-                                   character*  ch = 
m_display_list.get_character(i);
-                                   // CASE INSENSITIVE compare.  In 
ActionScript 2.0, this
-                                   // changes to CASE SENSITIVE!!!
-                                   if (name == ch->get_text_name())
-                                       {
-                                           const char* text = val.to_string();
-                                           ch->set_text_value(text);
-                                           success = true;
-                                       }
-                               }
-                           if (success) return;
-                       }
-
-                   // If that didn't work, set a variable within this 
environment.
-                   m_as_environment.set_member(name, val);
-               }
-
-
-           /* sprite_instance */
-           virtual movie*      get_relative_target(const tu_string& name)
-               // Find the movie which is one degree removed from us,
-               // given the relative pathname.
-               //
-               // If the pathname is "..", then return our parent.
-               // If the pathname is ".", then return ourself.  If
-               // the pathname is "_level0" or "_root", then return
-               // the root movie.
-               //
-               // Otherwise, the name should refer to one our our
-               // named characters, so we return it.
-               //
-               // NOTE: In ActionScript 2.0, top level names (like
-               // "_root" and "_level0") are CASE SENSITIVE.
-               // Character names in a display list are CASE
-               // SENSITIVE. Member names are CASE INSENSITIVE.  Gah.
+               /// Set the named member to the value. 
                //
-               // In ActionScript 1.0, everything seems to be CASE
-               // INSENSITIVE.
-               {
-                   if (name == "." || name == "this")
-                       {
-                           return this;
-                       }
-                   else if (name == "..")
-                       {
-                           return get_parent();
-                       }
-                   else if (name == "_level0"
-                            || name == "_root")
-                       {
-                           return m_root->m_movie.get_ptr();
-                       }
-
-                   // See if we have a match on the display list.
-                   return m_display_list.get_character_by_name(name);
-               }
-
-
-           /* sprite_instance */
-           virtual void        call_frame_actions(const as_value& frame_spec)
-               // Execute the actions for the specified frame.  The
-               // frame_spec could be an integer or a string.
-               {
-                   int frame_number = -1;
-
-                   // Figure out what frame to call.
-                   if (frame_spec.get_type() == as_value::STRING)
-                       {
-                           if 
(m_def->get_labeled_frame(frame_spec.to_string(), &frame_number) == false)
-                               {
-                                   // Try converting to integer.
-                                   frame_number = (int) frame_spec.to_number();
-                               }
-                       }
-                   else
-                       {
-                           // convert from 1-based to 0-based
-                           frame_number = (int) frame_spec.to_number() - 1;
-                       }
-
-                   if (frame_number < 0 || frame_number >= 
m_def->get_frame_count())
-                       {
-                           // No dice.
-                           log_error("error: call_frame('%s') -- unknown 
frame\n", frame_spec.to_string());
-                           return;
-                       }
-
-                   int top_action = m_action_list.size();
+               /// Return true if we have
+               /// that member; false otherwise.
+               virtual void set_member(const tu_stringi& name,
+                       const as_value& val);
+
+
+               /// Find the movie which is one degree removed from us,
+               /// given the relative pathname.
+               ///
+               /// If the pathname is "..", then return our parent.
+               /// If the pathname is ".", then return ourself.  If
+               /// the pathname is "_level0" or "_root", then return
+               /// the root movie.
+               ///
+               /// Otherwise, the name should refer to one our our
+               /// named characters, so we return it.
+               ///
+               /// NOTE: In ActionScript 2.0, top level names (like
+               /// "_root" and "_level0") are CASE SENSITIVE.
+               /// Character names in a display list are CASE
+               /// SENSITIVE. Member names are CASE INSENSITIVE.  Gah.
+               ///
+               /// In ActionScript 1.0, everything seems to be CASE
+               /// INSENSITIVE.
+               virtual movie*  get_relative_target(const tu_string& name);
 
-                   // Execute the actions.
-                   const array<execute_tag*>&  playlist = 
m_def->get_playlist(frame_number);
-                   for (int i = 0; i < playlist.size(); i++)
-                       {
-                           execute_tag*        e = playlist[i];
-                           if (e->is_action_tag())
-                               {
-                                   e->execute(this);
-                               }
-                       }
 
-                   // Execute any new actions triggered by the tag,
-                   // leaving existing actions to be executed.
-                   while (m_action_list.size() > top_action)
-                       {
-                           
m_action_list[top_action]->execute(&m_as_environment);
-                           m_action_list.remove(top_action);
-                       }
-                   assert(m_action_list.size() == top_action);
-               }
+               /// Execute the actions for the specified frame. 
+               //
+               /// The frame_spec could be an integer or a string.
+               ///
+               virtual void call_frame_actions(const as_value& frame_spec);
 
 
-           /* sprite_instance */
-           virtual void        set_drag_state(const drag_state& st)
-               {
+               virtual void set_drag_state(const drag_state& st) {
                    m_root->m_drag_state = st;
                }
 
-           /* sprite_instance */
-           virtual void        stop_drag()
-               {
+               virtual void stop_drag() {
                    assert(m_parent == NULL);   // we must be the root movie!!!
                                
                    m_root->stop_drag();
                }
 
-
-           /* sprite_instance */
-           virtual void        get_drag_state(drag_state* st)
+               /* sprite_instance */
+               virtual void    get_drag_state(drag_state* st)
                {
                    *st = m_root->m_drag_state;
                }
 
 
-           void        clone_display_object(const tu_string& name, const 
tu_string& newname, Uint16 depth)
-               // Duplicate the object with the specified name and add it with 
a new name 
-               // at a new depth.
-               {
-                   character* ch = m_display_list.get_character_by_name(name);
-                   if (ch)
-                       {
-                           array<swf_event*>   dummy_event_handlers;
-
-                           add_display_object(
-                               ch->get_id(),
-                               newname.c_str(),
-                               dummy_event_handlers,
-                               depth,
-                               true,   // replace if depth is occupied
-                               ch->get_cxform(),
-                               ch->get_matrix(),
-                               ch->get_ratio(),
-                               ch->get_clip_depth());
-                           // @@ TODO need to duplicate ch's event handlers, 
and presumably other members?
-                           // Probably should make a character::clone() 
function to handle this.
-                       }
-               }
-
-
-           void        remove_display_object(const tu_string& name)
-               // Remove the object with the specified name.
-               {
-                   character* ch = m_display_list.get_character_by_name(name);
-                   if (ch)
-                       {
-                           // @@ TODO: should only remove movies that were 
created via clone_display_object --
-                           // apparently original movies, placed by anim 
events, are immune to this.
-                           remove_display_object(ch->get_depth(), 
ch->get_id());
-                       }
-               }
-
-                       
-           /* sprite_instance */
-           virtual bool        on_event(event_id id)
-               // Dispatch event handler(s), if any.
-               {
-                   // Keep m_as_environment alive during any method calls!
-                   smart_ptr<as_object_interface>      this_ptr(this);
-
-                   bool called = false;
-                               
-                   // First, check for built-in event handler.
-                   {
-                       as_value        method;
-                       if (get_event_handler(id, &method))
-                           {
-                               // Dispatch.
-                               call_method0(method, &m_as_environment, this);
-
-                               called = true;
-                               // Fall through and call the function also, if 
it's defined!
-                               // (@@ Seems to be the behavior for mouse 
events; not tested & verified for
-                               // every event type.)
-                           }
-                   }
-
-                   // Check for member function.
-                   {
-                       // In ActionScript 2.0, event method names are CASE 
SENSITIVE.
-                       // In ActionScript 1.0, event method names are CASE 
INSENSITIVE.
-                       const tu_stringi&       method_name = 
id.get_function_name().to_tu_stringi();
-                       if (method_name.length() > 0)
-                           {
-                               as_value        method;
-                               if (get_member(method_name, &method))
-                                   {
-                                       call_method0(method, &m_as_environment, 
this);
-                                       called = true;
-                                   }
-                           }
-                   }
-
-                   return called;
-               }
-
-
-           /*sprite_instance*/
-           virtual void        on_event_load()
-               // Do the events that (appear to) happen as the movie
-               // loads.  frame1 tags and actions are executed (even
-               // before advance() is called).  Then the onLoad event
-               // is triggered.
+               /// Duplicate the object with the specified name
+               /// and add it with a new name  at a new depth.
+               void clone_display_object(const tu_string& name,
+                       const tu_string& newname, Uint16 depth);
+
+               /// Remove the object with the specified name.
+               void remove_display_object(const tu_string& name);
+
+               /// Dispatch event handler(s), if any.
+               virtual bool    on_event(event_id id);
+
+
+               /// Do the events that (appear to) happen as the movie
+               /// loads.  frame1 tags and actions are executed (even
+               /// before advance() is called).  Then the onLoad event
+               /// is triggered.
+               virtual void    on_event_load()
                {
                    execute_frame_tags(0);
                    do_actions();
                    on_event(event_id::LOAD);
                }
 
-           // Do the events that happen when there is XML data waiting
-           // on the XML socket connection.
-           virtual void        on_event_xmlsocket_onxml()
+               /// Do the events that happen when there is XML data waiting
+               /// on the XML socket connection.
+               /// FIXME: unimplemented
+               virtual void    on_event_xmlsocket_onxml()
                {
                    log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
                    on_event(event_id::SOCK_XML);
                }
                        
-           // Do the events that (appear to) happen on a specified interval.
-           virtual void        on_event_interval_timer()
+               /// Do the events that (appear to) happen on a
+               /// specified interval.
+               virtual void    on_event_interval_timer()
                {
                    log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
                    on_event(event_id::TIMER);
                }
 
-           // Do the events that happen as a MovieClip (swf 7 only) loads.
-           virtual void        on_event_load_progress()
+               /// Do the events that happen as a MovieClip (swf 7 only) loads.
+               virtual void    on_event_load_progress()
                {
                    log_msg("FIXME: %s: unimplemented\n", __FUNCTION__);
                    on_event(event_id::LOAD_PROGRESS);
                }
 
-           /*sprite_instance*/
-           virtual const char* call_method_args(const char* method_name, const 
char* method_arg_fmt, va_list args)
+               /// Call a method with a list of arguments
+               virtual const char* call_method_args(const char* method_name,
+                       const char* method_arg_fmt, va_list args)
                {
                    // Keep m_as_environment alive during any method calls!
                    smart_ptr<as_object_interface>      this_ptr(this);
 
-                   return call_method_parsed(&m_as_environment, this, 
method_name, method_arg_fmt, args);
+                   return call_method_parsed(&m_as_environment, this,
+                               method_name, method_arg_fmt, args);
                }
 
-           /* sprite_instance */
-           virtual void        attach_display_callback(const char* 
path_to_object, void (*callback)(void*), void* user_ptr)
+               virtual void    attach_display_callback(
+                       const char* path_to_object,
+                       void (*callback)(void*), void* user_ptr)
                {
-                   assert(m_parent == NULL);   // should only be called on the 
root movie.
+                       // should only be called on the root movie.
+                       assert(m_parent == NULL);
 
-                   array<with_stack_entry>     dummy;
-                   as_value    obj = 
m_as_environment.get_variable(tu_string(path_to_object), dummy);
-                   as_object_interface*        as_obj = obj.to_object();
-                   if (as_obj)
+                       array<with_stack_entry> dummy;
+                       as_value obj = 
m_as_environment.get_variable(tu_string(path_to_object), dummy);
+                       as_object_interface*    as_obj = obj.to_object();
+                       if (as_obj)
                        {
-                           movie*      m = as_obj->to_movie();
-                           if (m)
+                               movie*  m = as_obj->to_movie();
+                               if (m)
                                {
-                                   m->set_display_callback(callback, user_ptr);
+                               m->set_display_callback(callback, user_ptr);
                                }
                        }
                }
@@ -1534,9 +725,9 @@
        character* sprite_definition::create_character_instance(movie* parent,
                int id)
        {
-           sprite_instance* si = new sprite_instance(this,
-               parent->get_root(), parent, id);
-           return si;
+               sprite_instance* si = new sprite_instance(this,
+                       parent->get_root(), parent, id);
+               return si;
        }
 
 
Index: gnash/server/action.cpp
diff -u gnash/server/action.cpp:1.6 gnash/server/action.cpp:1.7
--- gnash/server/action.cpp:1.6 Wed Jan 25 13:38:31 2006
+++ gnash/server/action.cpp     Fri Jan 27 00:54:38 2006
@@ -1381,7 +1381,7 @@
        //
 
 
-       // Thin wrapper around action_buffer.
+       /// Thin wrapper around action_buffer.
        struct do_action : public execute_tag
        {
                action_buffer   m_buf;
Index: gnash/server/action.h
diff -u gnash/server/action.h:1.4 gnash/server/action.h:1.5
--- gnash/server/action.h:1.4   Thu Jan 26 00:15:57 2006
+++ gnash/server/action.h       Fri Jan 27 00:54:38 2006
@@ -732,16 +732,17 @@
        };
 
 
-       // ActionScript "environment", essentially VM state?
+       /// ActionScript "environment", essentially VM state?
        struct as_environment
        {
                array<as_value> m_stack;
                as_value        m_global_register[4];
-               array<as_value> m_local_register;       // function2 uses this
+               /// function2 uses this
+               array<as_value> m_local_register;
                movie*  m_target;
                stringi_hash<as_value>  m_variables;
 
-               // For local vars.  Use empty names to separate frames.
+               /// For local vars.  Use empty names to separate frames.
                struct frame_slot
                {
                        tu_string       m_name;
@@ -765,6 +766,7 @@
                // stack access/manipulation
                // @@ TODO do more checking on these
                template<class T>
+               // stack access/manipulation
                void    push(T val) { push_val(as_value(val)); }
                void    push_val(const as_value& val) { m_stack.push_back(val); 
}
                as_value        pop() { as_value result = m_stack.back(); 
m_stack.pop_back(); return result; }
@@ -775,16 +777,21 @@
                int     get_top_index() const { return m_stack.size() - 1; }
 
                as_value        get_variable(const tu_string& varname, const 
array<with_stack_entry>& with_stack) const;
-               // no path stuff:
+
+               /// no path stuff
                as_value        get_variable_raw(const tu_string& varname, 
const array<with_stack_entry>& with_stack) const;
 
                void    set_variable(const tu_string& path, const as_value& 
val, const array<with_stack_entry>& with_stack);
-               // no path stuff:
+
+               /// no path stuff
                void    set_variable_raw(const tu_string& path, const as_value& 
val, const array<with_stack_entry>& with_stack);
 
                void    set_local(const tu_string& varname, const as_value& 
val);
-               void    add_local(const tu_string& varname, const as_value& 
val);       // when you know it doesn't exist.
-               void    declare_local(const tu_string& varname);        // 
Declare varname; undefined unless it already exists.
+               /// when you know it doesn't exist.
+               void    add_local(const tu_string& varname, const as_value& 
val);
+
+               /// Declare varname; undefined unless it already exists.
+               void    declare_local(const tu_string& varname);
 
                bool    get_member(const tu_stringi& varname, as_value* val) 
const;
                void    set_member(const tu_stringi& varname, const as_value& 
val);
Index: gnash/server/gnash.h
diff -u gnash/server/gnash.h:1.3 gnash/server/gnash.h:1.4
--- gnash/server/gnash.h:1.3    Thu Jan 26 00:15:57 2006
+++ gnash/server/gnash.h        Fri Jan 27 00:54:38 2006
@@ -139,7 +139,7 @@
        sound_handler*  create_sound_handler_sdl();
 
 
-       // For stuff that's tricky to keep track of w/r/t ownership & cleanup.
+       /// For stuff that's tricky to keep track of w/r/t ownership & cleanup.
        struct ref_counted
        {
                ref_counted();
@@ -159,8 +159,7 @@
        struct character_def;
        struct sound_sample;
        
-       /// An interface for casting to different types of
-       /// resources.
+       /// An interface for casting to different types of resources.
        struct resource : public ref_counted
        {
                virtual ~resource() {}
@@ -174,8 +173,7 @@
 
        /// This is the base class for all ActionScript-able objects
        //
-       /// ("as_" stands for ActionScript).
-       ///
+       // ("as_" stands for ActionScript).
        struct as_object_interface : public resource
        {
                virtual ~as_object_interface() {}
@@ -213,7 +211,6 @@
        /// can be mixed into movie_definition, movie_definition_sub,
        /// and sprite_definition, without using multiple inheritance.
        ///
-       ///
        struct character_def : public resource
        {
        private:
Index: gnash/server/impl.cpp
diff -u gnash/server/impl.cpp:1.9 gnash/server/impl.cpp:1.10
--- gnash/server/impl.cpp:1.9   Thu Jan 26 00:13:56 2006
+++ gnash/server/impl.cpp       Fri Jan 27 00:54:38 2006
@@ -752,6 +752,7 @@
     delete [] n;
 }
 
+/// SWF Tag SetBackgroundColor (9)
 struct set_background_color : public execute_tag
 {
     rgba       m_color;
@@ -1434,10 +1435,7 @@
 
 
 
-//
-// place_object_2
-//
-       
+/// SWF Tag PlaceObject2 (9) 
 struct place_object_2 : public execute_tag
 {
     int        m_tag_type;
@@ -1782,11 +1780,7 @@
 }
 
 
-//
-// remove_object_2
-//
-
-       
+/// SWF Tag RemoveObject2 (28) 
 struct remove_object_2 : public execute_tag
 {
     int        m_depth, m_id;
Index: gnash/server/impl.h
diff -u gnash/server/impl.h:1.5 gnash/server/impl.h:1.6
--- gnash/server/impl.h:1.5     Thu Jan 26 00:15:57 2006
+++ gnash/server/impl.h Fri Jan 27 00:54:38 2006
@@ -627,9 +627,10 @@
 
 #endif
 
-       // Execute tags include things that control the operation of
-       // the movie.  Essentially, these are the events associated
-       // with a frame.
+       /// Execute tags include things that control the operation of the 
movie. 
+       //
+       /// Essentially, these are the events associated with a frame.
+       ///
        struct execute_tag
        {
                virtual ~execute_tag() {}
Index: gnash/server/sound.cpp
diff -u gnash/server/sound.cpp:1.1 gnash/server/sound.cpp:1.2
--- gnash/server/sound.cpp:1.1  Tue Dec 20 21:01:18 2005
+++ gnash/server/sound.cpp      Fri Jan 27 00:54:38 2006
@@ -122,6 +122,7 @@
        }
 
 
+       /// SWF Tag StartSound (15) 
        struct start_sound_tag : public execute_tag
        {
                Uint16  m_handler_id;
Index: gnash/server/text.cpp
diff -u gnash/server/text.cpp:1.1 gnash/server/text.cpp:1.2
--- gnash/server/text.cpp:1.1   Tue Dec 20 21:01:18 2005
+++ gnash/server/text.cpp       Fri Jan 27 00:54:38 2006
@@ -346,8 +346,8 @@
        };
 
 
+       /// Read a DefineText tag.
        void    define_text_loader(stream* in, int tag_type, 
movie_definition_sub* m)
-       // Read a DefineText tag.
        {
                assert(tag_type == 11 || tag_type == 33);
 




reply via email to

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