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#include "config.h"
32#include "core/dom/ElementData.h"
33
34#include "core/css/StylePropertySet.h"
35#include "core/dom/QualifiedName.h"
36#include "wtf/Vector.h"
37
38namespace blink {
39
40struct SameSizeAsElementData : public RefCountedWillBeGarbageCollectedFinalized<SameSizeAsElementData> {
41    unsigned bitfield;
42    void* pointers[3];
43};
44
45COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
46
47static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
48{
49    return sizeof(ShareableElementData) + sizeof(Attribute) * count;
50}
51
52ElementData::ElementData()
53    : m_isUnique(true)
54    , m_arraySize(0)
55    , m_presentationAttributeStyleIsDirty(false)
56    , m_styleAttributeIsDirty(false)
57    , m_animatedSVGAttributesAreDirty(false)
58{
59}
60
61ElementData::ElementData(unsigned arraySize)
62    : m_isUnique(false)
63    , m_arraySize(arraySize)
64    , m_presentationAttributeStyleIsDirty(false)
65    , m_styleAttributeIsDirty(false)
66    , m_animatedSVGAttributesAreDirty(false)
67{
68}
69
70ElementData::ElementData(const ElementData& other, bool isUnique)
71    : m_isUnique(isUnique)
72    , m_arraySize(isUnique ? 0 : other.attributes().size())
73    , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
74    , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
75    , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
76    , m_classNames(other.m_classNames)
77    , m_idForStyleResolution(other.m_idForStyleResolution)
78{
79    // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
80}
81
82#if ENABLE(OILPAN)
83void ElementData::finalizeGarbageCollectedObject()
84{
85    if (m_isUnique)
86        toUniqueElementData(this)->~UniqueElementData();
87    else
88        toShareableElementData(this)->~ShareableElementData();
89}
90#else
91void ElementData::destroy()
92{
93    if (m_isUnique)
94        delete toUniqueElementData(this);
95    else
96        delete toShareableElementData(this);
97}
98#endif
99
100PassRefPtrWillBeRawPtr<UniqueElementData> ElementData::makeUniqueCopy() const
101{
102    if (isUnique())
103        return adoptRefWillBeNoop(new UniqueElementData(toUniqueElementData(*this)));
104    return adoptRefWillBeNoop(new UniqueElementData(toShareableElementData(*this)));
105}
106
107bool ElementData::isEquivalent(const ElementData* other) const
108{
109    AttributeCollection attributes = this->attributes();
110    if (!other)
111        return attributes.isEmpty();
112
113    AttributeCollection otherAttributes = other->attributes();
114    if (attributes.size() != otherAttributes.size())
115        return false;
116
117    AttributeCollection::iterator end = attributes.end();
118    for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
119        const Attribute* otherAttr = otherAttributes.find(it->name());
120        if (!otherAttr || it->value() != otherAttr->value())
121            return false;
122    }
123    return true;
124}
125
126void ElementData::trace(Visitor* visitor)
127{
128    if (m_isUnique)
129        toUniqueElementData(this)->traceAfterDispatch(visitor);
130    else
131        toShareableElementData(this)->traceAfterDispatch(visitor);
132}
133
134void ElementData::traceAfterDispatch(Visitor* visitor)
135{
136    visitor->trace(m_inlineStyle);
137}
138
139ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
140    : ElementData(attributes.size())
141{
142    for (unsigned i = 0; i < m_arraySize; ++i)
143        new (&m_attributeArray[i]) Attribute(attributes[i]);
144}
145
146ShareableElementData::~ShareableElementData()
147{
148    for (unsigned i = 0; i < m_arraySize; ++i)
149        m_attributeArray[i].~Attribute();
150}
151
152ShareableElementData::ShareableElementData(const UniqueElementData& other)
153    : ElementData(other, false)
154{
155    ASSERT(!other.m_presentationAttributeStyle);
156
157    if (other.m_inlineStyle) {
158        m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
159    }
160
161    for (unsigned i = 0; i < m_arraySize; ++i)
162        new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
163}
164
165PassRefPtrWillBeRawPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
166{
167#if ENABLE(OILPAN)
168    void* slot = Heap::allocate<ElementData>(sizeForShareableElementDataWithAttributeCount(attributes.size()));
169#else
170    void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
171#endif
172    return adoptRefWillBeNoop(new (slot) ShareableElementData(attributes));
173}
174
175UniqueElementData::UniqueElementData()
176{
177}
178
179UniqueElementData::UniqueElementData(const UniqueElementData& other)
180    : ElementData(other, true)
181    , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
182    , m_attributeVector(other.m_attributeVector)
183{
184    m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : nullptr;
185}
186
187UniqueElementData::UniqueElementData(const ShareableElementData& other)
188    : ElementData(other, true)
189{
190    // An ShareableElementData should never have a mutable inline StylePropertySet attached.
191    ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
192    m_inlineStyle = other.m_inlineStyle;
193
194    unsigned length = other.attributes().size();
195    m_attributeVector.reserveCapacity(length);
196    for (unsigned i = 0; i < length; ++i)
197        m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
198}
199
200PassRefPtrWillBeRawPtr<UniqueElementData> UniqueElementData::create()
201{
202    return adoptRefWillBeNoop(new UniqueElementData);
203}
204
205PassRefPtrWillBeRawPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
206{
207#if ENABLE(OILPAN)
208    void* slot = Heap::allocate<ElementData>(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
209#else
210    void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
211#endif
212    return adoptRefWillBeNoop(new (slot) ShareableElementData(*this));
213}
214
215void UniqueElementData::traceAfterDispatch(Visitor* visitor)
216{
217    visitor->trace(m_presentationAttributeStyle);
218    ElementData::traceAfterDispatch(visitor);
219}
220
221} // namespace blink
222