Gnash  0.8.10
Property.h
Go to the documentation of this file.
00001 // 
00002 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
00003 //   Free Software Foundation, Inc
00004 // 
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 3 of the License, or
00008 // (at your option) any later version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 
00020 #ifndef GNASH_PROPERTY_H
00021 #define GNASH_PROPERTY_H
00022 
00023 #include <boost/variant.hpp>
00024 #include <cassert>
00025 #include <boost/bind.hpp>
00026 #include <typeinfo>
00027 
00028 #include "PropFlags.h"
00029 #include "as_value.h"
00030 #include "ObjectURI.h"
00031 
00032 namespace gnash {
00033     typedef as_value (*as_c_function_ptr)(const fn_call& fn);
00034     class as_function;
00035 }
00036 
00037 namespace gnash {
00038 
00040 //
00043 class GetterSetter
00044 {
00045     class NativeGetterSetter;
00046 
00047     // The following helper structs define common operations on the 
00048     // Two types of GetterSetter. Some operations are applicable only to
00049     // one type.
00050 
00052     //
00056     template<typename Arg, typename S>
00057     struct GetSetVisitor : boost::static_visitor<typename S::result_type>
00058     {
00059         GetSetVisitor(const Arg& arg) : _arg(arg) {}
00060         template<typename T> typename S::result_type operator()(T& t) const {
00061             return S()(t, _arg);
00062         }
00063     private:
00064         const Arg& _arg;
00065     };
00066 
00068     struct Set
00069     {
00070         typedef void result_type;
00071         template<typename T, typename Arg>
00072         result_type operator()(T& t, Arg& a) const {
00073             t.set(a);
00074         }
00075     };
00076                                 
00078     struct Get
00079     {
00080         typedef as_value result_type;
00081         template<typename T, typename Arg>
00082         result_type operator()(T& t, Arg& a) const {
00083             return t.get(a);
00084         }
00085     };
00086 
00088     //
00090     struct SetUnderlying : boost::static_visitor<>
00091     {
00092         template<typename T>
00093         result_type operator()(T& gs, const as_value& val) const {
00094             gs.setUnderlying(val);
00095         }
00096         result_type operator()(NativeGetterSetter&, const as_value&) const {}
00097     };
00098     
00100     //
00102     struct GetUnderlying : boost::static_visitor<as_value>
00103     {
00104         template<typename T>
00105         result_type operator()(const T& gs) const {
00106             return gs.getUnderlying();
00107         }
00108         result_type operator()(const NativeGetterSetter&) const {
00109             return result_type();
00110         }
00111     };
00112     
00114     struct MarkReachable : boost::static_visitor<>
00115     {
00116         template<typename T>
00117         result_type operator()(const T& gs) const {
00118             gs.markReachableResources();
00119         }
00120     };
00121 
00122 public:
00123 
00125         GetterSetter(as_function* getter, as_function* setter)
00126                 :
00127                 _getset(UserDefinedGetterSetter(getter, setter))
00128         {}
00129 
00131         GetterSetter(as_c_function_ptr getter, as_c_function_ptr setter)
00132                 :
00133                 _getset(NativeGetterSetter(getter, setter))
00134         {}
00135 
00137         as_value get(fn_call& fn) const {
00138         GetSetVisitor<const fn_call, Get> s(fn);
00139         return boost::apply_visitor(s, _getset);
00140         }
00141 
00143         void set(const fn_call& fn) {
00144         GetSetVisitor<fn_call, Set> s(fn);
00145         boost::apply_visitor(s, _getset);
00146         }
00147 
00149         void setCache(const as_value& v) {
00150         boost::apply_visitor(boost::bind(SetUnderlying(), _1, v), _getset);
00151     }
00152 
00154         as_value getCache() const {
00155         return boost::apply_visitor(GetUnderlying(), _getset);
00156         }
00157 
00158         void markReachableResources() const {
00159         boost::apply_visitor(MarkReachable(), _getset);
00160         }
00161 
00162 private:
00163 
00165         class UserDefinedGetterSetter
00166     {
00167         public:
00168 
00169                 UserDefinedGetterSetter(as_function* get, as_function* set)
00170                         :
00171                         _getter(get),
00172                         _setter(set),
00173                         _underlyingValue(),
00174                         _beingAccessed(false)
00175                 {}
00176 
00178                 as_value get(const fn_call& fn) const;
00179 
00181                 void set(const fn_call& fn);
00182 
00184                 const as_value& getUnderlying() const { return _underlyingValue; }
00185 
00187                 void setUnderlying(const as_value& v) { _underlyingValue = v; }
00188 
00189                 void markReachableResources() const;
00190 
00191         private:
00192 
00196         //
00199                 class ScopedLock : boost::noncopyable
00200         {
00201                 public:
00202 
00203                         explicit ScopedLock(const UserDefinedGetterSetter& na)
00204                 :
00205                 _a(na),
00206                 _obtainedLock(_a._beingAccessed ? false : true)
00207                         {
00208                 // If we didn't obtain the lock it would be true anyway,
00209                 // but it's probably polite to avoid touching it.
00210                 if (_obtainedLock) _a._beingAccessed = true;
00211                         }
00212 
00213                         ~ScopedLock() { if ( _obtainedLock) _a._beingAccessed = false; }
00214 
00216                         //
00221                         bool obtainedLock() const { return _obtainedLock; }
00222 
00223         private:
00224 
00225                         const UserDefinedGetterSetter& _a;
00226                         bool _obtainedLock;
00227 
00228         };
00229 
00230                 as_function* _getter;
00231                 as_function* _setter;
00232                 as_value _underlyingValue;
00233                 mutable bool _beingAccessed;
00234     };
00235 
00237         class NativeGetterSetter 
00238     {
00239         public:
00240 
00241                 NativeGetterSetter(as_c_function_ptr get, as_c_function_ptr set)
00242                         :
00243                         _getter(get), _setter(set) {}
00244 
00246                 as_value get(const fn_call& fn) const {
00247                         return _getter(fn);
00248                 }
00249 
00251                 void set(const fn_call& fn) {
00252                         _setter(fn);
00253                 }
00254 
00256         void markReachableResources() const {}
00257 
00258         private:
00259                 as_c_function_ptr _getter;
00260                 as_c_function_ptr _setter;
00261         };
00262 
00263         boost::variant<UserDefinedGetterSetter, NativeGetterSetter> _getset;
00264 
00265 };
00266 
00268 //
00270 //
00274 class Property
00275 {
00276 
00278     struct SetReachable : boost::static_visitor<>
00279     {
00280         result_type operator()(const as_value& val) const {
00281             val.setReachable();
00282         }
00283         result_type operator()(const GetterSetter& gs) const {
00284             return gs.markReachableResources();
00285         }
00286     };
00287 
00288 public:
00289 
00290         Property(const ObjectURI& uri, const as_value& value,
00291             const PropFlags& flags)
00292         :
00293         _bound(value),
00294                 _uri(uri),
00295                 _flags(flags),
00296         _destructive(false)
00297         {}
00298 
00299         Property(const ObjectURI& uri,
00300                 as_function* getter, as_function* setter, 
00301                 const PropFlags& flags, bool destroy = false)
00302         :
00303         _bound(GetterSetter(getter, setter)),
00304         _uri(uri),
00305                 _flags(flags), 
00306                 _destructive(destroy)
00307         {}
00308 
00309         Property(const ObjectURI& uri, as_c_function_ptr getter,
00310             as_c_function_ptr setter, const PropFlags& flags,
00311             bool destroy = false)
00312                 :
00313         _bound(GetterSetter(getter, setter)),
00314         _uri(uri),
00315                 _flags(flags),
00316         _destructive(destroy)
00317         {}
00318 
00320         Property(const Property& p)
00321         :
00322         _bound(p._bound),
00323         _uri(p._uri),
00324                 _flags(p._flags),
00325         _destructive(p._destructive)
00326         {}
00327 
00329         const PropFlags& getFlags() const { return _flags; }
00330 
00332     void setFlags(const PropFlags& flags) const {
00333         _flags = flags;
00334     }
00335 
00337         //
00345         as_value getValue(const as_object& this_ptr) const;
00346 
00348         //
00354         as_value getCache() const;
00355 
00357         //
00363         void setCache(const as_value& v);
00364 
00366         //
00381         bool setValue(as_object& this_ptr, const as_value &value) const;
00382 
00384         bool isGetterSetter() const {
00385         return _bound.type() == typeid(GetterSetter);
00386     }
00387 
00389         void clearVisible(int swfVersion) { _flags.clear_visible(swfVersion); }
00390 
00392     const ObjectURI& uri() const {
00393         return _uri;
00394     }
00395 
00397         void setReachable() const {
00398         return boost::apply_visitor(SetReachable(), _bound);
00399     }
00400 
00401 private:
00402 
00403         // Store the various types of things that can be held.
00404         typedef boost::variant<as_value, GetterSetter> BoundType;
00405 
00407         mutable BoundType _bound;
00408         
00410     ObjectURI _uri;
00411 
00413         mutable PropFlags _flags;
00414 
00415         // If true, as soon as getValue has been invoked once, the
00416         // returned value becomes a fixed return (though it can be
00417         // overwritten if not readOnly)
00418         mutable bool _destructive;
00419 
00420 };
00421         
00423 inline bool
00424 readOnly(const Property& prop) {
00425     return prop.getFlags().test<PropFlags::readOnly>();
00426 }
00427 
00429 inline bool
00430 visible(const Property& prop, int version) {
00431     return prop.getFlags().get_visible(version);
00432 }
00433 
00434 } // namespace gnash
00435 
00436 #endif // GNASH_PROPERTY_H