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