• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace blink {
41 
42 template <typename Container, typename ContainerMemberType = Container>
43 class AttributeCollectionGeneric {
44 public:
45     typedef typename Container::ValueType ValueType;
46     typedef ValueType* iterator;
47 
AttributeCollectionGeneric(Container & attributes)48     AttributeCollectionGeneric(Container& attributes)
49         : m_attributes(attributes)
50     { }
51 
52     ValueType& operator[](unsigned index) const { return at(index); }
at(unsigned index)53     ValueType& at(unsigned index) const
54     {
55         RELEASE_ASSERT(index < size());
56         return begin()[index];
57     }
58 
begin()59     iterator begin() const { return m_attributes.data(); }
end()60     iterator end() const { return begin() + size(); }
61 
size()62     unsigned size() const { return m_attributes.size(); }
isEmpty()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 {
78 public:
79     typedef const Attribute ValueType;
80 
AttributeArray(const Attribute * array,unsigned size)81     AttributeArray(const Attribute* array, unsigned size)
82         : m_array(array)
83         , m_size(size)
84     { }
85 
data()86     const Attribute* data() const { return m_array; }
size()87     unsigned size() const { return m_size; }
88 
89 private:
90     const Attribute* m_array;
91     unsigned m_size;
92 };
93 
94 class AttributeCollection : public AttributeCollectionGeneric<const AttributeArray> {
95 public:
AttributeCollection()96     AttributeCollection()
97         : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(nullptr, 0))
98     { }
99 
AttributeCollection(const Attribute * array,unsigned size)100     AttributeCollection(const Attribute* array, unsigned size)
101         : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(array, size))
102     { }
103 };
104 
105 typedef Vector<Attribute, 4> AttributeVector;
106 class MutableAttributeCollection : public AttributeCollectionGeneric<AttributeVector, AttributeVector&> {
107 public:
MutableAttributeCollection(AttributeVector & attributes)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 
append(const QualifiedName & name,const AtomicString & value)117 inline void MutableAttributeCollection::append(const QualifiedName& name, const AtomicString& value)
118 {
119     m_attributes.append(Attribute(name, value));
120 }
121 
remove(unsigned index)122 inline void MutableAttributeCollection::remove(unsigned index)
123 {
124     m_attributes.remove(index);
125 }
126 
127 template <typename Container, typename ContainerMemberType>
find(const AtomicString & name,bool shouldIgnoreCase)128 inline 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 
134 template <typename Container, typename ContainerMemberType>
findIndex(const QualifiedName & name,bool shouldIgnoreCase)135 inline 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).
148 template <typename Container, typename ContainerMemberType>
findIndex(const AtomicString & name,bool shouldIgnoreCase)149 inline 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 
172 template <typename Container, typename ContainerMemberType>
find(const QualifiedName & name)173 inline 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 
183 template <typename Container, typename ContainerMemberType>
findIndex(Attr * attr)184 size_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 
196 template <typename Container, typename ContainerMemberType>
findSlowCase(const AtomicString & name,bool shouldIgnoreAttributeCase)197 size_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