1 /* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef ElementData_h 32 #define ElementData_h 33 34 #include "core/dom/Attribute.h" 35 #include "core/dom/SpaceSplitString.h" 36 #include "wtf/text/AtomicString.h" 37 38 namespace WebCore { 39 40 class Attr; 41 class ShareableElementData; 42 class StylePropertySet; 43 class UniqueElementData; 44 45 class ElementData : public RefCounted<ElementData> { 46 WTF_MAKE_FAST_ALLOCATED; 47 public: 48 // Override RefCounted's deref() to ensure operator delete is called on 49 // the appropriate subclass type. 50 void deref(); 51 52 void clearClass() const { m_classNames.clear(); } 53 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); } 54 const SpaceSplitString& classNames() const { return m_classNames; } 55 56 const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; } 57 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; } 58 59 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } 60 61 const StylePropertySet* presentationAttributeStyle() const; 62 63 size_t length() const; 64 bool isEmpty() const { return !length(); } 65 66 const Attribute* attributeItem(unsigned index) const; 67 const Attribute* getAttributeItem(const QualifiedName&) const; 68 size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const; 69 size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 70 size_t getAttrIndex(Attr*) const; 71 72 bool hasID() const { return !m_idForStyleResolution.isNull(); } 73 bool hasClass() const { return !m_classNames.isNull(); } 74 75 bool isEquivalent(const ElementData* other) const; 76 77 bool isUnique() const { return m_isUnique; } 78 79 protected: 80 ElementData(); 81 explicit ElementData(unsigned arraySize); 82 ElementData(const ElementData&, bool isUnique); 83 84 unsigned m_isUnique : 1; 85 unsigned m_arraySize : 28; 86 mutable unsigned m_presentationAttributeStyleIsDirty : 1; 87 mutable unsigned m_styleAttributeIsDirty : 1; 88 mutable unsigned m_animatedSVGAttributesAreDirty : 1; 89 90 mutable RefPtr<StylePropertySet> m_inlineStyle; 91 mutable SpaceSplitString m_classNames; 92 mutable AtomicString m_idForStyleResolution; 93 94 private: 95 friend class Element; 96 friend class ShareableElementData; 97 friend class UniqueElementData; 98 friend class SVGElement; 99 100 void destroy(); 101 102 const Attribute* attributeBase() const; 103 const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 104 size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 105 106 PassRefPtr<UniqueElementData> makeUniqueCopy() const; 107 }; 108 109 #if COMPILER(MSVC) 110 #pragma warning(push) 111 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning 112 #endif 113 114 class ShareableElementData : public ElementData { 115 public: 116 static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&); 117 118 explicit ShareableElementData(const Vector<Attribute>&); 119 explicit ShareableElementData(const UniqueElementData&); 120 ~ShareableElementData(); 121 122 Attribute m_attributeArray[0]; 123 }; 124 125 #if COMPILER(MSVC) 126 #pragma warning(pop) 127 #endif 128 129 class UniqueElementData : public ElementData { 130 public: 131 static PassRefPtr<UniqueElementData> create(); 132 PassRefPtr<ShareableElementData> makeShareableCopy() const; 133 134 // These functions do no error/duplicate checking. 135 void addAttribute(const QualifiedName&, const AtomicString&); 136 void removeAttribute(size_t index); 137 138 Attribute* attributeItem(unsigned index); 139 Attribute* getAttributeItem(const QualifiedName&); 140 141 UniqueElementData(); 142 explicit UniqueElementData(const ShareableElementData&); 143 explicit UniqueElementData(const UniqueElementData&); 144 145 mutable RefPtr<StylePropertySet> m_presentationAttributeStyle; 146 Vector<Attribute, 4> m_attributeVector; 147 }; 148 149 inline void ElementData::deref() 150 { 151 if (!derefBase()) 152 return; 153 destroy(); 154 } 155 156 inline size_t ElementData::length() const 157 { 158 if (isUnique()) 159 return static_cast<const UniqueElementData*>(this)->m_attributeVector.size(); 160 return m_arraySize; 161 } 162 163 inline const StylePropertySet* ElementData::presentationAttributeStyle() const 164 { 165 if (!m_isUnique) 166 return 0; 167 return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get(); 168 } 169 170 inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const 171 { 172 size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase); 173 if (index != kNotFound) 174 return attributeItem(index); 175 return 0; 176 } 177 178 inline const Attribute* ElementData::attributeBase() const 179 { 180 if (m_isUnique) 181 return static_cast<const UniqueElementData*>(this)->m_attributeVector.begin(); 182 return static_cast<const ShareableElementData*>(this)->m_attributeArray; 183 } 184 185 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const 186 { 187 const Attribute* begin = attributeBase(); 188 // Cache length for performance as ElementData::length() contains a conditional branch. 189 unsigned len = length(); 190 for (unsigned i = 0; i < len; ++i) { 191 const Attribute& attribute = begin[i]; 192 if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) 193 return i; 194 } 195 return kNotFound; 196 } 197 198 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller 199 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). 200 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const 201 { 202 // Cache length for performance as ElementData::length() contains a conditional branch. 203 unsigned len = length(); 204 bool doSlowCheck = shouldIgnoreAttributeCase; 205 206 // Optimize for the case where the attribute exists and its name exactly matches. 207 const Attribute* begin = attributeBase(); 208 for (unsigned i = 0; i < len; ++i) { 209 const Attribute& attribute = begin[i]; 210 // FIXME: Why check the prefix? Namespaces should be all that matter. 211 // Most attributes (all of HTML and CSS) have no namespace. 212 if (!attribute.name().hasPrefix()) { 213 if (name == attribute.localName()) 214 return i; 215 } else { 216 doSlowCheck = true; 217 } 218 } 219 220 if (doSlowCheck) 221 return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase); 222 return kNotFound; 223 } 224 225 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const 226 { 227 const Attribute* begin = attributeBase(); 228 for (unsigned i = 0; i < length(); ++i) { 229 const Attribute& attribute = begin[i]; 230 if (attribute.name().matches(name)) 231 return &attribute; 232 } 233 return 0; 234 } 235 236 inline const Attribute* ElementData::attributeItem(unsigned index) const 237 { 238 RELEASE_ASSERT(index < length()); 239 return attributeBase() + index; 240 } 241 242 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value) 243 { 244 m_attributeVector.append(Attribute(attributeName, value)); 245 } 246 247 inline void UniqueElementData::removeAttribute(size_t index) 248 { 249 m_attributeVector.remove(index); 250 } 251 252 inline Attribute* UniqueElementData::attributeItem(unsigned index) 253 { 254 return &m_attributeVector.at(index); 255 } 256 257 } // namespace WebCore 258 259 #endif // ElementData_h 260