blob: b6e47af897c46994163af35ea1dfd27fc2230fe8 [file] [log] [blame]
/*
* Copyright (C) 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008, 2009 Google. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef V8SVGPODTypeWrapper_h
#define V8SVGPODTypeWrapper_h
#if ENABLE(SVG)
#include <utility>
#include "SVGElement.h"
#include "SVGList.h"
#include "V8Proxy.h"
#include <wtf/Assertions.h>
#include <wtf/HashFunctions.h>
#include <wtf/HashMap.h>
#include <wtf/RefCounted.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
template<typename PODType>
class V8SVGPODTypeWrapper : public RefCounted<V8SVGPODTypeWrapper<PODType> > {
public:
V8SVGPODTypeWrapper() { }
virtual ~V8SVGPODTypeWrapper() { }
virtual operator PODType() = 0;
virtual void commitChange(PODType, SVGElement*) = 0;
};
template<typename PODType>
class V8SVGPODTypeWrapperCreatorForList : public V8SVGPODTypeWrapper<PODType> {
public:
typedef SVGPODListItem<PODType> PODListItemPtrType;
typedef PODType (SVGPODListItem<PODType>::*GetterMethod)() const;
typedef void (SVGPODListItem<PODType>::*SetterMethod)(PODType);
static PassRefPtr<V8SVGPODTypeWrapperCreatorForList> create(PassRefPtr<PODListItemPtrType> creator, const QualifiedName& attributeName)
{
return adoptRef(new V8SVGPODTypeWrapperCreatorForList(creator, attributeName));
}
virtual ~V8SVGPODTypeWrapperCreatorForList() { }
// Getter wrapper
virtual operator PODType() { return (m_creator.get()->*m_getter)(); }
// Setter wrapper
virtual void commitChange(PODType type, SVGElement* context)
{
if (!m_setter)
return;
(m_creator.get()->*m_setter)(type);
if (context)
context->svgAttributeChanged(m_associatedAttributeName);
}
private:
V8SVGPODTypeWrapperCreatorForList(PassRefPtr<PODListItemPtrType> creator, const QualifiedName& attributeName)
: m_creator(creator)
, m_getter(&SVGPODListItem<PODType>::value)
, m_setter(&SVGPODListItem<PODType>::setValue)
, m_associatedAttributeName(attributeName)
{
ASSERT(m_creator);
ASSERT(m_getter);
ASSERT(m_setter);
}
// Update callbacks
RefPtr<SVGPODListItem<PODType> > m_creator;
GetterMethod m_getter;
SetterMethod m_setter;
const QualifiedName& m_associatedAttributeName;
};
template<typename PODType>
class V8SVGStaticPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> {
public:
static PassRefPtr<V8SVGStaticPODTypeWrapper> create(PODType type)
{
return adoptRef(new V8SVGStaticPODTypeWrapper(type));
}
virtual ~V8SVGStaticPODTypeWrapper() { }
// Getter wrapper
virtual operator PODType() { return m_podType; }
// Setter wrapper
virtual void commitChange(PODType type, SVGElement*)
{
m_podType = type;
}
protected:
V8SVGStaticPODTypeWrapper(PODType type)
: m_podType(type)
{
}
PODType m_podType;
};
template<typename PODType, typename ParentTypeArg>
class V8SVGStaticPODTypeWrapperWithPODTypeParent : public V8SVGStaticPODTypeWrapper<PODType> {
public:
typedef V8SVGPODTypeWrapper<ParentTypeArg> ParentType;
static PassRefPtr<V8SVGStaticPODTypeWrapperWithPODTypeParent> create(PODType type, PassRefPtr<ParentType> parent)
{
return adoptRef(new V8SVGStaticPODTypeWrapperWithPODTypeParent(type, parent));
}
virtual void commitChange(PODType type, SVGElement* context)
{
V8SVGStaticPODTypeWrapper<PODType>::commitChange(type, context);
m_parentType->commitChange(ParentTypeArg(type), context);
}
private:
V8SVGStaticPODTypeWrapperWithPODTypeParent(PODType type, PassRefPtr<ParentType> parent)
: V8SVGStaticPODTypeWrapper<PODType>(type)
, m_parentType(parent)
{
}
RefPtr<ParentType> m_parentType;
};
template<typename PODType, typename ParentType>
class V8SVGStaticPODTypeWrapperWithParent : public V8SVGPODTypeWrapper<PODType> {
public:
typedef PODType (ParentType::*GetterMethod)() const;
typedef void (ParentType::*SetterMethod)(const PODType&);
static PassRefPtr<V8SVGStaticPODTypeWrapperWithParent> create(PassRefPtr<ParentType> parent, GetterMethod getter, SetterMethod setter)
{
return adoptRef(new V8SVGStaticPODTypeWrapperWithParent(parent, getter, setter));
}
virtual operator PODType()
{
return (m_parent.get()->*m_getter)();
}
virtual void commitChange(PODType type, SVGElement* context)
{
(m_parent.get()->*m_setter)(type);
}
private:
V8SVGStaticPODTypeWrapperWithParent(PassRefPtr<ParentType> parent, GetterMethod getter, SetterMethod setter)
: m_parent(parent)
, m_getter(getter)
, m_setter(setter)
{
ASSERT(m_parent);
ASSERT(m_getter);
ASSERT(m_setter);
}
RefPtr<ParentType> m_parent;
GetterMethod m_getter;
SetterMethod m_setter;
};
template<typename PODType, typename PODTypeCreator>
class V8SVGDynamicPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> {
public:
typedef PODType (PODTypeCreator::*GetterMethod)() const;
typedef void (PODTypeCreator::*SetterMethod)(PODType);
typedef void (*CacheRemovalCallback)(V8SVGPODTypeWrapper<PODType>*);
static PassRefPtr<V8SVGDynamicPODTypeWrapper> create(PassRefPtr<PODTypeCreator> creator, GetterMethod getter, SetterMethod setter, CacheRemovalCallback cacheRemovalCallback)
{
return adoptRef(new V8SVGDynamicPODTypeWrapper(creator, getter, setter, cacheRemovalCallback));
}
virtual ~V8SVGDynamicPODTypeWrapper() {
ASSERT(m_cacheRemovalCallback);
(*m_cacheRemovalCallback)(this);
}
// Getter wrapper
virtual operator PODType() { return (m_creator.get()->*m_getter)(); }
// Setter wrapper
virtual void commitChange(PODType type, SVGElement* context)
{
(m_creator.get()->*m_setter)(type);
if (context)
context->svgAttributeChanged(m_creator->associatedAttributeName());
}
private:
V8SVGDynamicPODTypeWrapper(PassRefPtr<PODTypeCreator> creator, GetterMethod getter, SetterMethod setter, CacheRemovalCallback cacheRemovalCallback)
: m_creator(creator)
, m_getter(getter)
, m_setter(setter)
, m_cacheRemovalCallback(cacheRemovalCallback)
{
ASSERT(m_creator); // |creator|'s pointer was taken by m_creator.
ASSERT(getter);
ASSERT(setter);
ASSERT(cacheRemovalCallback);
}
// Update callbacks
RefPtr<PODTypeCreator> m_creator;
GetterMethod m_getter;
SetterMethod m_setter;
CacheRemovalCallback m_cacheRemovalCallback;
};
// Caching facilities
template<typename PODType, typename PODTypeCreator>
struct PODTypeWrapperCacheInfo {
typedef PODType (PODTypeCreator::*GetterMethod)() const;
typedef void (PODTypeCreator::*SetterMethod)(PODType);
// Empty value
PODTypeWrapperCacheInfo()
: creator(0)
, getter(0)
, setter(0)
, fieldHash(0)
{ }
// Deleted value
explicit PODTypeWrapperCacheInfo(WTF::HashTableDeletedValueType)
: creator(reinterpret_cast<PODTypeCreator*>(-1))
, getter(0)
, setter(0)
, fieldHash(0)
{
}
bool isHashTableDeletedValue() const
{
return creator == reinterpret_cast<PODTypeCreator*>(-1);
}
PODTypeWrapperCacheInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter, unsigned _fieldHash)
: creator(_creator)
, getter(_getter)
, setter(_setter)
, fieldHash(_fieldHash)
{
ASSERT(creator);
ASSERT(getter);
}
bool operator==(const PODTypeWrapperCacheInfo& other) const
{
return creator == other.creator && fieldHash == other.fieldHash && getter == other.getter && setter == other.setter;
}
PODTypeCreator* creator;
GetterMethod getter;
SetterMethod setter;
unsigned fieldHash;
};
template<typename PODType, typename PODTypeCreator>
struct PODTypeWrapperCacheInfoHash {
static unsigned hash(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& info)
{
// We can't hash member function pointers, but we have enough material
// to hash the pointer and field identifier, and on a collision
// operator== will still differentiate the member function pointers.
return WTF::PairHash<void*, unsigned>::hash(std::pair<void*, unsigned>(info.creator, info.fieldHash));
}
static bool equal(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& a, const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& b)
{
return a == b;
}
static const bool safeToCompareToEmptyOrDeleted = true;
};
template<typename PODType, typename PODTypeCreator>
struct PODTypeWrapperCacheInfoTraits : WTF::GenericHashTraits<PODTypeWrapperCacheInfo<PODType, PODTypeCreator> > {
typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo;
static const bool emptyValueIsZero = true;
static const bool needsDestruction = false;
static const CacheInfo& emptyValue()
{
DEFINE_STATIC_LOCAL(CacheInfo, key, ());
return key;
}
static void constructDeletedValue(CacheInfo& slot)
{
new (&slot) CacheInfo(WTF::HashTableDeletedValue);
}
static bool isDeletedValue(const CacheInfo& value)
{
return value.isHashTableDeletedValue();
}
};
template<typename PODType, typename PODTypeCreator>
class V8SVGDynamicPODTypeWrapperCache {
public:
typedef PODType (PODTypeCreator::*GetterMethod)() const;
typedef void (PODTypeCreator::*SetterMethod)(PODType);
typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo;
typedef PODTypeWrapperCacheInfoHash<PODType, PODTypeCreator> CacheInfoHash;
typedef PODTypeWrapperCacheInfoTraits<PODType, PODTypeCreator> CacheInfoTraits;
typedef V8SVGPODTypeWrapper<PODType> WrapperBase;
typedef V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator> DynamicWrapper;
typedef HashMap<CacheInfo, DynamicWrapper*, CacheInfoHash, CacheInfoTraits> DynamicWrapperHashMap;
typedef typename DynamicWrapperHashMap::const_iterator DynamicWrapperHashMapIterator;
static DynamicWrapperHashMap& dynamicWrapperHashMap()
{
DEFINE_STATIC_LOCAL(DynamicWrapperHashMap, dynamicWrapperHashMap, ());
return dynamicWrapperHashMap;
}
// Used for readwrite attributes only
static PassRefPtr<WrapperBase> lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter, unsigned fieldHash)
{
DynamicWrapperHashMap& map(dynamicWrapperHashMap());
CacheInfo info(creator, getter, setter, fieldHash);
if (map.contains(info))
return map.get(info);
RefPtr<DynamicWrapper> wrapper = V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator>::create(creator, getter, setter, forgetWrapper);
map.set(info, wrapper.get());
return wrapper.release();
}
static void forgetWrapper(V8SVGPODTypeWrapper<PODType>* wrapper)
{
DynamicWrapperHashMap& map(dynamicWrapperHashMap());
DynamicWrapperHashMapIterator it = map.begin();
DynamicWrapperHashMapIterator end = map.end();
for (; it != end; ++it) {
if (it->second != wrapper)
continue;
// It's guaranteed that there's just one object we need to take care of.
map.remove(it->first);
break;
}
}
};
class V8SVGPODTypeUtil {
public:
template <class P>
static P toSVGPODType(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> object, bool& ok);
};
template <class P>
P V8SVGPODTypeUtil::toSVGPODType(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> object, bool& ok)
{
void *wrapper = V8DOMWrapper::convertToSVGPODTypeImpl(type, object);
if (wrapper == NULL) {
ok = false;
return P();
} else {
ok = true;
return *static_cast<V8SVGPODTypeWrapper<P>*>(wrapper);
}
}
} // namespace WebCore
#endif // ENABLE(SVG)
#endif // V8SVGPODTypeWrapper_h