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())
55 _condition(std::move(cmp
))
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
= nullptr) 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() : nullptr;
187 as_function
* constructor() {
188 return _super
? getConstructor(*_super
) : nullptr;
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), nullptr);
205 if (fname
.empty() || getSWFVersion(*this) <= 6) {
206 return new as_super(getGlobal(*this), proto
);
209 as_object
* owner
= nullptr;
210 proto
->findProperty(fname
, &owner
);
211 if (!owner
) return nullptr;
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()),
283 _displayObject(nullptr),
290 as_object::as_object(VM
& vm
)
292 GcResource(vm
.getRoot().gc()),
293 _displayObject(nullptr),
301 as_object::call(const fn_call
& /*fn*/)
303 throw ActionTypeError();
307 as_object::stringValue() const
309 return "[object Object]";
313 as_object::delProperty(const ObjectURI
& uri
)
315 return _members
.delProperty(uri
);
320 as_object::add_property(const std::string
& name
, as_function
& getter
,
323 const ObjectURI
& uri
= getURI(vm(), name
);
325 Property
* prop
= _members
.getProperty(uri
);
328 const as_value
& cacheVal
= prop
->getCache();
329 // Used to return the return value of addGetterSetter, but this
331 _members
.addGetterSetter(uri
, getter
, setter
, cacheVal
);
333 // NOTE: watch triggers not called when adding a new
334 // getter-setter property
338 _members
.addGetterSetter(uri
, getter
, setter
, as_value());
340 // Nothing more to do if there are no triggers.
341 if (!_trigs
.get()) return;
343 // check if we have a trigger, if so, invoke it
344 // and set val to its return
345 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
347 if (trigIter
!= _trigs
->end()) {
349 Trigger
& trig
= trigIter
->second
;
351 log_debug("add_property: property %s is being watched", name
);
352 as_value v
= trig
.call(as_value(), as_value(), *this);
354 // The trigger call could have deleted the property,
355 // so we check for its existence again, and do NOT put
356 // it back in if it was deleted
357 prop
= _members
.getProperty(uri
);
359 log_debug("Property %s deleted by trigger on create (getter-setter)", name
);
369 /// Order of property lookup:
371 /// 1. Visible own properties.
372 /// 2. If DisplayObject, magic properties
373 /// 3. Visible own properties of all __proto__ objects (a DisplayObject
375 /// 4. __resolve property of this object and all __proto__ objects (a Display
376 /// Object ends the chain). This should ignore visibility but doesn't.
378 as_object::get_member(const ObjectURI
& uri
, as_value
* val
)
382 const int version
= getSWFVersion(*this);
384 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
386 Property
* prop
= pr
.getProperty();
388 if (displayObject()) {
389 DisplayObject
* d
= displayObject();
390 if (getDisplayObjectProperty(*d
, uri
, *val
)) return true;
393 if ((prop
= pr
.getProperty())) break;
397 // If the property isn't found or doesn't apply to any objects in the
398 // inheritance chain, try the __resolve property.
401 PrototypeRecursor
<Exists
> pr(this, NSV::PROP_uuRESOLVE
);
406 Property
* res
= pr
.getProperty();
408 resolve
= res
->isGetterSetter() ? res
->getCache() :
409 res
->getValue(*this);
410 if (version
< 7) break;
411 if (resolve
.is_object()) break;
413 // Finished searching.
414 if (!pr()) return false;
417 // If __resolve exists, call it with the name of the undefined
419 string_table
& st
= getStringTable(*this);
420 const std::string
& undefinedName
= st
.value(getName(uri
));
423 args
+= undefinedName
;
425 // Invoke the __resolve property.
426 *val
= invoke(resolve
, as_environment(getVM(*this)), this, args
);
432 *val
= prop
->getValue(*this);
435 catch (const ActionTypeError
& exc
) {
436 IF_VERBOSE_ASCODING_ERRORS(
437 log_aserror(_("Caught exception: %s"), exc
.what());
445 as_object::get_super(const ObjectURI
& fname
)
447 // Super references the super class of our class prototype.
448 // Our class prototype is __proto__.
449 // Our class superclass prototype is __proto__.__proto__
451 // Our class prototype is __proto__.
452 as_object
* proto
= get_prototype();
454 if ( ! fname
.empty() && getSWFVersion(*this) > 6) {
455 as_object
* owner
= nullptr;
456 findProperty(fname
, &owner
);
457 // should be 0 if findProperty returned 0
458 if (owner
!= this) proto
= owner
;
461 as_object
* super
= new as_super(getGlobal(*this), proto
);
467 as_object::get_super()
469 // Our class prototype is __proto__.
470 as_object
* proto
= get_prototype();
471 as_object
* super
= new as_super(getGlobal(*this), proto
);
477 as_object::findProperty(const ObjectURI
& uri
, as_object
** owner
)
480 const int version
= getSWFVersion(*this);
482 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
485 Property
* prop
= pr
.getProperty(owner
);
486 if (prop
) return prop
;
494 as_object::findUpdatableProperty(const ObjectURI
& uri
)
497 PrototypeRecursor
<Exists
> pr(this, uri
);
499 Property
* prop
= pr
.getProperty();
501 // We won't scan the inheritance chain if we find a member,
502 // even if invisible.
503 if (prop
) return prop
;
505 const int swfVersion
= getSWFVersion(*this);
508 if ((prop
= pr
.getProperty())) {
509 if (prop
->isGetterSetter() && visible(*prop
, swfVersion
)) {
518 as_object::set_prototype(const as_value
& proto
)
520 // TODO: check what happens if __proto__ is set as a user-defined
522 // TODO: check triggers !!
523 _members
.setValue(NSV::PROP_uuPROTOuu
, proto
, as_object::DefaultFlags
);
527 as_object::executeTriggers(Property
* prop
, const ObjectURI
& uri
,
531 // check if we have a trigger, if so, invoke it
532 // and set val to its return
533 TriggerContainer::iterator trigIter
;
535 // If there are no triggers or the trigger is not found, just set
537 if (!_trigs
.get() || (trigIter
= _trigs
->find(uri
)) == _trigs
->end()) {
539 prop
->setValue(*this, val
);
540 prop
->clearVisible(getSWFVersion(*this));
545 Trigger
& trig
= trigIter
->second
;
548 _trigs
->erase(trigIter
);
552 // WARNING: getValue might itself invoke a trigger
553 // (getter-setter)... ouch ?
554 // TODO: in this case, return the underlying value !
555 const as_value
& curVal
= prop
? prop
->getCache() : as_value();
556 const as_value
& newVal
= trig
.call(curVal
, val
, *this);
558 // This is a particularly clear and concise way of removing dead triggers.
559 EraseIf(*_trigs
, std::bind(std::mem_fn(&Trigger::dead
),
560 std::bind(&TriggerContainer::value_type::second
,
561 std::placeholders::_1
)));
563 // The trigger call could have deleted the property,
564 // so we check for its existence again, and do NOT put
565 // it back in if it was deleted
566 prop
= findUpdatableProperty(uri
);
569 prop
->setValue(*this, newVal
);
570 prop
->clearVisible(getSWFVersion(*this));
574 /// Order of property lookup:
576 /// 0. MovieClip textfield variables. TODO: this is a hack and should be
578 /// 1. Own properties even if invisible or not getter-setters.
579 /// 2. If DisplayObject, magic properties
580 /// 3. Visible own getter-setter properties of all __proto__ objects
581 /// (a DisplayObject ends the chain).
583 as_object::set_member(const ObjectURI
& uri
, const as_value
& val
, bool ifFound
)
586 bool tfVarFound
= false;
587 if (displayObject()) {
588 MovieClip
* mc
= dynamic_cast<MovieClip
*>(displayObject());
589 if (mc
) tfVarFound
= mc
->setTextFieldVariables(uri
, val
);
590 // We still need to set the member.
593 // Handle the length property for arrays. NB: checkArrayLength() will
594 // call this function again if the key is a valid index.
595 if (array()) checkArrayLength(*this, uri
, val
);
597 PrototypeRecursor
<Exists
> pr(this, uri
);
599 Property
* prop
= pr
.getProperty();
601 // We won't scan the inheritance chain if we find a member,
602 // even if invisible.
605 if (displayObject()) {
606 DisplayObject
* d
= displayObject();
607 if (setDisplayObjectProperty(*d
, uri
, val
)) return true;
608 // TODO: should we execute triggers?
611 const int version
= getSWFVersion(*this);
613 if ((prop
= pr
.getProperty())) {
614 if ((prop
->isGetterSetter()) && visible(*prop
, version
)) {
623 if (readOnly(*prop
)) {
624 IF_VERBOSE_ASCODING_ERRORS(
625 ObjectURI::Logger
l(getStringTable(*this));
626 log_aserror(_("Attempt to set read-only property '%s'"),
633 executeTriggers(prop
, uri
, val
);
635 catch (const ActionTypeError
& exc
) {
636 IF_VERBOSE_ASCODING_ERRORS(
638 _("%s: %s"), getStringTable(*this).value(getName(uri
)), exc
.what());
645 // Else, add new property...
646 if (ifFound
) return false;
648 // Property does not exist, so it won't be read-only. Set it.
649 if (!_members
.setValue(uri
, val
)) {
651 IF_VERBOSE_ASCODING_ERRORS(
652 ObjectURI::Logger
l(getStringTable(*this));
653 log_aserror(_("Unknown failure in setting property '%s' on "
654 "object '%p'"), l(uri
), (void*) this);
659 executeTriggers(prop
, uri
, val
);
661 // Return true if we found a textfield variable.
662 if (tfVarFound
) return true;
669 as_object::init_member(const std::string
& key1
, const as_value
& val
, int flags
)
671 const ObjectURI
& uri(getURI(vm(), key1
));
672 init_member(uri
, val
, flags
);
676 as_object::init_member(const ObjectURI
& uri
, const as_value
& val
, int flags
)
679 // Set (or create) a SimpleProperty
680 if (!_members
.setValue(uri
, val
, flags
)) {
681 ObjectURI::Logger
l(getStringTable(*this));
682 log_error(_("Attempt to initialize read-only property '%s'"
683 " on object '%p' twice"), l(uri
), (void*)this);
684 // We shouldn't attempt to initialize a member twice, should we ?
690 as_object::init_property(const std::string
& name
, as_function
& getter
,
691 as_function
& setter
, int flags
)
693 const ObjectURI
& uri
= getURI(vm(), name
);
694 init_property(uri
, getter
, setter
, flags
);
698 as_object::init_property(const ObjectURI
& uri
, as_function
& getter
,
699 as_function
& setter
, int flags
)
701 _members
.addGetterSetter(uri
, getter
, &setter
, as_value(), flags
);
705 as_object::init_property(const std::string
& name
, as_c_function_ptr getter
,
706 as_c_function_ptr setter
, int flags
)
708 const ObjectURI
& uri
= getURI(vm(), name
);
709 init_property(uri
, getter
, setter
, flags
);
713 as_object::init_property(const ObjectURI
& uri
, as_c_function_ptr getter
,
714 as_c_function_ptr setter
, int flags
)
716 _members
.addGetterSetter(uri
, getter
, setter
, flags
);
720 as_object::init_destructive_property(const ObjectURI
& uri
, as_function
& getter
,
723 return _members
.addDestructiveGetter(uri
, getter
, flags
);
727 as_object::init_destructive_property(const ObjectURI
& uri
,
728 as_c_function_ptr getter
, int flags
)
730 return _members
.addDestructiveGetter(uri
, getter
, flags
);
734 as_object::init_readonly_property(const std::string
& name
, as_function
& getter
,
737 const ObjectURI
& uri
= getURI(vm(), name
);
739 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
740 assert(_members
.getProperty(uri
));
744 as_object::init_readonly_property(const std::string
& name
,
745 as_c_function_ptr getter
, int initflags
)
747 const ObjectURI
& uri
= getURI(vm(), name
);
748 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
749 assert(_members
.getProperty(uri
));
753 as_object::set_member_flags(const ObjectURI
& uri
, int setTrue
, int setFalse
)
755 _members
.setFlags(uri
, setTrue
, setFalse
);
759 as_object::addInterface(as_object
* obj
)
762 if (std::find(_interfaces
.begin(), _interfaces
.end(), obj
) ==
764 _interfaces
.push_back(obj
);
769 as_object::instanceOf(as_object
* ctor
)
772 /// An object is never an instance of a null prototype.
773 if (!ctor
) return false;
776 if (!ctor
->get_member(NSV::PROP_PROTOTYPE
, &protoVal
)) {
777 #ifdef GNASH_DEBUG_INSTANCE_OF
778 log_debug("Object %p can't be an instance of an object (%p) with no 'prototype'",
779 (void*)this, (void*)ctor
);
784 as_object
* ctorProto
= toObject(protoVal
, getVM(*this));
786 #ifdef GNASH_DEBUG_INSTANCE_OF
787 log_debug("Object %p can't be an instance of an object (%p) with non-object 'prototype' (%s)",
788 (void*)this, (void*)ctor
, protoVal
);
793 // TODO: cleanup the iteration, make it more readable ...
794 std::set
<as_object
*> visited
;
796 as_object
* obj
= this;
797 while (obj
&& visited
.insert(obj
).second
) {
798 as_object
* thisProto
= obj
->get_prototype();
804 if (thisProto
== ctorProto
) {
805 #ifdef GNASH_DEBUG_INSTANCE_OF
806 log_debug("Object %p is an instance of constructor %p as the constructor exposes our __proto__ %p",
807 (void*)obj
, (void*)ctor
, (void*)thisProto
);
812 // Check our proto interfaces
813 if (std::find(thisProto
->_interfaces
.begin(),
814 thisProto
->_interfaces
.end(), ctorProto
)
815 != thisProto
->_interfaces
.end()) {
817 #ifdef GNASH_DEBUG_INSTANCE_OF
818 log_debug("Object %p __proto__ %p had one interface matching with the constructor prototype %p",
819 (void*)obj
, (void*)thisProto
, (void*)ctorProto
);
831 as_object::prototypeOf(as_object
& instance
)
833 as_object
* obj
= &instance
;
835 std::set
<as_object
*> visited
;
837 while (obj
&& visited
.insert(obj
).second
) {
838 if (obj
->get_prototype() == this) return true;
839 obj
= obj
->get_prototype();
842 // See actionscript.all/Inheritance.as for a way to trigger this
843 IF_VERBOSE_ASCODING_ERRORS(
844 if (obj
) log_aserror(_("Circular inheritance chain detected "
845 "during isPrototypeOf call"));
852 as_object::dump_members()
854 log_debug("%d members of object %p follow", _members
.size(),
855 static_cast<const void*>(this));
860 as_object::setPropFlags(const as_value
& props_val
, int set_false
, int set_true
)
863 if (props_val
.is_null()) {
864 // Take all the members of the object
865 _members
.setFlagsAll(set_true
, set_false
);
869 std::string propstr
= props_val
.to_string();
874 size_t next_comma
=propstr
.find(",");
875 if (next_comma
== std::string::npos
) {
879 prop
= propstr
.substr(0,next_comma
);
880 propstr
= propstr
.substr(next_comma
+1);
883 // set_member_flags will take care of case conversion
884 set_member_flags(getURI(vm(), prop
), set_true
, set_false
);
886 if (next_comma
== std::string::npos
) {
895 as_object::copyProperties(const as_object
& o
)
897 PropsCopier
copier(*this);
899 // TODO: check if non-visible properties should be also copied !
900 o
.visitProperties
<Exists
>(copier
);
904 as_object::visitKeys(KeyVisitor
& visitor
) const
906 // Hack to handle MovieClips.
907 if (displayObject()) {
908 displayObject()->visitNonProperties(visitor
);
911 // this set will keep track of visited objects,
912 // to avoid infinite loops
913 std::set
<const as_object
*> visited
;
915 PropertyList::PropertyTracker doneList
;
917 const as_object
* current(this);
918 while (current
&& visited
.insert(current
).second
) {
919 current
->_members
.visitKeys(visitor
, doneList
);
920 current
= current
->get_prototype();
926 as_object::getOwnProperty(const ObjectURI
& uri
)
928 return _members
.getProperty(uri
);
932 as_object::get_prototype() const
934 int swfVersion
= getSWFVersion(*this);
936 Property
* prop
= _members
.getProperty(NSV::PROP_uuPROTOuu
);
937 if (!prop
) return nullptr;
938 if (!visible(*prop
, swfVersion
)) return nullptr;
940 const as_value
& proto
= prop
->getValue(*this);
942 return toObject(proto
, getVM(*this));
946 getURLEncodedVars(as_object
& o
)
948 SortedPropertyList props
= enumerateProperties(o
);
951 string_table
& st
= getStringTable(o
);
953 for (SortedPropertyList::const_reverse_iterator i
= props
.rbegin(),
954 e
= props
.rend(); i
!= e
; ++i
) {
956 const std::string
& name
= i
->first
.toString(st
);
957 const std::string
& value
= i
->second
.to_string();
960 if (!name
.empty() && name
[0] == '$') continue;
963 if (i
!= props
.rbegin()) data
+= '&';
965 data
+= name
+ "=" + value
;
972 as_object::watch(const ObjectURI
& uri
, as_function
& trig
,
973 const as_value
& cust
)
976 std::string propname
= getStringTable(*this).value(getName(uri
));
978 if (!_trigs
.get()) _trigs
.reset(new TriggerContainer
);
980 TriggerContainer::iterator it
= _trigs
->find(uri
);
981 if (it
== _trigs
->end()) {
982 return _trigs
->insert(
983 std::make_pair(uri
, Trigger(propname
, trig
, cust
))).second
;
985 it
->second
= Trigger(propname
, trig
, cust
);
990 as_object::unwatch(const ObjectURI
& uri
)
992 if (!_trigs
.get()) return false;
994 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
995 if (trigIter
== _trigs
->end()) {
996 log_debug("No watch for property %s",
997 getStringTable(*this).value(getName(uri
)));
1000 Property
* prop
= _members
.getProperty(uri
);
1001 if (prop
&& prop
->isGetterSetter()) {
1002 log_debug("Watch on %s not removed (is a getter-setter)",
1003 getStringTable(*this).value(getName(uri
)));
1006 trigIter
->second
.kill();
1011 as_object::markReachableResources() const
1013 _members
.setReachable();
1016 for (TriggerContainer::const_iterator it
= _trigs
->begin();
1017 it
!= _trigs
->end(); ++it
) {
1018 it
->second
.setReachable();
1022 // Mark interfaces reachable.
1023 std::for_each(_interfaces
.begin(), _interfaces
.end(),
1024 std::mem_fun(&as_object::setReachable
));
1026 // Proxy objects can contain references to other as_objects.
1027 if (_relay
) _relay
->setReachable();
1028 if (_displayObject
) _displayObject
->setReachable();
1032 Trigger::setReachable() const
1034 _func
->setReachable();
1035 _customArg
.setReachable();
1039 Trigger::call(const as_value
& oldval
, const as_value
& newval
,
1040 as_object
& this_obj
)
1044 if (_executing
) return newval
;
1050 const as_environment
env(getVM(this_obj
));
1053 args
+= _propname
, oldval
, newval
, _customArg
;
1055 fn_call
fn(&this_obj
, env
, args
);
1056 as_value ret
= _func
->call(fn
);
1062 catch (const GnashException
&) {
1069 enumerateProperties(as_object
& obj
)
1072 // this set will keep track of visited objects,
1073 // to avoid infinite loops
1074 std::set
<as_object
*> visited
;
1076 SortedPropertyList to
;
1077 PropertyEnumerator
e(to
);
1078 as_object
* current(&obj
);
1080 while (current
&& visited
.insert(current
).second
) {
1081 current
->visitProperties
<IsEnumerable
>(e
);
1082 current
= current
->get_prototype();
1089 getPathElement(as_object
& o
, const ObjectURI
& uri
)
1092 if (!o
.get_member(uri
, &tmp
)) return nullptr;
1093 if (!tmp
.is_object()) return nullptr;
1094 return toObject(tmp
, getVM(o
));
1099 sendEvent(as_object
& o
, const as_environment
& env
, const ObjectURI
& name
)
1101 Property
* prop
= o
.findProperty(name
);
1104 invoke(prop
->getValue(o
), env
, &o
, args
);
1109 getObjectWithPrototype(Global_as
& gl
, const ObjectURI
& c
)
1111 as_object
* ctor
= toObject(getMember(gl
, c
), getVM(gl
));
1112 as_object
* proto
= ctor
?
1113 toObject(getMember(*ctor
, NSV::PROP_PROTOTYPE
), getVM(gl
)) : nullptr;
1115 as_object
* o
= createObject(gl
);
1116 o
->set_prototype(proto
? proto
: as_value());
1120 /// Get the VM from an as_object
1122 getVM(const as_object
& o
)
1127 /// Get the movie_root from an as_object
1129 getRoot(const as_object
& o
)
1131 return o
.vm().getRoot();
1134 /// Get the string_table from an as_object
1136 getStringTable(const as_object
& o
)
1138 return o
.vm().getStringTable();
1142 getRunResources(const as_object
& o
)
1144 return o
.vm().getRoot().runResources();
1148 getSWFVersion(const as_object
& o
)
1150 return o
.vm().getSWFVersion();
1154 getGlobal(const as_object
& o
)
1156 return *o
.vm().getGlobal();
1159 } // end of gnash namespace
1163 // indent-tabs-mode: nil