1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 2014 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifndef ElementData_h
33#define ElementData_h
34
35#include "core/dom/Attribute.h"
36#include "core/dom/AttributeCollection.h"
37#include "core/dom/SpaceSplitString.h"
38#include "platform/heap/Handle.h"
39#include "wtf/text/AtomicString.h"
40
41namespace blink {
42
43class ShareableElementData;
44class StylePropertySet;
45class UniqueElementData;
46
47// ElementData represents very common, but not necessarily unique to an element,
48// data such as attributes, inline style, and parsed class names and ids.
49class ElementData : public RefCountedWillBeGarbageCollectedFinalized<ElementData> {
50    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
51public:
52#if ENABLE(OILPAN)
53    // Override GarbageCollectedFinalized's finalizeGarbageCollectedObject to
54    // dispatch to the correct subclass destructor.
55    void finalizeGarbageCollectedObject();
56#else
57    // Override RefCounted's deref() to ensure operator delete is called on
58    // the appropriate subclass type.
59    void deref();
60#endif
61
62    void clearClass() const { m_classNames.clear(); }
63    void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
64    const SpaceSplitString& classNames() const { return m_classNames; }
65
66    const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
67    void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
68
69    const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
70
71    const StylePropertySet* presentationAttributeStyle() const;
72
73    AttributeCollection attributes() const;
74
75    bool hasID() const { return !m_idForStyleResolution.isNull(); }
76    bool hasClass() const { return !m_classNames.isNull(); }
77
78    bool isEquivalent(const ElementData* other) const;
79
80    bool isUnique() const { return m_isUnique; }
81
82    void traceAfterDispatch(Visitor*);
83    void trace(Visitor*);
84
85protected:
86    ElementData();
87    explicit ElementData(unsigned arraySize);
88    ElementData(const ElementData&, bool isUnique);
89
90    // Keep the type in a bitfield instead of using virtual destructors to avoid adding a vtable.
91    unsigned m_isUnique : 1;
92    unsigned m_arraySize : 28;
93    mutable unsigned m_presentationAttributeStyleIsDirty : 1;
94    mutable unsigned m_styleAttributeIsDirty : 1;
95    mutable unsigned m_animatedSVGAttributesAreDirty : 1;
96
97    mutable RefPtrWillBeMember<StylePropertySet> m_inlineStyle;
98    mutable SpaceSplitString m_classNames;
99    mutable AtomicString m_idForStyleResolution;
100
101private:
102    friend class Element;
103    friend class ShareableElementData;
104    friend class UniqueElementData;
105    friend class SVGElement;
106
107#if !ENABLE(OILPAN)
108    void destroy();
109#endif
110
111    PassRefPtrWillBeRawPtr<UniqueElementData> makeUniqueCopy() const;
112};
113
114#define DEFINE_ELEMENT_DATA_TYPE_CASTS(thisType,  pointerPredicate, referencePredicate) \
115    template<typename T> inline thisType* to##thisType(const RefPtr<T>& data) { return to##thisType(data.get()); } \
116    DEFINE_TYPE_CASTS(thisType, ElementData, data, pointerPredicate, referencePredicate)
117
118#if COMPILER(MSVC)
119#pragma warning(push)
120#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
121#endif
122
123// SharableElementData is managed by ElementDataCache and is produced by
124// the parser during page load for elements that have identical attributes. This
125// is a memory optimization since it's very common for many elements to have
126// duplicate sets of attributes (ex. the same classes).
127class ShareableElementData FINAL : public ElementData {
128public:
129    static PassRefPtrWillBeRawPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
130
131    explicit ShareableElementData(const Vector<Attribute>&);
132    explicit ShareableElementData(const UniqueElementData&);
133    ~ShareableElementData();
134
135    void traceAfterDispatch(Visitor* visitor) { ElementData::traceAfterDispatch(visitor); }
136
137    // Add support for placement new as ShareableElementData is not allocated
138    // with a fixed size. Instead the allocated memory size is computed based on
139    // the number of attributes. This requires us to use Heap::allocate directly
140    // with the computed size and subsequently call placement new with the
141    // allocated memory address.
142    void* operator new(std::size_t, void* location)
143    {
144        return location;
145    }
146
147    AttributeCollection attributes() const;
148
149    Attribute m_attributeArray[0];
150};
151
152DEFINE_ELEMENT_DATA_TYPE_CASTS(ShareableElementData, !data->isUnique(), !data.isUnique());
153
154#if COMPILER(MSVC)
155#pragma warning(pop)
156#endif
157
158// UniqueElementData is created when an element needs to mutate its attributes
159// or gains presentation attribute style (ex. width="10"). It does not need to
160// be created to fill in values in the ElementData that are derived from
161// attributes. For example populating the m_inlineStyle from the style attribute
162// doesn't require a UniqueElementData as all elements with the same style
163// attribute will have the same inline style.
164class UniqueElementData FINAL : public ElementData {
165public:
166    static PassRefPtrWillBeRawPtr<UniqueElementData> create();
167    PassRefPtrWillBeRawPtr<ShareableElementData> makeShareableCopy() const;
168
169    MutableAttributeCollection attributes();
170    AttributeCollection attributes() const;
171
172    UniqueElementData();
173    explicit UniqueElementData(const ShareableElementData&);
174    explicit UniqueElementData(const UniqueElementData&);
175
176    void traceAfterDispatch(Visitor*);
177
178    // FIXME: We might want to support sharing element data for elements with
179    // presentation attribute style. Lots of table cells likely have the same
180    // attributes. Most modern pages don't use presentation attributes though
181    // so this might not make sense.
182    mutable RefPtrWillBeMember<StylePropertySet> m_presentationAttributeStyle;
183    AttributeVector m_attributeVector;
184};
185
186DEFINE_ELEMENT_DATA_TYPE_CASTS(UniqueElementData, data->isUnique(), data.isUnique());
187
188#if !ENABLE(OILPAN)
189inline void ElementData::deref()
190{
191    if (!derefBase())
192        return;
193    destroy();
194}
195#endif
196
197inline const StylePropertySet* ElementData::presentationAttributeStyle() const
198{
199    if (!m_isUnique)
200        return 0;
201    return toUniqueElementData(this)->m_presentationAttributeStyle.get();
202}
203
204inline AttributeCollection ElementData::attributes() const
205{
206    if (isUnique())
207        return toUniqueElementData(this)->attributes();
208    return toShareableElementData(this)->attributes();
209}
210
211inline AttributeCollection ShareableElementData::attributes() const
212{
213    return AttributeCollection(m_attributeArray, m_arraySize);
214}
215
216inline AttributeCollection UniqueElementData::attributes() const
217{
218    return AttributeCollection(m_attributeVector.data(), m_attributeVector.size());
219}
220
221inline MutableAttributeCollection UniqueElementData::attributes()
222{
223    return MutableAttributeCollection(m_attributeVector);
224}
225
226} // namespace blink
227
228#endif // ElementData_h
229