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#include "config.h"
27#include "ElementData.h"
28
29#include "Attr.h"
30#include "HTMLNames.h"
31#include "StyleProperties.h"
32#include "XMLNames.h"
33
34namespace WebCore {
35
36void ElementData::destroy()
37{
38 if (is<UniqueElementData>(*this))
39 delete downcast<UniqueElementData>(this);
40 else
41 delete downcast<ShareableElementData>(this);
42}
43
44ElementData::ElementData()
45 : m_arraySizeAndFlags(s_flagIsUnique)
46{
47}
48
49ElementData::ElementData(unsigned arraySize)
50 : m_arraySizeAndFlags(arraySize << s_flagCount)
51{
52}
53
54struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
55 unsigned bitfield;
56 void* refPtrs[3];
57};
58
59COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
60
61static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
62{
63 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
64}
65
66Ref<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
67{
68 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
69 return adoptRef(*new (NotNull, slot) ShareableElementData(attributes));
70}
71
72Ref<UniqueElementData> UniqueElementData::create()
73{
74 return adoptRef(*new UniqueElementData);
75}
76
77ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
78 : ElementData(attributes.size())
79{
80 unsigned attributeArraySize = arraySize();
81 for (unsigned i = 0; i < attributeArraySize; ++i)
82 new (NotNull, &m_attributeArray[i]) Attribute(attributes[i]);
83}
84
85ShareableElementData::~ShareableElementData()
86{
87 unsigned attributeArraySize = arraySize();
88 for (unsigned i = 0; i < attributeArraySize; ++i)
89 m_attributeArray[i].~Attribute();
90}
91
92ShareableElementData::ShareableElementData(const UniqueElementData& other)
93 : ElementData(other, false)
94{
95 ASSERT(!other.m_presentationAttributeStyle);
96
97 if (other.m_inlineStyle) {
98 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
99 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
100 }
101
102 unsigned attributeArraySize = arraySize();
103 for (unsigned i = 0; i < attributeArraySize; ++i)
104 new (NotNull, &m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
105}
106
107inline uint32_t ElementData::arraySizeAndFlagsFromOther(const ElementData& other, bool isUnique)
108{
109 if (isUnique) {
110 // Set isUnique and ignore arraySize.
111 return (other.m_arraySizeAndFlags | s_flagIsUnique) & s_flagsMask;
112 }
113 // Clear isUnique and set arraySize.
114 return (other.m_arraySizeAndFlags & (s_flagsMask & ~s_flagIsUnique)) | other.length() << s_flagCount;
115}
116
117ElementData::ElementData(const ElementData& other, bool isUnique)
118 : m_arraySizeAndFlags(ElementData::arraySizeAndFlagsFromOther(other, isUnique))
119 , m_classNames(other.m_classNames)
120 , m_idForStyleResolution(other.m_idForStyleResolution)
121{
122 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
123}
124
125UniqueElementData::UniqueElementData()
126{
127}
128
129UniqueElementData::UniqueElementData(const UniqueElementData& other)
130 : ElementData(other, true)
131 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
132 , m_attributeVector(other.m_attributeVector)
133{
134 if (other.m_inlineStyle)
135 m_inlineStyle = other.m_inlineStyle->mutableCopy();
136}
137
138UniqueElementData::UniqueElementData(const ShareableElementData& other)
139 : ElementData(other, true)
140{
141 // An ShareableElementData should never have a mutable inline StyleProperties attached.
142 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
143 m_inlineStyle = other.m_inlineStyle;
144
145 unsigned otherLength = other.length();
146 m_attributeVector.reserveCapacity(otherLength);
147 for (unsigned i = 0; i < otherLength; ++i)
148 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
149}
150
151Ref<UniqueElementData> ElementData::makeUniqueCopy() const
152{
153 if (isUnique())
154 return adoptRef(*new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
155 return adoptRef(*new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
156}
157
158Ref<ShareableElementData> UniqueElementData::makeShareableCopy() const
159{
160 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
161 return adoptRef(*new (NotNull, slot) ShareableElementData(*this));
162}
163
164bool ElementData::isEquivalent(const ElementData* other) const
165{
166 if (!other)
167 return isEmpty();
168
169 if (length() != other->length())
170 return false;
171
172 for (const Attribute& attribute : attributesIterator()) {
173 const Attribute* otherAttr = other->findAttributeByName(attribute.name());
174 if (!otherAttr || attribute.value() != otherAttr->value())
175 return false;
176 }
177
178 return true;
179}
180
181Attribute* UniqueElementData::findAttributeByName(const QualifiedName& name)
182{
183 for (auto& attribute : m_attributeVector) {
184 if (attribute.name().matches(name))
185 return &attribute;
186 }
187 return nullptr;
188}
189
190const Attribute* ElementData::findLanguageAttribute() const
191{
192 ASSERT(XMLNames::langAttr->localName() == HTMLNames::langAttr->localName());
193
194 const Attribute* attributes = attributeBase();
195 // Spec: xml:lang takes precedence over html:lang -- http://www.w3.org/TR/xhtml1/#C_7
196 const Attribute* languageAttribute = nullptr;
197 for (unsigned i = 0, count = length(); i < count; ++i) {
198 const QualifiedName& name = attributes[i].name();
199 if (name.localName() != HTMLNames::langAttr->localName())
200 continue;
201 if (name.namespaceURI() == XMLNames::langAttr->namespaceURI())
202 return &attributes[i];
203 if (name.namespaceURI() == HTMLNames::langAttr->namespaceURI())
204 languageAttribute = &attributes[i];
205 }
206 return languageAttribute;
207}
208
209}
210
211