2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // 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>
28 #include "PropFlags.h"
30 #include "ObjectURI.h"
31 #include "dsodefs.h" // for DSOTEXPORT
34 typedef as_value (*as_c_function_ptr
)(const fn_call
& fn
);
40 /// Holder for getter/setter functions
42 /// Getter setter can be user-defined or native ones.
43 /// This class abstracts the two.
46 class NativeGetterSetter
;
48 // The following helper structs define common operations on the
49 // Two types of GetterSetter. Some operations are applicable only to
52 /// Get or set a GetterSetter
54 /// @tparam S A type that determines what operation to call on the
56 /// @param Arg The type of the argument to the get or set function.
57 template<typename Arg
, typename S
>
58 struct GetSetVisitor
: boost::static_visitor
<typename
S::result_type
>
60 GetSetVisitor(const Arg
& arg
) : _arg(arg
) {}
61 template<typename T
> typename
S::result_type
operator()(T
& t
) const {
68 /// Set a GetterSetter
71 typedef void result_type
;
72 template<typename T
, typename Arg
>
73 result_type
operator()(T
& t
, Arg
& a
) const {
78 /// Get a GetterSetter
81 typedef as_value result_type
;
82 template<typename T
, typename Arg
>
83 result_type
operator()(T
& t
, Arg
& a
) const {
88 /// Set the underlying value of a GetterSetter
90 /// This does not apply to NativeGetterSetters.
91 struct SetUnderlying
: boost::static_visitor
<>
94 result_type
operator()(T
& gs
, const as_value
& val
) const {
95 gs
.setUnderlying(val
);
97 result_type
operator()(NativeGetterSetter
&, const as_value
&) const {}
100 /// Get the underlying value of a GetterSetter
102 /// This does not apply to NativeGetterSetters.
103 struct GetUnderlying
: boost::static_visitor
<as_value
>
106 result_type
operator()(const T
& gs
) const {
107 return gs
.getUnderlying();
109 result_type
operator()(const NativeGetterSetter
&) const {
110 return result_type();
114 /// Mark a GetterSetter reachable
115 struct MarkReachable
: boost::static_visitor
<>
118 result_type
operator()(const T
& gs
) const {
119 gs
.markReachableResources();
125 /// Construct a user-defined getter-setter
126 GetterSetter(as_function
* getter
, as_function
* setter
)
128 _getset(UserDefinedGetterSetter(getter
, setter
))
131 /// Construct a native getter-setter
132 GetterSetter(as_c_function_ptr getter
, as_c_function_ptr setter
)
134 _getset(NativeGetterSetter(getter
, setter
))
137 /// Invoke the getter
138 as_value
get(fn_call
& fn
) const {
139 GetSetVisitor
<const fn_call
, Get
> s(fn
);
140 return boost::apply_visitor(s
, _getset
);
143 /// Invoke the setter
144 void set(const fn_call
& fn
) {
145 GetSetVisitor
<fn_call
, Set
> s(fn
);
146 boost::apply_visitor(s
, _getset
);
149 /// Set the cache value (for user-defined getter-setters)
150 void setCache(const as_value
& v
) {
151 boost::apply_visitor(
152 std::bind(SetUnderlying(), std::placeholders::_1
, v
), _getset
);
155 /// Get the cache value (for user-defined getter-setters)
156 as_value
getCache() const {
157 return boost::apply_visitor(GetUnderlying(), _getset
);
160 void markReachableResources() const {
161 boost::apply_visitor(MarkReachable(), _getset
);
166 /// User-defined getter/setter
167 class UserDefinedGetterSetter
171 UserDefinedGetterSetter(as_function
* get
, as_function
* set
)
176 _beingAccessed(false)
179 /// Invoke the getter
180 as_value
get(const fn_call
& fn
) const;
182 /// Invoke the setter
183 void set(const fn_call
& fn
);
185 /// Get the underlying value
186 const as_value
& getUnderlying() const { return _underlyingValue
; }
188 /// Set the underlying value
189 void setUnderlying(const as_value
& v
) { _underlyingValue
= v
; }
191 void markReachableResources() const;
195 /// For SWF6 (not higher) a user-defined getter-setter would not
196 /// be invoked while being set. This ScopedLock helps marking a
197 /// Getter-Setter as being invoked in an exception-safe manner.
199 /// Note this is not thread safe and does not attempt to provide
201 class ScopedLock
: boost::noncopyable
205 explicit ScopedLock(const UserDefinedGetterSetter
& na
)
208 _obtainedLock(_a
._beingAccessed
? false : true)
210 // If we didn't obtain the lock it would be true anyway,
211 // but it's probably polite to avoid touching it.
212 if (_obtainedLock
) _a
._beingAccessed
= true;
215 ~ScopedLock() { if ( _obtainedLock
) _a
._beingAccessed
= false; }
217 /// Return true if the lock was obtained
219 /// If false is returned, we're being called recursively,
220 /// which means we should set the underlyingValue instead
221 /// of calling the setter (for SWF6, again).
223 bool obtainedLock() const { return _obtainedLock
; }
227 const UserDefinedGetterSetter
& _a
;
232 as_function
* _getter
;
233 as_function
* _setter
;
234 as_value _underlyingValue
;
235 mutable bool _beingAccessed
;
238 /// Native GetterSetter
239 class NativeGetterSetter
243 NativeGetterSetter(as_c_function_ptr get
, as_c_function_ptr set
)
245 _getter(get
), _setter(set
) {}
247 /// Invoke the getter
248 as_value
get(const fn_call
& fn
) const {
252 /// Invoke the setter
253 void set(const fn_call
& fn
) {
257 /// Nothing to do for native setters.
258 void markReachableResources() const {}
261 as_c_function_ptr _getter
;
262 as_c_function_ptr _setter
;
265 boost::variant
<UserDefinedGetterSetter
, NativeGetterSetter
> _getset
;
269 /// An abstract property
271 /// A Property is a holder for a value or a getter-setter.
273 /// Properties have special const semantics: the value of a Property does
274 /// not affect its outward state, so the value of a const Property can be
279 /// Mark the stored value reachable.
280 struct SetReachable
: boost::static_visitor
<>
282 result_type
operator()(const as_value
& val
) const {
285 result_type
operator()(const GetterSetter
& gs
) const {
286 return gs
.markReachableResources();
292 Property(ObjectURI uri
, const as_value
& value
,
296 _uri(std::move(uri
)),
297 _flags(std::move(flags
)),
301 Property(ObjectURI uri
,
302 as_function
* getter
, as_function
* setter
,
303 PropFlags flags
, bool destroy
= false)
305 _bound(GetterSetter(getter
, setter
)),
306 _uri(std::move(uri
)),
307 _flags(std::move(flags
)),
308 _destructive(destroy
)
311 Property(ObjectURI uri
, as_c_function_ptr getter
,
312 as_c_function_ptr setter
, PropFlags flags
,
313 bool destroy
= false)
315 _bound(GetterSetter(getter
, setter
)),
316 _uri(std::move(uri
)),
317 _flags(std::move(flags
)),
318 _destructive(destroy
)
321 /// accessor to the properties flags
322 const PropFlags
& getFlags() const { return _flags
; }
324 /// Set the flags of the property
325 void setFlags(const PropFlags
& flags
) const {
329 /// Get value of this property
332 /// The as_object used to set the 'this' pointer.
333 /// for calling getter function (GetterSetterProperty);
334 /// it will be unused when getting or setting SimpleProperty
336 /// @return the value of this property
338 DSOTEXPORT as_value
getValue(const as_object
& this_ptr
) const;
340 /// Get internal cached value of this property
342 /// For simple properties, this is the usual value;
343 /// for user-defined getter-setter this is a cached value
344 /// to watch for infinitely recurse on calling the getter
345 /// or setter; Native getter-setter has no cache,
346 /// undefined will be returned for them.
347 as_value
getCache() const;
349 /// Set internal cached value of this property
351 /// For simple properties, this is the usual value;
352 /// for user-defined getter-setter this is a cached value
353 /// to watch for infinitely recurse on calling the getter
354 /// or setter; Native getter-setter has no cache,
355 /// nothing would happen for them.
356 void setCache(const as_value
& v
);
358 /// Set value of this property
360 /// @param this_ptr The as_object used to set the 'this' pointer
361 /// for calling getter/setter function
362 /// It will be unused when getting or setting
363 /// simple properties.
364 /// This parameter is non-const as nothing prevents an
365 /// eventual "Setter" function from actually modifying it,
366 /// so we can't promise constness.
367 /// @param value The new value for this property. It will be used as first
368 /// argument of the 'setter' function if this is a Getter/Setter
369 /// property. @see isGetterSetter().
370 /// @return true if the property was set, otherwise false. Read-only
371 /// properties can generally not be set, but destructive
372 /// properties are still allowed to be replaced, as this
373 /// should be invisible to the user.
374 bool setValue(as_object
& this_ptr
, const as_value
&value
) const;
376 /// Is this a getter/setter property?
377 bool isGetterSetter() const {
378 return _bound
.type() == typeid(GetterSetter
);
381 /// Clear visibility flags
382 void clearVisible(int swfVersion
) { _flags
.clear_visible(swfVersion
); }
384 /// The name-namespace pair (ObjectURI) of this Property
385 const ObjectURI
& uri() const {
389 /// Mark this property as being reachable (for the GC)
390 void setReachable() const {
391 return boost::apply_visitor(SetReachable(), _bound
);
396 // Store the various types of things that can be held.
397 typedef boost::variant
<as_value
, GetterSetter
> BoundType
;
399 /// The value of the property.
400 mutable BoundType _bound
;
402 /// The property identifier (name).
406 mutable PropFlags _flags
;
408 // If true, as soon as getValue has been invoked once, the
409 // returned value becomes a fixed return (though it can be
410 // overwritten if not readOnly)
411 mutable bool _destructive
;
415 /// is this a read-only member ?
417 readOnly(const Property
& prop
) {
418 return prop
.getFlags().test
<PropFlags::readOnly
>();
421 /// Is this member supposed to be visible by a VM of given version ?
423 visible(const Property
& prop
, int version
) {
424 return prop
.getFlags().get_visible(version
);
429 #endif // GNASH_PROPERTY_H