OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2014 Apple Inc. All rights reserved. |
3 * | 4 * |
4 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
6 * met: | 7 * met: |
7 * | 8 * |
8 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 11 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 12 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 13 * in the documentation and/or other materials provided with the |
(...skipping 22 matching lines...) Expand all Loading... |
35 #include "core/dom/SpaceSplitString.h" | 36 #include "core/dom/SpaceSplitString.h" |
36 #include "wtf/text/AtomicString.h" | 37 #include "wtf/text/AtomicString.h" |
37 | 38 |
38 namespace WebCore { | 39 namespace WebCore { |
39 | 40 |
40 class Attr; | 41 class Attr; |
41 class ShareableElementData; | 42 class ShareableElementData; |
42 class StylePropertySet; | 43 class StylePropertySet; |
43 class UniqueElementData; | 44 class UniqueElementData; |
44 | 45 |
| 46 class AttributeConstIterator { |
| 47 public: |
| 48 AttributeConstIterator(const Attribute* array, unsigned index) |
| 49 : m_array(array) |
| 50 , m_index(index) |
| 51 { } |
| 52 |
| 53 const Attribute* operator*() const { return &m_array[m_index]; } |
| 54 const Attribute* operator->() const { return &m_array[m_index]; } |
| 55 AttributeConstIterator& operator++() { ++m_index; return *this; } |
| 56 |
| 57 bool operator==(const AttributeConstIterator& other) const { return m_index
== other.m_index; } |
| 58 bool operator!=(const AttributeConstIterator& other) const { return !(*this
== other); } |
| 59 |
| 60 unsigned index() const { return m_index; } |
| 61 |
| 62 private: |
| 63 const Attribute* m_array; |
| 64 unsigned m_index; |
| 65 }; |
| 66 |
| 67 class AttributeIteratorAccessor { |
| 68 public: |
| 69 AttributeIteratorAccessor(const Attribute* array, unsigned size) |
| 70 : m_array(array) |
| 71 , m_size(size) |
| 72 { } |
| 73 |
| 74 AttributeConstIterator begin() const { return AttributeConstIterator(m_array
, 0); } |
| 75 AttributeConstIterator end() const { return AttributeConstIterator(m_array,
m_size); } |
| 76 |
| 77 unsigned size() const { return m_size; } |
| 78 |
| 79 private: |
| 80 const Attribute* m_array; |
| 81 unsigned m_size; |
| 82 }; |
| 83 |
45 // ElementData represents very common, but not necessarily unique to an element, | 84 // ElementData represents very common, but not necessarily unique to an element, |
46 // data such as attributes, inline style, and parsed class names and ids. | 85 // data such as attributes, inline style, and parsed class names and ids. |
47 class ElementData : public RefCounted<ElementData> { | 86 class ElementData : public RefCounted<ElementData> { |
48 WTF_MAKE_FAST_ALLOCATED; | 87 WTF_MAKE_FAST_ALLOCATED; |
49 public: | 88 public: |
50 // Override RefCounted's deref() to ensure operator delete is called on | 89 // Override RefCounted's deref() to ensure operator delete is called on |
51 // the appropriate subclass type. | 90 // the appropriate subclass type. |
52 void deref(); | 91 void deref(); |
53 | 92 |
54 void clearClass() const { m_classNames.clear(); } | 93 void clearClass() const { m_classNames.clear(); } |
55 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_
classNames.set(className, shouldFoldCase); } | 94 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_
classNames.set(className, shouldFoldCase); } |
56 const SpaceSplitString& classNames() const { return m_classNames; } | 95 const SpaceSplitString& classNames() const { return m_classNames; } |
57 | 96 |
58 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu
tion; } | 97 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu
tion; } |
59 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle
Resolution = newId; } | 98 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle
Resolution = newId; } |
60 | 99 |
61 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } | 100 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } |
62 | 101 |
63 const StylePropertySet* presentationAttributeStyle() const; | 102 const StylePropertySet* presentationAttributeStyle() const; |
64 | 103 |
65 // This is not a trivial getter and its return value should be cached for pe
rformance. | 104 // This is not a trivial getter and its return value should be cached for pe
rformance. |
66 size_t length() const; | 105 size_t length() const; |
67 bool isEmpty() const { return !length(); } | 106 bool isEmpty() const { return !length(); } |
68 | 107 |
| 108 AttributeIteratorAccessor attributesIterator() const; |
| 109 |
69 const Attribute& attributeItem(unsigned index) const; | 110 const Attribute& attributeItem(unsigned index) const; |
70 const Attribute* getAttributeItem(const QualifiedName&) const; | 111 const Attribute* getAttributeItem(const QualifiedName&) const; |
71 size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = f
alse) const; | 112 size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = f
alse) const; |
72 size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttr
ibuteCase) const; | 113 size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttr
ibuteCase) const; |
73 size_t getAttrIndex(Attr*) const; | 114 size_t getAttrIndex(Attr*) const; |
74 | 115 |
75 bool hasID() const { return !m_idForStyleResolution.isNull(); } | 116 bool hasID() const { return !m_idForStyleResolution.isNull(); } |
76 bool hasClass() const { return !m_classNames.isNull(); } | 117 bool hasClass() const { return !m_classNames.isNull(); } |
77 | 118 |
78 bool isEquivalent(const ElementData* other) const; | 119 bool isEquivalent(const ElementData* other) const; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 | 236 |
196 inline const Attribute* ElementData::attributeBase() const | 237 inline const Attribute* ElementData::attributeBase() const |
197 { | 238 { |
198 if (m_isUnique) | 239 if (m_isUnique) |
199 return static_cast<const UniqueElementData*>(this)->m_attributeVector.be
gin(); | 240 return static_cast<const UniqueElementData*>(this)->m_attributeVector.be
gin(); |
200 return static_cast<const ShareableElementData*>(this)->m_attributeArray; | 241 return static_cast<const ShareableElementData*>(this)->m_attributeArray; |
201 } | 242 } |
202 | 243 |
203 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool
shouldIgnoreCase) const | 244 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool
shouldIgnoreCase) const |
204 { | 245 { |
205 const Attribute* begin = attributeBase(); | 246 AttributeIteratorAccessor attributes = attributesIterator(); |
206 // Cache length for performance as ElementData::length() contains a conditio
nal branch. | 247 AttributeConstIterator end = attributes.end(); |
207 unsigned length = this->length(); | 248 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
208 for (unsigned i = 0; i < length; ++i) { | 249 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) |
209 const Attribute& attribute = begin[i]; | 250 return it.index(); |
210 if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)
) | |
211 return i; | |
212 } | 251 } |
213 return kNotFound; | 252 return kNotFound; |
214 } | 253 } |
215 | 254 |
216 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th
at the caller | 255 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th
at the caller |
217 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is
not). | 256 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is
not). |
218 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool
shouldIgnoreAttributeCase) const | 257 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool
shouldIgnoreAttributeCase) const |
219 { | 258 { |
220 // Cache length for performance as ElementData::length() contains a conditio
nal branch. | |
221 unsigned length = this->length(); | |
222 bool doSlowCheck = shouldIgnoreAttributeCase; | 259 bool doSlowCheck = shouldIgnoreAttributeCase; |
223 | 260 |
224 // Optimize for the case where the attribute exists and its name exactly mat
ches. | 261 // Optimize for the case where the attribute exists and its name exactly mat
ches. |
225 const Attribute* begin = attributeBase(); | 262 AttributeIteratorAccessor attributes = attributesIterator(); |
226 for (unsigned i = 0; i < length; ++i) { | 263 AttributeConstIterator end = attributes.end(); |
227 const Attribute& attribute = begin[i]; | 264 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
228 // FIXME: Why check the prefix? Namespaces should be all that matter. | 265 // FIXME: Why check the prefix? Namespaces should be all that matter. |
229 // Most attributes (all of HTML and CSS) have no namespace. | 266 // Most attributes (all of HTML and CSS) have no namespace. |
230 if (!attribute.name().hasPrefix()) { | 267 if (!it->name().hasPrefix()) { |
231 if (name == attribute.localName()) | 268 if (name == it->localName()) |
232 return i; | 269 return it.index(); |
233 } else { | 270 } else { |
234 doSlowCheck = true; | 271 doSlowCheck = true; |
235 } | 272 } |
236 } | 273 } |
237 | 274 |
238 if (doSlowCheck) | 275 if (doSlowCheck) |
239 return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase); | 276 return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase); |
240 return kNotFound; | 277 return kNotFound; |
241 } | 278 } |
242 | 279 |
| 280 inline AttributeIteratorAccessor ElementData::attributesIterator() const |
| 281 { |
| 282 if (isUnique()) { |
| 283 const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueEl
ementData*>(this)->m_attributeVector; |
| 284 return AttributeIteratorAccessor(attributeVector.data(), attributeVector
.size()); |
| 285 } |
| 286 return AttributeIteratorAccessor(static_cast<const ShareableElementData*>(th
is)->m_attributeArray, m_arraySize); |
| 287 } |
| 288 |
243 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name)
const | 289 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name)
const |
244 { | 290 { |
245 const Attribute* begin = attributeBase(); | 291 AttributeIteratorAccessor attributes = attributesIterator(); |
246 unsigned length = this->length(); | 292 AttributeConstIterator end = attributes.end(); |
247 for (unsigned i = 0; i < length; ++i) { | 293 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
248 const Attribute& attribute = begin[i]; | 294 if (it->name().matches(name)) |
249 if (attribute.name().matches(name)) | 295 return *it; |
250 return &attribute; | |
251 } | 296 } |
252 return 0; | 297 return 0; |
253 } | 298 } |
254 | 299 |
255 inline const Attribute& ElementData::attributeItem(unsigned index) const | 300 inline const Attribute& ElementData::attributeItem(unsigned index) const |
256 { | 301 { |
257 RELEASE_ASSERT(index < length()); | 302 RELEASE_ASSERT(index < length()); |
258 ASSERT(attributeBase() + index); | 303 ASSERT(attributeBase() + index); |
259 return *(attributeBase() + index); | 304 return *(attributeBase() + index); |
260 } | 305 } |
261 | 306 |
262 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName,
const AtomicString& value) | 307 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName,
const AtomicString& value) |
263 { | 308 { |
264 m_attributeVector.append(Attribute(attributeName, value)); | 309 m_attributeVector.append(Attribute(attributeName, value)); |
265 } | 310 } |
266 | 311 |
267 inline void UniqueElementData::removeAttribute(size_t index) | 312 inline void UniqueElementData::removeAttribute(size_t index) |
268 { | 313 { |
269 m_attributeVector.remove(index); | 314 m_attributeVector.remove(index); |
270 } | 315 } |
271 | 316 |
272 inline Attribute& UniqueElementData::attributeItem(unsigned index) | 317 inline Attribute& UniqueElementData::attributeItem(unsigned index) |
273 { | 318 { |
274 return m_attributeVector.at(index); | 319 return m_attributeVector.at(index); |
275 } | 320 } |
276 | 321 |
277 } // namespace WebCore | 322 } // namespace WebCore |
278 | 323 |
279 #endif // ElementData_h | 324 #endif // ElementData_h |
OLD | NEW |