1 // as_object.cpp: ActionScript Object class and its properties, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "as_object.h"
24 #include <boost/algorithm/string/case_conv.hpp>
25 #include <utility> // for std::pair
27 #include "RunResources.h"
29 #include "as_function.h"
30 #include "as_environment.h"
31 #include "movie_root.h"
35 #include "GnashException.h"
38 #include "as_function.h"
39 #include "Global_as.h"
40 #include "GnashAlgorithm.h"
41 #include "DisplayObject.h"
42 #include "namedStrings.h"
47 as_object::PrototypeRecursor
50 PrototypeRecursor(as_object
* top
, const ObjectURI
& uri
, T cmp
= T())
60 /// Iterate to the next object in the inheritance chain.
62 /// This function throws an ActionLimitException when the maximum
63 /// number of recursions is reached.
65 /// @return false if there is no next object. In this case calling
66 /// the other functions will abort.
71 // See swfdec/prototype-recursion-get-?.swf
72 if (_iterations
> 256) {
73 throw ActionLimitException("Lookup depth exceeded.");
76 _object
= _object
->get_prototype();
78 // TODO: there is recursion prevention anyway; is this extra
79 // check for circularity really necessary?
80 if (!_visited
.insert(_object
).second
) return 0;
81 return _object
&& !_object
->displayObject();
84 /// Return the wanted property if it exists and satisfies the predicate.
86 /// This will abort if there is no current object.
87 Property
* getProperty(as_object
** owner
= 0) const {
90 Property
* prop
= _object
->_members
.getProperty(_uri
);
92 if (prop
&& _condition(*prop
)) {
93 if (owner
) *owner
= _object
;
101 const ObjectURI
& _uri
;
102 std::set
<const as_object
*> _visited
;
107 // Anonymous namespace used for module-static defs
111 getConstructor(as_object
& o
)
114 if (!o
.get_member(NSV::PROP_uuCONSTRUCTORuu
, &ctorVal
)) {
117 return ctorVal
.to_function();
120 /// 'super' is a special kind of object
122 /// See http://wiki.gnashdev.org/wiki/index.php/ActionScriptSuper
124 /// We make it derive from as_function instead of as_object
125 /// to avoid touching too many files (ie: an as_object is not considered
126 /// something that can be called by current Gnash code). We may want
127 /// to change this in the future to implement what ECMA-262 refers to
128 /// as the [[Call]] property of objects.
130 class as_super
: public as_object
134 as_super(Global_as
& gl
, as_object
* super
)
139 set_prototype(prototype());
142 virtual bool isSuper() const { return true; }
144 virtual as_object
* get_super(const ObjectURI
& fname
);
146 // Fetching members from 'super' yelds a lookup on the associated prototype
147 virtual bool get_member(const ObjectURI
& uri
, as_value
* val
)
149 as_object
* proto
= prototype();
150 if (proto
) return proto
->get_member(uri
, val
);
151 log_debug("Super has no associated prototype");
156 virtual as_value
call(const fn_call
& fn
)
159 // TODO: this is a hack to make sure objects are constructed, not
160 // converted (fn.isInstantiation() must be true).
161 fn_call::Args::container_type
argsIn(fn
.getArgs());
165 fn_call
fn2(fn
.this_ptr
, fn
.env(), args
, fn
.super
, true);
166 assert(fn2
.isInstantiation());
167 as_function
* ctor
= constructor();
168 if (ctor
) return ctor
->call(fn2
);
169 log_debug("Super has no associated constructor");
175 virtual void markReachableResources() const
177 if (_super
) _super
->setReachable();
178 as_object::markReachableResources();
183 as_object
* prototype() {
184 return _super
? _super
->get_prototype() : 0;
187 as_function
* constructor() {
188 return _super
? getConstructor(*_super
) : 0;
195 as_super::get_super(const ObjectURI
& fname
)
197 // Super references the super class of our class prototype.
198 // Our class prototype is __proto__.
199 // Our class superclass prototype is __proto__.__proto__
201 // Our class prototype is __proto__.
202 as_object
* proto
= get_prototype();
203 if (!proto
) return new as_super(getGlobal(*this), 0);
205 if (fname
.empty() || getSWFVersion(*this) <= 6) {
206 return new as_super(getGlobal(*this), proto
);
209 as_object
* owner
= 0;
210 proto
->findProperty(fname
, &owner
);
211 if (!owner
) return 0;
213 if (owner
== proto
) return new as_super(getGlobal(*this), proto
);
215 as_object
* tmp
= proto
;
216 while (tmp
&& tmp
->get_prototype() != owner
) {
217 tmp
= tmp
->get_prototype();
219 // ok, now 'tmp' should be the object whose __proto__ member
220 // contains the actual named method.
222 // in the C:B:A:F case this would be B when calling
223 // super.myName() from C.prototype.myName()
225 // well, since we found the property, it must be somewhere!
228 if (tmp
!= proto
) { return new as_super(getGlobal(*this), tmp
); }
229 return new as_super(getGlobal(*this), owner
);
233 /// A PropertyList visitor copying properties to an object
234 class PropsCopier
: public PropertyVisitor
240 /// Initialize a PropsCopier instance associating it
241 /// with a target object (an object whose members has to be set)
243 PropsCopier(as_object
& tgt
)
249 /// Set *inherited* properties of the given target object
250 bool accept(const ObjectURI
& uri
, const as_value
& val
) {
251 if (getName(uri
) == NSV::PROP_uuPROTOuu
) return true;
252 _tgt
.set_member(uri
, val
);
259 class PropertyEnumerator
: public PropertyVisitor
262 PropertyEnumerator(SortedPropertyList
& to
)
267 bool accept(const ObjectURI
& uri
, const as_value
& val
) {
268 _to
.push_back(std::make_pair(uri
, val
));
272 SortedPropertyList
& _to
;
275 } // anonymous namespace
278 const int as_object::DefaultFlags
;
280 as_object::as_object(const Global_as
& gl
)
282 GcResource(getRoot(gl
).gc()),
291 as_object::as_object(VM
& vm
)
293 GcResource(vm
.getRoot().gc()),
303 as_object::call(const fn_call
& /*fn*/)
305 throw ActionTypeError();
309 as_object::stringValue() const
311 return "[object Object]";
315 as_object::delProperty(const ObjectURI
& uri
)
317 return _members
.delProperty(uri
);
322 as_object::add_property(const std::string
& name
, as_function
& getter
,
325 const ObjectURI
& uri
= getURI(vm(), name
);
327 Property
* prop
= _members
.getProperty(uri
);
330 const as_value
& cacheVal
= prop
->getCache();
331 // Used to return the return value of addGetterSetter, but this
333 _members
.addGetterSetter(uri
, getter
, setter
, cacheVal
);
335 // NOTE: watch triggers not called when adding a new
336 // getter-setter property
340 _members
.addGetterSetter(uri
, getter
, setter
, as_value());
342 // Nothing more to do if there are no triggers.
343 if (!_trigs
.get()) return;
345 // check if we have a trigger, if so, invoke it
346 // and set val to its return
347 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
349 if (trigIter
!= _trigs
->end()) {
351 Trigger
& trig
= trigIter
->second
;
353 log_debug("add_property: property %s is being watched", name
);
354 as_value v
= trig
.call(as_value(), as_value(), *this);
356 // The trigger call could have deleted the property,
357 // so we check for its existence again, and do NOT put
358 // it back in if it was deleted
359 prop
= _members
.getProperty(uri
);
361 log_debug("Property %s deleted by trigger on create (getter-setter)", name
);
371 /// Order of property lookup:
373 /// 1. Visible own properties.
374 /// 2. If DisplayObject, magic properties
375 /// 3. Visible own properties of all __proto__ objects (a DisplayObject
377 /// 4. __resolve property of this object and all __proto__ objects (a Display
378 /// Object ends the chain). This should ignore visibility but doesn't.
380 as_object::get_member(const ObjectURI
& uri
, as_value
* val
)
384 const int version
= getSWFVersion(*this);
386 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
388 Property
* prop
= pr
.getProperty();
390 if (displayObject()) {
391 DisplayObject
* d
= displayObject();
392 if (getDisplayObjectProperty(*d
, uri
, *val
)) return true;
395 if ((prop
= pr
.getProperty())) break;
399 // If the property isn't found or doesn't apply to any objects in the
400 // inheritance chain, try the __resolve property.
403 PrototypeRecursor
<Exists
> pr(this, NSV::PROP_uuRESOLVE
);
408 Property
* res
= pr
.getProperty();
410 resolve
= res
->isGetterSetter() ? res
->getCache() :
411 res
->getValue(*this);
412 if (version
< 7) break;
413 if (resolve
.is_object()) break;
415 // Finished searching.
416 if (!pr()) return false;
419 // If __resolve exists, call it with the name of the undefined
421 string_table
& st
= getStringTable(*this);
422 const std::string
& undefinedName
= st
.value(getName(uri
));
425 args
+= undefinedName
;
427 // Invoke the __resolve property.
428 *val
= invoke(resolve
, as_environment(getVM(*this)), this, args
);
434 *val
= prop
->getValue(*this);
437 catch (const ActionTypeError
& exc
) {
438 IF_VERBOSE_ASCODING_ERRORS(
439 log_aserror(_("Caught exception: %s"), exc
.what());
447 as_object::get_super(const ObjectURI
& fname
)
449 // Super references the super class of our class prototype.
450 // Our class prototype is __proto__.
451 // Our class superclass prototype is __proto__.__proto__
453 // Our class prototype is __proto__.
454 as_object
* proto
= get_prototype();
456 if ( ! fname
.empty() && getSWFVersion(*this) > 6) {
457 as_object
* owner
= 0;
458 findProperty(fname
, &owner
);
459 // should be 0 if findProperty returned 0
460 if (owner
!= this) proto
= owner
;
463 as_object
* super
= new as_super(getGlobal(*this), proto
);
469 as_object::get_super()
471 // Our class prototype is __proto__.
472 as_object
* proto
= get_prototype();
473 as_object
* super
= new as_super(getGlobal(*this), proto
);
479 as_object::findProperty(const ObjectURI
& uri
, as_object
** owner
)
482 const int version
= getSWFVersion(*this);
484 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
487 Property
* prop
= pr
.getProperty(owner
);
488 if (prop
) return prop
;
496 as_object::findUpdatableProperty(const ObjectURI
& uri
)
499 PrototypeRecursor
<Exists
> pr(this, uri
);
501 Property
* prop
= pr
.getProperty();
503 // We won't scan the inheritance chain if we find a member,
504 // even if invisible.
505 if (prop
) return prop
;
507 const int swfVersion
= getSWFVersion(*this);
510 if ((prop
= pr
.getProperty())) {
511 if (prop
->isGetterSetter() && visible(*prop
, swfVersion
)) {
520 as_object::set_prototype(const as_value
& proto
)
522 // TODO: check what happens if __proto__ is set as a user-defined
524 // TODO: check triggers !!
525 _members
.setValue(NSV::PROP_uuPROTOuu
, proto
, as_object::DefaultFlags
);
529 as_object::executeTriggers(Property
* prop
, const ObjectURI
& uri
,
533 // check if we have a trigger, if so, invoke it
534 // and set val to its return
535 TriggerContainer::iterator trigIter
;
537 // If there are no triggers or the trigger is not found, just set
539 if (!_trigs
.get() || (trigIter
= _trigs
->find(uri
)) == _trigs
->end()) {
541 prop
->setValue(*this, val
);
542 prop
->clearVisible(getSWFVersion(*this));
547 Trigger
& trig
= trigIter
->second
;
550 _trigs
->erase(trigIter
);
554 // WARNING: getValue might itself invoke a trigger
555 // (getter-setter)... ouch ?
556 // TODO: in this case, return the underlying value !
557 const as_value
& curVal
= prop
? prop
->getCache() : as_value();
558 const as_value
& newVal
= trig
.call(curVal
, val
, *this);
560 // This is a particularly clear and concise way of removing dead triggers.
561 EraseIf(*_trigs
, boost::bind(boost::mem_fn(&Trigger::dead
),
562 boost::bind(&TriggerContainer::value_type::second
, _1
)));
564 // The trigger call could have deleted the property,
565 // so we check for its existence again, and do NOT put
566 // it back in if it was deleted
567 prop
= findUpdatableProperty(uri
);
570 prop
->setValue(*this, newVal
);
571 prop
->clearVisible(getSWFVersion(*this));
575 /// Order of property lookup:
577 /// 0. MovieClip textfield variables. TODO: this is a hack and should be
579 /// 1. Own properties even if invisible or not getter-setters.
580 /// 2. If DisplayObject, magic properties
581 /// 3. Visible own getter-setter properties of all __proto__ objects
582 /// (a DisplayObject ends the chain).
584 as_object::set_member(const ObjectURI
& uri
, const as_value
& val
, bool ifFound
)
587 bool tfVarFound
= false;
588 if (displayObject()) {
589 MovieClip
* mc
= dynamic_cast<MovieClip
*>(displayObject());
590 if (mc
) tfVarFound
= mc
->setTextFieldVariables(uri
, val
);
591 // We still need to set the member.
594 // Handle the length property for arrays. NB: checkArrayLength() will
595 // call this function again if the key is a valid index.
596 if (array()) checkArrayLength(*this, uri
, val
);
598 PrototypeRecursor
<Exists
> pr(this, uri
);
600 Property
* prop
= pr
.getProperty();
602 // We won't scan the inheritance chain if we find a member,
603 // even if invisible.
606 if (displayObject()) {
607 DisplayObject
* d
= displayObject();
608 if (setDisplayObjectProperty(*d
, uri
, val
)) return true;
609 // TODO: should we execute triggers?
612 const int version
= getSWFVersion(*this);
614 if ((prop
= pr
.getProperty())) {
615 if ((prop
->isGetterSetter()) && visible(*prop
, version
)) {
624 if (readOnly(*prop
)) {
625 IF_VERBOSE_ASCODING_ERRORS(
626 ObjectURI::Logger
l(getStringTable(*this));
627 log_aserror(_("Attempt to set read-only property '%s'"),
634 executeTriggers(prop
, uri
, val
);
636 catch (const ActionTypeError
& exc
) {
637 IF_VERBOSE_ASCODING_ERRORS(
639 _("%s: %s"), getStringTable(*this).value(getName(uri
)), exc
.what());
646 // Else, add new property...
647 if (ifFound
) return false;
649 // Property does not exist, so it won't be read-only. Set it.
650 if (!_members
.setValue(uri
, val
)) {
652 IF_VERBOSE_ASCODING_ERRORS(
653 ObjectURI::Logger
l(getStringTable(*this));
654 log_aserror(_("Unknown failure in setting property '%s' on "
655 "object '%p'"), l(uri
), (void*) this);
660 executeTriggers(prop
, uri
, val
);
662 // Return true if we found a textfield variable.
663 if (tfVarFound
) return true;
670 as_object::init_member(const std::string
& key1
, const as_value
& val
, int flags
)
672 const ObjectURI
& uri(getURI(vm(), key1
));
673 init_member(uri
, val
, flags
);
677 as_object::init_member(const ObjectURI
& uri
, const as_value
& val
, int flags
)
680 // Set (or create) a SimpleProperty
681 if (!_members
.setValue(uri
, val
, flags
)) {
682 ObjectURI::Logger
l(getStringTable(*this));
683 log_error(_("Attempt to initialize read-only property '%s'"
684 " on object '%p' twice"), l(uri
), (void*)this);
685 // We shouldn't attempt to initialize a member twice, should we ?
691 as_object::init_property(const std::string
& name
, as_function
& getter
,
692 as_function
& setter
, int flags
)
694 const ObjectURI
& uri
= getURI(vm(), name
);
695 init_property(uri
, getter
, setter
, flags
);
699 as_object::init_property(const ObjectURI
& uri
, as_function
& getter
,
700 as_function
& setter
, int flags
)
702 _members
.addGetterSetter(uri
, getter
, &setter
, as_value(), flags
);
706 as_object::init_property(const std::string
& name
, as_c_function_ptr getter
,
707 as_c_function_ptr setter
, int flags
)
709 const ObjectURI
& uri
= getURI(vm(), name
);
710 init_property(uri
, getter
, setter
, flags
);
714 as_object::init_property(const ObjectURI
& uri
, as_c_function_ptr getter
,
715 as_c_function_ptr setter
, int flags
)
717 _members
.addGetterSetter(uri
, getter
, setter
, flags
);
721 as_object::init_destructive_property(const ObjectURI
& uri
, as_function
& getter
,
724 return _members
.addDestructiveGetter(uri
, getter
, flags
);
728 as_object::init_destructive_property(const ObjectURI
& uri
,
729 as_c_function_ptr getter
, int flags
)
731 return _members
.addDestructiveGetter(uri
, getter
, flags
);
735 as_object::init_readonly_property(const std::string
& name
, as_function
& getter
,
738 const ObjectURI
& uri
= getURI(vm(), name
);
740 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
741 assert(_members
.getProperty(uri
));
745 as_object::init_readonly_property(const std::string
& name
,
746 as_c_function_ptr getter
, int initflags
)
748 const ObjectURI
& uri
= getURI(vm(), name
);
749 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
750 assert(_members
.getProperty(uri
));
754 as_object::set_member_flags(const ObjectURI
& uri
, int setTrue
, int setFalse
)
756 _members
.setFlags(uri
, setTrue
, setFalse
);
760 as_object::addInterface(as_object
* obj
)
763 if (std::find(_interfaces
.begin(), _interfaces
.end(), obj
) ==
765 _interfaces
.push_back(obj
);
770 as_object::instanceOf(as_object
* ctor
)
773 /// An object is never an instance of a null prototype.
774 if (!ctor
) return false;
777 if (!ctor
->get_member(NSV::PROP_PROTOTYPE
, &protoVal
)) {
778 #ifdef GNASH_DEBUG_INSTANCE_OF
779 log_debug("Object %p can't be an instance of an object (%p) with no 'prototype'",
780 (void*)this, (void*)ctor
);
785 as_object
* ctorProto
= toObject(protoVal
, getVM(*this));
787 #ifdef GNASH_DEBUG_INSTANCE_OF
788 log_debug("Object %p can't be an instance of an object (%p) with non-object 'prototype' (%s)",
789 (void*)this, (void*)ctor
, protoVal
);
794 // TODO: cleanup the iteration, make it more readable ...
795 std::set
<as_object
*> visited
;
797 as_object
* obj
= this;
798 while (obj
&& visited
.insert(obj
).second
) {
799 as_object
* thisProto
= obj
->get_prototype();
805 if (thisProto
== ctorProto
) {
806 #ifdef GNASH_DEBUG_INSTANCE_OF
807 log_debug("Object %p is an instance of constructor %p as the constructor exposes our __proto__ %p",
808 (void*)obj
, (void*)ctor
, (void*)thisProto
);
813 // Check our proto interfaces
814 if (std::find(thisProto
->_interfaces
.begin(),
815 thisProto
->_interfaces
.end(), ctorProto
)
816 != thisProto
->_interfaces
.end()) {
818 #ifdef GNASH_DEBUG_INSTANCE_OF
819 log_debug("Object %p __proto__ %p had one interface matching with the constructor prototype %p",
820 (void*)obj
, (void*)thisProto
, (void*)ctorProto
);
832 as_object::prototypeOf(as_object
& instance
)
834 as_object
* obj
= &instance
;
836 std::set
<as_object
*> visited
;
838 while (obj
&& visited
.insert(obj
).second
) {
839 if (obj
->get_prototype() == this) return true;
840 obj
= obj
->get_prototype();
843 // See actionscript.all/Inheritance.as for a way to trigger this
844 IF_VERBOSE_ASCODING_ERRORS(
845 if (obj
) log_aserror(_("Circular inheritance chain detected "
846 "during isPrototypeOf call"));
853 as_object::dump_members()
855 log_debug("%d members of object %p follow", _members
.size(),
856 static_cast<const void*>(this));
861 as_object::setPropFlags(const as_value
& props_val
, int set_false
, int set_true
)
864 if (props_val
.is_null()) {
865 // Take all the members of the object
866 _members
.setFlagsAll(set_true
, set_false
);
870 std::string propstr
= props_val
.to_string();
875 size_t next_comma
=propstr
.find(",");
876 if (next_comma
== std::string::npos
) {
880 prop
= propstr
.substr(0,next_comma
);
881 propstr
= propstr
.substr(next_comma
+1);
884 // set_member_flags will take care of case conversion
885 set_member_flags(getURI(vm(), prop
), set_true
, set_false
);
887 if (next_comma
== std::string::npos
) {
896 as_object::copyProperties(const as_object
& o
)
898 PropsCopier
copier(*this);
900 // TODO: check if non-visible properties should be also copied !
901 o
.visitProperties
<Exists
>(copier
);
905 as_object::visitKeys(KeyVisitor
& visitor
) const
907 // Hack to handle MovieClips.
908 if (displayObject()) {
909 displayObject()->visitNonProperties(visitor
);
912 // this set will keep track of visited objects,
913 // to avoid infinite loops
914 std::set
<const as_object
*> visited
;
916 PropertyList::PropertyTracker doneList
;
918 const as_object
* current(this);
919 while (current
&& visited
.insert(current
).second
) {
920 current
->_members
.visitKeys(visitor
, doneList
);
921 current
= current
->get_prototype();
927 as_object::getOwnProperty(const ObjectURI
& uri
)
929 return _members
.getProperty(uri
);
933 as_object::get_prototype() const
935 int swfVersion
= getSWFVersion(*this);
937 Property
* prop
= _members
.getProperty(NSV::PROP_uuPROTOuu
);
939 if (!visible(*prop
, swfVersion
)) return 0;
941 const as_value
& proto
= prop
->getValue(*this);
943 return toObject(proto
, getVM(*this));
947 getURLEncodedVars(as_object
& o
)
949 SortedPropertyList props
= enumerateProperties(o
);
952 string_table
& st
= getStringTable(o
);
954 for (SortedPropertyList::const_reverse_iterator i
= props
.rbegin(),
955 e
= props
.rend(); i
!= e
; ++i
) {
957 const std::string
& name
= i
->first
.toString(st
);
958 const std::string
& value
= i
->second
.to_string();
961 if (!name
.empty() && name
[0] == '$') continue;
964 if (i
!= props
.rbegin()) data
+= '&';
966 data
+= name
+ "=" + value
;
973 as_object::watch(const ObjectURI
& uri
, as_function
& trig
,
974 const as_value
& cust
)
977 std::string propname
= getStringTable(*this).value(getName(uri
));
979 if (!_trigs
.get()) _trigs
.reset(new TriggerContainer
);
981 TriggerContainer::iterator it
= _trigs
->find(uri
);
982 if (it
== _trigs
->end()) {
983 return _trigs
->insert(
984 std::make_pair(uri
, Trigger(propname
, trig
, cust
))).second
;
986 it
->second
= Trigger(propname
, trig
, cust
);
991 as_object::unwatch(const ObjectURI
& uri
)
993 if (!_trigs
.get()) return false;
995 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
996 if (trigIter
== _trigs
->end()) {
997 log_debug("No watch for property %s",
998 getStringTable(*this).value(getName(uri
)));
1001 Property
* prop
= _members
.getProperty(uri
);
1002 if (prop
&& prop
->isGetterSetter()) {
1003 log_debug("Watch on %s not removed (is a getter-setter)",
1004 getStringTable(*this).value(getName(uri
)));
1007 trigIter
->second
.kill();
1012 as_object::markReachableResources() const
1014 _members
.setReachable();
1017 for (TriggerContainer::const_iterator it
= _trigs
->begin();
1018 it
!= _trigs
->end(); ++it
) {
1019 it
->second
.setReachable();
1023 // Mark interfaces reachable.
1024 std::for_each(_interfaces
.begin(), _interfaces
.end(),
1025 std::mem_fun(&as_object::setReachable
));
1027 // Proxy objects can contain references to other as_objects.
1028 if (_relay
) _relay
->setReachable();
1029 if (_displayObject
) _displayObject
->setReachable();
1033 Trigger::setReachable() const
1035 _func
->setReachable();
1036 _customArg
.setReachable();
1040 Trigger::call(const as_value
& oldval
, const as_value
& newval
,
1041 as_object
& this_obj
)
1045 if (_executing
) return newval
;
1051 const as_environment
env(getVM(this_obj
));
1054 args
+= _propname
, oldval
, newval
, _customArg
;
1056 fn_call
fn(&this_obj
, env
, args
);
1057 as_value ret
= _func
->call(fn
);
1063 catch (const GnashException
&) {
1070 enumerateProperties(as_object
& obj
)
1073 // this set will keep track of visited objects,
1074 // to avoid infinite loops
1075 std::set
<as_object
*> visited
;
1077 SortedPropertyList to
;
1078 PropertyEnumerator
e(to
);
1079 as_object
* current(&obj
);
1081 while (current
&& visited
.insert(current
).second
) {
1082 current
->visitProperties
<IsEnumerable
>(e
);
1083 current
= current
->get_prototype();
1090 getPathElement(as_object
& o
, const ObjectURI
& uri
)
1093 if (!o
.get_member(uri
, &tmp
)) return 0;
1094 if (!tmp
.is_object()) return 0;
1095 return toObject(tmp
, getVM(o
));
1100 sendEvent(as_object
& o
, const as_environment
& env
, const ObjectURI
& name
)
1102 Property
* prop
= o
.findProperty(name
);
1105 invoke(prop
->getValue(o
), env
, &o
, args
);
1110 getObjectWithPrototype(Global_as
& gl
, const ObjectURI
& c
)
1112 as_object
* ctor
= toObject(getMember(gl
, c
), getVM(gl
));
1113 as_object
* proto
= ctor
?
1114 toObject(getMember(*ctor
, NSV::PROP_PROTOTYPE
), getVM(gl
)) : 0;
1116 as_object
* o
= createObject(gl
);
1117 o
->set_prototype(proto
? proto
: as_value());
1121 /// Get the VM from an as_object
1123 getVM(const as_object
& o
)
1128 /// Get the movie_root from an as_object
1130 getRoot(const as_object
& o
)
1132 return o
.vm().getRoot();
1135 /// Get the string_table from an as_object
1137 getStringTable(const as_object
& o
)
1139 return o
.vm().getStringTable();
1143 getRunResources(const as_object
& o
)
1145 return o
.vm().getRoot().runResources();
1149 getSWFVersion(const as_object
& o
)
1151 return o
.vm().getSWFVersion();
1155 getGlobal(const as_object
& o
)
1157 return *o
.vm().getGlobal();
1160 } // end of gnash namespace
1164 // indent-tabs-mode: nil