blob: 50c2879d46ae0420457f111fe8e4773674aaf161 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE COPYRIGHT
* OWNER 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 ElementData_h
#define ElementData_h
#include "core/dom/Attribute.h"
#include "core/dom/SpaceSplitString.h"
#include "wtf/text/AtomicString.h"
namespace WebCore {
class Attr;
class ShareableElementData;
class StylePropertySet;
class UniqueElementData;
class ElementData : public RefCounted<ElementData> {
WTF_MAKE_FAST_ALLOCATED;
public:
// Override RefCounted's deref() to ensure operator delete is called on
// the appropriate subclass type.
void deref();
void clearClass() const { m_classNames.clear(); }
void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
const SpaceSplitString& classNames() const { return m_classNames; }
const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
const StylePropertySet* presentationAttributeStyle() const;
size_t length() const;
bool isEmpty() const { return !length(); }
const Attribute* attributeItem(unsigned index) const;
const Attribute* getAttributeItem(const QualifiedName&) const;
size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
size_t getAttrIndex(Attr*) const;
bool hasID() const { return !m_idForStyleResolution.isNull(); }
bool hasClass() const { return !m_classNames.isNull(); }
bool isEquivalent(const ElementData* other) const;
bool isUnique() const { return m_isUnique; }
protected:
ElementData();
explicit ElementData(unsigned arraySize);
ElementData(const ElementData&, bool isUnique);
unsigned m_isUnique : 1;
unsigned m_arraySize : 28;
mutable unsigned m_presentationAttributeStyleIsDirty : 1;
mutable unsigned m_styleAttributeIsDirty : 1;
mutable unsigned m_animatedSVGAttributesAreDirty : 1;
mutable RefPtr<StylePropertySet> m_inlineStyle;
mutable SpaceSplitString m_classNames;
mutable AtomicString m_idForStyleResolution;
private:
friend class Element;
friend class ShareableElementData;
friend class UniqueElementData;
friend class SVGElement;
const Attribute* attributeBase() const;
const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
PassRefPtr<UniqueElementData> makeUniqueCopy() const;
};
#if COMPILER(MSVC)
#pragma warning(push)
#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
#endif
class ShareableElementData : public ElementData {
public:
static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
explicit ShareableElementData(const Vector<Attribute>&);
explicit ShareableElementData(const UniqueElementData&);
~ShareableElementData();
Attribute m_attributeArray[0];
};
#if COMPILER(MSVC)
#pragma warning(pop)
#endif
class UniqueElementData : public ElementData {
public:
static PassRefPtr<UniqueElementData> create();
PassRefPtr<ShareableElementData> makeShareableCopy() const;
// These functions do no error/duplicate checking.
void addAttribute(const QualifiedName&, const AtomicString&);
void removeAttribute(size_t index);
Attribute* attributeItem(unsigned index);
Attribute* getAttributeItem(const QualifiedName&);
UniqueElementData();
explicit UniqueElementData(const ShareableElementData&);
explicit UniqueElementData(const UniqueElementData&);
mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
Vector<Attribute, 4> m_attributeVector;
};
inline size_t ElementData::length() const
{
if (isUnique())
return static_cast<const UniqueElementData*>(this)->m_attributeVector.size();
return m_arraySize;
}
inline const StylePropertySet* ElementData::presentationAttributeStyle() const
{
if (!m_isUnique)
return 0;
return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get();
}
inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const
{
size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
if (index != kNotFound)
return attributeItem(index);
return 0;
}
inline const Attribute* ElementData::attributeBase() const
{
if (m_isUnique)
return static_cast<const UniqueElementData*>(this)->m_attributeVector.begin();
return static_cast<const ShareableElementData*>(this)->m_attributeArray;
}
inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
{
const Attribute* begin = attributeBase();
for (unsigned i = 0; i < length(); ++i) {
const Attribute& attribute = begin[i];
if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
return i;
}
return kNotFound;
}
// We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
// can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const
{
unsigned len = length();
bool doSlowCheck = shouldIgnoreAttributeCase;
// Optimize for the case where the attribute exists and its name exactly matches.
const Attribute* begin = attributeBase();
for (unsigned i = 0; i < len; ++i) {
const Attribute& attribute = begin[i];
if (!attribute.name().hasPrefix()) {
if (name == attribute.localName())
return i;
} else {
doSlowCheck = true;
}
}
if (doSlowCheck)
return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
return kNotFound;
}
inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const
{
const Attribute* begin = attributeBase();
for (unsigned i = 0; i < length(); ++i) {
const Attribute& attribute = begin[i];
if (attribute.name().matches(name))
return &attribute;
}
return 0;
}
inline const Attribute* ElementData::attributeItem(unsigned index) const
{
RELEASE_ASSERT(index < length());
return attributeBase() + index;
}
} // namespace WebCore
#endif // ElementData_h