1/* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * Copyright (C) 2014 Apple Inc. All rights reserved. 4 * Copyright (C) 2014 Samsung Electronics. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Google Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 31 */ 32 33#ifndef AttributeCollection_h 34#define AttributeCollection_h 35 36#include "core/dom/Attr.h" 37#include "core/dom/Attribute.h" 38#include "wtf/Vector.h" 39 40namespace blink { 41 42template <typename Container, typename ContainerMemberType = Container> 43class AttributeCollectionGeneric { 44public: 45 typedef typename Container::ValueType ValueType; 46 typedef ValueType* iterator; 47 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 71protected: 72 size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; 73 74 ContainerMemberType m_attributes; 75}; 76 77class AttributeArray { 78public: 79 typedef const Attribute ValueType; 80 81 AttributeArray(const Attribute* array, unsigned size) 82 : m_array(array) 83 , m_size(size) 84 { } 85 86 const Attribute* data() const { return m_array; } 87 unsigned size() const { return m_size; } 88 89private: 90 const Attribute* m_array; 91 unsigned m_size; 92}; 93 94class AttributeCollection : public AttributeCollectionGeneric<const AttributeArray> { 95public: 96 AttributeCollection() 97 : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(nullptr, 0)) 98 { } 99 100 AttributeCollection(const Attribute* array, unsigned size) 101 : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(array, size)) 102 { } 103}; 104 105typedef Vector<Attribute, 4> AttributeVector; 106class MutableAttributeCollection : public AttributeCollectionGeneric<AttributeVector, AttributeVector&> { 107public: 108 explicit MutableAttributeCollection(AttributeVector& attributes) 109 : AttributeCollectionGeneric<AttributeVector, AttributeVector&>(attributes) 110 { } 111 112 // These functions do no error/duplicate checking. 113 void append(const QualifiedName&, const AtomicString& value); 114 void remove(unsigned index); 115}; 116 117inline void MutableAttributeCollection::append(const QualifiedName& name, const AtomicString& value) 118{ 119 m_attributes.append(Attribute(name, value)); 120} 121 122inline void MutableAttributeCollection::remove(unsigned index) 123{ 124 m_attributes.remove(index); 125} 126 127template <typename Container, typename ContainerMemberType> 128inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iterator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const AtomicString& name, bool shouldIgnoreCase) const 129{ 130 size_t index = findIndex(name, shouldIgnoreCase); 131 return index != kNotFound ? &at(index) : 0; 132} 133 134template <typename Container, typename ContainerMemberType> 135inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(const QualifiedName& name, bool shouldIgnoreCase) const 136{ 137 iterator end = this->end(); 138 unsigned index = 0; 139 for (iterator it = begin(); it != end; ++it, ++index) { 140 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) 141 return index; 142 } 143 return kNotFound; 144} 145 146// We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller 147// can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). 148template <typename Container, typename ContainerMemberType> 149inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(const AtomicString& name, bool shouldIgnoreCase) const 150{ 151 bool doSlowCheck = shouldIgnoreCase; 152 153 // Optimize for the case where the attribute exists and its name exactly matches. 154 iterator end = this->end(); 155 unsigned index = 0; 156 for (iterator it = begin(); it != end; ++it, ++index) { 157 // FIXME: Why check the prefix? Namespaces should be all that matter. 158 // Most attributes (all of HTML and CSS) have no namespace. 159 if (!it->name().hasPrefix()) { 160 if (name == it->localName()) 161 return index; 162 } else { 163 doSlowCheck = true; 164 } 165 } 166 167 if (doSlowCheck) 168 return findSlowCase(name, shouldIgnoreCase); 169 return kNotFound; 170} 171 172template <typename Container, typename ContainerMemberType> 173inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iterator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const QualifiedName& name) const 174{ 175 iterator end = this->end(); 176 for (iterator it = begin(); it != end; ++it) { 177 if (it->name().matches(name)) 178 return it; 179 } 180 return 0; 181} 182 183template <typename Container, typename ContainerMemberType> 184size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(Attr* attr) const 185{ 186 // This relies on the fact that Attr's QualifiedName == the Attribute's name. 187 iterator end = this->end(); 188 unsigned index = 0; 189 for (iterator it = begin(); it != end; ++it, ++index) { 190 if (it->name() == attr->qualifiedName()) 191 return index; 192 } 193 return kNotFound; 194} 195 196template <typename Container, typename ContainerMemberType> 197size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const 198{ 199 // Continue to checking case-insensitively and/or full namespaced names if necessary: 200 iterator end = this->end(); 201 unsigned index = 0; 202 for (iterator it = begin(); it != end; ++it, ++index) { 203 // FIXME: Why check the prefix? Namespace is all that should matter 204 // and all HTML/SVG attributes have a null namespace! 205 if (!it->name().hasPrefix()) { 206 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, it->localName())) 207 return index; 208 } else { 209 // FIXME: Would be faster to do this comparison without calling toString, which 210 // generates a temporary string by concatenation. But this branch is only reached 211 // if the attribute name has a prefix, which is rare in HTML. 212 if (equalPossiblyIgnoringCase(name, it->name().toString(), shouldIgnoreAttributeCase)) 213 return index; 214 } 215 } 216 return kNotFound; 217} 218 219} // namespace blink 220 221#endif // AttributeCollection_h 222