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/Attr.h"
36 #include "core/dom/QualifiedName.h"
37 #include "wtf/Vector.h"
38
39 namespace WebCore {
40
41 struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
42 unsigned bitfield;
43 void* refPtrs[3];
44 };
45
46 COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
47
sizeForShareableElementDataWithAttributeCount(unsigned count)48 static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
49 {
50 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
51 }
52
ElementData()53 ElementData::ElementData()
54 : m_isUnique(true)
55 , m_arraySize(0)
56 , m_presentationAttributeStyleIsDirty(false)
57 , m_styleAttributeIsDirty(false)
58 , m_animatedSVGAttributesAreDirty(false)
59 {
60 }
61
ElementData(unsigned arraySize)62 ElementData::ElementData(unsigned arraySize)
63 : m_isUnique(false)
64 , m_arraySize(arraySize)
65 , m_presentationAttributeStyleIsDirty(false)
66 , m_styleAttributeIsDirty(false)
67 , m_animatedSVGAttributesAreDirty(false)
68 {
69 }
70
ElementData(const ElementData & other,bool isUnique)71 ElementData::ElementData(const ElementData& other, bool isUnique)
72 : m_isUnique(isUnique)
73 , m_arraySize(isUnique ? 0 : other.length())
74 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
75 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
76 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
77 , m_classNames(other.m_classNames)
78 , m_idForStyleResolution(other.m_idForStyleResolution)
79 {
80 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
81 }
82
destroy()83 void ElementData::destroy()
84 {
85 if (m_isUnique)
86 delete static_cast<UniqueElementData*>(this);
87 else
88 delete static_cast<ShareableElementData*>(this);
89 }
90
makeUniqueCopy() const91 PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
92 {
93 if (isUnique())
94 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
95 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
96 }
97
isEquivalent(const ElementData * other) const98 bool ElementData::isEquivalent(const ElementData* other) const
99 {
100 if (!other)
101 return isEmpty();
102
103 unsigned len = length();
104 if (len != other->length())
105 return false;
106
107 for (unsigned i = 0; i < len; i++) {
108 const Attribute* attribute = attributeItem(i);
109 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
110 if (!otherAttr || attribute->value() != otherAttr->value())
111 return false;
112 }
113
114 return true;
115 }
116
getAttrIndex(Attr * attr) const117 size_t ElementData::getAttrIndex(Attr* attr) const
118 {
119 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
120 for (unsigned i = 0; i < length(); ++i) {
121 if (attributeItem(i)->name() == attr->qualifiedName())
122 return i;
123 }
124 return kNotFound;
125 }
126
getAttributeItemIndexSlowCase(const AtomicString & name,bool shouldIgnoreAttributeCase) const127 size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
128 {
129 // Continue to checking case-insensitively and/or full namespaced names if necessary:
130 for (unsigned i = 0; i < length(); ++i) {
131 const Attribute* attribute = attributeItem(i);
132 // FIXME: Why check the prefix? Namespace is all that should matter
133 // and all HTML/SVG attributes have a null namespace!
134 if (!attribute->name().hasPrefix()) {
135 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
136 return i;
137 } else {
138 // FIXME: Would be faster to do this comparison without calling toString, which
139 // generates a temporary string by concatenation. But this branch is only reached
140 // if the attribute name has a prefix, which is rare in HTML.
141 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
142 return i;
143 }
144 }
145 return kNotFound;
146 }
147
ShareableElementData(const Vector<Attribute> & attributes)148 ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
149 : ElementData(attributes.size())
150 {
151 for (unsigned i = 0; i < m_arraySize; ++i)
152 new (&m_attributeArray[i]) Attribute(attributes[i]);
153 }
154
~ShareableElementData()155 ShareableElementData::~ShareableElementData()
156 {
157 for (unsigned i = 0; i < m_arraySize; ++i)
158 m_attributeArray[i].~Attribute();
159 }
160
ShareableElementData(const UniqueElementData & other)161 ShareableElementData::ShareableElementData(const UniqueElementData& other)
162 : ElementData(other, false)
163 {
164 ASSERT(!other.m_presentationAttributeStyle);
165
166 if (other.m_inlineStyle) {
167 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
168 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
169 }
170
171 for (unsigned i = 0; i < m_arraySize; ++i)
172 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
173 }
174
createWithAttributes(const Vector<Attribute> & attributes)175 PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
176 {
177 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
178 return adoptRef(new (slot) ShareableElementData(attributes));
179 }
180
UniqueElementData()181 UniqueElementData::UniqueElementData()
182 {
183 }
184
UniqueElementData(const UniqueElementData & other)185 UniqueElementData::UniqueElementData(const UniqueElementData& other)
186 : ElementData(other, true)
187 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
188 , m_attributeVector(other.m_attributeVector)
189 {
190 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
191 }
192
UniqueElementData(const ShareableElementData & other)193 UniqueElementData::UniqueElementData(const ShareableElementData& other)
194 : ElementData(other, true)
195 {
196 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
197 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
198 m_inlineStyle = other.m_inlineStyle;
199
200 m_attributeVector.reserveCapacity(other.length());
201 for (unsigned i = 0; i < other.length(); ++i)
202 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
203 }
204
create()205 PassRefPtr<UniqueElementData> UniqueElementData::create()
206 {
207 return adoptRef(new UniqueElementData);
208 }
209
makeShareableCopy() const210 PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
211 {
212 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
213 return adoptRef(new (slot) ShareableElementData(*this));
214 }
215
getAttributeItem(const QualifiedName & name)216 Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
217 {
218 for (unsigned i = 0; i < length(); ++i) {
219 if (m_attributeVector.at(i).name().matches(name))
220 return &m_attributeVector.at(i);
221 }
222 return 0;
223 }
224
225 } // namespace WebCore
226