Home | History | Annotate | Download | only in js
      1 /*
      2  * Copyright (C) 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2008 Apple Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #ifndef JSSVGPODTypeWrapper_h
     28 #define JSSVGPODTypeWrapper_h
     29 
     30 #if ENABLE(SVG)
     31 #include "JSSVGContextCache.h"
     32 #include "SVGElement.h"
     33 #include <wtf/StdLibExtras.h>
     34 
     35 namespace WebCore {
     36 
     37 class DOMObject;
     38 
     39 template<typename PODType>
     40 class JSSVGPODTypeWrapper : public RefCounted<JSSVGPODTypeWrapper<PODType> > {
     41 public:
     42     virtual ~JSSVGPODTypeWrapper() { }
     43 
     44     virtual operator PODType() = 0;
     45     virtual void commitChange(PODType, DOMObject*) = 0;
     46 };
     47 
     48 // This file contains JS wrapper objects for SVG datatypes, that are passed around by value
     49 // in WebCore/svg (aka. 'POD types'). For instance SVGMatrix is mapped to AffineTransform, and
     50 // passed around as const reference. SVG DOM demands these objects to be "live", changes to any
     51 // of the writable attributes of SVGMatrix need to be reflected in the object which exposed the
     52 // SVGMatrix object (i.e. 'someElement.transform.matrix.a = 50.0', in that case 'SVGTransform').
     53 // The SVGTransform class stores its "AffineTransform m_matrix" object on the stack. If it would
     54 // be stored as pointer we could just build an auto-generated JSSVG* wrapper object around it
     55 // and all changes to that object would automatically affect the AffineTransform* object stored
     56 // in the SVGTransform object. For the sake of efficiency and memory we don't pass around any
     57 // primitive values as pointers, so a custom JS wrapper object is needed for all SVG types, that
     58 // are internally represented by POD types (SVGRect <-> FloatRect, SVGPoint <-> FloatPoint, ...).
     59 // Those custom wrappers are called JSSVGPODTypeWrapper and are capable of updating the POD types
     60 // by taking function pointers to the getter & setter functions of the "creator object", the object
     61 // which exposed a SVG POD type. For example, the JSSVGPODTypeWrapper object wrapping a SVGMatrix
     62 // object takes (SVGTransform*, &SVGTransform::matrix, &SVGTransform::setMatrix). A JS call like
     63 // "someElement.transform.matrix.a = 50.0' causes the JSSVGMatrix object to call SVGTransform::setMatrix,
     64 // method, which in turn notifies 'someElement' that the 'SVGNames::transformAttr' has changed.
     65 // That's a short sketch of our SVG DOM implementation.
     66 
     67 // Represents a JS wrapper object for SVGAnimated* classes, exposing SVG POD types that contain writable properties
     68 // (Two cases: SVGAnimatedLength exposing SVGLength, SVGAnimatedRect exposing SVGRect)
     69 
     70 #if COMPILER(MSVC)
     71 // GetterMethod and SetterMethod are each 12 bytes. We have to pack to a size
     72 // greater than or equal to that to avoid an alignment warning (C4121). 16 is
     73 // the next-largest size allowed for packing, so we use that.
     74 #pragma pack(push, 16)
     75 #endif
     76 template<typename PODType, typename PODTypeCreator>
     77 class JSSVGDynamicPODTypeWrapper : public JSSVGPODTypeWrapper<PODType> {
     78 public:
     79     typedef PODType (PODTypeCreator::*GetterMethod)() const;
     80     typedef void (PODTypeCreator::*SetterMethod)(const PODType&);
     81 
     82     static PassRefPtr<JSSVGDynamicPODTypeWrapper> create(PassRefPtr<PODTypeCreator> creator, GetterMethod getter, SetterMethod setter)
     83     {
     84         return adoptRef(new JSSVGDynamicPODTypeWrapper(creator, getter, setter));
     85     }
     86 
     87     virtual operator PODType()
     88     {
     89         return (m_creator.get()->*m_getter)();
     90     }
     91 
     92     virtual void commitChange(PODType type, DOMObject* wrapper)
     93     {
     94         (m_creator.get()->*m_setter)(type);
     95         JSSVGContextCache::propagateSVGDOMChange(wrapper, m_creator->associatedAttributeName());
     96     }
     97 
     98 private:
     99     JSSVGDynamicPODTypeWrapper(PassRefPtr<PODTypeCreator> creator, GetterMethod getter, SetterMethod setter)
    100         : m_creator(creator)
    101         , m_getter(getter)
    102         , m_setter(setter)
    103     {
    104         ASSERT(m_creator);
    105         ASSERT(m_getter);
    106         ASSERT(m_setter);
    107     }
    108 
    109     virtual ~JSSVGDynamicPODTypeWrapper();
    110 
    111     // Update callbacks
    112     RefPtr<PODTypeCreator> m_creator;
    113     GetterMethod m_getter;
    114     SetterMethod m_setter;
    115 };
    116 #if COMPILER(MSVC)
    117 #pragma pack(pop)
    118 #endif
    119 
    120 // Represents a JS wrapper object for SVG POD types (not for SVGAnimated* classes). Any modification to the SVG POD
    121 // types don't cause any updates unlike JSSVGDynamicPODTypeWrapper. This class is used for return values (ie. getBBox())
    122 // and for properties where SVG specification explicitly states, that the contents of the POD type are immutable.
    123 
    124 template<typename PODType>
    125 class JSSVGStaticPODTypeWrapper : public JSSVGPODTypeWrapper<PODType> {
    126 public:
    127     static PassRefPtr<JSSVGStaticPODTypeWrapper> create(PODType type)
    128     {
    129         return adoptRef(new JSSVGStaticPODTypeWrapper(type));
    130     }
    131 
    132     virtual operator PODType()
    133     {
    134         return m_podType;
    135     }
    136 
    137     virtual void commitChange(PODType type, DOMObject*)
    138     {
    139         m_podType = type;
    140     }
    141 
    142 protected:
    143     JSSVGStaticPODTypeWrapper(PODType type)
    144         : m_podType(type)
    145     {
    146     }
    147 
    148     PODType m_podType;
    149 };
    150 
    151 template<typename PODType, typename ParentTypeArg>
    152 class JSSVGStaticPODTypeWrapperWithPODTypeParent : public JSSVGStaticPODTypeWrapper<PODType> {
    153 public:
    154     typedef JSSVGPODTypeWrapper<ParentTypeArg> ParentType;
    155 
    156     static PassRefPtr<JSSVGStaticPODTypeWrapperWithPODTypeParent> create(PODType type, PassRefPtr<ParentType> parent)
    157     {
    158         return adoptRef(new JSSVGStaticPODTypeWrapperWithPODTypeParent(type, parent));
    159     }
    160 
    161     virtual void commitChange(PODType type, DOMObject* wrapper)
    162     {
    163         JSSVGStaticPODTypeWrapper<PODType>::commitChange(type, wrapper);
    164         m_parentType->commitChange(ParentTypeArg(type), wrapper);
    165     }
    166 
    167 private:
    168     JSSVGStaticPODTypeWrapperWithPODTypeParent(PODType type, PassRefPtr<ParentType> parent)
    169         : JSSVGStaticPODTypeWrapper<PODType>(type)
    170         , m_parentType(parent)
    171     {
    172     }
    173 
    174     RefPtr<ParentType> m_parentType;
    175 };
    176 
    177 #if COMPILER(MSVC)
    178 // GetterMethod and SetterMethod are each 12 bytes. We have to pack to a size
    179 // greater than or equal to that to avoid an alignment warning (C4121). 16 is
    180 // the next-largest size allowed for packing, so we use that.
    181 #pragma pack(push, 16)
    182 #endif
    183 template<typename PODType, typename ParentType>
    184 class JSSVGStaticPODTypeWrapperWithParent : public JSSVGPODTypeWrapper<PODType> {
    185 public:
    186     typedef PODType (ParentType::*GetterMethod)() const;
    187     typedef void (ParentType::*SetterMethod)(const PODType&);
    188 
    189     static PassRefPtr<JSSVGStaticPODTypeWrapperWithParent> create(PassRefPtr<ParentType> parent, GetterMethod getter, SetterMethod setter)
    190     {
    191         return adoptRef(new JSSVGStaticPODTypeWrapperWithParent(parent, getter, setter));
    192     }
    193 
    194     virtual operator PODType()
    195     {
    196         return (m_parent.get()->*m_getter)();
    197     }
    198 
    199     virtual void commitChange(PODType type, DOMObject*)
    200     {
    201         (m_parent.get()->*m_setter)(type);
    202     }
    203 
    204 private:
    205     JSSVGStaticPODTypeWrapperWithParent(PassRefPtr<ParentType> parent, GetterMethod getter, SetterMethod setter)
    206         : m_parent(parent)
    207         , m_getter(getter)
    208         , m_setter(setter)
    209     {
    210         ASSERT(m_parent);
    211         ASSERT(m_getter);
    212         ASSERT(m_setter);
    213     }
    214 
    215     // Update callbacks
    216     RefPtr<ParentType> m_parent;
    217     GetterMethod m_getter;
    218     SetterMethod m_setter;
    219 };
    220 
    221 template<typename PODType>
    222 class SVGPODListItem;
    223 
    224 // Just like JSSVGDynamicPODTypeWrapper, but only used for SVGList* objects wrapping around POD values.
    225 
    226 template<typename PODType>
    227 class JSSVGPODTypeWrapperCreatorForList : public JSSVGPODTypeWrapper<PODType> {
    228 public:
    229     typedef SVGPODListItem<PODType> PODListItemPtrType;
    230 
    231     typedef PODType (SVGPODListItem<PODType>::*GetterMethod)() const;
    232     typedef void (SVGPODListItem<PODType>::*SetterMethod)(const PODType&);
    233 
    234     static PassRefPtr<JSSVGPODTypeWrapperCreatorForList> create(PassRefPtr<PODListItemPtrType> creator, const QualifiedName& attributeName)
    235     {
    236         return adoptRef(new JSSVGPODTypeWrapperCreatorForList(creator, attributeName));
    237     }
    238 
    239     virtual operator PODType()
    240     {
    241         return (m_creator.get()->*m_getter)();
    242     }
    243 
    244     virtual void commitChange(PODType type, DOMObject* wrapper)
    245     {
    246         if (!m_setter)
    247             return;
    248 
    249         (m_creator.get()->*m_setter)(type);
    250         JSSVGContextCache::propagateSVGDOMChange(wrapper, m_associatedAttributeName);
    251     }
    252 
    253 private:
    254     JSSVGPODTypeWrapperCreatorForList(PassRefPtr<PODListItemPtrType> creator, const QualifiedName& attributeName)
    255         : m_creator(creator)
    256         , m_getter(&PODListItemPtrType::value)
    257         , m_setter(&PODListItemPtrType::setValue)
    258         , m_associatedAttributeName(attributeName)
    259     {
    260         ASSERT(m_creator);
    261         ASSERT(m_getter);
    262         ASSERT(m_setter);
    263     }
    264 
    265     // Update callbacks
    266     RefPtr<PODListItemPtrType> m_creator;
    267     GetterMethod m_getter;
    268     SetterMethod m_setter;
    269     const QualifiedName& m_associatedAttributeName;
    270 };
    271 
    272 // Caching facilities
    273 template<typename PODType, typename PODTypeCreator>
    274 struct PODTypeWrapperCacheInfo {
    275     typedef PODType (PODTypeCreator::*GetterMethod)() const;
    276     typedef void (PODTypeCreator::*SetterMethod)(const PODType&);
    277 
    278     // Empty value
    279     PODTypeWrapperCacheInfo()
    280         : creator(0)
    281         , getter(0)
    282         , setter(0)
    283     {
    284     }
    285 
    286     // Deleted value
    287     PODTypeWrapperCacheInfo(WTF::HashTableDeletedValueType)
    288         : creator(reinterpret_cast<PODTypeCreator*>(-1))
    289         , getter(0)
    290         , setter(0)
    291     {
    292     }
    293     bool isHashTableDeletedValue() const
    294     {
    295         return creator == reinterpret_cast<PODTypeCreator*>(-1);
    296     }
    297 
    298     PODTypeWrapperCacheInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter)
    299         : creator(_creator)
    300         , getter(_getter)
    301         , setter(_setter)
    302     {
    303         ASSERT(creator);
    304         ASSERT(getter);
    305     }
    306 
    307     bool operator==(const PODTypeWrapperCacheInfo& other) const
    308     {
    309         return creator == other.creator && getter == other.getter && setter == other.setter;
    310     }
    311 
    312     PODTypeCreator* creator;
    313     GetterMethod getter;
    314     SetterMethod setter;
    315 };
    316 #if COMPILER(MSVC)
    317 #pragma pack(pop)
    318 #endif
    319 
    320 template<typename PODType, typename PODTypeCreator>
    321 struct PODTypeWrapperCacheInfoHash {
    322     typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo;
    323 
    324     static unsigned hash(const CacheInfo& info)
    325     {
    326         return StringImpl::computeHash(reinterpret_cast<const UChar*>(&info), sizeof(CacheInfo) / sizeof(UChar));
    327     }
    328 
    329     static bool equal(const CacheInfo& a, const CacheInfo& b)
    330     {
    331         return a == b;
    332     }
    333 
    334     static const bool safeToCompareToEmptyOrDeleted = true;
    335 };
    336 
    337 template<typename PODType, typename PODTypeCreator>
    338 struct PODTypeWrapperCacheInfoTraits : WTF::GenericHashTraits<PODTypeWrapperCacheInfo<PODType, PODTypeCreator> > {
    339     typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo;
    340 
    341     static const bool emptyValueIsZero = true;
    342     static const bool needsDestruction = false;
    343 
    344     static const CacheInfo& emptyValue()
    345     {
    346         DEFINE_STATIC_LOCAL(CacheInfo, key, ());
    347         return key;
    348     }
    349 
    350     static void constructDeletedValue(CacheInfo& slot)
    351     {
    352         new (&slot) CacheInfo(WTF::HashTableDeletedValue);
    353     }
    354 
    355     static bool isDeletedValue(const CacheInfo& value)
    356     {
    357         return value.isHashTableDeletedValue();
    358     }
    359 };
    360 
    361 // Used for dynamic read-write attributes
    362 template<typename PODType, typename PODTypeCreator>
    363 class JSSVGDynamicPODTypeWrapperCache {
    364 public:
    365     typedef PODType (PODTypeCreator::*GetterMethod)() const;
    366     typedef void (PODTypeCreator::*SetterMethod)(const PODType&);
    367 
    368     typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo;
    369     typedef PODTypeWrapperCacheInfoHash<PODType, PODTypeCreator> CacheInfoHash;
    370     typedef PODTypeWrapperCacheInfoTraits<PODType, PODTypeCreator> CacheInfoTraits;
    371 
    372     typedef JSSVGPODTypeWrapper<PODType> WrapperBase;
    373     typedef JSSVGDynamicPODTypeWrapper<PODType, PODTypeCreator> Wrapper;
    374     typedef HashMap<CacheInfo, Wrapper*, CacheInfoHash, CacheInfoTraits> WrapperMap;
    375 
    376     static WrapperMap& wrapperMap()
    377     {
    378         DEFINE_STATIC_LOCAL(WrapperMap, s_wrapperMap, ());
    379         return s_wrapperMap;
    380     }
    381 
    382     static PassRefPtr<WrapperBase> lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
    383     {
    384         CacheInfo info(creator, getter, setter);
    385         pair<typename WrapperMap::iterator, bool> result = wrapperMap().add(info, 0);
    386         if (!result.second) // pre-existing entry
    387             return result.first->second;
    388 
    389         RefPtr<Wrapper> wrapper = Wrapper::create(creator, getter, setter);
    390         result.first->second = wrapper.get();
    391         return wrapper.release();
    392     }
    393 
    394     static void forgetWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
    395     {
    396         CacheInfo info(creator, getter, setter);
    397         wrapperMap().remove(info);
    398     }
    399 };
    400 
    401 template<typename PODType, typename PODTypeCreator>
    402 JSSVGDynamicPODTypeWrapper<PODType, PODTypeCreator>::~JSSVGDynamicPODTypeWrapper()
    403 {
    404     JSSVGDynamicPODTypeWrapperCache<PODType, PODTypeCreator>::forgetWrapper(m_creator.get(), m_getter, m_setter);
    405 }
    406 
    407 } // namespace WebCore
    408 
    409 #endif // ENABLE(SVG)
    410 #endif // JSSVGPODTypeWrapper_h
    411