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.attributeCount())
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 !hasAttributes();
102
103 AttributeCollection attributes = this->attributes();
104 if (attributes.size() != other->attributeCount())
105 return false;
106
107 AttributeCollection::const_iterator end = attributes.end();
108 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
109 const Attribute* otherAttr = other->findAttributeByName(it->name());
110 if (!otherAttr || it->value() != otherAttr->value())
111 return false;
112 }
113 return true;
114 }
115
findAttrNodeIndex(Attr * attr) const116 size_t ElementData::findAttrNodeIndex(Attr* attr) const
117 {
118 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
119 AttributeCollection attributes = this->attributes();
120 AttributeCollection::const_iterator end = attributes.end();
121 unsigned index = 0;
122 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) {
123 if (it->name() == attr->qualifiedName())
124 return index;
125 }
126 return kNotFound;
127 }
128
findAttributeIndexByNameSlowCase(const AtomicString & name,bool shouldIgnoreAttributeCase) const129 size_t ElementData::findAttributeIndexByNameSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
130 {
131 // Continue to checking case-insensitively and/or full namespaced names if necessary:
132 AttributeCollection attributes = this->attributes();
133 AttributeCollection::const_iterator end = attributes.end();
134 unsigned index = 0;
135 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) {
136 // FIXME: Why check the prefix? Namespace is all that should matter
137 // and all HTML/SVG attributes have a null namespace!
138 if (!it->name().hasPrefix()) {
139 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, it->localName()))
140 return index;
141 } else {
142 // FIXME: Would be faster to do this comparison without calling toString, which
143 // generates a temporary string by concatenation. But this branch is only reached
144 // if the attribute name has a prefix, which is rare in HTML.
145 if (equalPossiblyIgnoringCase(name, it->name().toString(), shouldIgnoreAttributeCase))
146 return index;
147 }
148 }
149 return kNotFound;
150 }
151
ShareableElementData(const Vector<Attribute> & attributes)152 ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
153 : ElementData(attributes.size())
154 {
155 for (unsigned i = 0; i < m_arraySize; ++i)
156 new (&m_attributeArray[i]) Attribute(attributes[i]);
157 }
158
~ShareableElementData()159 ShareableElementData::~ShareableElementData()
160 {
161 for (unsigned i = 0; i < m_arraySize; ++i)
162 m_attributeArray[i].~Attribute();
163 }
164
ShareableElementData(const UniqueElementData & other)165 ShareableElementData::ShareableElementData(const UniqueElementData& other)
166 : ElementData(other, false)
167 {
168 ASSERT(!other.m_presentationAttributeStyle);
169
170 if (other.m_inlineStyle) {
171 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
172 }
173
174 for (unsigned i = 0; i < m_arraySize; ++i)
175 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
176 }
177
createWithAttributes(const Vector<Attribute> & attributes)178 PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
179 {
180 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
181 return adoptRef(new (slot) ShareableElementData(attributes));
182 }
183
UniqueElementData()184 UniqueElementData::UniqueElementData()
185 {
186 }
187
UniqueElementData(const UniqueElementData & other)188 UniqueElementData::UniqueElementData(const UniqueElementData& other)
189 : ElementData(other, true)
190 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
191 , m_attributeVector(other.m_attributeVector)
192 {
193 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : nullptr;
194 }
195
UniqueElementData(const ShareableElementData & other)196 UniqueElementData::UniqueElementData(const ShareableElementData& other)
197 : ElementData(other, true)
198 {
199 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
200 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
201 m_inlineStyle = other.m_inlineStyle;
202
203 unsigned length = other.attributeCount();
204 m_attributeVector.reserveCapacity(length);
205 for (unsigned i = 0; i < length; ++i)
206 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
207 }
208
create()209 PassRefPtr<UniqueElementData> UniqueElementData::create()
210 {
211 return adoptRef(new UniqueElementData);
212 }
213
makeShareableCopy() const214 PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
215 {
216 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
217 return adoptRef(new (slot) ShareableElementData(*this));
218 }
219
findAttributeByName(const QualifiedName & name)220 Attribute* UniqueElementData::findAttributeByName(const QualifiedName& name)
221 {
222 unsigned length = m_attributeVector.size();
223 for (unsigned i = 0; i < length; ++i) {
224 if (m_attributeVector.at(i).name().matches(name))
225 return &m_attributeVector.at(i);
226 }
227 return 0;
228 }
229
230 } // namespace WebCore
231