gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r10393: More blend mode implementati


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10393: More blend mode implementations. It should now be ready for a renderer
Date: Fri, 05 Dec 2008 11:22:53 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10393
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Fri 2008-12-05 11:22:53 +0100
message:
  More blend mode implementations. It should now be ready for a renderer
  implementation.
modified:
  libcore/Button.cpp
  libcore/DisplayList.cpp
  libcore/MovieClip.cpp
  libcore/MovieClip.h
  libcore/TextField.cpp
  libcore/as_value.cpp
  libcore/asobj/XMLNode_as.cpp
  libcore/character.cpp
  libcore/character.h
  libcore/generic_character.cpp
  libcore/movie_root.cpp
  libcore/swf/PlaceObject2Tag.cpp
  libcore/swf/PlaceObject2Tag.h
  testsuite/actionscript.all/MovieClip.as
  testsuite/misc-ming.all/RollOverOutTest-Runner.cpp
    ------------------------------------------------------------
    revno: 10391.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2008-12-05 09:03:35 +0100
    message:
      Line breaks, drop old debugging messages.
    modified:
      libcore/as_value.cpp
      libcore/asobj/XMLNode_as.cpp
    ------------------------------------------------------------
    revno: 10391.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2008-12-05 09:57:08 +0100
    message:
      Make blend mode a property of character, and move the blendMode 
getter/setter
      to character.cpp. Implement static (parsed) blendMode setting.
    modified:
      libcore/MovieClip.cpp
      libcore/MovieClip.h
      libcore/character.cpp
      libcore/character.h
      libcore/swf/PlaceObject2Tag.cpp
      libcore/swf/PlaceObject2Tag.h
    ------------------------------------------------------------
    revno: 10391.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2008-12-05 10:37:07 +0100
    message:
      Put character.h into some sort of order. Make _visible private, use
      accessor (isVisible());
    modified:
      libcore/Button.cpp
      libcore/DisplayList.cpp
      libcore/MovieClip.cpp
      libcore/TextField.cpp
      libcore/character.cpp
      libcore/character.h
      libcore/generic_character.cpp
      libcore/movie_root.cpp
      testsuite/misc-ming.all/RollOverOutTest-Runner.cpp
    ------------------------------------------------------------
    revno: 10391.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: work
    timestamp: Fri 2008-12-05 10:58:55 +0100
    message:
      Minor blend mode correction.
    modified:
      libcore/character.cpp
      testsuite/actionscript.all/MovieClip.as
=== modified file 'libcore/Button.cpp'
--- a/libcore/Button.cpp        2008-12-02 11:45:42 +0000
+++ b/libcore/Button.cpp        2008-12-05 09:37:07 +0000
@@ -417,7 +417,7 @@
 // Return the topmost entity that the given point covers.  NULL if none.
 // I.e. check against ourself.
 {
-    if ( (!get_visible()) || (!get_enabled()))
+    if ( (!isVisible()) || (!get_enabled()))
     {
         return 0;
     }
@@ -442,7 +442,7 @@
                 it!=itE; ++it)
         {
             character* ch = *it;
-            if ( ! ch->get_visible() ) continue;
+            if ( ! ch->isVisible() ) continue;
             character *hit = ch->get_topmost_mouse_entity(p.x, p.y);
             if ( hit ) return hit;
         }
@@ -814,7 +814,7 @@
 {
 
     // Not visible anyway
-    if (!m_visible) return;
+    if (!isVisible()) return;
 
     ranges.add(m_old_invalidated_ranges);  
 

=== modified file 'libcore/DisplayList.cpp'
--- a/libcore/DisplayList.cpp   2008-12-03 08:22:34 +0000
+++ b/libcore/DisplayList.cpp   2008-12-05 09:37:07 +0000
@@ -616,7 +616,7 @@
         character* ch = it->get();
 
         character* mask = ch->getMask();
-        if ( mask && ch->get_visible() && ! mask->isUnloaded() )
+        if ( mask && ch->isVisible() && ! mask->isUnloaded() )
         {
             render::begin_submit_mask();
             
@@ -658,7 +658,7 @@
         }
         
         // check for non-mask hiden characters
-        if( !renderAsMask && (ch->get_visible() == false))
+        if( !renderAsMask && (!ch->isVisible()))
         {
             ch->omit_display();
             // Don't display non-mask hidden characters

=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp     2008-12-04 14:58:12 +0000
+++ b/libcore/MovieClip.cpp     2008-12-05 09:37:07 +0000
@@ -66,7 +66,6 @@
 #include <algorithm> // for std::swap
 #include <boost/algorithm/string/case_conv.hpp>
 #include <boost/lexical_cast.hpp>
-#include <boost/assign/list_of.hpp>
 #include <boost/bind.hpp>
 
 namespace gnash {
@@ -95,7 +94,6 @@
     void attachMovieClipProperties(character& o);
 
     as_value movieclip_transform(const fn_call& fn);
-    as_value movieclip_blendMode(const fn_call& fn);
     as_value movieclip_scale9Grid(const fn_call& fn);
     as_value movieclip_attachVideo(const fn_call& fn);
     as_value movieclip_attachAudio(const fn_call& fn);
@@ -153,12 +151,6 @@
     as_value movieclip_loadVariables(const fn_call& fn);
     as_value movieclip_(const fn_call& fn);
 
-    /// Match blend modes.
-    typedef std::map<MovieClip::BlendMode, std::string> BlendModeMap;
-    const BlendModeMap& getBlendModeMap();
-    bool blendModeMatches(const BlendModeMap::value_type& val,
-            const std::string& mode);
-
 }
 
 /// Anonymous namespace for module-private definitions
@@ -275,7 +267,6 @@
     _drawable(new DynamicShape()),
     _drawable_inst(_drawable->create_character_instance(this, 0)),
     m_play_state(PLAY),
-    _blendMode(BLENDMODE_NORMAL),
     m_current_frame(0),
     m_has_looped(false),
     _callingFrameActions(false),
@@ -1322,6 +1313,11 @@
         ch->set_name(instance_name);
     }
 
+    if (tag->hasBlendMode()) {
+        boost::uint8_t bm = tag->getBlendMode();
+        ch->setBlendMode(static_cast<character::BlendMode>(bm));
+    }
+
     // Attach event handlers (if any).
     const std::vector<swf_event*>& event_handlers = tag->getEventHandlers();
     for (size_t i = 0, n = event_handlers.size(); i < n; i++)
@@ -1545,9 +1541,6 @@
 
         if ( ch->isMaskLayer() )
         {
-            //if ( ! ch->get_visible() ) {
-            //    log_debug("invisible mask in MouseEntityFinder.");
-            //}
             if ( ! ch->pointInShape(_wp.x, _wp.y) )
             {
 #ifdef DEBUG_MOUSE_ENTITY_FINDING
@@ -1570,7 +1563,7 @@
             return;
         }
 
-        if ( ! ch->get_visible() ) return;
+        if ( ! ch->isVisible() ) return;
 
         _candidates.push_back(ch);
 
@@ -1724,7 +1717,7 @@
 bool
 MovieClip::pointInVisibleShape(boost::int32_t x, boost::int32_t y) const
 {
-    if ( ! get_visible() ) return false;
+    if ( ! isVisible() ) return false;
     if ( isDynamicMask() && ! can_handle_mouse_event() )
     {
         // see testsuite/misc-ming.all/masks_test.swf
@@ -1735,7 +1728,7 @@
         return false;
     }
     character* mask = getMask(); // dynamic one
-    if ( mask && mask->get_visible() && ! mask->pointInShape(x, y) )
+    if ( mask && mask->isVisible() && ! mask->pointInShape(x, y) )
     {
 #ifdef GNASH_DEBUG_HITTEST
         log_debug(_("%s is dynamically masked by %s, which "
@@ -1782,10 +1775,7 @@
 {
     //GNASH_REPORT_FUNCTION;
 
-    if (get_visible() == false)
-    {
-        return NULL;
-    }
+    if (!isVisible()) return 0;
 
     // point is in parent's space, we need to convert it in world space
     point    wp(x, y);
@@ -1877,7 +1867,7 @@
 
         if ( ch->isMaskLayer() )
         {
-            if ( ! ch->get_visible() )
+            if ( ! ch->isVisible() )
             {
                 log_debug(_("FIXME: invisible mask in MouseEntityFinder."));
             }
@@ -1937,7 +1927,7 @@
 {
     if ( this == dragging ) return 0; // not here...
 
-    if ( ! get_visible() ) return 0; // isn't me !
+    if ( ! isVisible() ) return 0; // isn't me !
 
     DropTargetFinder finder(x, y, dragging);
     m_display_list.visitAll(finder);
@@ -2117,7 +2107,7 @@
 {
 
     // nothing to do if this movieclip is not visible
-    if (!m_visible || get_cxform().is_invisible() )
+    if (!isVisible() || get_cxform().is_invisible() )
     {
         ranges.add(m_old_invalidated_ranges); // (in case we just hided)
         return;
@@ -2971,8 +2961,8 @@
                     movieclip_lineGradientStyle));
         o.init_member("attachBitmap", new builtin_function(
                     movieclip_attachBitmap));
-        o.init_property("blendMode", &movieclip_blendMode,
-                &movieclip_blendMode);
+        o.init_property("blendMode", &character::blendMode,
+                &character::blendMode);
         o.init_property("cacheAsBitmap", &movieclip_cacheAsBitmap, 
                 &movieclip_cacheAsBitmap);
         o.init_property("filters", &movieclip_filters, &movieclip_filters);
@@ -3096,68 +3086,6 @@
 
 
 as_value
-movieclip_blendMode(const fn_call& fn)
-{
-    boost::intrusive_ptr<MovieClip> movieclip =
-        ensureType<MovieClip>(fn.this_ptr);
-
-    // This is AS-correct, but doesn't do anything.
-    // TODO: implement in the renderers!
-    LOG_ONCE(log_unimpl(_("MovieClip.blendMode()")));
-
-    if (!fn.nargs)
-    {
-        // Getter
-        MovieClip::BlendMode bm = movieclip->getBlendMode();
-
-        /// If the blend mode is undefined, it doesn't return a string.
-        if (bm == MovieClip::BLENDMODE_UNDEFINED) return as_value();
-
-        std::ostringstream blendMode;
-        blendMode << bm;
-        return as_value(blendMode.str());
-    }
-
-    //
-    // Setter
-    //
-    
-    // Numeric argument.
-    const as_value& bm = fn.arg(0);
-    if (bm.is_number()) {
-        double mode = bm.to_number();
-
-        // hardlight is the last known value
-        if (mode < 0 || mode > MovieClip::BLENDMODE_HARDLIGHT) {
-
-            // An invalid string argument becomes undefined.
-            movieclip->setBlendMode(MovieClip::BLENDMODE_UNDEFINED);
-        }
-        else {
-            movieclip->setBlendMode(static_cast<MovieClip::BlendMode>(mode));
-        }
-        return as_value();
-    }
-
-    // Other arguments use toString method.
-    const std::string& mode = bm.to_string();
-
-    const BlendModeMap& bmm = getBlendModeMap();
-    BlendModeMap::const_iterator it = std::find_if(bmm.begin(), bmm.end(),
-            boost::bind(blendModeMatches, _1, mode));
-
-    if (it != bmm.end()) {
-        movieclip->setBlendMode(it->first);
-    }
-
-    // An invalid string argument has no effect.
-
-    return as_value();
-
-}
-
-
-as_value
 movieclip_cacheAsBitmap(const fn_call& fn)
 {
     boost::intrusive_ptr<MovieClip> movieclip =
@@ -3517,7 +3445,7 @@
 
         // Check we're not swapping the our own depth so
         // to avoid unecessary bounds invalidation and immunizing
-        // the instance from subsequent PlaceObjec tags attempting
+        // the instance from subsequent PlaceObject tags attempting
         // to transform it.
         if ( movieclip->get_depth() == target_depth )
         {
@@ -5374,10 +5302,6 @@
     if ( ! o.get_parent() ) o.init_member( "$version",
             VM::get().getPlayerVersion(), 0); 
 
-    //
-    // Properties (TODO: move to appropriate SWF version section)
-    //
-    
     as_c_function_ptr gettersetter;
 
     gettersetter = character::x_getset;
@@ -5464,49 +5388,8 @@
     return proto.get();
 }
 
-const BlendModeMap&
-getBlendModeMap()
-{
-    /// BLENDMODE_UNDEFINED has no matching string in AS. It is included
-    /// here for logging purposes.
-    static const BlendModeMap bm = boost::assign::map_list_of
-        (MovieClip::BLENDMODE_UNDEFINED, "undefined")
-        (MovieClip::BLENDMODE_NORMAL, "normal")
-        (MovieClip::BLENDMODE_LAYER, "layer")
-        (MovieClip::BLENDMODE_MULTIPLY, "multiply")
-        (MovieClip::BLENDMODE_SCREEN, "screen")
-        (MovieClip::BLENDMODE_LIGHTEN, "lighten")
-        (MovieClip::BLENDMODE_DARKEN, "darken")
-        (MovieClip::BLENDMODE_DIFFERENCE, "difference")
-        (MovieClip::BLENDMODE_ADD, "add")
-        (MovieClip::BLENDMODE_SUBTRACT, "subtract")
-        (MovieClip::BLENDMODE_INVERT, "invert")
-        (MovieClip::BLENDMODE_ALPHA, "alpha")
-        (MovieClip::BLENDMODE_ERASE, "erase")
-        (MovieClip::BLENDMODE_OVERLAY, "overlay")
-        (MovieClip::BLENDMODE_HARDLIGHT, "hardlight");
-
-    return bm;
-}
-
-// Match a blend mode to its string.
-bool
-blendModeMatches(const BlendModeMap::value_type& val, const std::string& mode)
-{
-    /// The match must be case-sensitive.
-    if (mode.empty()) return false;
-    return (val.second == mode);
-}
-
 } // anonymous namespace
 
 
-std::ostream&
-operator<<(std::ostream& o, MovieClip::BlendMode bm)
-{
-    const BlendModeMap& bmm = getBlendModeMap();
-    return (o << bmm.find(bm)->second);
-}
-
 
 } // namespace gnash

=== modified file 'libcore/MovieClip.h'
--- a/libcore/MovieClip.h       2008-12-04 14:58:12 +0000
+++ b/libcore/MovieClip.h       2008-12-05 08:57:08 +0000
@@ -111,25 +111,6 @@
         STOP
     };
 
-    enum BlendMode
-    {
-        BLENDMODE_UNDEFINED = 0,
-        BLENDMODE_NORMAL = 1,
-        BLENDMODE_LAYER,
-        BLENDMODE_MULTIPLY,
-        BLENDMODE_SCREEN,
-        BLENDMODE_LIGHTEN,
-        BLENDMODE_DARKEN,
-        BLENDMODE_DIFFERENCE,
-        BLENDMODE_ADD,
-        BLENDMODE_SUBTRACT,
-        BLENDMODE_INVERT,
-        BLENDMODE_ALPHA,
-        BLENDMODE_ERASE,
-        BLENDMODE_OVERLAY,
-        BLENDMODE_HARDLIGHT = 14
-    };
-
     /// Type of execute tags
     //
     /// TODO: move to ControlTag.h ?
@@ -235,14 +216,6 @@
 
     play_state get_play_state() const { return m_play_state; }
 
-    BlendMode getBlendMode() const {
-        return _blendMode;
-    }
- 
-    void setBlendMode(BlendMode bm) {
-        _blendMode = bm;
-    }
-
     character* get_character(int character_id);
 
     // delegates to movie_root (possibly wrong)
@@ -938,8 +911,6 @@
 
     play_state  m_play_state;
 
-    BlendMode _blendMode;
-
     // 0-based index to current frame
     size_t      m_current_frame;
 
@@ -1057,10 +1028,6 @@
 /// Initialize the global MovieClip class
 void movieclip_class_init(as_object& global);
 
-/// Stream operator for MovieClip blend mode.
-std::ostream&
-operator<<(std::ostream& o, MovieClip::BlendMode bm);
-
 } // end of namespace gnash
 
 #endif // GNASH_SPRITE_INSTANCE_H

=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp     2008-12-02 11:45:42 +0000
+++ b/libcore/TextField.cpp     2008-12-05 09:37:07 +0000
@@ -476,7 +476,7 @@
 TextField::get_topmost_mouse_entity(boost::int32_t x, boost::int32_t y)
 {
 
-    if (!get_visible()) return NULL;
+    if (!isVisible()) return 0;
     
     // shouldn't this be !can_handle_mouse_event() instead ?
     // not selectable, so don't catch mouse events!
@@ -744,7 +744,7 @@
         break;
     case NSV::PROP_uVISIBLE:
     {
-        val->set_bool(get_visible());
+        val->set_bool(isVisible());
         return true;
     }
     case NSV::PROP_uALPHA:

=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2008-11-25 11:44:58 +0000
+++ b/libcore/as_value.cpp      2008-12-05 08:03:35 +0000
@@ -1957,7 +1957,8 @@
           log_unimpl("AMF3 data type is not supported yet");
           break;
       default:
-          log_unimpl("Element to as_value - unsupported Element type %d", 
el.getType());
+          log_unimpl("Element to as_value - unsupported Element type %d", 
+                  el.getType());
           break;
     }
 }

=== modified file 'libcore/asobj/XMLNode_as.cpp'
--- a/libcore/asobj/XMLNode_as.cpp      2008-12-04 08:23:23 +0000
+++ b/libcore/asobj/XMLNode_as.cpp      2008-12-05 08:03:35 +0000
@@ -161,17 +161,12 @@
         oldparent->_children.remove(node);
     }
 
-//  log_unimpl("%s: partially unimplemented", __PRETTY_FUNCTION__);
 }
 
 boost::intrusive_ptr<XMLNode_as> 
 XMLNode_as::cloneNode(bool deep)
 {
-    //GNASH_REPORT_FUNCTION;
-    //log_debug(_("%s: deep is %d"), __PRETTY_FUNCTION__, deep);
-
     boost::intrusive_ptr<XMLNode_as> newnode = new XMLNode_as(*this, deep);
-
     return newnode;
 }
 

=== modified file 'libcore/character.cpp'
--- a/libcore/character.cpp     2008-12-03 08:54:10 +0000
+++ b/libcore/character.cpp     2008-12-05 09:58:55 +0000
@@ -38,12 +38,24 @@
 #endif
 
 #include <boost/algorithm/string/case_conv.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
 
 #undef set_invalidated
 
 namespace gnash
 {
 
+// Forward declarations.
+namespace {
+    /// Match blend modes.
+    typedef std::map<MovieClip::BlendMode, std::string> BlendModeMap;
+    const BlendModeMap& getBlendModeMap();
+    bool blendModeMatches(const BlendModeMap::value_type& val,
+            const std::string& mode);
+}
+
+
 // Define static const members or there will be linkage problems.
 const int character::lowerAccessibleBound;
 const int character::upperAccessibleBound;
@@ -525,6 +537,75 @@
 
 }
 
+as_value
+character::blendMode(const fn_call& fn)
+{
+    boost::intrusive_ptr<character> ch =
+        ensureType<character>(fn.this_ptr);
+
+    // This is AS-correct, but doesn't do anything.
+    // TODO: implement in the renderers!
+    LOG_ONCE(log_unimpl(_("blendMode")));
+
+    if (!fn.nargs)
+    {
+        // Getter
+        BlendMode bm = ch->getBlendMode();
+
+        /// If the blend mode is undefined, it doesn't return a string.
+        if (bm == BLENDMODE_UNDEFINED) return as_value();
+
+        std::ostringstream blendMode;
+        blendMode << bm;
+        return as_value(blendMode.str());
+    }
+
+    //
+    // Setter
+    //
+    
+    const as_value& bm = fn.arg(0);
+
+    // Undefined argument sets blend mode to normal.
+    if (bm.is_undefined()) {
+        ch->setBlendMode(BLENDMODE_NORMAL);
+        return as_value();
+    }
+
+    // Numeric argument.
+    if (bm.is_number()) {
+        double mode = bm.to_number();
+
+        // hardlight is the last known value
+        if (mode < 0 || mode > BLENDMODE_HARDLIGHT) {
+
+            // An invalid numeric argument becomes undefined.
+            ch->setBlendMode(BLENDMODE_UNDEFINED);
+        }
+        else {
+            ch->setBlendMode(static_cast<BlendMode>(mode));
+        }
+        return as_value();
+    }
+
+    // Other arguments use toString method.
+    const std::string& mode = bm.to_string();
+
+    const BlendModeMap& bmm = getBlendModeMap();
+    BlendModeMap::const_iterator it = std::find_if(bmm.begin(), bmm.end(),
+            boost::bind(blendModeMatches, _1, mode));
+
+    if (it != bmm.end()) {
+        ch->setBlendMode(it->first);
+    }
+
+    // An invalid string argument has no effect.
+
+    return as_value();
+
+}
+
+
 /// _visible can be set with true/false, but also
 /// 0 and 1.
 as_value
@@ -535,7 +616,7 @@
        as_value rv;
        if (!fn.nargs) // getter
        {
-               rv = as_value(ptr->get_visible());
+               rv = as_value(ptr->isVisible());
        }
        else // setter
        {
@@ -613,17 +694,17 @@
 void
 character::set_visible(bool visible)
 {
-    if (m_visible != visible) set_invalidated(__FILE__, __LINE__);
+    if (_visible != visible) set_invalidated(__FILE__, __LINE__);
 
     // Remove focus from this character if it changes from visible to
     // invisible (see Selection.as).
-    if (m_visible && !visible) {
+    if (_visible && !visible) {
         movie_root& mr = _vm.getRoot();
         if (mr.getFocus().get() == this) {
             mr.setFocus(0);
         }
     }
-    m_visible = visible;      
+    _visible = visible;      
 }
 void
 character::set_width(double newwidth)
@@ -1327,6 +1408,51 @@
     return get_root();
 }
 
+namespace {
+
+const BlendModeMap&
+getBlendModeMap()
+{
+    /// BLENDMODE_UNDEFINED has no matching string in AS. It is included
+    /// here for logging purposes.
+    static const BlendModeMap bm = boost::assign::map_list_of
+        (character::BLENDMODE_UNDEFINED, "undefined")
+        (character::BLENDMODE_NORMAL, "normal")
+        (character::BLENDMODE_LAYER, "layer")
+        (character::BLENDMODE_MULTIPLY, "multiply")
+        (character::BLENDMODE_SCREEN, "screen")
+        (character::BLENDMODE_LIGHTEN, "lighten")
+        (character::BLENDMODE_DARKEN, "darken")
+        (character::BLENDMODE_DIFFERENCE, "difference")
+        (character::BLENDMODE_ADD, "add")
+        (character::BLENDMODE_SUBTRACT, "subtract")
+        (character::BLENDMODE_INVERT, "invert")
+        (character::BLENDMODE_ALPHA, "alpha")
+        (character::BLENDMODE_ERASE, "erase")
+        (character::BLENDMODE_OVERLAY, "overlay")
+        (character::BLENDMODE_HARDLIGHT, "hardlight");
+
+    return bm;
+}
+
+// Match a blend mode to its string.
+bool
+blendModeMatches(const BlendModeMap::value_type& val, const std::string& mode)
+{
+    /// The match must be case-sensitive.
+    if (mode.empty()) return false;
+    return (val.second == mode);
+}
+
+}
+
+std::ostream&
+operator<<(std::ostream& o, character::BlendMode bm)
+{
+    const BlendModeMap& bmm = getBlendModeMap();
+    return (o << bmm.find(bm)->second);
+}
+
 
 } // namespace gnash
 

=== modified file 'libcore/character.h'
--- a/libcore/character.h       2008-12-03 08:22:34 +0000
+++ b/libcore/character.h       2008-12-05 09:37:07 +0000
@@ -64,257 +64,32 @@
 
 public:
 
-  // action_buffer is externally owned
-  typedef std::vector<const action_buffer*> BufferList;
-  typedef std::map<event_id, BufferList> Events;
-
-#ifdef USE_SWFTREE
-  typedef std::pair<std::string, std::string> StringPair; // ifdef USE_MENU...
-  typedef tree<StringPair> InfoTree; // ifdef USE_MENU
-#endif
-
-  /// Set the current focus to this character.
-  //
-  /// @return false if the character cannot receive focus, true if it can
-  ///         (and does).
-  //
-  /// Button, Textfield and MovieClip can receive focus. In SWF6 and above,
-  /// MovieClip can only receive focus if the focusEnabled property
-  /// evaluates to true.
-  virtual bool handleFocus() { 
-      return false;
-  }
-
-  /// Some characters require actions on losing focus.
-  //
-  /// Default is a no-op. TextField implements this function.
-  virtual void killFocus() {}
-
-private:
-
-  int m_id;
-
-  int m_depth;
-  cxform  m_color_transform;
-  SWFMatrix  m_matrix;
-
-  /// Cache values for ActionScript access.
-  /// NOTE: not all characters need this, just the
-  ///       ones which are ActionScript-referenceable
-  double _xscale, _yscale, _rotation;
-
-  /// Volume control associated to this character
-  //
-  /// This is used by Sound objects
-  ///
-  /// NOTE: probably only ActionScript-referenceable characters
-  ///       need this (assuming soft ref don't rebind to other
-  ///       kind of characters).
-  ///
-  int  _volume;
-
-  int   m_ratio;
-  int m_clip_depth;
-  Events  _event_handlers;
-
-  /// Used to assign a name to unnamed instances
-  static unsigned int _lastUnnamedInstanceNum;
-
-  /// Set to yes when this instance has been unloaded
-  bool _unloaded;
-
-  /// This flag should be set to true by a call to destroy()
-  bool _destroyed;
-
-  /// Build the _target member recursive on parent
-  std::string computeTargetPath() const;
-
-  /// The character masking this instance (if any)
-  character* _mask;
-
-  /// The character masked by this instance (if any)
-  character* _maskee;
-
-  /// Original target, as at construction time
-  std::string _origTarget;
-
-  /// Register a character masked by this instance
-  void setMaskee(character* maskee);
-
-protected:
-
-  /// Register currently computable target as
-  /// the "original" one. This will be used by
-  /// soft references (as_value) and should be
-  /// called as soon as the stagePlacementCallback
-  /// is invoked.
-  ///
-  void saveOriginalTarget()
-  {
-    _origTarget=getTarget();
-  }
-
-#ifdef GNASH_USE_GC
-  /// Mark all reachable resources, override from as_object.
-  //
-  /// The default implementation calls markCharacterReachable().
-  ///
-  /// If a derived class provides access to more GC-managed
-  /// resources, it should override this method and call 
-  /// markCharacterReachableResources() as the last step.
-  ///
-  virtual void markReachableResources() const
-  {
-    markCharacterReachable();
-  }
-
-  /// Mark character-specific reachable resources
-  //
-  /// These are: the character's parent, mask, maskee and the default
-  ///             as_object reachable stuff.
-  ///
-  void markCharacterReachable() const;
-#endif // GNASH_USE_GC
-
-  const Events& get_event_handlers() const
-  {
-      return _event_handlers;
-  }
-
-  /// Return a user defined event handler, if any
-  //
-  /// @param name
-  ///   Function name to fetch. It will be converted to 
-  /// lowercase if current VM has been initialized against
-  /// an SWF version inferior to 7.
-  ///
-  /// @return
-  /// A function if a member with the given name exists and
-  /// casts to an as_function. A NULL pointer otherwise.
-  ///
-  boost::intrusive_ptr<as_function> getUserDefinedEventHandler(const 
std::string& name) const;
-
-  /// Return a user defined event handler, if any
-  //
-  /// @param key
-  ///   Function key to fetch. 
-  ///
-  /// @return
-  /// A function if a member with the given key exists and
-  /// casts to an as_function. A NULL pointer otherwise.
-  ///
-  boost::intrusive_ptr<as_function> 
getUserDefinedEventHandler(string_table::key key) const;
-
-  void set_event_handlers(const Events& copyfrom);
-
-  /// Used to assign a name to unnamed instances
-  static std::string getNextUnnamedInstanceName();
-
-  /// Name of this character (if any)
-  std::string _name;
-
-  bool m_visible;
-
-  boost::intrusive_ptr<character> m_parent;
-
-  /// look for '.', 'this',  '..', '_parent', '_level0' and '_root'
-  //
-  /// NOTE: case insensitive up to SWF6, sensitive from SWF7 up
-  ///
-  as_object* get_path_element_character(string_table::key key);
-
-  /// \brief
-  /// Set when the visual aspect of this particular character or movie
-  /// has been changed and redrawing is necessary.  
-  //
-  /// This is initialized to true as the initial state for
-  /// any character is the "invisible" state (it wasn't there)
-  /// so it starts in invalidated mode.
-  ///
-  bool m_invalidated;
-
-  /// Just like m_invalidated but set when a child is invalidated instead
-  /// of this character instance. m_invalidated and m_child_invalidated
-  /// can be set at the same time. 
-  bool m_child_invalidated;
-
-  /// \brief
-  /// Bounds of this character instance before first invalidation
-  /// since last call to clear_invalidated().
-  ///
-  /// This stores the bounds of the character before it has been changed, ie. 
-  /// the position when set_invalidated() is being called. While drawing, both 
-  /// the old and the new bounds are updated (rendered). When moving a 
-  /// character A to B then both the position A needs to be re-rendered (to 
-  /// reveal the backgrond) and the position B needs to be re-rendered (to 
show 
-  /// the character in it's new position). The bounds may be identical or 
-  /// overlap, but SnappingRanges takes care of that.
-  /// 
-  /// Will be set by set_invalidated() and used by
-  /// get_invalidated_bounds().
-  ///
-  InvalidatedRanges m_old_invalidated_ranges;
-
-  /// Wheter this character has been transformed by ActionScript code
-  //
-  /// Once we've been moved by ActionScript,
-  /// Don't accept moves from anim tags (PlaceObject)
-  ///
-  /// See get_accept_anim_moves() function
-  ///
-  bool _scriptTransformed;
-
-  bool _dynamicallyCreated;
-
-  /// @{ Common ActionScript getter-setters for characters
-
-public:  // TODO: make protected
-
-  /// Getter-setter for _x
-  static as_value x_getset(const fn_call& fn);
-
-  /// Getter-setter for _y
-  static as_value y_getset(const fn_call& fn);
-
-  /// Getter-setter for _xscale
-  static as_value xscale_getset(const fn_call& fn);
-
-  /// Getter-setter for _yscale
-  static as_value yscale_getset(const fn_call& fn);
-
-  /// Getter-setter for _xmouse
-  static as_value xmouse_get(const fn_call& fn);
-
-  /// Getter-setter for _ymouse
-  static as_value ymouse_get(const fn_call& fn);
-
-  /// Getter-setter for _alpha
-  static as_value alpha_getset(const fn_call& fn);
-
-  /// Getter-setter for _visible
-  static as_value visible_getset(const fn_call& fn);
-
-  /// Getter-setter for _width
-  static as_value width_getset(const fn_call& fn);
-
-  /// Getter-setter for _height
-  static as_value height_getset(const fn_call& fn);
-
-  /// Getter-setter for _rotation
-  static as_value rotation_getset(const fn_call& fn);
-
-  /// Getter-setter for _parent 
-  static as_value parent_getset(const fn_call& fn);
-
-  /// Getter-setter for _target 
-  static as_value target_getset(const fn_call& fn);
-
-  /// Getter-setter for _name
-  static as_value name_getset(const fn_call& fn);
-
-  /// @} Common ActionScript getter-setters for characters
-
-public:
+    character(character* parent, int id)
+        :
+        m_parent(parent),
+        m_invalidated(true),
+        m_child_invalidated(true),
+        m_id(id),
+        m_depth(0),
+        _xscale(100),
+        _yscale(100),
+        _rotation(0),
+        _volume(100),
+        m_ratio(0),
+        m_clip_depth(noClipDepthValue),
+        _unloaded(false),
+        _destroyed(false),
+        _mask(0),
+        _maskee(0),
+        _blendMode(BLENDMODE_NORMAL),
+        _visible(true),
+        _scriptTransformed(false),
+        _dynamicallyCreated(false)
+    {
+        assert((parent == NULL && m_id == -1) || 
+                (parent != NULL && m_id >= 0));
+        assert(m_old_invalidated_ranges.isNull());
+    }
 
     /// The lowest placeable and accessible depth for a character.
     /// Macromedia Flash help says: depth starts at -16383 (0x3FFF)
@@ -350,7 +125,8 @@
     /// So, to recap:
     ///   1:  -32769 to -16385 are removed
     ///   2:  -16384 to      0 are statics
-    ///   3:  Max depth for a PlaceoObject call is 16384 (which becomes 0 in 
the statics)
+    ///   3:  Max depth for a PlaceoObject call is 16384 (which becomes 
+    ///       0 in the statics)
     /// (all of the above correct?)
     ///
     ///
@@ -384,65 +160,35 @@
     ///
     static const int dynClipDepthValue = -2000000;
 
-    character(character* parent, int id)
-        :
-        m_id(id),
-        m_depth(0),
-        m_color_transform(),
-        m_matrix(),
-       _xscale(100),
-       _yscale(100),
-       _rotation(0),
-        _volume(100),
-        m_ratio(0),
-        m_clip_depth(noClipDepthValue),
-        _unloaded(false),
-        _destroyed(false),
-        _mask(0),
-        _maskee(0),
-        _origTarget(),
-        m_visible(true),
-        m_parent(parent),
-        m_invalidated(true),
-        m_child_invalidated(true),
-        m_old_invalidated_ranges(),
-        _scriptTransformed(false),
-        _dynamicallyCreated(false)
-    {
-      assert((parent == NULL && m_id == -1)
-       || (parent != NULL && m_id >= 0));
-      assert(m_old_invalidated_ranges.isNull());
+    /// Return a reference to the variable scope of this character.
+    //
+    /// TODO: make const/return const& ?
+    ///
+    virtual as_environment& get_environment() {
+        // MovieClip must override this
+        // and any other character will have
+        // a parent!
+        assert(m_parent != NULL);
+        return m_parent->get_environment();
     }
 
-  /// Return a reference to the variable scope of this character.
-  //
-  /// TODO: make const/return const& ?
-  ///
-  virtual as_environment& get_environment() {
-    // MovieClip must override this
-    // and any other character will have
-    // a parent!
-    assert(m_parent != NULL);
-    return m_parent->get_environment();
-  }
-
     // Accessors for basic display info.
     int get_id() const { return m_id; }
 
-  /// \brief
-  /// Return the parent of this character, or NULL if
-  /// the character has no parent.
-  character* get_parent() const
-  {
-      return m_parent.get();
-  }
+    /// \brief
+    /// Return the parent of this character, or NULL if
+    /// the character has no parent.
+    character* get_parent() const
+    {
+        return m_parent.get();
+    }
 
-  /// for extern movie
-  void set_parent(character* parent)
-  {
-    assert(_origTarget.empty());
-    m_parent = parent;
-  }
+    /// for extern movie
+    void set_parent(character* parent)
+    {
+        assert(_origTarget.empty());
+        m_parent = parent;
+    }
 
     int get_depth() const { return m_depth; }
 
@@ -473,7 +219,7 @@
     /// @param updateCache if true, updates the cache values
     ///        from the SWFMatrix (only if SWFMatrix != current SWFMatrix)
     ///
-    void  setMatrix(const SWFMatrix& m, bool updateCache=false);
+    void setMatrix(const SWFMatrix& m, bool updateCache=false);
 
     /// Set the xscale value of current SWFMatrix
     //
@@ -529,19 +275,21 @@
 
     void  set_cxform(const cxform& cx) 
     {       
-      if (!(cx == m_color_transform)) {
-        set_invalidated(__FILE__, __LINE__);
-        m_color_transform = cx;
-      }
-    }
-
-    void  concatenate_cxform(const cxform& cx) { 
m_color_transform.concatenate(cx); }
-
-    void  concatenateMatrix(const SWFMatrix& m) { m_matrix.concatenate(m); }
-
-    int   get_ratio() const { return m_ratio; }
-
-    void  set_ratio(int r)
+        if (!(cx == m_color_transform)) {
+            set_invalidated(__FILE__, __LINE__);
+            m_color_transform = cx;
+        }
+    }
+
+    void concatenate_cxform(const cxform& cx) {
+        m_color_transform.concatenate(cx);
+    }
+
+    void concatenateMatrix(const SWFMatrix& m) { m_matrix.concatenate(m); }
+
+    int get_ratio() const { return m_ratio; }
+
+    void set_ratio(int r)
     {
       if (r!=m_ratio) set_invalidated(__FILE__, __LINE__); 
       m_ratio = r;       
@@ -556,75 +304,76 @@
     ///  
     int get_clip_depth() const { return m_clip_depth; }
 
-  /// See get_clip_depth()
-  void set_clip_depth(int d)
-  {
-    m_clip_depth = d;
-  }
-    
-  /// Returns true when the character (and it's childs) is used as a mask
-  /// for other characters at higher depth (up to get_clip_depth).
-  /// isMaskLayer() does *not* return true when one of it's
-  /// parents is a mask and the character itself is not.
-  ///
-  /// See also isDynamicMask() and isMask()
-  ///   
-  bool isMaskLayer() const
-  {
-    // TODO: is dynClipDepthValue still needed ?
-    //       since we have a _maskee member now, we may use that instead..
-    return (m_clip_depth!=noClipDepthValue && m_clip_depth!=dynClipDepthValue);
-  }
-
-  /// Returns true when the character (and it's childs) is used as a mask
-  /// for another character.
-  /// isDynamicMask() does *not* return true when one of it's
-  /// parents is a mask and the character itself is not.
-  ///
-  /// NOTE: there's no way to obtain the maskee from a dynamic mask
-  ///
-  /// See also isMaskLayer() and isMask()
-  ///   
-  bool isDynamicMask() const
-  {
-    return (m_clip_depth==dynClipDepthValue);
-  }
-
-  character* to_character() { return this; }
-
-  /// Return the character masking this instance (if any)
-  character* getMask() const
-  {
-    if ( ! _mask ) return NULL;
-    if ( _mask->_maskee != this )
-    {
-      // TODO: fix this !
-      log_error("Our mask maskee is not us");
-      return NULL; // for correctness;
-    }
-    return _mask;
-  }
-
-  /// Register a character as a mask for this instance.
-  ///
-  /// @param mask The character to use as a mask, possibly NULL.
-  /// A reference to us will be registered with the mask, if
-  /// not null, so it'll know it's a mask for us, and would stop
-  /// being a mask for anything else.
-  ///
-  void setMask(character* mask);
-
-  /// Returns true if this character is a mask (either layer or dynamic mask)
-  bool isMask() const
-  {
-    return isDynamicMask() || isMaskLayer();
-  }
-
-  /// Set character name, initializing the original target member
-  void set_name(const std::string& name)
-  {
-    _name = name;
-  }
+    /// See get_clip_depth()
+    void set_clip_depth(int d)
+    {
+        m_clip_depth = d;
+    }
+        
+    /// Returns true when the character (and it's childs) is used as a mask
+    /// for other characters at higher depth (up to get_clip_depth).
+    /// isMaskLayer() does *not* return true when one of it's
+    /// parents is a mask and the character itself is not.
+    ///
+    /// See also isDynamicMask() and isMask()
+    ///     
+    bool isMaskLayer() const
+    {
+        // TODO: is dynClipDepthValue still needed ?
+        //       since we have a _maskee member now, we may use that instead..
+        return (m_clip_depth != noClipDepthValue && 
+                m_clip_depth != dynClipDepthValue);
+    }
+
+    /// Returns true when the character (and it's childs) is used as a mask
+    /// for another character.
+    /// isDynamicMask() does *not* return true when one of it's
+    /// parents is a mask and the character itself is not.
+    ///
+    /// NOTE: there's no way to obtain the maskee from a dynamic mask
+    ///
+    /// See also isMaskLayer() and isMask()
+    ///     
+    bool isDynamicMask() const
+    {
+        return (m_clip_depth==dynClipDepthValue);
+    }
+
+    character* to_character() { return this; }
+
+    /// Return the character masking this instance (if any)
+    character* getMask() const
+    {
+        if ( ! _mask ) return NULL;
+        if ( _mask->_maskee != this )
+        {
+            // TODO: fix this !
+            log_error("Our mask maskee is not us");
+            return NULL; // for correctness;
+        }
+        return _mask;
+    }
+
+    /// Register a character as a mask for this instance.
+    ///
+    /// @param mask The character to use as a mask, possibly NULL.
+    /// A reference to us will be registered with the mask, if
+    /// not null, so it'll know it's a mask for us, and would stop
+    /// being a mask for anything else.
+    ///
+    void setMask(character* mask);
+
+    /// Returns true if this character is a mask (either layer or dynamic mask)
+    bool isMask() const
+    {
+        return isDynamicMask() || isMaskLayer();
+    }
+
+    /// Set character name, initializing the original target member
+    void set_name(const std::string& name)
+    {
+        _name = name;
+    }
 
     const std::string& get_name() const { return _name; }
 
@@ -636,560 +385,566 @@
         return false;
     }
 
-  /// \brief
-  /// Get our concatenated SWFMatrix (all our ancestor transforms,
-  /// times our SWFMatrix). 
-  ///
-  /// Maps from our local space into "world" space
-  /// (i.e. root movie space).
-  virtual SWFMatrix  getWorldMatrix() const;
-
-  /// \brief
-  /// Get our concatenated color transform (all our ancestor transforms,
-  /// times our cxform). 
-  ///
-  /// Maps from our local space into normal color space.
-  virtual cxform  get_world_cxform() const;
-
-  /// Get the built-in function handlers code for the given event
-  //
-  /// NOTE: this function is only for getting statically-defined
-  ///       event handlers, which are the ones attached to a character
-  ///       with a PlaceObject2. It's the character's responsibility
-  ///       to properly fetch any user-defined event handler, which 
-  ///       are the ones attached to a character with ActionScript code.
-  ///
-  std::auto_ptr<ExecutableCode> get_event_handler(const event_id& id) const;
-
-  /// Set a built-in function handler for the given event
-  //
-  /// Mark the character as having mouse or Key event
-  /// handlers if this is the case.
-  ///
-  /// NOTE: this function is only for registering statically-defined
-  ///       event handlers, which are the ones attached to a character
-  ///       with a PlaceObject2. It's the character's responsibility
-  ///       to properly invoke any user-defined event handler, which 
-  ///       are the ones attached to a character with ActionScript code.
-  ///
-  /// @param id
-  /// The event triggering the handler.
-  ///
-  /// @param code
-  /// An action buffer to execute when given event is triggered.
-  /// The buffer is externally owned (not copied), make sure it
-  /// is kept alive for the whole lifetime of this character.
-  ///
-  void add_event_handler(const event_id& id, const action_buffer& code);
-
-  /// Render this character
-  virtual void  display() {}
-
-  /// Returns local, untransformed height of this character in TWIPS
-  //
-  /// Use getBounds() if you need more then simply the height.
-  ///
-  boost::int32_t get_height() const
-  {
-    rect bounds = getBounds();
-    return bounds.height();
-  }
-
-  /// Returns local, untransformed width of this character in TWIPS
-  //
-  /// Use getBounds() if you need more then simply the width.
-  ///
-  boost::int32_t get_width() const
-  {
-    rect bounds = getBounds();
-    return bounds.width();
-  }
-
-      /// Returns local, untransformed bounds of this character in TWIPS
-  //
-  /// The default implementation prints an error and returns a NULL rect.
-  ///
-  /// Container characters (sprite and buttons) return the composite
-  /// bounds of all their childrens, appropriaterly transformed with
-  /// their local SWFMatrix.
-  ///
-  virtual rect getBounds() const
-  {
-    log_error("FIXME: character %s did not override the getBounds() method",
-        typeid(*this).name());
-    return rect();
-  }
-
-  /// Return true if the given point falls in this character's bounds
-  //
-  /// Point coordinates are in world TWIPS
-  ///
-  bool pointInBounds(boost::int32_t x, boost::int32_t y) const
-  {
-    rect bounds = getBounds();
-    SWFMatrix wm = getWorldMatrix();
-    wm.transform(bounds);
-    return bounds.point_test(x, y);
-  }
-
-  /// Return true if the given point falls in this character's shape
-  //
-  /// Point coordinates are in world TWIPS
-  ///
-  /// The default implementation warns about a missing
-  /// override and invokes pointInBounds().
-  ///
-  ///
-  virtual bool pointInShape(boost::int32_t x, boost::int32_t y) const
-  {
-    log_error("Character %s did not override pointInShape() - using 
pointInBounds() instead", typeid(*this).name());
-    return pointInBounds(x, y);
-  }
-
-  /// Return true if the given point falls in this character's visible shape
-  //
-  /// Point coordinates are in world TWIPS
-  ///
-  /// The default implementation returns false if the character is
-  /// not visible, calling pointInShape() otherwise.
-  ///
-  /// Note that this is good for simple characters but needs
-  /// to be overridden for characters with childs. When a
-  /// character has childs it must take into account the case
-  /// in which some childs are visible and some are not.
-  ///
-  virtual bool pointInVisibleShape(boost::int32_t x, boost::int32_t y) const
-  {
-    if ( ! get_visible() ) return false;
-    if ( isMask() ) return false;
-    return pointInShape(x, y);
-  }
-
-  /// Return the relative root of this character
-  //
-  /// The "relative" is the movie_instance created by
-  /// the same SWF definition that contained the
-  /// definition of this character.
-  ///
-  /// The default implementation is to invoke get_root
-  /// against this character's parent.
-  ///
-  virtual movie_instance* get_root() const {
-    return get_parent()->get_root();
-  }
-
-  /// Return the _root ActionScript property of this character.
-  //
-  /// By default calls get_root().
-  ///
-  virtual const MovieClip* getAsRoot() const;
-
-  /// Find the object 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 as_object* get_path_element(string_table::key key)
-  {
-    return get_path_element_character(key);
-  }
-
-  /// Restart the character
-  //
-  /// This is only meaningful for sprite instances, but default
-  /// it's a no-op.
-  ///
-  /// It is needed by Button
-  /// TODO: have Button cast to_movie()
-  ///       and drop this one
-  virtual void  restart() { }
-
-  /// Advance this character to next frame.
-  //
-  /// Character advancement is only meaningful for sprites
-  /// and sprite containers (button characters) because
-  /// sprites are the only characters that have frames.
-  /// 
-  /// Frame advancement include execution of all control tags.
-  /// 
-  virtual void advance()
-  {
-    // GNASH_REPORT_FUNCTION 
-  }
-
-  // TODO: verify if this is really needed (I guess not)
-  virtual void  goto_frame(size_t /*target_frame*/) {}
-
-  /// \brief
-  /// Return true if PlaceObjects tag are allowed to move
-  /// this character.
-  //
-  /// Once a character has been transformed by ActionScript,
-  /// further transformation trought non-action SWF constrol tags
-  /// is not allowed.
-  ///
-  /// See scriptTransformed()
-  ///
-  bool get_accept_anim_moves() const
-  {
-    return ! _scriptTransformed && ! _dynamicallyCreated;
-  }
-
-  /// Was this character dynamically created ?
-  //
-  /// "Dynamically created" means created trough ActionScript.
-  ///
-  /// NOTE, With current code:
-  /// - Characters created by means of a loadMovie are 
-  ///   NOT set as dynamic (should check if they should)
-  /// - Characters created by attachMovie ARE dynamic
-  /// - Characters created by duplicateMovieClip ARE dynamic
-  /// - Characters created by createEmptyMovieClip ARE dynamic
-  /// - Characters created by new Video ARE dynamic
-  /// - Characters created by createTextField ARE dynamic
-  ///
-  ///
-  bool isDynamic() const {
-    return _dynamicallyCreated;
-  }
-
-  /// Mark this character as dynamically created
-  void setDynamic() {
-    _dynamicallyCreated = true;
-  }
-
-  /// \brief
-  /// Call this function when the sprite has been
-  /// transformed due to ActionScript code.
-  //
-  /// This information will be used while executing
-  /// PlaceObject tags in that ActionScript-transformed
-  /// characters won't be allowed to be moved.
-  ///
-  /// TODO: make protected
-  ///
-  void transformedByScript() 
-  {
-    _scriptTransformed = true;
-  }
-
-  // Set whether this character should be rendered
-  void set_visible(bool visible);
-
-  // Return true if this character should be rendered
-  bool get_visible() const { return m_visible; }
-
-  /// Return mouse state in given variables
-  //
-  /// Use this to retrieve the last state of the mouse, as set via
-  /// notify_mouse_state().  Coordinates are in PIXELS, NOT TWIPS.
-  ///
-  /// The default implementation calls get_mouse_state against
-  /// the character's parent. The final parent (a MovieClip)
-  /// will delegate the call to it's associated movie_root, which
-  /// does all the work.
-  ///
-  //virtual void get_mouse_state(int& x, int& y, int& buttons);
-
-  /// These have been moved down from movie.h to remove that file
-  /// from the inheritance chain. It is probably still a misdesign
-  /// to require these functions for all characters.
-  /// @{
-
-  virtual movie_definition *get_movie_definition()
-  {
-    return NULL;
-  }
-
-  /// ActionScript event handler.  Returns true if a handler was called.
-  //
-  /// Must be overridden or will always return false.
-  ///
-  virtual bool on_event(const event_id& /* id */)
-  {
-    return false;
-  }
-
-  /// Queue event in the global action queue.
-  //
-  /// on_event(id) will be called by execution of the queued
-  /// action
-  ///
-  void queueEvent(const event_id& id, int lvl);
-
-  /// Return true if an handler for the given event is defined
-  //
-  /// NOTE that we look for both clip-defined and user-defined
-  /// handlers, which is likely error prone since we're doing
-  /// this in a non-virtual function. Main use for this method
-  /// is for being called by ::unload() to verify an Unload handler
-  /// is available.
-  ///
-  bool hasEventHandler(const event_id& id) const;
-
-  virtual void on_button_event(const event_id& id)
-  {
-    on_event(id);
-  }
-
-  /// \brief
-  /// Return the topmost entity covering the given point
-  /// and enabled to receive mouse events.
-  //
-  /// Return NULL if no "active" entity is found under the pointer.
-  ///
-  /// Coordinates of the point are given in parent's coordinate space.
-  /// This means that in order to convert the point to the local coordinate
-  /// space you need to apply an inverse transformation using this
-  /// character SWFMatrix. Example:
-  ///
-  /// point p(x,y);
-  /// getMatrix().transform_by_inverse(p);
-  /// -- p is now in local coordinates
-  ///
-  /// Don't blame me for this mess, I'm just trying to document the existing
-  /// functions ... --strk
-  ///
-  /// @param x
-  ///   X ordinate of the pointer, in parent's coordinate space.
-  ///
-  /// @param y
-  ///   Y ordinate of the pointer, in parent's coordiante space.
-  ///
-  virtual character* get_topmost_mouse_entity(boost::int32_t /* x */, 
boost::int32_t /* y */)
-  {
-    return NULL;
-  }
-
-  /// Find highest depth character whose shape contains the given
-  /// point and is not the character being dragged or any of its childs.
-  //
-  /// Point coordinates in global twips.
-  ///
-  virtual const character* findDropTarget(boost::int32_t x, boost::int32_t y, 
character* dragging) const
-  {
-    if ( this != dragging && get_visible()
-      && pointInVisibleShape(x, y) )
-    {
-      return this;
-    }
-    else return 0;
-  }
-
-  /// Returns true when the object (type) should get a instance name even 
-  /// if none is provided manually.
-  virtual bool wantsInstanceName() const
-  {
-    return false; 
-  }
-
-  /// Returns true when the object (type) can be referenced by ActionScipt
-  bool isActionScriptReferenceable() const
-  {
-    // The way around
-    // [ wantsInstanceName() returning isActionScriptReferenceable() ]
-    // would be cleaner, but I wouldn't want to touch all files now.
-    return wantsInstanceName();
-  }
-
-  /// Returns the closest as-referenceable ancestor
-  character* getClosestASReferenceableAncestor() 
-  {
-    if ( isActionScriptReferenceable() ) return this;
-    assert(m_parent);
-    return m_parent->getClosestASReferenceableAncestor();
-  }
-
-  const character* getClosestASReferenceableAncestor() const
-  {
-    character* nonconst_this = const_cast<character*>(this);
-    return nonconst_this->getClosestASReferenceableAncestor();
-  }
-
-  /// @}
-
-  /// \brief
-  /// This function marks the character as being modified in aspect
-  /// and keeps track of current invalidated bounds the first time
-  /// it's called after each call to clear_invalidated().
-  //
-  /// Call this function *before* any change in this character
-  /// that modifies its rendering. This information will be used
-  /// to detect visual changes that need to be redrawn.
-  ///
-  /// It is *important* to call this function *before* the change
-  /// rather then after as it will also take care of updating the
-  /// previously invalidated bounds (m_old_invalidated_bounds)
-  ///
-  /// Calling this function multiple time is a no-op, unless
-  /// clear_invalidated() is called in between.
-  ///
-  /// NOTE: Marking a character as invalidated automatically marks
-  ///       it's parent as being invalidated.
-  ///
-  /// @see \ref region_update
-  ///
-  void set_invalidated();
-  void set_invalidated(const char* debug_file, int debug_line);
-  
-  
-  /// Calls set_invalidated() and extends old_invalidated_ranges to the
-  /// given value so that also this area gets re-rendered (used when
-  /// replacing characters).  
-  void extend_invalidated_bounds(const InvalidatedRanges& ranges);
-  
-  
-  /// Called by a child to signalize it has changed visibily. The
-  /// difference to set_invalidated() is that *this* character does
-  /// not need to redraw itself completely. This function will 
-  /// recursively inform all it's parents of the change.
-  void set_child_invalidated();
-  
-  /// Clear invalidated flag and reset m_old_invalidated_bounds to null.
-  ///
-  /// It is very important that each character with any m_XXXX_invalidated flag
-  /// set calls clear_invalidated() during the rendering of one frame. 
-  /// Basically this means each call to display() must match a call to 
-  /// clear_invalidated. This includes no-op display() calls, i.e. when the
-  /// character is outside of the screen. The DisplayList must still call
-  /// clear_invalidated() even if display() is not necessary.
-  ///
-  /// Not doing so will result in a stale invalidated flag which in turn will
-  /// prevent the parent to be informed when this character (or a child) is
-  /// invalidated again (see set_invalidated() recursion).
-  ///  
-  void clear_invalidated() {
-    m_invalidated = false;
-    m_child_invalidated = false;    
-    m_old_invalidated_ranges.setNull();
-  }
-  
-  /// \brief
-  /// Add the character's invalidated bounds *to* the given ranges list.
-  //
-  /// NOTE that this method should include the bounds that it
-  /// covered the last time clear_invalidated() was called,
-  /// as those need to be rerendered as well (to clear the region
-  /// previously occupied by this character).
-  ///
-  /// That's why it returns the *union* of old_invalidated_ranges and
-  /// the current bounds. The function is also used internally by 
-  /// set_invalidated() to update m_old_invalidated_ranges itself (you may 
-  /// notice some kind of circular reference), but that's no problem since 
-  /// old_invalidated_ranges is NULL during that call. 
-  ///
-  /// It is used to determine what area needs to be re-rendered.
-  /// The coordinates are world coordinates (in TWIPS).
-  /// Only instances with m_invalidated flag set are checked unless
-  /// force is set.
-  ///
-  virtual void add_invalidated_bounds(InvalidatedRanges& ranges, bool force) = 
0;
-
-  /// Called instead of display() when the character is not visible on stage.
-  /// Used to clear the invalidated flags.
-  virtual void omit_display() { clear_invalidated(); }; 
-  
-  /// Callback invoked whenever a character is placed on stage
-  //
-  /// This function must be called when the character is placed on
-  /// stage for the first time.
-  ///
-  /// The character version of this call sets the original target
-  /// of the character, for soft references to work.
-  /// If you override the method remember to call saveOriginalTarget()
-  /// as the first thing.
-  ///
-  virtual void stagePlacementCallback(as_object* = 0)
-  {
-    saveOriginalTarget();
-  }
-
-  /// Unload this instance from the stage.
-  //
-  /// This function must be called when the character is removed
-  /// from the stage.
-  /// It will take care of properly calling
-  /// unload against any child characters and queuing the
-  /// 'UNLOAD' event handler.
-  ///
-  /// @return true if any onUnload event handler was defined
-  ///         by either this or any child characters, false
-  ///         otherwise.
-  ///
-  virtual bool unload();
-
-  /// Return true if this character was unloaded from the stage
-  bool isUnloaded() { return _unloaded; }
-
-  /// Mark this character as destroyed
-  //
-  /// A character should be destroyed when is removed from the display
-  /// list and is not more needed for names (target) resolutions.
-  /// Sprites are needed for names resolution whenever themselves
-  /// or a contained object has an onUnload event handler defined, 
-  /// in which case we want the event handler to find the 'this'
-  /// variable w/out attempting to rebind it.
-  ///
-  /// Note: this function can safely release most memory associated
-  ///       with the character as it will not be needed anymore.
-  ///
-  virtual void destroy();
-
-  /// Return true if this character was destroyed.
-  //
-  /// See destroy() for more info.
-  ///
-  bool isDestroyed() const { return _destroyed; }
-  
-  /// Returns true when the character bounds intersect with the current  
-  /// rendering clipping area.
-  ///
-  /// There is no need to do any rendering for this character when this 
-  /// function returns false because the renderer will not change any pixels
-  /// in the area where this character is placed.  
-  bool boundsInClippingArea() const; 
-
-public: // istn't this 'public' reduntant ?
-
-  /// Return full path to this object, in slash notation
-  //
-  /// e.g. "/sprite1/sprite2/ourSprite"
-  ///
-  std::string getTargetPath() const;
-
-  /// Return original target path to this object, in dot notation
-  /// as of at construction time.
-  //
-  /// This is needed to properly dereference dangling soft-references
-  /// See testcase misc-swfc.all/soft_reference_test1.sc
-  ///
-  const std::string& getOrigTarget() const
-  {
-    return _origTarget;
-  }
-
-  /// Return full path to this object, in dot notation
-  //
-  /// e.g. "_level0.sprite1.sprite2.ourSprite"
-  ///
-  std::string DSOEXPORT getTarget() const;
+    /// \brief
+    /// Get our concatenated SWFMatrix (all our ancestor transforms,
+    /// times our SWFMatrix). 
+    ///
+    /// Maps from our local space into "world" space
+    /// (i.e. root movie space).
+    virtual SWFMatrix    getWorldMatrix() const;
+
+    /// \brief
+    /// Get our concatenated color transform (all our ancestor transforms,
+    /// times our cxform). 
+    ///
+    /// Maps from our local space into normal color space.
+    virtual cxform    get_world_cxform() const;
+
+    /// Get the built-in function handlers code for the given event
+    //
+    /// NOTE: this function is only for getting statically-defined
+    ///             event handlers, which are the ones attached to a character
+    ///             with a PlaceObject2. It's the character's responsibility
+    ///             to properly fetch any user-defined event handler, which 
+    ///             are the ones attached to a character with ActionScript 
code.
+    ///
+    std::auto_ptr<ExecutableCode> get_event_handler(const event_id& id) const;
+
+    /// Set a built-in function handler for the given event
+    //
+    /// Mark the character as having mouse or Key event
+    /// handlers if this is the case.
+    ///
+    /// NOTE: this function is only for registering statically-defined
+    ///             event handlers, which are the ones attached to a character
+    ///             with a PlaceObject2. It's the character's responsibility
+    ///             to properly invoke any user-defined event handler, which 
+    ///             are the ones attached to a character with ActionScript 
code.
+    ///
+    /// @param id
+    /// The event triggering the handler.
+    ///
+    /// @param code
+    /// An action buffer to execute when given event is triggered.
+    /// The buffer is externally owned (not copied), make sure it
+    /// is kept alive for the whole lifetime of this character.
+    ///
+    void add_event_handler(const event_id& id, const action_buffer& code);
+
+    /// Render this character
+    virtual void    display() {}
+
+    /// Returns local, untransformed height of this character in TWIPS
+    //
+    /// Use getBounds() if you need more then simply the height.
+    ///
+    boost::int32_t get_height() const
+    {
+        rect bounds = getBounds();
+        return bounds.height();
+    }
+
+    /// Returns local, untransformed width of this character in TWIPS
+    //
+    /// Use getBounds() if you need more then simply the width.
+    ///
+    boost::int32_t get_width() const
+    {
+        rect bounds = getBounds();
+        return bounds.width();
+    }
+
+    /// Returns local, untransformed bounds of this character in TWIPS
+    //
+    /// The default implementation prints an error and returns a NULL rect.
+    ///
+    /// Container characters (sprite and buttons) return the composite
+    /// bounds of all their childrens, appropriaterly transformed with
+    /// their local SWFMatrix.
+    ///
+    virtual rect getBounds() const
+    {
+        log_error("FIXME: character %s did not override the getBounds() 
method",
+                typeid(*this).name());
+        return rect();
+    }
+
+    /// Return true if the given point falls in this character's bounds
+    //
+    /// Point coordinates are in world TWIPS
+    ///
+    bool pointInBounds(boost::int32_t x, boost::int32_t y) const
+    {
+        rect bounds = getBounds();
+        SWFMatrix wm = getWorldMatrix();
+        wm.transform(bounds);
+        return bounds.point_test(x, y);
+    }
+
+    /// Return true if the given point falls in this character's shape
+    //
+    /// Point coordinates are in world TWIPS
+    ///
+    /// The default implementation warns about a missing
+    /// override and invokes pointInBounds().
+    ///
+    ///
+    virtual bool pointInShape(boost::int32_t x, boost::int32_t y) const
+    {
+        log_error("Character %s did not override pointInShape() - "
+                "using pointInBounds() instead", typeid(*this).name());
+        return pointInBounds(x, y);
+    }
+
+    /// Return true if the given point falls in this character's visible shape
+    //
+    /// Point coordinates are in world TWIPS
+    ///
+    /// The default implementation returns false if the character is
+    /// not visible, calling pointInShape() otherwise.
+    ///
+    /// Note that this is good for simple characters but needs
+    /// to be overridden for characters with childs. When a
+    /// character has childs it must take into account the case
+    /// in which some childs are visible and some are not.
+    ///
+    virtual bool pointInVisibleShape(boost::int32_t x, boost::int32_t y) const
+    {
+        if ( ! isVisible() ) return false;
+        if ( isMask() ) return false;
+        return pointInShape(x, y);
+    }
+
+    /// Return the relative root of this character
+    //
+    /// The "relative" is the movie_instance created by
+    /// the same SWF definition that contained the
+    /// definition of this character.
+    ///
+    /// The default implementation is to invoke get_root
+    /// against this character's parent.
+    ///
+    virtual movie_instance* get_root() const {
+        return get_parent()->get_root();
+    }
+
+    /// Return the _root ActionScript property of this character.
+    //
+    /// By default calls get_root().
+    ///
+    virtual const MovieClip* getAsRoot() const;
+
+    /// Find the object 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 as_object* get_path_element(string_table::key key)
+    {
+        return get_path_element_character(key);
+    }
+
+    /// Restart the character
+    //
+    /// This is only meaningful for sprite instances, but default
+    /// it's a no-op.
+    ///
+    /// It is needed by Button
+    /// TODO: have Button cast to_movie()
+    ///             and drop this one
+    virtual void restart() { }
+
+    /// Advance this character to next frame.
+    //
+    /// Character advancement is only meaningful for sprites
+    /// and sprite containers (button characters) because
+    /// sprites are the only characters that have frames.
+    /// 
+    /// Frame advancement include execution of all control tags.
+    /// 
+    virtual void advance()
+    {
+        // GNASH_REPORT_FUNCTION 
+    }
+
+    // TODO: verify if this is really needed (I guess not)
+    virtual void    goto_frame(size_t /*target_frame*/) {}
+
+    /// \brief
+    /// Return true if PlaceObjects tag are allowed to move
+    /// this character.
+    //
+    /// Once a character has been transformed by ActionScript,
+    /// further transformation trought non-action SWF constrol tags
+    /// is not allowed.
+    ///
+    /// See scriptTransformed()
+    ///
+    bool get_accept_anim_moves() const
+    {
+        return ! _scriptTransformed && ! _dynamicallyCreated;
+    }
+
+    /// Was this character dynamically created ?
+    //
+    /// "Dynamically created" means created trough ActionScript.
+    ///
+    /// NOTE, With current code:
+    /// - Characters created by means of a loadMovie are 
+    ///     NOT set as dynamic (should check if they should)
+    /// - Characters created by attachMovie ARE dynamic
+    /// - Characters created by duplicateMovieClip ARE dynamic
+    /// - Characters created by createEmptyMovieClip ARE dynamic
+    /// - Characters created by new Video ARE dynamic
+    /// - Characters created by createTextField ARE dynamic
+    ///
+    ///
+    bool isDynamic() const {
+        return _dynamicallyCreated;
+    }
+
+    /// Mark this character as dynamically created
+    void setDynamic() {
+        _dynamicallyCreated = true;
+    }
+
+    /// \brief
+    /// Call this function when the sprite has been
+    /// transformed due to ActionScript code.
+    //
+    /// This information will be used while executing
+    /// PlaceObject tags in that ActionScript-transformed
+    /// characters won't be allowed to be moved.
+    ///
+    /// TODO: make protected
+    ///
+    void transformedByScript() 
+    {
+        _scriptTransformed = true;
+    }
+
+    /// Set whether this character should be rendered
+    //
+    /// TODO: handle all visible getter/setters in character, not in 
+    /// subclasses, and drop this / make it private.
+    void set_visible(bool visible);
+
+    // Return true if this character should be rendered
+    bool isVisible() const { return _visible; }
+
+    /// Return mouse state in given variables
+    //
+    /// Use this to retrieve the last state of the mouse, as set via
+    /// notify_mouse_state().    Coordinates are in PIXELS, NOT TWIPS.
+    ///
+    /// The default implementation calls get_mouse_state against
+    /// the character's parent. The final parent (a MovieClip)
+    /// will delegate the call to it's associated movie_root, which
+    /// does all the work.
+    ///
+    //virtual void get_mouse_state(int& x, int& y, int& buttons);
+
+    /// These have been moved down from movie.h to remove that file
+    /// from the inheritance chain. It is probably still a misdesign
+    /// to require these functions for all characters.
+    /// @{
+
+    virtual movie_definition *get_movie_definition()
+    {
+        return NULL;
+    }
+
+    /// ActionScript event handler.    Returns true if a handler was called.
+    //
+    /// Must be overridden or will always return false.
+    ///
+    virtual bool on_event(const event_id& /* id */)
+    {
+        return false;
+    }
+
+    /// Queue event in the global action queue.
+    //
+    /// on_event(id) will be called by execution of the queued
+    /// action
+    ///
+    void queueEvent(const event_id& id, int lvl);
+
+    /// Return true if an handler for the given event is defined
+    //
+    /// NOTE that we look for both clip-defined and user-defined
+    /// handlers, which is likely error prone since we're doing
+    /// this in a non-virtual function. Main use for this method
+    /// is for being called by ::unload() to verify an Unload handler
+    /// is available.
+    ///
+    bool hasEventHandler(const event_id& id) const;
+
+    virtual void on_button_event(const event_id& id)
+    {
+        on_event(id);
+    }
+
+    /// \brief
+    /// Return the topmost entity covering the given point
+    /// and enabled to receive mouse events.
+    //
+    /// Return NULL if no "active" entity is found under the pointer.
+    ///
+    /// Coordinates of the point are given in parent's coordinate space.
+    /// This means that in order to convert the point to the local coordinate
+    /// space you need to apply an inverse transformation using this
+    /// character SWFMatrix. Example:
+    ///
+    /// point p(x,y);
+    /// getMatrix().transform_by_inverse(p);
+    /// -- p is now in local coordinates
+    ///
+    /// Don't blame me for this mess, I'm just trying to document the existing
+    /// functions ... --strk
+    ///
+    /// @param x
+    ///     X ordinate of the pointer, in parent's coordinate space.
+    ///
+    /// @param y
+    ///     Y ordinate of the pointer, in parent's coordiante space.
+    ///
+    virtual character* get_topmost_mouse_entity(boost::int32_t /*x*/,
+            boost::int32_t /*y*/)
+    {
+        return NULL;
+    }
+
+    /// Find highest depth character whose shape contains the given
+    /// point and is not the character being dragged or any of its childs.
+    //
+    /// Point coordinates in global twips.
+    ///
+    virtual const character* findDropTarget(boost::int32_t x, 
+            boost::int32_t y, character* dragging) const
+    {
+        if (this != dragging && isVisible() && pointInVisibleShape(x, y)) {
+            return this;
+        }
+        
+        return 0;
+    }
+
+    /// Returns true when the object (type) should get a instance name even 
+    /// if none is provided manually.
+    virtual bool wantsInstanceName() const
+    {
+        return false; 
+    }
+
+    /// Returns true when the object (type) can be referenced by ActionScipt
+    bool isActionScriptReferenceable() const
+    {
+        // The way around
+        // [ wantsInstanceName() returning isActionScriptReferenceable() ]
+        // would be cleaner, but I wouldn't want to touch all files now.
+        return wantsInstanceName();
+    }
+
+    /// Returns the closest as-referenceable ancestor
+    character* getClosestASReferenceableAncestor() 
+    {
+        if ( isActionScriptReferenceable() ) return this;
+        assert(m_parent);
+        return m_parent->getClosestASReferenceableAncestor();
+    }
+
+    const character* getClosestASReferenceableAncestor() const
+    {
+        character* nonconst_this = const_cast<character*>(this);
+        return nonconst_this->getClosestASReferenceableAncestor();
+    }
+
+    /// @}
+
+    /// \brief
+    /// This function marks the character as being modified in aspect
+    /// and keeps track of current invalidated bounds the first time
+    /// it's called after each call to clear_invalidated().
+    //
+    /// Call this function *before* any change in this character
+    /// that modifies its rendering. This information will be used
+    /// to detect visual changes that need to be redrawn.
+    ///
+    /// It is *important* to call this function *before* the change
+    /// rather then after as it will also take care of updating the
+    /// previously invalidated bounds (m_old_invalidated_bounds)
+    ///
+    /// Calling this function multiple time is a no-op, unless
+    /// clear_invalidated() is called in between.
+    ///
+    /// NOTE: Marking a character as invalidated automatically marks
+    ///             it's parent as being invalidated.
+    ///
+    /// @see \ref region_update
+    ///
+    void set_invalidated();
+    void set_invalidated(const char* debug_file, int debug_line);
+    
+    
+    /// Calls set_invalidated() and extends old_invalidated_ranges to the
+    /// given value so that also this area gets re-rendered (used when
+    /// replacing characters).    
+    void extend_invalidated_bounds(const InvalidatedRanges& ranges);
+    
+    
+    /// Called by a child to signalize it has changed visibily. The
+    /// difference to set_invalidated() is that *this* character does
+    /// not need to redraw itself completely. This function will 
+    /// recursively inform all it's parents of the change.
+    void set_child_invalidated();
+    
+
+    /// Clear invalidated flag and reset m_old_invalidated_bounds to null.
+    ///
+    /// It is very important that each character with any m_XXXX_invalidated
+    /// flag set calls clear_invalidated() during the rendering of one frame. 
+    /// Basically this means each call to display() must match a call to 
+    /// clear_invalidated. This includes no-op display() calls, i.e. when the
+    /// character is outside of the screen. The DisplayList must still call
+    /// clear_invalidated() even if display() is not necessary.
+    ///
+    /// Not doing so will result in a stale invalidated flag which in turn will
+    /// prevent the parent to be informed when this character (or a child) is
+    /// invalidated again (see set_invalidated() recursion).
+    ///    
+    void clear_invalidated() {
+        m_invalidated = false;
+        m_child_invalidated = false;        
+        m_old_invalidated_ranges.setNull();
+    }
+    
+    /// \brief
+    /// Add the character's invalidated bounds *to* the given ranges list.
+    //
+    /// NOTE that this method should include the bounds that it
+    /// covered the last time clear_invalidated() was called,
+    /// as those need to be rerendered as well (to clear the region
+    /// previously occupied by this character).
+    ///
+    /// That's why it returns the *union* of old_invalidated_ranges and
+    /// the current bounds. The function is also used internally by 
+    /// set_invalidated() to update m_old_invalidated_ranges itself (you may 
+    /// notice some kind of circular reference), but that's no problem since 
+    /// old_invalidated_ranges is NULL during that call. 
+    ///
+    /// It is used to determine what area needs to be re-rendered.
+    /// The coordinates are world coordinates (in TWIPS).
+    /// Only instances with m_invalidated flag set are checked unless
+    /// force is set.
+    ///
+    virtual void add_invalidated_bounds(InvalidatedRanges& ranges, 
+            bool force) = 0;
+
+    /// Called instead of display() when the character is not visible on stage.
+    /// Used to clear the invalidated flags.
+    virtual void omit_display() { clear_invalidated(); }; 
+    
+    /// Callback invoked whenever a character is placed on stage
+    //
+    /// This function must be called when the character is placed on
+    /// stage for the first time.
+    ///
+    /// The character version of this call sets the original target
+    /// of the character, for soft references to work.
+    /// If you override the method remember to call saveOriginalTarget()
+    /// as the first thing.
+    ///
+    virtual void stagePlacementCallback(as_object* = 0)
+    {
+        saveOriginalTarget();
+    }
+
+    /// Unload this instance from the stage.
+    //
+    /// This function must be called when the character is removed
+    /// from the stage.
+    /// It will take care of properly calling
+    /// unload against any child characters and queuing the
+    /// 'UNLOAD' event handler.
+    ///
+    /// @return true if any onUnload event handler was defined
+    ///                 by either this or any child characters, false
+    ///                 otherwise.
+    ///
+    virtual bool unload();
+
+    /// Return true if this character was unloaded from the stage
+    bool isUnloaded() { return _unloaded; }
+
+    /// Mark this character as destroyed
+    //
+    /// A character should be destroyed when is removed from the display
+    /// list and is not more needed for names (target) resolutions.
+    /// Sprites are needed for names resolution whenever themselves
+    /// or a contained object has an onUnload event handler defined, 
+    /// in which case we want the event handler to find the 'this'
+    /// variable w/out attempting to rebind it.
+    ///
+    /// Note: this function can safely release most memory associated
+    ///             with the character as it will not be needed anymore.
+    ///
+    virtual void destroy();
+
+    /// Return true if this character was destroyed.
+    //
+    /// See destroy() for more info.
+    ///
+    bool isDestroyed() const { return _destroyed; }
+    
+    /// Returns true when the character bounds intersect with the current    
+    /// rendering clipping area.
+    ///
+    /// There is no need to do any rendering for this character when this 
+    /// function returns false because the renderer will not change any pixels
+    /// in the area where this character is placed.    
+    bool boundsInClippingArea() const; 
+
+    /// Return full path to this object, in slash notation
+    //
+    /// e.g. "/sprite1/sprite2/ourSprite"
+    ///
+    std::string getTargetPath() const;
+
+    /// Return original target path to this object, in dot notation
+    /// as of at construction time.
+    //
+    /// This is needed to properly dereference dangling soft-references
+    /// See testcase misc-swfc.all/soft_reference_test1.sc
+    ///
+    const std::string& getOrigTarget() const
+    {
+        return _origTarget;
+    }
+
+    /// Return full path to this object, in dot notation
+    //
+    /// e.g. "_level0.sprite1.sprite2.ourSprite"
+    ///
+    std::string DSOEXPORT getTarget() const;
 
 #ifdef NEW_KEY_LISTENER_LIST_DESIGN
-  boost::intrusive_ptr<as_function> getUserDefinedEventHandler(const 
std::string& name) const;
+    boost::intrusive_ptr<as_function> getUserDefinedEventHandler(
+            const std::string& name) const;
 #endif
 
   /// Return true if this character is a selectable TextField
@@ -1206,22 +961,303 @@
   virtual bool allowHandCursor() const { return true; }
 
 #ifdef USE_SWFTREE
-  /// Append character info in the tree
-  //
-  /// @param tr
-  /// The tree to append movie to
-  ///
-  /// @param it
-  /// The iterator to append info to.
-  ///
-  /// @return iterator the appended subtree
-  ///
-  // TODO: use a typedef for tree<StringPair> ?
-  virtual InfoTree::iterator getMovieInfo(InfoTree& tr, InfoTree::iterator it);
+    typedef std::pair<std::string, std::string> StringPair; 
+    typedef tree<StringPair> InfoTree; 
+    /// Append character info in the tree
+    //
+    /// @param tr
+    /// The tree to append movie to
+    ///
+    /// @param it
+    /// The iterator to append info to.
+    ///
+    /// @return iterator the appended subtree
+    ///
+    // TODO: use a typedef for tree<StringPair> ?
+    virtual InfoTree::iterator getMovieInfo(InfoTree& tr,
+            InfoTree::iterator it);
 #endif
 
+    enum BlendMode
+    {
+        BLENDMODE_UNDEFINED = 0,
+        BLENDMODE_NORMAL = 1,
+        BLENDMODE_LAYER,
+        BLENDMODE_MULTIPLY,
+        BLENDMODE_SCREEN,
+        BLENDMODE_LIGHTEN,
+        BLENDMODE_DARKEN,
+        BLENDMODE_DIFFERENCE,
+        BLENDMODE_ADD,
+        BLENDMODE_SUBTRACT,
+        BLENDMODE_INVERT,
+        BLENDMODE_ALPHA,
+        BLENDMODE_ERASE,
+        BLENDMODE_OVERLAY,
+        BLENDMODE_HARDLIGHT = 14
+    };
+
+    BlendMode getBlendMode() const {
+        return _blendMode;
+    }
+ 
+    void setBlendMode(BlendMode bm) {
+        _blendMode = bm;
+    }
+
+    // action_buffer is externally owned
+    typedef std::vector<const action_buffer*> BufferList;
+    typedef std::map<event_id, BufferList> Events;
+
+  /// Set the current focus to this character.
+  //
+  /// @return false if the character cannot receive focus, true if it can
+  ///         (and does).
+  //
+  /// Button, Textfield and MovieClip can receive focus. In SWF6 and above,
+  /// MovieClip can only receive focus if the focusEnabled property
+  /// evaluates to true.
+  virtual bool handleFocus() { 
+      return false;
+  }
+
+  /// Some characters require actions on losing focus.
+  //
+  /// Default is a no-op. TextField implements this function.
+  virtual void killFocus() {}
+
+  // TODO: make protected:
+
+  static as_value blendMode(const fn_call& fn);
+
+  /// Getter-setter for _x
+  static as_value x_getset(const fn_call& fn);
+
+  /// Getter-setter for _y
+  static as_value y_getset(const fn_call& fn);
+
+  /// Getter-setter for _xscale
+  static as_value xscale_getset(const fn_call& fn);
+
+  /// Getter-setter for _yscale
+  static as_value yscale_getset(const fn_call& fn);
+
+  /// Getter-setter for _xmouse
+  static as_value xmouse_get(const fn_call& fn);
+
+  /// Getter-setter for _ymouse
+  static as_value ymouse_get(const fn_call& fn);
+
+  /// Getter-setter for _alpha
+  static as_value alpha_getset(const fn_call& fn);
+
+  /// Getter-setter for _visible
+  static as_value visible_getset(const fn_call& fn);
+
+  /// Getter-setter for _width
+  static as_value width_getset(const fn_call& fn);
+
+  /// Getter-setter for _height
+  static as_value height_getset(const fn_call& fn);
+
+  /// Getter-setter for _rotation
+  static as_value rotation_getset(const fn_call& fn);
+
+  /// Getter-setter for _parent 
+  static as_value parent_getset(const fn_call& fn);
+
+  /// Getter-setter for _target 
+  static as_value target_getset(const fn_call& fn);
+
+  /// Getter-setter for _name
+  static as_value name_getset(const fn_call& fn);
+
+  /// @} Common ActionScript getter-setters for characters
+
+protected:
+
+    /// Register currently computable target as
+    /// the "original" one. This will be used by
+    /// soft references (as_value) and should be
+    /// called as soon as the stagePlacementCallback
+    /// is invoked.
+    ///
+    void saveOriginalTarget()
+    {
+        _origTarget=getTarget();
+    }
+
+#ifdef GNASH_USE_GC
+    /// Mark all reachable resources, override from as_object.
+    //
+    /// The default implementation calls markCharacterReachable().
+    ///
+    /// If a derived class provides access to more GC-managed
+    /// resources, it should override this method and call 
+    /// markCharacterReachableResources() as the last step.
+    ///
+    virtual void markReachableResources() const
+    {
+        markCharacterReachable();
+    }
+
+    /// Mark character-specific reachable resources
+    //
+    /// These are: the character's parent, mask, maskee and the default
+    ///                         as_object reachable stuff.
+    ///
+    void markCharacterReachable() const;
+#endif // GNASH_USE_GC
+
+    const Events& get_event_handlers() const
+    {
+            return _event_handlers;
+    }
+
+    /// Return a user defined event handler, if any
+    //
+    /// @param name
+    ///     Function name to fetch. It will be converted to 
+    /// lowercase if current VM has been initialized against
+    /// an SWF version inferior to 7.
+    ///
+    /// @return
+    /// A function if a member with the given name exists and
+    /// casts to an as_function. A NULL pointer otherwise.
+    ///
+    boost::intrusive_ptr<as_function> getUserDefinedEventHandler(const 
std::string& name) const;
+
+    /// Return a user defined event handler, if any
+    //
+    /// @param key
+    ///     Function key to fetch. 
+    ///
+    /// @return
+    /// A function if a member with the given key exists and
+    /// casts to an as_function. A NULL pointer otherwise.
+    ///
+    boost::intrusive_ptr<as_function> 
getUserDefinedEventHandler(string_table::key key) const;
+
+    void set_event_handlers(const Events& copyfrom);
+
+    /// Used to assign a name to unnamed instances
+    static std::string getNextUnnamedInstanceName();
+
+    /// Name of this character (if any)
+    std::string _name;
+
+    boost::intrusive_ptr<character> m_parent;
+
+    /// look for '.', 'this',    '..', '_parent', '_level0' and '_root'
+    //
+    /// NOTE: case insensitive up to SWF6, sensitive from SWF7 up
+    ///
+    as_object* get_path_element_character(string_table::key key);
+
+    /// \brief
+    /// Set when the visual aspect of this particular character or movie
+    /// has been changed and redrawing is necessary.    
+    //
+    /// This is initialized to true as the initial state for
+    /// any character is the "invisible" state (it wasn't there)
+    /// so it starts in invalidated mode.
+    ///
+    bool m_invalidated;
+
+    /// Just like m_invalidated but set when a child is invalidated instead
+    /// of this character instance. m_invalidated and m_child_invalidated
+    /// can be set at the same time. 
+    bool m_child_invalidated;
+
+    /// \brief
+    /// Bounds of this character instance before first invalidation
+    /// since last call to clear_invalidated().
+    ///
+    /// This stores the bounds of the character before it has been changed, 
ie. 
+    /// the position when set_invalidated() is being called. While drawing, 
both 
+    /// the old and the new bounds are updated (rendered). When moving a 
+    /// character A to B then both the position A needs to be re-rendered (to 
+    /// reveal the backgrond) and the position B needs to be re-rendered (to
+    /// show the character in its new position). The bounds may be identical 
or 
+    /// overlap, but SnappingRanges takes care of that.
+    /// 
+    /// Will be set by set_invalidated() and used by
+    /// get_invalidated_bounds().
+    ///
+    InvalidatedRanges m_old_invalidated_ranges;
+
+private:
+
+    /// Register a character masked by this instance
+    void setMaskee(character* maskee);
+
+    /// Build the _target member recursive on parent
+    std::string computeTargetPath() const;
+
+    int m_id;
+
+    int m_depth;
+    cxform  m_color_transform;
+    SWFMatrix  m_matrix;
+
+    /// Cache values for ActionScript access.
+    /// NOTE: not all characters need this, just the
+    ///       ones which are ActionScript-referenceable
+    double _xscale, _yscale, _rotation;
+
+    /// Volume control associated to this character
+    //
+    /// This is used by Sound objects
+    ///
+    /// NOTE: probably only ActionScript-referenceable characters
+    ///       need this (assuming soft ref don't rebind to other
+    ///       kind of characters).
+    ///
+    int  _volume;
+
+    int   m_ratio;
+    int m_clip_depth;
+    Events  _event_handlers;
+
+    /// Used to assign a name to unnamed instances
+    static unsigned int _lastUnnamedInstanceNum;
+
+    /// Set to yes when this instance has been unloaded
+    bool _unloaded;
+
+    /// This flag should be set to true by a call to destroy()
+    bool _destroyed;
+
+    /// The character masking this instance (if any)
+    character* _mask;
+
+    /// The character masked by this instance (if any)
+    character* _maskee;
+
+    /// Original target, as at construction time
+    std::string _origTarget;
+
+    BlendMode _blendMode;
+
+    bool _visible;
+
+    /// Whether this character has been transformed by ActionScript code
+    //
+    /// Once we've been moved by ActionScript,
+    /// Don't accept moves from anim tags (PlaceObject)
+    ///
+    /// See get_accept_anim_moves() function
+    ///
+    bool _scriptTransformed;
+
+    bool _dynamicallyCreated;
+
 };
 
+/// Stream operator for character blend mode.
+std::ostream&
+operator<<(std::ostream& o, character::BlendMode bm);
+
 
 } // end namespace gnash
 

=== modified file 'libcore/generic_character.cpp'
--- a/libcore/generic_character.cpp     2008-10-19 18:04:05 +0000
+++ b/libcore/generic_character.cpp     2008-12-05 09:37:07 +0000
@@ -27,7 +27,7 @@
   bool force)
 {
   ranges.add(m_old_invalidated_ranges);
-  if (m_visible && (m_invalidated||force))
+  if (isVisible() && (m_invalidated||force))
   {
     rect bounds;    
     bounds.expand_to_transformed_rect(getWorldMatrix(), 

=== modified file 'libcore/movie_root.cpp'
--- a/libcore/movie_root.cpp    2008-12-03 08:22:34 +0000
+++ b/libcore/movie_root.cpp    2008-12-05 09:37:07 +0000
@@ -1130,7 +1130,7 @@
 
                movie->clear_invalidated();
 
-               if (movie->get_visible() == false) continue;
+               if (movie->isVisible() == false) continue;
 
                // null frame size ? don't display !
                const rect& sub_frame_size = movie->get_frame_size();
@@ -1151,7 +1151,7 @@
 
                ch->clear_invalidated();
 
-               if (ch->get_visible() == false) continue;
+               if (ch->isVisible() == false) continue;
 
                ch->display();
 

=== modified file 'libcore/swf/PlaceObject2Tag.cpp'
--- a/libcore/swf/PlaceObject2Tag.cpp   2008-11-14 00:46:35 +0000
+++ b/libcore/swf/PlaceObject2Tag.cpp   2008-12-05 08:57:08 +0000
@@ -86,6 +86,8 @@
         }
     );
     
+    boost::uint32_t all_event_flags;
+
     // The logical 'or' of all the following handlers.
     if (movie_version >= 6)
     {
@@ -327,7 +329,6 @@
     // PlaceObject3 speckfic flags, first 3 bits are unused
     m_has_flags3 = in.read_u8();
     
-    boost::uint8_t blend_mode = 0;
     boost::uint8_t bitmask = 0;
     std::string className;
 
@@ -337,50 +338,41 @@
     // tags with either className or hasImage defined are rare to
     // non-existent. Alexis' SWF reference has neither of them,
     // instead specifying 5 reserved bits in the PlaceObject3 flags.
-    if (hasClassName() || (hasImage() && hasCharacter()))
-    {
+    if (hasClassName() || (hasImage() && hasCharacter())) {
         log_unimpl("PLACEOBJECT3 with associated class name");
         in.read_string(className);
     }
 
-    if (hasCharacter())
-    {
+    if (hasCharacter()) {
         in.ensureBytes(2);
         m_character_id = in.read_u16();
     }
 
-    if (hasMatrix())
-    {
+    if (hasMatrix()) {
         m_matrix.read(in);
     }
 
-    if (hasCxform())
-    {
+    if (hasCxform()) {
         m_color_transform.read_rgba(in);
     }
 
-    if (hasRatio()) 
-    {
+    if (hasRatio()) {
         in.ensureBytes(2);
         m_ratio = in.read_u16();
     }
     
-    if (hasName())
-    {
+    if (hasName()) {
         in.read_string(m_name);
     }
 
-    if (hasClipDepth())
-    {
+    if (hasClipDepth()) {
         in.ensureBytes(2);
         m_clip_depth = in.read_u16()+character::staticDepthOffset;
     }
-    else
-    {
+    else {
         m_clip_depth = character::noClipDepthValue;
     }
 
-
     if ( hasFilters() )
     {
         Filters v; // TODO: Attach the filters to the display object.
@@ -392,29 +384,10 @@
     if ( hasBlendMode() )
     {
         in.ensureBytes(1);
-        blend_mode = in.read_u8();
-           // 0 or 1 : normal
-           // 2 : layer
-           // 3 : multiply
-        // 4 : screen
-        // 5 : lighten
-        // 6 : darken
-        // 7 : add
-        // 8 : subtract
-        // 9 : difference
-        // 10 : invert
-        // 11 : alpha
-        // 12 : erase
-        // 13 : overlay
-        // 14 : hardlight
-        // 15 to 255 reserved  
-        //
-        // at time of writing no renderer supports blend modes
-        LOG_ONCE( log_unimpl("Blend mode") );
+        _blendMode = in.read_u8();
     }
 
-    if ( hasBitmapCaching() )
-    {
+    if ( hasBitmapCaching() ) {
         // cacheAsBitmap is a boolean value, so the flag itself ought to be
         // enough. Alexis' SWF reference is unsure about this, but suggests
         // reading a byte here. The official SWF format spec doesn't mention
@@ -430,8 +403,7 @@
            LOG_ONCE( log_unimpl("Bitmap caching") );
     }
 
-    if ( hasClipActions() )
-    {
+    if ( hasClipActions() ) {
         readPlaceActions(in);
     }
 

=== modified file 'libcore/swf/PlaceObject2Tag.h'
--- a/libcore/swf/PlaceObject2Tag.h     2008-10-28 21:17:19 +0000
+++ b/libcore/swf/PlaceObject2Tag.h     2008-12-05 08:57:08 +0000
@@ -27,13 +27,12 @@
 #include "swf.h" // for tag_type definition
 #include "SWFMatrix.h" // for composition
 #include "cxform.h" // for composition 
-
+#include "character.h" // BlendMode enum
 #include <vector>
 
 // Forward declarations
 namespace gnash {
     class SWFStream;
-    class MovieClip;
     class swf_event;
     class action_buffer;
     class movie_definition;
@@ -101,8 +100,8 @@
         m_has_flags3(0),
         m_character_id(0),
         m_ratio(0),
-        m_name(""),
         m_clip_depth(0),
+        _blendMode(0),
         _movie_def(def)
     {
     }
@@ -118,7 +117,9 @@
     static void loader(SWFStream& in, tag_type tag, movie_definition& m,
             const RunInfo& r);
 
-    int getPlaceType() const { return m_has_flags2 & (HAS_CHARACTER_MASK | 
MOVE_MASK); } 
+    int getPlaceType() const { 
+        return m_has_flags2 & (HAS_CHARACTER_MASK | MOVE_MASK);
+    } 
     int getRatio()     const { return m_ratio; }
     int getClipDepth() const { return m_clip_depth; }
     int getID()        const { return m_character_id; }
@@ -136,10 +137,30 @@
     bool hasCharacter()   const { return m_has_flags2 & HAS_CHARACTER_MASK; }
 
     bool hasImage()         const { return m_has_flags3 & HAS_IMAGE_MASK; }
-    bool hasClassName()     const { return m_has_flags3 & HAS_CLASS_NAME_MASK; 
}
-    bool hasBitmapCaching() const { return m_has_flags3 & 
HAS_BITMAP_CACHING_MASK; }
-    bool hasBlendMode()     const { return m_has_flags3 & HAS_BLEND_MODE_MASK; 
}
-    bool hasFilters()       const { return m_has_flags3 & HAS_FILTERS_MASK; }  
    
+
+    bool hasClassName() const {
+        return m_has_flags3 & HAS_CLASS_NAME_MASK;
+    }
+
+    bool hasBitmapCaching() const { 
+        return m_has_flags3 & HAS_BITMAP_CACHING_MASK;
+    }
+
+    bool hasBlendMode() const {
+        return m_has_flags3 & HAS_BLEND_MODE_MASK;
+    }
+
+    bool hasFilters() const {
+        return m_has_flags3 & HAS_FILTERS_MASK;
+    }
+
+    /// Get an associated blend mode.
+    //
+    /// This is stored as a uint8_t to allow for future expansion of
+    /// blend modes.
+    boost::uint8_t getBlendMode() const {
+        return _blendMode;
+    }
 
 private:
     int m_tag_type;
@@ -151,8 +172,9 @@
     int     m_ratio;
     std::string m_name;
     int     m_clip_depth;
-    boost::uint32_t all_event_flags; 
     
+    boost::uint8_t _blendMode;
+
     /// NOTE: getPlaceType() is dependent on the enum values.
     enum PlaceType
     {

=== modified file 'testsuite/actionscript.all/MovieClip.as'
--- a/testsuite/actionscript.all/MovieClip.as   2008-12-04 14:58:12 +0000
+++ b/testsuite/actionscript.all/MovieClip.as   2008-12-05 09:58:55 +0000
@@ -123,7 +123,7 @@
 #endif
 
 #if OUTPUT_VERSION >= 8
-       check_totals(935); // SWF8+
+       check_totals(936); // SWF8+
 #endif
 
        play();
@@ -2199,6 +2199,8 @@
 check_equals(_root.blendMode, "lighten");
 _root.blendMode = "NORMAL";
 check_equals(_root.blendMode, "lighten");
+_root.blendMode = undefined;
+check_equals(_root.blendMode, "normal");
 
 // Set back to normal so we can see the results...
 _root.blendMode = "normal";

=== modified file 'testsuite/misc-ming.all/RollOverOutTest-Runner.cpp'
--- a/testsuite/misc-ming.all/RollOverOutTest-Runner.cpp        2008-10-25 
10:38:32 +0000
+++ b/testsuite/misc-ming.all/RollOverOutTest-Runner.cpp        2008-12-05 
09:37:07 +0000
@@ -56,8 +56,8 @@
        const character* mc2 = tester.findDisplayItemByName(*root, "square2");
        check(mc2);
 
-       check_equals(mc1->get_visible(), true);
-       check_equals(mc2->get_visible(), false);
+       check_equals(mc1->isVisible(), true);
+       check_equals(mc2->isVisible(), false);
        check_equals(root->get_play_state(), MovieClip::STOP);
        check_equals(root->get_current_frame(), 1);
 


reply via email to

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