Delete WebMetal implementation in favor of WebGPU
[WebKit-https.git] / Source / WebCore / dom / ElementData.h
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 #pragma once
27
28 #include "Attribute.h"
29 #include "SpaceSplitString.h"
30 #include <wtf/RefCounted.h>
31 #include <wtf/TypeCasts.h>
32
33 namespace WebCore {
34
35 class Attr;
36 class ShareableElementData;
37 class StyleProperties;
38 class UniqueElementData;
39
40 class AttributeConstIterator {
41 public:
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
55 private:
56     const Attribute* m_array;
57     unsigned m_offset;
58 };
59
60 class AttributeIteratorAccessor {
61 public:
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
73 private:
74     const Attribute* m_array;
75     unsigned m_size;
76 };
77
78 class ElementData : public RefCounted<ElementData> {
79     WTF_MAKE_FAST_ALLOCATED;
80 public:
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 setClassNames(const SpaceSplitString& classNames) const { m_classNames = classNames; }
88     const SpaceSplitString& classNames() const { return m_classNames; }
89     static ptrdiff_t classNamesMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_classNames); }
90
91     const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
92     static ptrdiff_t idForStyleResolutionMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_idForStyleResolution); }
93     void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
94
95     const StyleProperties* inlineStyle() const { return m_inlineStyle.get(); }
96     const StyleProperties* presentationAttributeStyle() const;
97
98     unsigned length() const;
99     bool isEmpty() const { return !length(); }
100
101     AttributeIteratorAccessor attributesIterator() const;
102     const Attribute& attributeAt(unsigned index) const;
103     const Attribute* findAttributeByName(const QualifiedName&) const;
104     unsigned findAttributeIndexByName(const QualifiedName&) const;
105     unsigned findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
106     const Attribute* findLanguageAttribute() const;
107
108     bool hasID() const { return !m_idForStyleResolution.isNull(); }
109     bool hasClass() const { return !m_classNames.isEmpty(); }
110     bool hasName() const { return m_arraySizeAndFlags & s_flagHasNameAttribute; }
111
112     bool isEquivalent(const ElementData* other) const;
113
114     bool isUnique() const { return m_arraySizeAndFlags & s_flagIsUnique; }
115     static uint32_t isUniqueFlag() { return s_flagIsUnique; }
116
117     static ptrdiff_t arraySizeAndFlagsMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_arraySizeAndFlags); }
118     static inline uint32_t styleAttributeIsDirtyFlag() { return s_flagStyleAttributeIsDirty; }
119     static uint32_t animatedSVGAttributesAreDirtyFlag() { return s_flagAnimatedSVGAttributesAreDirty; }
120
121     static uint32_t arraySizeOffset() { return s_flagCount; }
122
123 private:
124     mutable uint32_t m_arraySizeAndFlags;
125
126     static const uint32_t s_arraySize = 27;
127     static const uint32_t s_flagCount = 5;
128     static const uint32_t s_flagIsUnique = 1;
129     static const uint32_t s_flagHasNameAttribute = 1 << 1;
130     static const uint32_t s_flagPresentationAttributeStyleIsDirty = 1 << 2;
131     static const uint32_t s_flagStyleAttributeIsDirty = 1 << 3;
132     static const uint32_t s_flagAnimatedSVGAttributesAreDirty = 1 << 4;
133     static const uint32_t s_flagsMask = (1 << s_flagCount) - 1;
134
135     inline void updateFlag(uint32_t flag, bool set) const
136     {
137         if (set)
138             m_arraySizeAndFlags |= flag;
139         else
140             m_arraySizeAndFlags &= ~flag;
141     }
142     static inline uint32_t arraySizeAndFlagsFromOther(const ElementData& other, bool isUnique);
143
144 protected:
145     ElementData();
146     explicit ElementData(unsigned arraySize);
147     ElementData(const ElementData&, bool isUnique);
148
149     unsigned arraySize() const { return m_arraySizeAndFlags >> s_flagCount; }
150
151     void setHasNameAttribute(bool hasName) const { updateFlag(s_flagHasNameAttribute, hasName); }
152
153     bool styleAttributeIsDirty() const { return m_arraySizeAndFlags & s_flagStyleAttributeIsDirty; }
154     void setStyleAttributeIsDirty(bool isDirty) const { updateFlag(s_flagStyleAttributeIsDirty, isDirty); }
155
156     bool presentationAttributeStyleIsDirty() const { return m_arraySizeAndFlags & s_flagPresentationAttributeStyleIsDirty; }
157     void setPresentationAttributeStyleIsDirty(bool isDirty) const { updateFlag(s_flagPresentationAttributeStyleIsDirty, isDirty); }
158
159     bool animatedSVGAttributesAreDirty() const { return m_arraySizeAndFlags & s_flagAnimatedSVGAttributesAreDirty; }
160     void setAnimatedSVGAttributesAreDirty(bool dirty) const { updateFlag(s_flagAnimatedSVGAttributesAreDirty, dirty); }
161
162     mutable RefPtr<StyleProperties> m_inlineStyle;
163     mutable SpaceSplitString m_classNames;
164     mutable AtomicString m_idForStyleResolution;
165
166 private:
167     friend class Element;
168     friend class StyledElement;
169     friend class ShareableElementData;
170     friend class UniqueElementData;
171     friend class SVGElement;
172
173     void destroy();
174
175     const Attribute* attributeBase() const;
176     const Attribute* findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
177
178     Ref<UniqueElementData> makeUniqueCopy() const;
179 };
180
181 #if COMPILER(MSVC)
182 #pragma warning(push)
183 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
184 #endif
185
186 class ShareableElementData : public ElementData {
187 public:
188     static Ref<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
189
190     explicit ShareableElementData(const Vector<Attribute>&);
191     explicit ShareableElementData(const UniqueElementData&);
192     ~ShareableElementData();
193
194     static ptrdiff_t attributeArrayMemoryOffset() { return OBJECT_OFFSETOF(ShareableElementData, m_attributeArray); }
195
196     Attribute m_attributeArray[0];
197 };
198
199 #if COMPILER(MSVC)
200 #pragma warning(pop)
201 #endif
202
203 class UniqueElementData : public ElementData {
204 public:
205     static Ref<UniqueElementData> create();
206     Ref<ShareableElementData> makeShareableCopy() const;
207
208     // These functions do no error/duplicate checking.
209     void addAttribute(const QualifiedName&, const AtomicString&);
210     void removeAttribute(unsigned index);
211
212     Attribute& attributeAt(unsigned index);
213     Attribute* findAttributeByName(const QualifiedName&);
214
215     UniqueElementData();
216     explicit UniqueElementData(const ShareableElementData&);
217     explicit UniqueElementData(const UniqueElementData&);
218
219     static ptrdiff_t attributeVectorMemoryOffset() { return OBJECT_OFFSETOF(UniqueElementData, m_attributeVector); }
220
221     mutable RefPtr<StyleProperties> m_presentationAttributeStyle;
222     typedef Vector<Attribute, 4> AttributeVector;
223     AttributeVector m_attributeVector;
224 };
225
226 inline void ElementData::deref()
227 {
228     if (!derefBase())
229         return;
230     destroy();
231 }
232
233 inline unsigned ElementData::length() const
234 {
235     if (is<UniqueElementData>(*this))
236         return downcast<UniqueElementData>(*this).m_attributeVector.size();
237     return arraySize();
238 }
239
240 inline const Attribute* ElementData::attributeBase() const
241 {
242     if (is<UniqueElementData>(*this))
243         return downcast<UniqueElementData>(*this).m_attributeVector.data();
244     return downcast<ShareableElementData>(*this).m_attributeArray;
245 }
246
247 inline const StyleProperties* ElementData::presentationAttributeStyle() const
248 {
249     if (!is<UniqueElementData>(*this))
250         return nullptr;
251     return downcast<UniqueElementData>(*this).m_presentationAttributeStyle.get();
252 }
253
254 inline AttributeIteratorAccessor ElementData::attributesIterator() const
255 {
256     if (is<UniqueElementData>(*this)) {
257         const Vector<Attribute, 4>& attributeVector = downcast<UniqueElementData>(*this).m_attributeVector;
258         return AttributeIteratorAccessor(attributeVector.data(), attributeVector.size());
259     }
260     return AttributeIteratorAccessor(downcast<ShareableElementData>(*this).m_attributeArray, arraySize());
261 }
262
263 ALWAYS_INLINE const Attribute* ElementData::findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const
264 {
265     unsigned index = findAttributeIndexByName(name, shouldIgnoreAttributeCase);
266     if (index != attributeNotFound)
267         return &attributeAt(index);
268     return nullptr;
269 }
270
271 ALWAYS_INLINE unsigned ElementData::findAttributeIndexByName(const QualifiedName& name) const
272 {
273     const Attribute* attributes = attributeBase();
274     for (unsigned i = 0, count = length(); i < count; ++i) {
275         if (attributes[i].name().matches(name))
276             return i;
277     }
278     return attributeNotFound;
279 }
280
281 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
282 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
283 ALWAYS_INLINE unsigned ElementData::findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const
284 {
285     unsigned attributeCount = length();
286     if (!attributeCount)
287         return attributeNotFound;
288
289     const Attribute* attributes = attributeBase();
290     const AtomicString& caseAdjustedName = shouldIgnoreAttributeCase ? name.convertToASCIILowercase() : name;
291
292     unsigned attributeIndex = 0;
293     do {
294         const Attribute& attribute = attributes[attributeIndex];
295         if (!attribute.name().hasPrefix()) {
296             if (attribute.localName() == caseAdjustedName)
297                 return attributeIndex;
298         } else {
299             if (attribute.name().toString() == caseAdjustedName)
300                 return attributeIndex;
301         }
302
303         ++attributeIndex;
304     } while (attributeIndex < attributeCount);
305
306     return attributeNotFound;
307 }
308
309 ALWAYS_INLINE const Attribute* ElementData::findAttributeByName(const QualifiedName& name) const
310 {
311     const Attribute* attributes = attributeBase();
312     for (unsigned i = 0, count = length(); i < count; ++i) {
313         if (attributes[i].name().matches(name))
314             return &attributes[i];
315     }
316     return 0;
317 }
318
319 inline const Attribute& ElementData::attributeAt(unsigned index) const
320 {
321     RELEASE_ASSERT(index < length());
322     return attributeBase()[index];
323 }
324
325 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
326 {
327     m_attributeVector.append(Attribute(attributeName, value));
328 }
329
330 inline void UniqueElementData::removeAttribute(unsigned index)
331 {
332     m_attributeVector.remove(index);
333 }
334
335 inline Attribute& UniqueElementData::attributeAt(unsigned index)
336 {
337     return m_attributeVector.at(index);
338 }
339
340 } // namespace WebCore
341
342 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ShareableElementData)
343     static bool isType(const WebCore::ElementData& elementData) { return !elementData.isUnique(); }
344 SPECIALIZE_TYPE_TRAITS_END()
345
346 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::UniqueElementData)
347     static bool isType(const WebCore::ElementData& elementData) { return elementData.isUnique(); }
348 SPECIALIZE_TYPE_TRAITS_END()