Make some things that return never-null pointers return references instead.
[WebKit-https.git] / Source / WebCore / dom / Attr.cpp
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) 2004, 2005, 2006, 2007, 2009, 2010, 2012 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 #include "config.h"
24 #include "Attr.h"
25
26 #include "ExceptionCode.h"
27 #include "HTMLNames.h"
28 #include "ScopedEventQueue.h"
29 #include "StylePropertySet.h"
30 #include "StyledElement.h"
31 #include "Text.h"
32 #include "XMLNSNames.h"
33 #include <wtf/text/AtomicString.h>
34 #include <wtf/text/StringBuilder.h>
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 Attr::Attr(Element* element, const QualifiedName& name)
41     : ContainerNode(element->document())
42     , m_element(element)
43     , m_name(name)
44     , m_ignoreChildrenChanged(0)
45     , m_specified(true)
46 {
47 }
48
49 Attr::Attr(Document* document, const QualifiedName& name, const AtomicString& standaloneValue)
50     : ContainerNode(document)
51     , m_element(0)
52     , m_name(name)
53     , m_standaloneValue(standaloneValue)
54     , m_ignoreChildrenChanged(0)
55     , m_specified(true)
56 {
57 }
58
59 PassRefPtr<Attr> Attr::create(Element* element, const QualifiedName& name)
60 {
61     RefPtr<Attr> attr = adoptRef(new Attr(element, name));
62     attr->createTextChild();
63     return attr.release();
64 }
65
66 PassRefPtr<Attr> Attr::create(Document* document, const QualifiedName& name, const AtomicString& value)
67 {
68     RefPtr<Attr> attr = adoptRef(new Attr(document, name, value));
69     attr->createTextChild();
70     return attr.release();
71 }
72
73 Attr::~Attr()
74 {
75 }
76
77 void Attr::createTextChild()
78 {
79     ASSERT(refCount());
80     if (!value().isEmpty()) {
81         RefPtr<Text> textNode = document()->createTextNode(value().string());
82
83         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
84         // but much more efficiently.
85         textNode->setParentOrShadowHostNode(this);
86         setFirstChild(textNode.get());
87         setLastChild(textNode.get());
88     }
89 }
90
91 void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
92 {
93     ec = 0;
94     checkSetPrefix(prefix, ec);
95     if (ec)
96         return;
97
98     if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI)
99         || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) {
100         ec = NAMESPACE_ERR;
101         return;
102     }
103
104     const AtomicString& newPrefix = prefix.isEmpty() ? nullAtom : prefix;
105
106     if (m_element)
107         elementAttribute().setPrefix(newPrefix);
108     m_name.setPrefix(newPrefix);
109 }
110
111 void Attr::setValue(const AtomicString& value)
112 {
113     EventQueueScope scope;
114     m_ignoreChildrenChanged++;
115     removeChildren();
116     if (m_element)
117         elementAttribute().setValue(value);
118     else
119         m_standaloneValue = value;
120     createTextChild();
121     m_ignoreChildrenChanged--;
122
123     invalidateNodeListCachesInAncestors(&m_name, m_element);
124 }
125
126 void Attr::setValue(const AtomicString& value, ExceptionCode&)
127 {
128     if (m_element)
129         m_element->willModifyAttribute(qualifiedName(), this->value(), value);
130
131     setValue(value);
132
133     if (m_element)
134         m_element->didModifyAttribute(qualifiedName(), value);
135 }
136
137 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
138 {
139     setValue(v, ec);
140 }
141
142 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
143 {
144     RefPtr<Attr> clone = adoptRef(new Attr(document(), qualifiedName(), value()));
145     cloneChildNodes(clone.get());
146     return clone.release();
147 }
148
149 // DOM Section 1.1.1
150 bool Attr::childTypeAllowed(NodeType type) const
151 {
152     switch (type) {
153         case TEXT_NODE:
154         case ENTITY_REFERENCE_NODE:
155             return true;
156         default:
157             return false;
158     }
159 }
160
161 void Attr::childrenChanged(bool, Node*, Node*, int)
162 {
163     if (m_ignoreChildrenChanged > 0)
164         return;
165
166     invalidateNodeListCachesInAncestors(&qualifiedName(), m_element);
167
168     // FIXME: We should include entity references in the value
169
170     StringBuilder valueBuilder;
171     for (Node *n = firstChild(); n; n = n->nextSibling()) {
172         if (n->isTextNode())
173             valueBuilder.append(toText(n)->data());
174     }
175
176     AtomicString newValue = valueBuilder.toAtomicString();
177     if (m_element)
178         m_element->willModifyAttribute(qualifiedName(), value(), newValue);
179
180     if (m_element)
181         elementAttribute().setValue(newValue);
182     else
183         m_standaloneValue = newValue;
184
185     if (m_element)
186         m_element->attributeChanged(qualifiedName(), newValue);
187 }
188
189 bool Attr::isId() const
190 {
191     return qualifiedName().matches(document()->idAttributeName());
192 }
193
194 CSSStyleDeclaration* Attr::style()
195 {
196     // This function only exists to support the Obj-C bindings.
197     if (!m_element || !m_element->isStyledElement())
198         return 0;
199     m_style = MutableStylePropertySet::create();
200     static_cast<StyledElement*>(m_element)->collectStyleForPresentationAttribute(qualifiedName(), value(), m_style.get());
201     return m_style->ensureCSSStyleDeclaration();
202 }
203
204 const AtomicString& Attr::value() const
205 {
206     if (m_element)
207         return m_element->getAttribute(qualifiedName());
208     return m_standaloneValue;
209 }
210
211 Attribute& Attr::elementAttribute()
212 {
213     ASSERT(m_element);
214     ASSERT(m_element->elementData());
215     return *m_element->ensureUniqueElementData().findAttributeByName(qualifiedName());
216 }
217
218 void Attr::detachFromElementWithValue(const AtomicString& value)
219 {
220     ASSERT(m_element);
221     ASSERT(m_standaloneValue.isNull());
222     m_standaloneValue = value;
223     m_element = 0;
224 }
225
226 void Attr::attachToElement(Element* element)
227 {
228     ASSERT(!m_element);
229     m_element = element;
230     m_standaloneValue = nullAtom;
231 }
232
233 }