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. | |
esprehn
2014/05/28 20:03:54
Do we really need to add Apple copyrights?
Inactive
2014/05/29 15:14:01
I don't know what the exact rules are but it seems
Inactive
2014/05/29 15:17:59
Also, this CL seems to hint that I am not the only
| |
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 { | |
esprehn
2014/05/28 20:03:54
This class seems unnecessary.
Inactive
2014/05/29 15:14:01
The main reason for this class (besides avoiding m
| |
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; | |
esprehn
2014/05/28 20:03:54
Can we just add attributesBegin() and attributesEn
Inactive
2014/05/29 15:14:01
If we do this then we will call ElementData::isUni
Inactive
2014/05/30 13:16:03
Note that we had issues before with callers not ca
| |
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 |