| 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 * Copyright (C) 2014 Apple Inc. All rights reserved. |
| 4 * Copyright (C) 2014 Samsung Electronics. All rights reserved. | 4 * Copyright (C) 2014 Samsung Electronics. All rights reserved. |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions are | 7 * modification, are permitted provided that the following conditions are |
| 8 * met: | 8 * met: |
| 9 * | 9 * |
| 10 * * Redistributions of source code must retain the above copyright | 10 * * Redistributions of source code must retain the above copyright |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 */ | 31 */ |
| 32 | 32 |
| 33 #ifndef AttributeCollection_h | 33 #ifndef AttributeCollection_h |
| 34 #define AttributeCollection_h | 34 #define AttributeCollection_h |
| 35 | 35 |
| 36 #include "core/dom/Attr.h" |
| 36 #include "core/dom/Attribute.h" | 37 #include "core/dom/Attribute.h" |
| 38 #include "wtf/Vector.h" |
| 37 | 39 |
| 38 namespace blink { | 40 namespace blink { |
| 39 | 41 |
| 40 class Attr; | 42 template <typename Container, typename ContainerMemberType = Container> |
| 43 class AttributeCollectionGeneric { |
| 44 public: |
| 45 typedef typename Container::ValueType ValueType; |
| 46 typedef ValueType* iterator; |
| 41 | 47 |
| 42 class AttributeCollection { | 48 AttributeCollectionGeneric(Container& attributes) |
| 49 : m_attributes(attributes) |
| 50 { } |
| 51 |
| 52 ValueType& operator[](unsigned index) const { return at(index); } |
| 53 ValueType& at(unsigned index) const |
| 54 { |
| 55 RELEASE_ASSERT(index < size()); |
| 56 return begin()[index]; |
| 57 } |
| 58 |
| 59 iterator begin() const { return m_attributes.data(); } |
| 60 iterator end() const { return begin() + size(); } |
| 61 |
| 62 unsigned size() const { return m_attributes.size(); } |
| 63 bool isEmpty() const { return !size(); } |
| 64 |
| 65 iterator find(const QualifiedName&) const; |
| 66 iterator find(const AtomicString& name, bool shouldIgnoreCase) const; |
| 67 size_t findIndex(const QualifiedName&, bool shouldIgnoreCase = false) const; |
| 68 size_t findIndex(const AtomicString& name, bool shouldIgnoreCase) const; |
| 69 size_t findIndex(Attr*) const; |
| 70 |
| 71 protected: |
| 72 size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase
) const; |
| 73 |
| 74 ContainerMemberType m_attributes; |
| 75 }; |
| 76 |
| 77 class AttributeArray { |
| 43 public: | 78 public: |
| 44 typedef const Attribute* const_iterator; | 79 typedef const Attribute ValueType; |
| 45 | 80 |
| 46 AttributeCollection(const Attribute* array, unsigned size) | 81 AttributeArray(const Attribute* array, unsigned size) |
| 47 : m_array(array) | 82 : m_array(array) |
| 48 , m_size(size) | 83 , m_size(size) |
| 49 { } | 84 { } |
| 50 | 85 |
| 51 const Attribute& operator[](unsigned index) const { return at(index); } | 86 const Attribute* data() const { return m_array; } |
| 52 const Attribute& at(unsigned index) const | |
| 53 { | |
| 54 RELEASE_ASSERT(index < m_size); | |
| 55 return m_array[index]; | |
| 56 } | |
| 57 | |
| 58 const Attribute* find(const QualifiedName&) const; | |
| 59 const Attribute* find(const AtomicString& name, bool shouldIgnoreCase) const
; | |
| 60 size_t findIndex(const QualifiedName&, bool shouldIgnoreCase = false) const; | |
| 61 size_t findIndex(const AtomicString& name, bool shouldIgnoreCase) const; | |
| 62 size_t findIndex(Attr*) const; | |
| 63 | |
| 64 const_iterator begin() const { return m_array; } | |
| 65 const_iterator end() const { return m_array + m_size; } | |
| 66 | |
| 67 unsigned size() const { return m_size; } | 87 unsigned size() const { return m_size; } |
| 68 bool isEmpty() const { return !m_size; } | |
| 69 | 88 |
| 70 private: | 89 private: |
| 71 size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase
) const; | |
| 72 | |
| 73 const Attribute* m_array; | 90 const Attribute* m_array; |
| 74 unsigned m_size; | 91 unsigned m_size; |
| 75 }; | 92 }; |
| 76 | 93 |
| 77 inline const Attribute* AttributeCollection::find(const AtomicString& name, bool
shouldIgnoreCase) const | 94 class AttributeCollection : public AttributeCollectionGeneric<const AttributeArr
ay> { |
| 95 public: |
| 96 typedef iterator const_iterator; |
| 97 |
| 98 AttributeCollection(const Attribute* array, unsigned size) |
| 99 : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(array,
size)) |
| 100 { } |
| 101 }; |
| 102 |
| 103 typedef Vector<Attribute, 4> AttributeVector; |
| 104 class MutableAttributeCollection : public AttributeCollectionGeneric<AttributeVe
ctor, AttributeVector&> { |
| 105 public: |
| 106 explicit MutableAttributeCollection(AttributeVector& attributes) |
| 107 : AttributeCollectionGeneric<AttributeVector, AttributeVector&>(attribut
es) |
| 108 { } |
| 109 |
| 110 // These functions do no error/duplicate checking. |
| 111 void append(const QualifiedName&, const AtomicString& value); |
| 112 void remove(unsigned index); |
| 113 }; |
| 114 |
| 115 inline void MutableAttributeCollection::append(const QualifiedName& name, const
AtomicString& value) |
| 116 { |
| 117 m_attributes.append(Attribute(name, value)); |
| 118 } |
| 119 |
| 120 inline void MutableAttributeCollection::remove(unsigned index) |
| 121 { |
| 122 m_attributes.remove(index); |
| 123 } |
| 124 |
| 125 template <typename Container, typename ContainerMemberType> |
| 126 inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iter
ator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const Atom
icString& name, bool shouldIgnoreCase) const |
| 78 { | 127 { |
| 79 size_t index = findIndex(name, shouldIgnoreCase); | 128 size_t index = findIndex(name, shouldIgnoreCase); |
| 80 return index != kNotFound ? &at(index) : 0; | 129 return index != kNotFound ? &at(index) : 0; |
| 81 } | 130 } |
| 82 | 131 |
| 83 inline size_t AttributeCollection::findIndex(const QualifiedName& name, bool sho
uldIgnoreCase) const | 132 template <typename Container, typename ContainerMemberType> |
| 133 inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIn
dex(const QualifiedName& name, bool shouldIgnoreCase) const |
| 84 { | 134 { |
| 85 const_iterator end = this->end(); | 135 iterator end = this->end(); |
| 86 unsigned index = 0; | 136 unsigned index = 0; |
| 87 for (const_iterator it = begin(); it != end; ++it, ++index) { | 137 for (iterator it = begin(); it != end; ++it, ++index) { |
| 88 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) | 138 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) |
| 89 return index; | 139 return index; |
| 90 } | 140 } |
| 91 return kNotFound; | 141 return kNotFound; |
| 92 } | 142 } |
| 93 | 143 |
| 94 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th
at the caller | 144 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th
at the caller |
| 95 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is
not). | 145 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is
not). |
| 96 inline size_t AttributeCollection::findIndex(const AtomicString& name, bool shou
ldIgnoreCase) const | 146 template <typename Container, typename ContainerMemberType> |
| 147 inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIn
dex(const AtomicString& name, bool shouldIgnoreCase) const |
| 97 { | 148 { |
| 98 bool doSlowCheck = shouldIgnoreCase; | 149 bool doSlowCheck = shouldIgnoreCase; |
| 99 | 150 |
| 100 // Optimize for the case where the attribute exists and its name exactly mat
ches. | 151 // Optimize for the case where the attribute exists and its name exactly mat
ches. |
| 101 const_iterator end = this->end(); | 152 iterator end = this->end(); |
| 102 unsigned index = 0; | 153 unsigned index = 0; |
| 103 for (const_iterator it = begin(); it != end; ++it, ++index) { | 154 for (iterator it = begin(); it != end; ++it, ++index) { |
| 104 // FIXME: Why check the prefix? Namespaces should be all that matter. | 155 // FIXME: Why check the prefix? Namespaces should be all that matter. |
| 105 // Most attributes (all of HTML and CSS) have no namespace. | 156 // Most attributes (all of HTML and CSS) have no namespace. |
| 106 if (!it->name().hasPrefix()) { | 157 if (!it->name().hasPrefix()) { |
| 107 if (name == it->localName()) | 158 if (name == it->localName()) |
| 108 return index; | 159 return index; |
| 109 } else { | 160 } else { |
| 110 doSlowCheck = true; | 161 doSlowCheck = true; |
| 111 } | 162 } |
| 112 } | 163 } |
| 113 | 164 |
| 114 if (doSlowCheck) | 165 if (doSlowCheck) |
| 115 return findSlowCase(name, shouldIgnoreCase); | 166 return findSlowCase(name, shouldIgnoreCase); |
| 116 return kNotFound; | 167 return kNotFound; |
| 117 } | 168 } |
| 118 | 169 |
| 119 inline const Attribute* AttributeCollection::find(const QualifiedName& name) con
st | 170 template <typename Container, typename ContainerMemberType> |
| 171 inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iter
ator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const Qual
ifiedName& name) const |
| 120 { | 172 { |
| 121 const_iterator end = this->end(); | 173 iterator end = this->end(); |
| 122 for (const_iterator it = begin(); it != end; ++it) { | 174 for (iterator it = begin(); it != end; ++it) { |
| 123 if (it->name().matches(name)) | 175 if (it->name().matches(name)) |
| 124 return it; | 176 return it; |
| 125 } | 177 } |
| 126 return 0; | 178 return 0; |
| 127 } | 179 } |
| 128 | 180 |
| 181 template <typename Container, typename ContainerMemberType> |
| 182 size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(Att
r* attr) const |
| 183 { |
| 184 // This relies on the fact that Attr's QualifiedName == the Attribute's name
. |
| 185 iterator end = this->end(); |
| 186 unsigned index = 0; |
| 187 for (iterator it = begin(); it != end; ++it, ++index) { |
| 188 if (it->name() == attr->qualifiedName()) |
| 189 return index; |
| 190 } |
| 191 return kNotFound; |
| 192 } |
| 193 |
| 194 template <typename Container, typename ContainerMemberType> |
| 195 size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findSlowCase(
const AtomicString& name, bool shouldIgnoreAttributeCase) const |
| 196 { |
| 197 // Continue to checking case-insensitively and/or full namespaced names if n
ecessary: |
| 198 iterator end = this->end(); |
| 199 unsigned index = 0; |
| 200 for (iterator it = begin(); it != end; ++it, ++index) { |
| 201 // FIXME: Why check the prefix? Namespace is all that should matter |
| 202 // and all HTML/SVG attributes have a null namespace! |
| 203 if (!it->name().hasPrefix()) { |
| 204 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, it->localNa
me())) |
| 205 return index; |
| 206 } else { |
| 207 // FIXME: Would be faster to do this comparison without calling toSt
ring, which |
| 208 // generates a temporary string by concatenation. But this branch is
only reached |
| 209 // if the attribute name has a prefix, which is rare in HTML. |
| 210 if (equalPossiblyIgnoringCase(name, it->name().toString(), shouldIgn
oreAttributeCase)) |
| 211 return index; |
| 212 } |
| 213 } |
| 214 return kNotFound; |
| 215 } |
| 216 |
| 129 } // namespace blink | 217 } // namespace blink |
| 130 | 218 |
| 131 #endif // AttributeCollection_h | 219 #endif // AttributeCollection_h |
| OLD | NEW |