Make elements that don't have attributes smaller.
[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     CSSMutableStyleDeclaration* inlineStyleDecl() { return attributeData()->m_inlineStyleDecl.get(); }
103     CSSMutableStyleDeclaration* ensureInlineStyleDecl();
104     void destroyInlineStyleDecl();
105
106 private:
107     NamedNodeMap(Element* element)
108         : m_element(element)
109     {
110     }
111
112     void detachAttributesFromElement();
113     void detachFromElement();
114     Attribute* getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const;
115     size_t getAttributeItemIndex(const String& name, bool shouldIgnoreAttributeCase) const;
116     size_t getAttributeItemIndexSlowCase(const String& name, bool shouldIgnoreAttributeCase) const;
117     void setAttributes(const NamedNodeMap&);
118     void clearAttributes();
119     void replaceAttribute(size_t index, PassRefPtr<Attribute>);
120
121     // FIXME: NamedNodeMap is being broken up into two classes, one containing data
122     //        for elements with attributes, and one for exposure to the DOM.
123     //        See <http://webkit.org/b/75069> for more information.
124     ElementAttributeData m_attributeData;
125
126     Element* m_element;
127     Vector<RefPtr<Attribute>, 4> m_attributes;
128 };
129
130 inline Attribute* NamedNodeMap::getAttributeItem(const QualifiedName& name) const
131 {
132     size_t index = getAttributeItemIndex(name);
133     if (index != notFound)
134         return m_attributes[index].get();
135     return 0;
136 }
137
138 inline size_t NamedNodeMap::getAttributeItemIndex(const QualifiedName& name) const
139 {
140     size_t len = length();
141     for (unsigned i = 0; i < len; ++i) {
142         if (m_attributes[i]->name().matches(name))
143             return i;
144     }
145     return notFound;
146 }
147
148 inline Attribute* NamedNodeMap::getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const
149 {
150     size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
151     if (index != notFound)
152         return m_attributes[index].get();
153     return 0;
154 }
155
156 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
157 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
158 inline size_t NamedNodeMap::getAttributeItemIndex(const String& name, bool shouldIgnoreAttributeCase) const
159 {
160     unsigned len = length();
161     bool doSlowCheck = shouldIgnoreAttributeCase;
162
163     // Optimize for the case where the attribute exists and its name exactly matches.
164     for (unsigned i = 0; i < len; ++i) {
165         const QualifiedName& attrName = m_attributes[i]->name();
166         if (!attrName.hasPrefix()) {
167             if (name == attrName.localName())
168                 return i;
169         } else
170             doSlowCheck = true;
171     }
172
173     if (doSlowCheck)
174         return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
175     return notFound;
176 }
177
178 inline void NamedNodeMap::removeAttribute(const QualifiedName& name)
179 {
180     size_t index = getAttributeItemIndex(name);
181     if (index == notFound)
182         return;
183
184     removeAttribute(index);
185 }
186
187 inline size_t NamedNodeMap::mappedAttributeCount() const
188 {
189     size_t count = 0;
190     for (size_t i = 0; i < m_attributes.size(); ++i) {
191         if (m_attributes[i]->decl())
192             ++count;
193     }
194     return count;
195 }
196
197 } // namespace WebCore
198
199 #endif // NamedNodeMap_h