Index: Source/core/dom/ElementData.h |
diff --git a/Source/core/dom/ElementData.h b/Source/core/dom/ElementData.h |
index e209f7fb1b8d76c4ed606df990128f10ce8e1580..99f2115f0f4afdccfa5e3b36fd7ba1d95613cafd 100644 |
--- a/Source/core/dom/ElementData.h |
+++ b/Source/core/dom/ElementData.h |
@@ -1,5 +1,6 @@ |
/* |
* Copyright (C) 2013 Google Inc. All rights reserved. |
+ * Copyright (C) 2014 Apple Inc. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions are |
@@ -42,6 +43,44 @@ class ShareableElementData; |
class StylePropertySet; |
class UniqueElementData; |
+class AttributeConstIterator { |
+public: |
+ AttributeConstIterator(const Attribute* array, unsigned index) |
+ : m_array(array) |
+ , m_index(index) |
+ { } |
+ |
+ const Attribute* operator*() const { return &m_array[m_index]; } |
+ const Attribute* operator->() const { return &m_array[m_index]; } |
+ AttributeConstIterator& operator++() { ++m_index; return *this; } |
+ |
+ bool operator==(const AttributeConstIterator& other) const { return m_index == other.m_index; } |
+ bool operator!=(const AttributeConstIterator& other) const { return !(*this == other); } |
+ |
+ unsigned index() const { return m_index; } |
+ |
+private: |
+ const Attribute* m_array; |
+ unsigned m_index; |
+}; |
+ |
+class AttributeIteratorAccessor { |
+public: |
+ AttributeIteratorAccessor(const Attribute* array, unsigned size) |
+ : m_array(array) |
+ , m_size(size) |
+ { } |
+ |
+ AttributeConstIterator begin() const { return AttributeConstIterator(m_array, 0); } |
+ AttributeConstIterator end() const { return AttributeConstIterator(m_array, m_size); } |
+ |
+ unsigned size() const { return m_size; } |
+ |
+private: |
+ const Attribute* m_array; |
+ unsigned m_size; |
+}; |
+ |
// ElementData represents very common, but not necessarily unique to an element, |
// data such as attributes, inline style, and parsed class names and ids. |
class ElementData : public RefCounted<ElementData> { |
@@ -66,6 +105,8 @@ public: |
size_t length() const; |
bool isEmpty() const { return !length(); } |
+ AttributeIteratorAccessor attributesIterator() const; |
+ |
const Attribute& attributeItem(unsigned index) const; |
const Attribute* getAttributeItem(const QualifiedName&) const; |
size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const; |
@@ -202,13 +243,11 @@ inline const Attribute* ElementData::attributeBase() const |
inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const |
{ |
- const Attribute* begin = attributeBase(); |
- // Cache length for performance as ElementData::length() contains a conditional branch. |
- unsigned length = this->length(); |
- for (unsigned i = 0; i < length; ++i) { |
- const Attribute& attribute = begin[i]; |
- if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) |
- return i; |
+ AttributeIteratorAccessor attributes = attributesIterator(); |
+ AttributeConstIterator end = attributes.end(); |
+ for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
+ if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) |
+ return it.index(); |
} |
return kNotFound; |
} |
@@ -217,19 +256,17 @@ inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool |
// can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). |
inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const |
{ |
- // Cache length for performance as ElementData::length() contains a conditional branch. |
- unsigned length = this->length(); |
bool doSlowCheck = shouldIgnoreAttributeCase; |
// Optimize for the case where the attribute exists and its name exactly matches. |
- const Attribute* begin = attributeBase(); |
- for (unsigned i = 0; i < length; ++i) { |
- const Attribute& attribute = begin[i]; |
+ AttributeIteratorAccessor attributes = attributesIterator(); |
+ AttributeConstIterator end = attributes.end(); |
+ for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
// FIXME: Why check the prefix? Namespaces should be all that matter. |
// Most attributes (all of HTML and CSS) have no namespace. |
- if (!attribute.name().hasPrefix()) { |
- if (name == attribute.localName()) |
- return i; |
+ if (!it->name().hasPrefix()) { |
+ if (name == it->localName()) |
+ return it.index(); |
} else { |
doSlowCheck = true; |
} |
@@ -240,14 +277,22 @@ inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool |
return kNotFound; |
} |
+inline AttributeIteratorAccessor ElementData::attributesIterator() const |
+{ |
+ if (isUnique()) { |
+ const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueElementData*>(this)->m_attributeVector; |
+ return AttributeIteratorAccessor(attributeVector.data(), attributeVector.size()); |
+ } |
+ return AttributeIteratorAccessor(static_cast<const ShareableElementData*>(this)->m_attributeArray, m_arraySize); |
+} |
+ |
inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const |
{ |
- const Attribute* begin = attributeBase(); |
- unsigned length = this->length(); |
- for (unsigned i = 0; i < length; ++i) { |
- const Attribute& attribute = begin[i]; |
- if (attribute.name().matches(name)) |
- return &attribute; |
+ AttributeIteratorAccessor attributes = attributesIterator(); |
+ AttributeConstIterator end = attributes.end(); |
+ for (AttributeConstIterator it = attributes.begin(); it != end; ++it) { |
+ if (it->name().matches(name)) |
+ return *it; |
} |
return 0; |
} |