1 // as_object.cpp: ActionScript Object class and its properties, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 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 "smart_ptr.h"
30 #include "as_function.h"
31 #include "as_environment.h"
32 #include "movie_root.h"
36 #include "GnashException.h"
39 #include "as_function.h"
40 #include "Global_as.h"
41 #include "GnashAlgorithm.h"
42 #include "DisplayObject.h"
43 #include "namedStrings.h"
48 as_object::PrototypeRecursor
51 PrototypeRecursor(as_object
* top
, const ObjectURI
& uri
, T cmp
= T())
61 /// Iterate to the next object in the inheritance chain.
63 /// This function throws an ActionLimitException when the maximum
64 /// number of recursions is reached.
66 /// @return false if there is no next object. In this case calling
67 /// the other functions will abort.
72 // See swfdec/prototype-recursion-get-?.swf
73 if (_iterations
> 256) {
74 throw ActionLimitException("Lookup depth exceeded.");
77 _object
= _object
->get_prototype();
79 // TODO: there is recursion prevention anyway; is this extra
80 // check for circularity really necessary?
81 if (!_visited
.insert(_object
).second
) return 0;
82 return _object
&& !_object
->displayObject();
85 /// Return the wanted property if it exists and satisfies the predicate.
87 /// This will abort if there is no current object.
88 Property
* getProperty(as_object
** owner
= 0) const {
91 Property
* prop
= _object
->_members
.getProperty(_uri
);
93 if (prop
&& _condition(*prop
)) {
94 if (owner
) *owner
= _object
;
102 const ObjectURI
& _uri
;
103 std::set
<const as_object
*> _visited
;
108 // Anonymous namespace used for module-static defs
112 getConstructor(as_object
& o
)
115 if (!o
.get_member(NSV::PROP_uuCONSTRUCTORuu
, &ctorVal
)) {
118 return ctorVal
.to_function();
121 /// 'super' is a special kind of object
123 /// See http://wiki.gnashdev.org/wiki/index.php/ActionScriptSuper
125 /// We make it derive from as_function instead of as_object
126 /// to avoid touching too many files (ie: an as_object is not considered
127 /// something that can be called by current Gnash code). We may want
128 /// to change this in the future to implement what ECMA-262 refers to
129 /// as the [[Call]] property of objects.
131 class as_super
: public as_object
135 as_super(Global_as
& gl
, as_object
* super
)
140 set_prototype(prototype());
143 virtual bool isSuper() const { return true; }
145 virtual as_object
* get_super(const ObjectURI
& fname
);
147 // Fetching members from 'super' yelds a lookup on the associated prototype
148 virtual bool get_member(const ObjectURI
& uri
, as_value
* val
)
150 as_object
* proto
= prototype();
151 if (proto
) return proto
->get_member(uri
, val
);
152 log_debug("Super has no associated prototype");
157 virtual as_value
call(const fn_call
& fn
)
160 // TODO: this is a hack to make sure objects are constructed, not
161 // converted (fn.isInstantiation() must be true).
162 fn_call::Args::container_type
argsIn(fn
.getArgs());
166 fn_call
fn2(fn
.this_ptr
, fn
.env(), args
, fn
.super
, true);
167 assert(fn2
.isInstantiation());
168 as_function
* ctor
= constructor();
169 if (ctor
) return ctor
->call(fn2
);
170 log_debug("Super has no associated constructor");
176 virtual void markReachableResources() const
178 if (_super
) _super
->setReachable();
179 as_object::markReachableResources();
184 as_object
* prototype() {
185 return _super
? _super
->get_prototype() : 0;
188 as_function
* constructor() {
189 return _super
? getConstructor(*_super
) : 0;
196 as_super::get_super(const ObjectURI
& fname
)
198 // Super references the super class of our class prototype.
199 // Our class prototype is __proto__.
200 // Our class superclass prototype is __proto__.__proto__
202 // Our class prototype is __proto__.
203 as_object
* proto
= get_prototype();
204 if (!proto
) return new as_super(getGlobal(*this), 0);
206 if (fname
.empty() || getSWFVersion(*this) <= 6) {
207 return new as_super(getGlobal(*this), proto
);
210 as_object
* owner
= 0;
211 proto
->findProperty(fname
, &owner
);
212 if (!owner
) return 0;
214 if (owner
== proto
) return new as_super(getGlobal(*this), proto
);
216 as_object
* tmp
= proto
;
217 while (tmp
&& tmp
->get_prototype() != owner
) {
218 tmp
= tmp
->get_prototype();
220 // ok, now 'tmp' should be the object whose __proto__ member
221 // contains the actual named method.
223 // in the C:B:A:F case this would be B when calling
224 // super.myName() from C.prototype.myName()
226 // well, since we found the property, it must be somewhere!
229 if (tmp
!= proto
) { return new as_super(getGlobal(*this), tmp
); }
230 return new as_super(getGlobal(*this), owner
);
234 /// A PropertyList visitor copying properties to an object
235 class PropsCopier
: public PropertyVisitor
241 /// Initialize a PropsCopier instance associating it
242 /// with a target object (an object whose members has to be set)
244 PropsCopier(as_object
& tgt
)
250 /// Set *inherited* properties of the given target object
251 bool accept(const ObjectURI
& uri
, const as_value
& val
) {
252 if (getName(uri
) == NSV::PROP_uuPROTOuu
) return true;
253 _tgt
.set_member(uri
, val
);
260 class PropertyEnumerator
: public PropertyVisitor
263 PropertyEnumerator(SortedPropertyList
& to
)
268 bool accept(const ObjectURI
& uri
, const as_value
& val
) {
269 _to
.push_back(std::make_pair(uri
, val
));
273 SortedPropertyList
& _to
;
276 } // anonymous namespace
279 const int as_object::DefaultFlags
;
281 as_object::as_object(const Global_as
& gl
)
283 GcResource(getRoot(gl
).gc()),
292 as_object::as_object(VM
& vm
)
294 GcResource(vm
.getRoot().gc()),
304 as_object::call(const fn_call
& /*fn*/)
306 throw ActionTypeError();
310 as_object::stringValue() const
312 return "[object Object]";
316 as_object::delProperty(const ObjectURI
& uri
)
318 return _members
.delProperty(uri
);
323 as_object::add_property(const std::string
& name
, as_function
& getter
,
326 const ObjectURI
& uri
= getURI(vm(), name
);
328 Property
* prop
= _members
.getProperty(uri
);
331 const as_value
& cacheVal
= prop
->getCache();
332 // Used to return the return value of addGetterSetter, but this
334 _members
.addGetterSetter(uri
, getter
, setter
, cacheVal
);
336 // NOTE: watch triggers not called when adding a new
337 // getter-setter property
341 _members
.addGetterSetter(uri
, getter
, setter
, as_value());
343 // Nothing more to do if there are no triggers.
344 if (!_trigs
.get()) return;
346 // check if we have a trigger, if so, invoke it
347 // and set val to its return
348 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
350 if (trigIter
!= _trigs
->end()) {
352 Trigger
& trig
= trigIter
->second
;
354 log_debug("add_property: property %s is being watched" , name
);
355 as_value v
= trig
.call(as_value(), as_value(), *this);
357 // The trigger call could have deleted the property,
358 // so we check for its existence again, and do NOT put
359 // it back in if it was deleted
360 prop
= _members
.getProperty(uri
);
362 log_debug("Property %s deleted by trigger on create "
363 "(getter-setter)", name
);
373 /// Order of property lookup:
375 /// 1. Visible own properties.
376 /// 2. If DisplayObject, magic properties
377 /// 3. Visible own properties of all __proto__ objects (a DisplayObject
379 /// 4. __resolve property of this object and all __proto__ objects (a Display
380 /// Object ends the chain). This should ignore visibility but doesn't.
382 as_object::get_member(const ObjectURI
& uri
, as_value
* val
)
386 const int version
= getSWFVersion(*this);
388 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
390 Property
* prop
= pr
.getProperty();
392 if (displayObject()) {
393 DisplayObject
* d
= displayObject();
394 if (getDisplayObjectProperty(*d
, uri
, *val
)) return true;
397 if ((prop
= pr
.getProperty())) break;
401 // If the property isn't found or doesn't apply to any objects in the
402 // inheritance chain, try the __resolve property.
405 Property
* res
= findProperty(NSV::PROP_uuRESOLVE
);
408 if (!res
) return false;
410 // If __resolve exists, call it with the name of the undefined
412 string_table
& st
= getStringTable(*this);
413 const std::string
& undefinedName
= st
.value(getName(uri
));
416 args
+= undefinedName
;
418 // Invoke the __resolve property.
419 *val
= invoke(res
->getValue(*this), as_environment(getVM(*this)),
426 *val
= prop
->getValue(*this);
429 catch (ActionLimitException
& exc
) {
430 // will be logged by outer catcher
433 catch (ActionTypeError
& exc
) {
434 IF_VERBOSE_ASCODING_ERRORS(
435 log_aserror(_("Caught exception: %s"), exc
.what());
444 as_object::get_super(const ObjectURI
& fname
)
446 // Super references the super class of our class prototype.
447 // Our class prototype is __proto__.
448 // Our class superclass prototype is __proto__.__proto__
450 // Our class prototype is __proto__.
451 as_object
* proto
= get_prototype();
453 if ( ! fname
.empty() && getSWFVersion(*this) > 6) {
454 as_object
* owner
= 0;
455 findProperty(fname
, &owner
);
456 // should be 0 if findProperty returned 0
457 if (owner
!= this) proto
= owner
;
460 as_object
* super
= new as_super(getGlobal(*this), proto
);
466 as_object::get_super()
468 // Our class prototype is __proto__.
469 as_object
* proto
= get_prototype();
470 as_object
* super
= new as_super(getGlobal(*this), proto
);
476 as_object::findProperty(const ObjectURI
& uri
, as_object
** owner
)
479 const int version
= getSWFVersion(*this);
481 PrototypeRecursor
<IsVisible
> pr(this, uri
, IsVisible(version
));
484 Property
* prop
= pr
.getProperty(owner
);
485 if (prop
) return prop
;
493 as_object::findUpdatableProperty(const ObjectURI
& uri
)
496 PrototypeRecursor
<Exists
> pr(this, uri
);
498 Property
* prop
= pr
.getProperty();
500 // We won't scan the inheritance chain if we find a member,
501 // even if invisible.
502 if (prop
) return prop
;
504 const int swfVersion
= getSWFVersion(*this);
507 if ((prop
= pr
.getProperty())) {
508 if (prop
->isGetterSetter() && visible(*prop
, swfVersion
)) {
517 as_object::set_prototype(const as_value
& proto
)
519 // TODO: check what happens if __proto__ is set as a user-defined
521 // TODO: check triggers !!
522 _members
.setValue(NSV::PROP_uuPROTOuu
, proto
, as_object::DefaultFlags
);
526 as_object::executeTriggers(Property
* prop
, const ObjectURI
& uri
,
530 // check if we have a trigger, if so, invoke it
531 // and set val to its return
532 TriggerContainer::iterator trigIter
;
534 // If there are no triggers or the trigger is not found, just set
536 if (!_trigs
.get() || (trigIter
= _trigs
->find(uri
)) == _trigs
->end()) {
538 prop
->setValue(*this, val
);
539 prop
->clearVisible(getSWFVersion(*this));
544 Trigger
& trig
= trigIter
->second
;
547 _trigs
->erase(trigIter
);
551 // WARNING: getValue might itself invoke a trigger
552 // (getter-setter)... ouch ?
553 // TODO: in this case, return the underlying value !
554 const as_value
& curVal
= prop
? prop
->getCache() : as_value();
555 const as_value
& newVal
= trig
.call(curVal
, val
, *this);
557 // This is a particularly clear and concise way of removing dead triggers.
558 EraseIf(*_trigs
, boost::bind(boost::mem_fn(&Trigger::dead
),
559 boost::bind(SecondElement
<TriggerContainer::value_type
>(), _1
)));
561 // The trigger call could have deleted the property,
562 // so we check for its existence again, and do NOT put
563 // it back in if it was deleted
564 prop
= findUpdatableProperty(uri
);
567 prop
->setValue(*this, newVal
);
568 prop
->clearVisible(getSWFVersion(*this));
572 /// Order of property lookup:
574 /// 0. MovieClip textfield variables. TODO: this is a hack and should be
576 /// 1. Own properties even if invisible or not getter-setters.
577 /// 2. If DisplayObject, magic properties
578 /// 3. Visible own getter-setter properties of all __proto__ objects
579 /// (a DisplayObject ends the chain).
581 as_object::set_member(const ObjectURI
& uri
, const as_value
& val
, bool ifFound
)
584 bool tfVarFound
= false;
585 if (displayObject()) {
586 MovieClip
* mc
= dynamic_cast<MovieClip
*>(displayObject());
587 if (mc
) tfVarFound
= mc
->setTextFieldVariables(uri
, val
);
588 // We still need to set the member.
591 // Handle the length property for arrays. NB: checkArrayLength() will
592 // call this function again if the key is a valid index.
593 if (array()) checkArrayLength(*this, uri
, val
);
595 PrototypeRecursor
<Exists
> pr(this, uri
);
597 Property
* prop
= pr
.getProperty();
599 // We won't scan the inheritance chain if we find a member,
600 // even if invisible.
603 if (displayObject()) {
604 DisplayObject
* d
= displayObject();
605 if (setDisplayObjectProperty(*d
, uri
, val
)) return true;
606 // TODO: should we execute triggers?
609 const int version
= getSWFVersion(*this);
611 if ((prop
= pr
.getProperty())) {
612 if ((prop
->isGetterSetter()) && visible(*prop
, version
)) {
621 if (readOnly(*prop
)) {
622 IF_VERBOSE_ASCODING_ERRORS(
623 ObjectURI::Logger
l(getStringTable(*this));
624 log_aserror(_("Attempt to set read-only property '%s'"),
631 executeTriggers(prop
, uri
, val
);
633 catch (const ActionTypeError
& exc
) {
634 IF_VERBOSE_ASCODING_ERRORS(
636 _("%s: %s"), getStringTable(*this).value(getName(uri
)), exc
.what());
643 // Else, add new property...
644 if (ifFound
) return false;
646 // Property does not exist, so it won't be read-only. Set it.
647 if (!_members
.setValue(uri
, val
)) {
649 IF_VERBOSE_ASCODING_ERRORS(
650 ObjectURI::Logger
l(getStringTable(*this));
651 log_aserror(_("Unknown failure in setting property '%s' on "
652 "object '%p'"), l(uri
), (void*) this);
657 executeTriggers(prop
, uri
, val
);
659 // Return true if we found a textfield variable.
660 if (tfVarFound
) return true;
667 as_object::init_member(const std::string
& key1
, const as_value
& val
, int flags
)
669 const ObjectURI
& uri(getURI(vm(), key1
));
670 init_member(uri
, val
, flags
);
674 as_object::init_member(const ObjectURI
& uri
, const as_value
& val
, int flags
)
677 // Set (or create) a SimpleProperty
678 if (!_members
.setValue(uri
, val
, flags
)) {
679 ObjectURI::Logger
l(getStringTable(*this));
680 log_error(_("Attempt to initialize read-only property '%s'"
681 " on object '%p' twice"), l(uri
), (void*)this);
682 // We shouldn't attempt to initialize a member twice, should we ?
688 as_object::init_property(const std::string
& name
, as_function
& getter
,
689 as_function
& setter
, int flags
)
691 const ObjectURI
& uri
= getURI(vm(), name
);
692 init_property(uri
, getter
, setter
, flags
);
696 as_object::init_property(const ObjectURI
& uri
, as_function
& getter
,
697 as_function
& setter
, int flags
)
699 _members
.addGetterSetter(uri
, getter
, &setter
, as_value(), flags
);
703 as_object::init_property(const std::string
& name
, as_c_function_ptr getter
,
704 as_c_function_ptr setter
, int flags
)
706 const ObjectURI
& uri
= getURI(vm(), name
);
707 init_property(uri
, getter
, setter
, flags
);
711 as_object::init_property(const ObjectURI
& uri
, as_c_function_ptr getter
,
712 as_c_function_ptr setter
, int flags
)
714 _members
.addGetterSetter(uri
, getter
, setter
, flags
);
718 as_object::init_destructive_property(const ObjectURI
& uri
, as_function
& getter
,
721 return _members
.addDestructiveGetter(uri
, getter
, flags
);
725 as_object::init_destructive_property(const ObjectURI
& uri
,
726 as_c_function_ptr getter
, int flags
)
728 return _members
.addDestructiveGetter(uri
, getter
, flags
);
732 as_object::init_readonly_property(const std::string
& name
, as_function
& getter
,
735 const ObjectURI
& uri
= getURI(vm(), name
);
737 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
738 assert(_members
.getProperty(uri
));
742 as_object::init_readonly_property(const std::string
& name
,
743 as_c_function_ptr getter
, int initflags
)
745 const ObjectURI
& uri
= getURI(vm(), name
);
746 init_property(uri
, getter
, getter
, initflags
| PropFlags::readOnly
);
747 assert(_members
.getProperty(uri
));
751 as_object::set_member_flags(const ObjectURI
& uri
, int setTrue
, int setFalse
)
753 _members
.setFlags(uri
, setTrue
, setFalse
);
757 as_object::addInterface(as_object
* obj
)
760 if (std::find(_interfaces
.begin(), _interfaces
.end(), obj
) ==
762 _interfaces
.push_back(obj
);
767 as_object::instanceOf(as_object
* ctor
)
770 /// An object is never an instance of a null prototype.
771 if (!ctor
) return false;
774 if (!ctor
->get_member(NSV::PROP_PROTOTYPE
, &protoVal
)) {
775 #ifdef GNASH_DEBUG_INSTANCE_OF
776 log_debug("Object %p can't be an instance of an object (%p) "
777 "with no 'prototype'",
778 (void*)this, (void*)ctor
);
783 as_object
* ctorProto
= toObject(protoVal
, getVM(*this));
785 #ifdef GNASH_DEBUG_INSTANCE_OF
786 log_debug("Object %p can't be an instance of an object (%p) "
787 "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 "
807 "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 "
820 "with the constructor prototype %p",
821 (void*)obj
, (void*)thisProto
, (void*)ctorProto
);
833 as_object::prototypeOf(as_object
& instance
)
835 as_object
* obj
= &instance
;
837 std::set
<as_object
*> visited
;
839 while (obj
&& visited
.insert(obj
).second
) {
840 if (obj
->get_prototype() == this) return true;
841 obj
= obj
->get_prototype();
844 // See actionscript.all/Inheritance.as for a way to trigger this
845 IF_VERBOSE_ASCODING_ERRORS(
846 if (obj
) log_aserror(_("Circular inheritance chain detected "
847 "during isPrototypeOf call"));
854 as_object::dump_members()
856 log_debug(_("%d members of object %p follow"), _members
.size(),
857 static_cast<const void*>(this));
862 as_object::setPropFlags(const as_value
& props_val
, int set_false
, int set_true
)
865 if (props_val
.is_null()) {
866 // Take all the members of the object
867 _members
.setFlagsAll(set_true
, set_false
);
871 std::string propstr
= props_val
.to_string();
876 size_t next_comma
=propstr
.find(",");
877 if (next_comma
== std::string::npos
) {
881 prop
= propstr
.substr(0,next_comma
);
882 propstr
= propstr
.substr(next_comma
+1);
885 // set_member_flags will take care of case conversion
886 set_member_flags(getURI(vm(), prop
), set_true
, set_false
);
888 if (next_comma
== std::string::npos
) {
897 as_object::copyProperties(const as_object
& o
)
899 PropsCopier
copier(*this);
901 // TODO: check if non-visible properties should be also copied !
902 o
.visitProperties
<Exists
>(copier
);
906 as_object::visitKeys(KeyVisitor
& visitor
) const
908 // Hack to handle MovieClips.
909 if (displayObject()) {
910 displayObject()->visitNonProperties(visitor
);
913 // this set will keep track of visited objects,
914 // to avoid infinite loops
915 std::set
<const as_object
*> visited
;
917 PropertyList::PropertyTracker doneList
;
919 const as_object
* current(this);
920 while (current
&& visited
.insert(current
).second
) {
921 current
->_members
.visitKeys(visitor
, doneList
);
922 current
= current
->get_prototype();
928 as_object::getOwnProperty(const ObjectURI
& uri
)
930 return _members
.getProperty(uri
);
934 as_object::get_prototype() const
936 int swfVersion
= getSWFVersion(*this);
938 Property
* prop
= _members
.getProperty(NSV::PROP_uuPROTOuu
);
940 if (!visible(*prop
, swfVersion
)) return 0;
942 const as_value
& proto
= prop
->getValue(*this);
944 return toObject(proto
, getVM(*this));
948 getURLEncodedVars(as_object
& o
)
950 SortedPropertyList props
= enumerateProperties(o
);
953 string_table
& st
= getStringTable(o
);
955 for (SortedPropertyList::const_reverse_iterator i
= props
.rbegin(),
956 e
= props
.rend(); i
!= e
; ++i
) {
958 const std::string
& name
= i
->first
.toString(st
);
959 const std::string
& value
= i
->second
.to_string();
962 if (!name
.empty() && name
[0] == '$') continue;
965 if (i
!= props
.rbegin()) data
+= '&';
967 data
+= name
+ "=" + value
;
974 as_object::watch(const ObjectURI
& uri
, as_function
& trig
,
975 const as_value
& cust
)
978 std::string propname
= getStringTable(*this).value(getName(uri
));
980 if (!_trigs
.get()) _trigs
.reset(new TriggerContainer
);
982 TriggerContainer::iterator it
= _trigs
->find(uri
);
983 if (it
== _trigs
->end()) {
984 return _trigs
->insert(
985 std::make_pair(uri
, Trigger(propname
, trig
, cust
))).second
;
987 it
->second
= Trigger(propname
, trig
, cust
);
992 as_object::unwatch(const ObjectURI
& uri
)
994 if (!_trigs
.get()) return false;
996 TriggerContainer::iterator trigIter
= _trigs
->find(uri
);
997 if (trigIter
== _trigs
->end()) {
998 log_debug("No watch for property %s",
999 getStringTable(*this).value(getName(uri
)));
1002 Property
* prop
= _members
.getProperty(uri
);
1003 if (prop
&& prop
->isGetterSetter()) {
1004 log_debug("Watch on %s not removed (is a getter-setter)",
1005 getStringTable(*this).value(getName(uri
)));
1008 trigIter
->second
.kill();
1013 as_object::markReachableResources() const
1015 _members
.setReachable();
1018 for (TriggerContainer::const_iterator it
= _trigs
->begin();
1019 it
!= _trigs
->end(); ++it
) {
1020 it
->second
.setReachable();
1024 // Mark interfaces reachable.
1025 std::for_each(_interfaces
.begin(), _interfaces
.end(),
1026 std::mem_fun(&as_object::setReachable
));
1028 // Proxy objects can contain references to other as_objects.
1029 if (_relay
) _relay
->setReachable();
1030 if (_displayObject
) _displayObject
->setReachable();
1034 Trigger::setReachable() const
1036 _func
->setReachable();
1037 _customArg
.setReachable();
1041 Trigger::call(const as_value
& oldval
, const as_value
& newval
,
1042 as_object
& this_obj
)
1046 if (_executing
) return newval
;
1052 const as_environment
env(getVM(this_obj
));
1055 args
+= _propname
, oldval
, newval
, _customArg
;
1057 fn_call
fn(&this_obj
, env
, args
);
1058 as_value ret
= _func
->call(fn
);
1064 catch (const GnashException
&) {
1071 enumerateProperties(as_object
& obj
)
1074 // this set will keep track of visited objects,
1075 // to avoid infinite loops
1076 std::set
<as_object
*> visited
;
1078 SortedPropertyList to
;
1079 PropertyEnumerator
e(to
);
1080 as_object
* current(&obj
);
1082 while (current
&& visited
.insert(current
).second
) {
1083 current
->visitProperties
<IsEnumerable
>(e
);
1084 current
= current
->get_prototype();
1091 getPathElement(as_object
& o
, const ObjectURI
& uri
)
1094 if (!o
.get_member(uri
, &tmp
)) return 0;
1095 if (!tmp
.is_object()) return 0;
1096 return toObject(tmp
, getVM(o
));
1101 sendEvent(as_object
& o
, const as_environment
& env
, const ObjectURI
& name
)
1103 Property
* prop
= o
.findProperty(name
);
1106 invoke(prop
->getValue(o
), env
, &o
, args
);
1111 getObjectWithPrototype(Global_as
& gl
, const ObjectURI
& c
)
1113 as_object
* ctor
= toObject(getMember(gl
, c
), getVM(gl
));
1114 as_object
* proto
= ctor
?
1115 toObject(getMember(*ctor
, NSV::PROP_PROTOTYPE
), getVM(gl
)) : 0;
1117 as_object
* o
= createObject(gl
);
1118 o
->set_prototype(proto
? proto
: as_value());
1122 /// Get the VM from an as_object
1124 getVM(const as_object
& o
)
1129 /// Get the movie_root from an as_object
1131 getRoot(const as_object
& o
)
1133 return o
.vm().getRoot();
1136 /// Get the string_table from an as_object
1138 getStringTable(const as_object
& o
)
1140 return o
.vm().getStringTable();
1144 getRunResources(const as_object
& o
)
1146 return o
.vm().getRoot().runResources();
1150 getSWFVersion(const as_object
& o
)
1152 return o
.vm().getSWFVersion();
1156 getGlobal(const as_object
& o
)
1158 return *o
.vm().getGlobal();
1161 } // end of gnash namespace
1165 // indent-tabs-mode: nil