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