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