[Top][All Lists]
[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);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r10393: More blend mode implementations. It should now be ready for a renderer,
Benjamin Wolsey <=