| 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;
|
| }
|
|
|