f6e8170e8ebe15fe23a01cf4c10a05a85903af5e
[WebKit-https.git] / Source / WebCore / dom / NamedNodeMap.h
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Peter Kelly (pmk@post.com)
5  *           (C) 2001 Dirk Mueller (mueller@kde.org)
6  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #ifndef NamedNodeMap_h
26 #define NamedNodeMap_h
27
28 #include "Attribute.h"
29 #include "ElementAttributeData.h"
30 #include "SpaceSplitString.h"
31 #include <wtf/NotFound.h>
32
33 namespace WebCore {
34
35 class Node;
36
37 typedef int ExceptionCode;
38
39 class NamedNodeMap {
40     friend class Element;
41 public:
42     static PassOwnPtr<NamedNodeMap> create(Element* element = 0)
43     {
44         return adoptPtr(new NamedNodeMap(element));
45     }
46
47     ~NamedNodeMap();
48
49     void ref();
50     void deref();
51
52     // Public DOM interface.
53
54     PassRefPtr<Node> getNamedItem(const String& name) const;
55     PassRefPtr<Node> removeNamedItem(const String& name, ExceptionCode&);
56
57     PassRefPtr<Node> getNamedItemNS(const String& namespaceURI, const String& localName) const;
58     PassRefPtr<Node> removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode&);
59
60     PassRefPtr<Node> getNamedItem(const QualifiedName& name) const;
61     PassRefPtr<Node> removeNamedItem(const QualifiedName& name, ExceptionCode&);
62     PassRefPtr<Node> setNamedItem(Node*, ExceptionCode&);
63     PassRefPtr<Node> setNamedItemNS(Node*, ExceptionCode&);
64
65     PassRefPtr<Node> item(unsigned index) const;
66     size_t length() const { return m_attributes.size(); }
67     bool isEmpty() const { return !length(); }
68
69     // Internal interface.
70
71     Attribute* attributeItem(unsigned index) const { return m_attributes[index].get(); }
72     Attribute* getAttributeItem(const QualifiedName&) const;
73     size_t getAttributeItemIndex(const QualifiedName&) const;
74
75     void copyAttributesToVector(Vector<RefPtr<Attribute> >&);
76
77     void shrinkToLength() { m_attributes.shrinkCapacity(length()); }
78     void reserveInitialCapacity(unsigned capacity) { m_attributes.reserveInitialCapacity(capacity); }
79
80     // Used during parsing: only inserts if not already there. No error checking!
81     void insertAttribute(PassRefPtr<Attribute> newAttribute, bool allowDuplicates)
82     {
83         ASSERT(!m_element);
84         if (allowDuplicates || !getAttributeItem(newAttribute->name()))
85             addAttribute(newAttribute);
86     }
87
88     bool mapsEquivalent(const NamedNodeMap* otherMap) const;
89
90     // These functions do no error checking.
91     void addAttribute(PassRefPtr<Attribute>);
92     void removeAttribute(const QualifiedName&);
93     void removeAttribute(size_t index);
94
95     Element* element() const { return m_element; }
96
97     size_t mappedAttributeCount() const;
98
99     ElementAttributeData* attributeData() { return &m_attributeData; }
100     const ElementAttributeData* attributeData() const { return &m_attributeData; }
101
102 private:
103     NamedNodeMap(Element* element)
104         : m_element(element)
105     {
106     }
107
108     void detachAttributesFromElement();
109     void detachFromElement();
110     Attribute* getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const;
111     size_t getAttributeItemIndex(const String& name, bool shouldIgnoreAttributeCase) const;
112     size_t getAttributeItemIndexSlowCase(const String& name, bool shouldIgnoreAttributeCase) const;
113     void setAttributes(const NamedNodeMap&);
114     void clearAttributes();
115     void replaceAttribute(size_t index, PassRefPtr<Attribute>);
116
117     // FIXME: NamedNodeMap is being broken up into two classes, one containing data
118     //        for elements with attributes, and one for exposure to the DOM.
119     //        See <http://webkit.org/b/75069> for more information.
120     ElementAttributeData m_attributeData;
121
122     Element* m_element;
123     Vector<RefPtr<Attribute>, 4> m_attributes;
124 };
125
126 inline Attribute* NamedNodeMap::getAttributeItem(const QualifiedName& name) const
127 {
128     size_t index = getAttributeItemIndex(name);
129     if (index != notFound)
130         return m_attributes[index].get();
131     return 0;
132 }
133
134 inline size_t NamedNodeMap::getAttributeItemIndex(const QualifiedName& name) const
135 {
136     size_t len = length();
137     for (unsigned i = 0; i < len; ++i) {
138         if (m_attributes[i]->name().matches(name))
139             return i;
140     }
141     return notFound;
142 }
143
144 inline Attribute* NamedNodeMap::getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const
145 {
146     size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
147     if (index != notFound)
148         return m_attributes[index].get();
149     return 0;
150 }
151
152 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
153 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
154 inline size_t NamedNodeMap::getAttributeItemIndex(const String& name, bool shouldIgnoreAttributeCase) const
155 {
156     unsigned len = length();
157     bool doSlowCheck = shouldIgnoreAttributeCase;
158
159     // Optimize for the case where the attribute exists and its name exactly matches.
160     for (unsigned i = 0; i < len; ++i) {
161         const QualifiedName& attrName = m_attributes[i]->name();
162         if (!attrName.hasPrefix()) {
163             if (name == attrName.localName())
164                 return i;
165         } else
166             doSlowCheck = true;
167     }
168
169     if (doSlowCheck)
170         return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
171     return notFound;
172 }
173
174 inline void NamedNodeMap::removeAttribute(const QualifiedName& name)
175 {
176     size_t index = getAttributeItemIndex(name);
177     if (index == notFound)
178         return;
179
180     removeAttribute(index);
181 }
182
183 inline size_t NamedNodeMap::mappedAttributeCount() const
184 {
185     size_t count = 0;
186     for (size_t i = 0; i < m_attributes.size(); ++i) {
187         if (m_attributes[i]->decl())
188             ++count;
189     }
190     return count;
191 }
192
193 } // namespace WebCore
194
195 #endif // NamedNodeMap_h