Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / ElementData.h
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 // ElementData represents very common, but not necessarily unique to an element,
46 // data such as attributes, inline style, and parsed class names and ids.
47 class ElementData : public RefCounted<ElementData> {
48     WTF_MAKE_FAST_ALLOCATED;
49 public:
50     // Override RefCounted's deref() to ensure operator delete is called on
51     // the appropriate subclass type.
52     void deref();
53
54     void clearClass() const { m_classNames.clear(); }
55     void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
56     const SpaceSplitString& classNames() const { return m_classNames; }
57
58     const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
59     void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
60
61     const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
62
63     const StylePropertySet* presentationAttributeStyle() const;
64
65     size_t length() const;
66     bool isEmpty() const { return !length(); }
67
68     const Attribute* attributeItem(unsigned index) const;
69     const Attribute* getAttributeItem(const QualifiedName&) const;
70     size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
71     size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
72     size_t getAttrIndex(Attr*) const;
73
74     bool hasID() const { return !m_idForStyleResolution.isNull(); }
75     bool hasClass() const { return !m_classNames.isNull(); }
76
77     bool isEquivalent(const ElementData* other) const;
78
79     bool isUnique() const { return m_isUnique; }
80
81 protected:
82     ElementData();
83     explicit ElementData(unsigned arraySize);
84     ElementData(const ElementData&, bool isUnique);
85
86     // Keep the type in a bitfield instead of using virtual destructors to avoid adding a vtable.
87     unsigned m_isUnique : 1;
88     unsigned m_arraySize : 28;
89     mutable unsigned m_presentationAttributeStyleIsDirty : 1;
90     mutable unsigned m_styleAttributeIsDirty : 1;
91     mutable unsigned m_animatedSVGAttributesAreDirty : 1;
92
93     mutable RefPtr<StylePropertySet> m_inlineStyle;
94     mutable SpaceSplitString m_classNames;
95     mutable AtomicString m_idForStyleResolution;
96
97 private:
98     friend class Element;
99     friend class ShareableElementData;
100     friend class UniqueElementData;
101     friend class SVGElement;
102
103     void destroy();
104
105     const Attribute* attributeBase() const;
106     const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
107     size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
108
109     PassRefPtr<UniqueElementData> makeUniqueCopy() const;
110 };
111
112 #if COMPILER(MSVC)
113 #pragma warning(push)
114 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
115 #endif
116
117 // SharableElementData is managed by ElementDataCache and is produced by
118 // the parser during page load for elements that have identical attributes. This
119 // is a memory optimization since it's very common for many elements to have
120 // duplicate sets of attributes (ex. the same classes).
121 class ShareableElementData FINAL : public ElementData {
122 public:
123     static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
124
125     explicit ShareableElementData(const Vector<Attribute>&);
126     explicit ShareableElementData(const UniqueElementData&);
127     ~ShareableElementData();
128
129     Attribute m_attributeArray[0];
130 };
131
132 #if COMPILER(MSVC)
133 #pragma warning(pop)
134 #endif
135
136 // UniqueElementData is created when an element needs to mutate its attributes
137 // or gains presentation attribute style (ex. width="10"). It does not need to
138 // be created to fill in values in the ElementData that are derived from
139 // attributes. For example populating the m_inlineStyle from the style attribute
140 // doesn't require a UniqueElementData as all elements with the same style
141 // attribute will have the same inline style.
142 class UniqueElementData FINAL : public ElementData {
143 public:
144     static PassRefPtr<UniqueElementData> create();
145     PassRefPtr<ShareableElementData> makeShareableCopy() const;
146
147     // These functions do no error/duplicate checking.
148     void addAttribute(const QualifiedName&, const AtomicString&);
149     void removeAttribute(size_t index);
150
151     Attribute* attributeItem(unsigned index);
152     Attribute* getAttributeItem(const QualifiedName&);
153
154     UniqueElementData();
155     explicit UniqueElementData(const ShareableElementData&);
156     explicit UniqueElementData(const UniqueElementData&);
157
158     // FIXME: We might want to support sharing element data for elements with
159     // presentation attribute style. Lots of table cells likely have the same
160     // attributes. Most modern pages don't use presentation attributes though
161     // so this might not make sense.
162     mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
163     Vector<Attribute, 4> m_attributeVector;
164 };
165
166 inline void ElementData::deref()
167 {
168     if (!derefBase())
169         return;
170     destroy();
171 }
172
173 inline size_t ElementData::length() const
174 {
175     if (isUnique())
176         return static_cast<const UniqueElementData*>(this)->m_attributeVector.size();
177     return m_arraySize;
178 }
179
180 inline const StylePropertySet* ElementData::presentationAttributeStyle() const
181 {
182     if (!m_isUnique)
183         return 0;
184     return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get();
185 }
186
187 inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const
188 {
189     size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
190     if (index != kNotFound)
191         return attributeItem(index);
192     return 0;
193 }
194
195 inline const Attribute* ElementData::attributeBase() const
196 {
197     if (m_isUnique)
198         return static_cast<const UniqueElementData*>(this)->m_attributeVector.begin();
199     return static_cast<const ShareableElementData*>(this)->m_attributeArray;
200 }
201
202 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
203 {
204     const Attribute* begin = attributeBase();
205     // Cache length for performance as ElementData::length() contains a conditional branch.
206     unsigned len = length();
207     for (unsigned i = 0; i < len; ++i) {
208         const Attribute& attribute = begin[i];
209         if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
210             return i;
211     }
212     return kNotFound;
213 }
214
215 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
216 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
217 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const
218 {
219     // Cache length for performance as ElementData::length() contains a conditional branch.
220     unsigned len = length();
221     bool doSlowCheck = shouldIgnoreAttributeCase;
222
223     // Optimize for the case where the attribute exists and its name exactly matches.
224     const Attribute* begin = attributeBase();
225     for (unsigned i = 0; i < len; ++i) {
226         const Attribute& attribute = begin[i];
227         // FIXME: Why check the prefix? Namespaces should be all that matter.
228         // Most attributes (all of HTML and CSS) have no namespace.
229         if (!attribute.name().hasPrefix()) {
230             if (name == attribute.localName())
231                 return i;
232         } else {
233             doSlowCheck = true;
234         }
235     }
236
237     if (doSlowCheck)
238         return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
239     return kNotFound;
240 }
241
242 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const
243 {
244     const Attribute* begin = attributeBase();
245     for (unsigned i = 0; i < length(); ++i) {
246         const Attribute& attribute = begin[i];
247         if (attribute.name().matches(name))
248             return &attribute;
249     }
250     return 0;
251 }
252
253 inline const Attribute* ElementData::attributeItem(unsigned index) const
254 {
255     RELEASE_ASSERT(index < length());
256     return attributeBase() + index;
257 }
258
259 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
260 {
261     m_attributeVector.append(Attribute(attributeName, value));
262 }
263
264 inline void UniqueElementData::removeAttribute(size_t index)
265 {
266     m_attributeVector.remove(index);
267 }
268
269 inline Attribute* UniqueElementData::attributeItem(unsigned index)
270 {
271     return &m_attributeVector.at(index);
272 }
273
274 } // namespace WebCore
275
276 #endif // ElementData_h