• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
clearClass()52     void clearClass() const { m_classNames.clear(); }
setClass(const AtomicString & className,bool shouldFoldCase)53     void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
classNames()54     const SpaceSplitString& classNames() const { return m_classNames; }
55 
idForStyleResolution()56     const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
setIdForStyleResolution(const AtomicString & newId)57     void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
58 
inlineStyle()59     const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
60 
61     const StylePropertySet* presentationAttributeStyle() const;
62 
63     size_t length() const;
isEmpty()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 
hasID()72     bool hasID() const { return !m_idForStyleResolution.isNull(); }
hasClass()73     bool hasClass() const { return !m_classNames.isNull(); }
74 
75     bool isEquivalent(const ElementData* other) const;
76 
isUnique()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 
deref()149 inline void ElementData::deref()
150 {
151     if (!derefBase())
152         return;
153     destroy();
154 }
155 
length()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 
presentationAttributeStyle()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 
getAttributeItem(const AtomicString & name,bool shouldIgnoreAttributeCase)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 
attributeBase()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 
getAttributeItemIndex(const QualifiedName & name,bool shouldIgnoreCase)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).
getAttributeItemIndex(const AtomicString & name,bool shouldIgnoreAttributeCase)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 
getAttributeItem(const QualifiedName & name)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 
attributeItem(unsigned index)236 inline const Attribute* ElementData::attributeItem(unsigned index) const
237 {
238     RELEASE_ASSERT(index < length());
239     return attributeBase() + index;
240 }
241 
addAttribute(const QualifiedName & attributeName,const AtomicString & value)242 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
243 {
244     m_attributeVector.append(Attribute(attributeName, value));
245 }
246 
removeAttribute(size_t index)247 inline void UniqueElementData::removeAttribute(size_t index)
248 {
249     m_attributeVector.remove(index);
250 }
251 
attributeItem(unsigned index)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