1/* 2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef ElementData_h 27#define ElementData_h 28 29#include "Attribute.h" 30#include "SpaceSplitString.h" 31#include <wtf/RefCounted.h> 32 33namespace WebCore { 34 35class Attr; 36class ShareableElementData; 37class StyleProperties; 38class UniqueElementData; 39 40class AttributeConstIterator { 41public: 42 AttributeConstIterator(const Attribute* array, unsigned offset) 43 : m_array(array) 44 , m_offset(offset) 45 { 46 } 47 48 const Attribute& operator*() const { return m_array[m_offset]; } 49 const Attribute* operator->() const { return &m_array[m_offset]; } 50 AttributeConstIterator& operator++() { ++m_offset; return *this; } 51 52 bool operator==(const AttributeConstIterator& other) const { return m_offset == other.m_offset; } 53 bool operator!=(const AttributeConstIterator& other) const { return !(*this == other); } 54 55private: 56 const Attribute* m_array; 57 unsigned m_offset; 58}; 59 60class AttributeIteratorAccessor { 61public: 62 AttributeIteratorAccessor(const Attribute* array, unsigned size) 63 : m_array(array) 64 , m_size(size) 65 { 66 } 67 68 AttributeConstIterator begin() const { return AttributeConstIterator(m_array, 0); } 69 AttributeConstIterator end() const { return AttributeConstIterator(m_array, m_size); } 70 71 unsigned attributeCount() const { return m_size; } 72 73private: 74 const Attribute* m_array; 75 unsigned m_size; 76}; 77 78class ElementData : public RefCounted<ElementData> { 79 WTF_MAKE_FAST_ALLOCATED; 80public: 81 // Override RefCounted's deref() to ensure operator delete is called on 82 // the appropriate subclass type. 83 void deref(); 84 85 static const unsigned attributeNotFound = static_cast<unsigned>(-1); 86 87 void clearClass() const { m_classNames.clear(); } 88 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); } 89 const SpaceSplitString& classNames() const { return m_classNames; } 90 static ptrdiff_t classNamesMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_classNames); } 91 92 const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; } 93 static ptrdiff_t idForStyleResolutionMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_idForStyleResolution); } 94 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; } 95 96 const StyleProperties* inlineStyle() const { return m_inlineStyle.get(); } 97 const StyleProperties* presentationAttributeStyle() const; 98 99 unsigned length() const; 100 bool isEmpty() const { return !length(); } 101 102 AttributeIteratorAccessor attributesIterator() const; 103 const Attribute& attributeAt(unsigned index) const; 104 const Attribute* findAttributeByName(const QualifiedName&) const; 105 unsigned findAttributeIndexByName(const QualifiedName&) const; 106 unsigned findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 107 unsigned findAttributeIndexByNameForAttributeNode(const Attr*, bool shouldIgnoreAttributeCase = false) const; 108 const Attribute* findLanguageAttribute() const; 109 110 bool hasID() const { return !m_idForStyleResolution.isNull(); } 111 bool hasClass() const { return !m_classNames.isEmpty(); } 112 bool hasName() const { return m_arraySizeAndFlags & s_flagHasNameAttribute; } 113 114 bool isEquivalent(const ElementData* other) const; 115 116 bool isUnique() const { return m_arraySizeAndFlags & s_flagIsUnique; } 117 static uint32_t isUniqueFlag() { return s_flagIsUnique; } 118 119 static ptrdiff_t arraySizeAndFlagsMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_arraySizeAndFlags); } 120 static inline uint32_t styleAttributeIsDirtyFlag() { return s_flagStyleAttributeIsDirty; } 121 static uint32_t animatedSVGAttributesAreDirtyFlag() { return s_flagAnimatedSVGAttributesAreDirty; } 122 123 static uint32_t arraySizeOffset() { return s_flagCount; } 124 125private: 126 mutable uint32_t m_arraySizeAndFlags; 127 128 static const uint32_t s_arraySize = 27; 129 static const uint32_t s_flagCount = 5; 130 static const uint32_t s_flagIsUnique = 1; 131 static const uint32_t s_flagHasNameAttribute = 1 << 1; 132 static const uint32_t s_flagPresentationAttributeStyleIsDirty = 1 << 2; 133 static const uint32_t s_flagStyleAttributeIsDirty = 1 << 3; 134 static const uint32_t s_flagAnimatedSVGAttributesAreDirty = 1 << 4; 135 static const uint32_t s_flagsMask = (1 << s_flagCount) - 1; 136 137 inline void updateFlag(uint32_t flag, bool set) const 138 { 139 if (set) 140 m_arraySizeAndFlags |= flag; 141 else 142 m_arraySizeAndFlags &= ~flag; 143 } 144 static inline uint32_t arraySizeAndFlagsFromOther(const ElementData& other, bool isUnique); 145 146protected: 147 ElementData(); 148 explicit ElementData(unsigned arraySize); 149 ElementData(const ElementData&, bool isUnique); 150 151 unsigned arraySize() const { return m_arraySizeAndFlags >> s_flagCount; } 152 153 void setHasNameAttribute(bool hasName) const { updateFlag(s_flagHasNameAttribute, hasName); } 154 155 bool styleAttributeIsDirty() const { return m_arraySizeAndFlags & s_flagStyleAttributeIsDirty; } 156 void setStyleAttributeIsDirty(bool isDirty) const { updateFlag(s_flagStyleAttributeIsDirty, isDirty); } 157 158 bool presentationAttributeStyleIsDirty() const { return m_arraySizeAndFlags & s_flagPresentationAttributeStyleIsDirty; } 159 void setPresentationAttributeStyleIsDirty(bool isDirty) const { updateFlag(s_flagPresentationAttributeStyleIsDirty, isDirty); } 160 161 bool animatedSVGAttributesAreDirty() const { return m_arraySizeAndFlags & s_flagAnimatedSVGAttributesAreDirty; } 162 void setAnimatedSVGAttributesAreDirty(bool dirty) const { updateFlag(s_flagAnimatedSVGAttributesAreDirty, dirty); } 163 164 mutable RefPtr<StyleProperties> m_inlineStyle; 165 mutable SpaceSplitString m_classNames; 166 mutable AtomicString m_idForStyleResolution; 167 168private: 169 friend class Element; 170 friend class StyledElement; 171 friend class ShareableElementData; 172 friend class UniqueElementData; 173 friend class SVGElement; 174 175 void destroy(); 176 177 const Attribute* attributeBase() const; 178 const Attribute* findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 179 unsigned findAttributeIndexByNameSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 180 181 PassRef<UniqueElementData> makeUniqueCopy() const; 182}; 183 184#if COMPILER(MSVC) 185#pragma warning(push) 186#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning 187#endif 188 189class ShareableElementData : public ElementData { 190public: 191 static PassRef<ShareableElementData> createWithAttributes(const Vector<Attribute>&); 192 193 explicit ShareableElementData(const Vector<Attribute>&); 194 explicit ShareableElementData(const UniqueElementData&); 195 ~ShareableElementData(); 196 197 static ptrdiff_t attributeArrayMemoryOffset() { return OBJECT_OFFSETOF(ShareableElementData, m_attributeArray); } 198 199 Attribute m_attributeArray[0]; 200}; 201 202#if COMPILER(MSVC) 203#pragma warning(pop) 204#endif 205 206class UniqueElementData : public ElementData { 207public: 208 static PassRef<UniqueElementData> create(); 209 PassRef<ShareableElementData> makeShareableCopy() const; 210 211 // These functions do no error/duplicate checking. 212 void addAttribute(const QualifiedName&, const AtomicString&); 213 void removeAttribute(unsigned index); 214 215 Attribute& attributeAt(unsigned index); 216 Attribute* findAttributeByName(const QualifiedName&); 217 218 UniqueElementData(); 219 explicit UniqueElementData(const ShareableElementData&); 220 explicit UniqueElementData(const UniqueElementData&); 221 222 static ptrdiff_t attributeVectorMemoryOffset() { return OBJECT_OFFSETOF(UniqueElementData, m_attributeVector); } 223 224 mutable RefPtr<StyleProperties> m_presentationAttributeStyle; 225 typedef Vector<Attribute, 4> AttributeVector; 226 AttributeVector m_attributeVector; 227}; 228 229inline void ElementData::deref() 230{ 231 if (!derefBase()) 232 return; 233 destroy(); 234} 235 236inline unsigned ElementData::length() const 237{ 238 if (isUnique()) 239 return static_cast<const UniqueElementData*>(this)->m_attributeVector.size(); 240 return arraySize(); 241} 242 243inline const Attribute* ElementData::attributeBase() const 244{ 245 if (isUnique()) 246 return static_cast<const UniqueElementData*>(this)->m_attributeVector.data(); 247 return static_cast<const ShareableElementData*>(this)->m_attributeArray; 248} 249 250inline const StyleProperties* ElementData::presentationAttributeStyle() const 251{ 252 if (!isUnique()) 253 return 0; 254 return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get(); 255} 256 257inline AttributeIteratorAccessor ElementData::attributesIterator() const 258{ 259 if (isUnique()) { 260 const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueElementData*>(this)->m_attributeVector; 261 return AttributeIteratorAccessor(attributeVector.data(), attributeVector.size()); 262 } 263 return AttributeIteratorAccessor(static_cast<const ShareableElementData*>(this)->m_attributeArray, arraySize()); 264} 265 266ALWAYS_INLINE const Attribute* ElementData::findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const 267{ 268 unsigned index = findAttributeIndexByName(name, shouldIgnoreAttributeCase); 269 if (index != attributeNotFound) 270 return &attributeAt(index); 271 return 0; 272} 273 274ALWAYS_INLINE unsigned ElementData::findAttributeIndexByName(const QualifiedName& name) const 275{ 276 const Attribute* attributes = attributeBase(); 277 for (unsigned i = 0, count = length(); i < count; ++i) { 278 if (attributes[i].name().matches(name)) 279 return i; 280 } 281 return attributeNotFound; 282} 283 284// We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller 285// can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). 286ALWAYS_INLINE unsigned ElementData::findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const 287{ 288 const Attribute* attributes = attributeBase(); 289 bool doSlowCheck = shouldIgnoreAttributeCase; 290 const AtomicString& caseAdjustedName = shouldIgnoreAttributeCase ? name.lower() : name; 291 292 // Optimize for the case where the attribute exists and its name exactly matches. 293 for (unsigned i = 0, count = length(); i < count; ++i) { 294 if (!attributes[i].name().hasPrefix()) { 295 if (caseAdjustedName == attributes[i].localName()) 296 return i; 297 } else 298 doSlowCheck = true; 299 } 300 301 if (doSlowCheck) 302 return findAttributeIndexByNameSlowCase(name, shouldIgnoreAttributeCase); 303 return attributeNotFound; 304} 305 306ALWAYS_INLINE const Attribute* ElementData::findAttributeByName(const QualifiedName& name) const 307{ 308 const Attribute* attributes = attributeBase(); 309 for (unsigned i = 0, count = length(); i < count; ++i) { 310 if (attributes[i].name().matches(name)) 311 return &attributes[i]; 312 } 313 return 0; 314} 315 316inline const Attribute& ElementData::attributeAt(unsigned index) const 317{ 318 RELEASE_ASSERT(index < length()); 319 return attributeBase()[index]; 320} 321 322inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value) 323{ 324 m_attributeVector.append(Attribute(attributeName, value)); 325} 326 327inline void UniqueElementData::removeAttribute(unsigned index) 328{ 329 m_attributeVector.remove(index); 330} 331 332inline Attribute& UniqueElementData::attributeAt(unsigned index) 333{ 334 return m_attributeVector.at(index); 335} 336 337} 338 339#endif 340 341