2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #ifndef GNASH_PROPERTY_H
21 #define GNASH_PROPERTY_H
23 #include <boost/variant.hpp>
25 #include <boost/bind.hpp>
28 #include "PropFlags.h"
30 #include "ObjectURI.h"
33 typedef as_value (*as_c_function_ptr
)(const fn_call
& fn
);
39 /// Holder for getter/setter functions
41 /// Getter setter can be user-defined or native ones.
42 /// This class abstracts the two.
45 class NativeGetterSetter
;
47 // The following helper structs define common operations on the
48 // Two types of GetterSetter. Some operations are applicable only to
51 /// Get or set a GetterSetter
53 /// @tparam S A type that determines what operation to call on the
55 /// @param Arg The type of the argument to the get or set function.
56 template<typename Arg
, typename S
>
57 struct GetSetVisitor
: boost::static_visitor
<typename
S::result_type
>
59 GetSetVisitor(const Arg
& arg
) : _arg(arg
) {}
60 template<typename T
> typename
S::result_type
operator()(T
& t
) const {
67 /// Set a GetterSetter
70 typedef void result_type
;
71 template<typename T
, typename Arg
>
72 result_type
operator()(T
& t
, Arg
& a
) const {
77 /// Get a GetterSetter
80 typedef as_value result_type
;
81 template<typename T
, typename Arg
>
82 result_type
operator()(T
& t
, Arg
& a
) const {
87 /// Set the underlying value of a GetterSetter
89 /// This does not apply to NativeGetterSetters.
90 struct SetUnderlying
: boost::static_visitor
<>
93 result_type
operator()(T
& gs
, const as_value
& val
) const {
94 gs
.setUnderlying(val
);
96 result_type
operator()(NativeGetterSetter
&, const as_value
&) const {}
99 /// Get the underlying value of a GetterSetter
101 /// This does not apply to NativeGetterSetters.
102 struct GetUnderlying
: boost::static_visitor
<as_value
>
105 result_type
operator()(const T
& gs
) const {
106 return gs
.getUnderlying();
108 result_type
operator()(const NativeGetterSetter
&) const {
109 return result_type();
113 /// Mark a GetterSetter reachable
114 struct MarkReachable
: boost::static_visitor
<>
117 result_type
operator()(const T
& gs
) const {
118 gs
.markReachableResources();
124 /// Construct a user-defined getter-setter
125 GetterSetter(as_function
* getter
, as_function
* setter
)
127 _getset(UserDefinedGetterSetter(getter
, setter
))
130 /// Construct a native getter-setter
131 GetterSetter(as_c_function_ptr getter
, as_c_function_ptr setter
)
133 _getset(NativeGetterSetter(getter
, setter
))
136 /// Invoke the getter
137 as_value
get(fn_call
& fn
) const {
138 GetSetVisitor
<const fn_call
, Get
> s(fn
);
139 return boost::apply_visitor(s
, _getset
);
142 /// Invoke the setter
143 void set(const fn_call
& fn
) {
144 GetSetVisitor
<fn_call
, Set
> s(fn
);
145 boost::apply_visitor(s
, _getset
);
148 /// Set the cache value (for user-defined getter-setters)
149 void setCache(const as_value
& v
) {
150 boost::apply_visitor(boost::bind(SetUnderlying(), _1
, v
), _getset
);
153 /// Get the cache value (for user-defined getter-setters)
154 as_value
getCache() const {
155 return boost::apply_visitor(GetUnderlying(), _getset
);
158 void markReachableResources() const {
159 boost::apply_visitor(MarkReachable(), _getset
);
164 /// User-defined getter/setter
165 class UserDefinedGetterSetter
169 UserDefinedGetterSetter(as_function
* get
, as_function
* set
)
174 _beingAccessed(false)
177 /// Invoke the getter
178 as_value
get(const fn_call
& fn
) const;
180 /// Invoke the setter
181 void set(const fn_call
& fn
);
183 /// Get the underlying value
184 const as_value
& getUnderlying() const { return _underlyingValue
; }
186 /// Set the underlying value
187 void setUnderlying(const as_value
& v
) { _underlyingValue
= v
; }
189 void markReachableResources() const;
193 /// For SWF6 (not higher) a user-defined getter-setter would not
194 /// be invoked while being set. This ScopedLock helps marking a
195 /// Getter-Setter as being invoked in an exception-safe manner.
197 /// Note this is not thread safe and does not attempt to provide
199 class ScopedLock
: boost::noncopyable
203 explicit ScopedLock(const UserDefinedGetterSetter
& na
)
206 _obtainedLock(_a
._beingAccessed
? false : true)
208 // If we didn't obtain the lock it would be true anyway,
209 // but it's probably polite to avoid touching it.
210 if (_obtainedLock
) _a
._beingAccessed
= true;
213 ~ScopedLock() { if ( _obtainedLock
) _a
._beingAccessed
= false; }
215 /// Return true if the lock was obtained
217 /// If false is returned, we're being called recursively,
218 /// which means we should set the underlyingValue instead
219 /// of calling the setter (for SWF6, again).
221 bool obtainedLock() const { return _obtainedLock
; }
225 const UserDefinedGetterSetter
& _a
;
230 as_function
* _getter
;
231 as_function
* _setter
;
232 as_value _underlyingValue
;
233 mutable bool _beingAccessed
;
236 /// Native GetterSetter
237 class NativeGetterSetter
241 NativeGetterSetter(as_c_function_ptr get
, as_c_function_ptr set
)
243 _getter(get
), _setter(set
) {}
245 /// Invoke the getter
246 as_value
get(const fn_call
& fn
) const {
250 /// Invoke the setter
251 void set(const fn_call
& fn
) {
255 /// Nothing to do for native setters.
256 void markReachableResources() const {}
259 as_c_function_ptr _getter
;
260 as_c_function_ptr _setter
;
263 boost::variant
<UserDefinedGetterSetter
, NativeGetterSetter
> _getset
;
267 /// An abstract property
269 /// A Property is a holder for a value or a getter-setter.
271 /// Properties have special const semantics: the value of a Property does
272 /// not affect its outward state, so the value of a const Property can be
277 /// Mark the stored value reachable.
278 struct SetReachable
: boost::static_visitor
<>
280 result_type
operator()(const as_value
& val
) const {
283 result_type
operator()(const GetterSetter
& gs
) const {
284 return gs
.markReachableResources();
290 Property(const ObjectURI
& uri
, const as_value
& value
,
291 const PropFlags
& flags
)
299 Property(const ObjectURI
& uri
,
300 as_function
* getter
, as_function
* setter
,
301 const PropFlags
& flags
, bool destroy
= false)
303 _bound(GetterSetter(getter
, setter
)),
306 _destructive(destroy
)
309 Property(const ObjectURI
& uri
, as_c_function_ptr getter
,
310 as_c_function_ptr setter
, const PropFlags
& flags
,
311 bool destroy
= false)
313 _bound(GetterSetter(getter
, setter
)),
316 _destructive(destroy
)
320 Property(const Property
& p
)
325 _destructive(p
._destructive
)
328 /// accessor to the properties flags
329 const PropFlags
& getFlags() const { return _flags
; }
331 /// Set the flags of the property
332 void setFlags(const PropFlags
& flags
) const {
336 /// Get value of this property
339 /// The as_object used to set the 'this' pointer.
340 /// for calling getter function (GetterSetterProperty);
341 /// it will be unused when getting or setting SimpleProperty
343 /// @return the value of this property
345 as_value
getValue(const as_object
& this_ptr
) const;
347 /// Get internal cached value of this property
349 /// For simple properties, this is the usual value;
350 /// for user-defined getter-setter this is a cached value
351 /// to watch for infinitely recurse on calling the getter
352 /// or setter; Native getter-setter has no cache,
353 /// undefined will be returned for them.
354 as_value
getCache() const;
356 /// Set internal cached value of this property
358 /// For simple properties, this is the usual value;
359 /// for user-defined getter-setter this is a cached value
360 /// to watch for infinitely recurse on calling the getter
361 /// or setter; Native getter-setter has no cache,
362 /// nothing would happen for them.
363 void setCache(const as_value
& v
);
365 /// Set value of this property
368 /// The as_object used to set the 'this' pointer.
369 /// for calling getter/setter function (GetterSetterProperty);
370 /// it will be unused when getting or setting SimpleProperty
372 /// This parameter is non-const as nothing prevents an
373 /// eventual "Setter" function from actually modifying it,
374 /// so we can't promise constness.
377 /// The new value for this property. It will be used as first
378 /// argument of the 'setter' function if this is a Getter/Setter
379 /// property. @see isGetterSetter().
380 void setValue(as_object
& this_ptr
, const as_value
&value
) const;
382 /// Is this a getter/setter property?
383 bool isGetterSetter() const {
384 return _bound
.type() == typeid(GetterSetter
);
387 /// Clear visibility flags
388 void clearVisible(int swfVersion
) { _flags
.clear_visible(swfVersion
); }
390 /// The name-namespace pair (ObjectURI) of this Property
391 const ObjectURI
& uri() const {
395 /// Mark this property as being reachable (for the GC)
396 void setReachable() const {
397 return boost::apply_visitor(SetReachable(), _bound
);
402 // Store the various types of things that can be held.
403 typedef boost::variant
<as_value
, GetterSetter
> BoundType
;
405 /// The value of the property.
406 mutable BoundType _bound
;
408 /// The property identifier (name).
412 mutable PropFlags _flags
;
414 // If true, as soon as getValue has been invoked once, the
415 // returned value becomes a fixed return (though it can be
416 // overwritten if not readOnly)
417 mutable bool _destructive
;
421 /// is this a read-only member ?
423 readOnly(const Property
& prop
) {
424 return prop
.getFlags().test
<PropFlags::readOnly
>();
427 /// Is this member supposed to be visible by a VM of given version ?
429 visible(const Property
& prop
, int version
) {
430 return prop
.getFlags().get_visible(version
);
435 #endif // GNASH_PROPERTY_H