Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/dom/Attr.h"
25
26 #include "bindings/core/v8/ExceptionState.h"
27 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
28 #include "core/dom/Document.h"
29 #include "core/dom/Element.h"
30 #include "core/dom/Text.h"
31 #include "core/events/ScopedEventQueue.h"
32 #include "core/frame/UseCounter.h"
33 #include "wtf/text/AtomicString.h"
34 #include "wtf/text/StringBuilder.h"
35
36 namespace blink {
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(nullptr)
51     , m_name(name)
52     , m_standaloneValueOrAttachedLocalName(standaloneValue)
53     , m_ignoreChildrenChanged(0)
54 {
55 }
56
57 PassRefPtrWillBeRawPtr<Attr> Attr::create(Element& element, const QualifiedName& name)
58 {
59     RefPtrWillBeRawPtr<Attr> attr = adoptRefWillBeNoop(new Attr(element, name));
60     attr->createTextChild();
61     return attr.release();
62 }
63
64 PassRefPtrWillBeRawPtr<Attr> Attr::create(Document& document, const QualifiedName& name, const AtomicString& value)
65 {
66     RefPtrWillBeRawPtr<Attr> attr = adoptRefWillBeNoop(new Attr(document, name, value));
67     attr->createTextChild();
68     return attr.release();
69 }
70
71 Attr::~Attr()
72 {
73 }
74
75 const QualifiedName Attr::qualifiedName() const
76 {
77     if (m_element && !m_standaloneValueOrAttachedLocalName.isNull()) {
78         // In the unlikely case the Element attribute has a local name
79         // that differs by case, construct the qualified name based on
80         // it. This is the qualified name that must be used when
81         // looking up the attribute on the element.
82         return QualifiedName(m_name.prefix(), m_standaloneValueOrAttachedLocalName, m_name.namespaceURI());
83     }
84
85     return m_name;
86 }
87
88 void Attr::createTextChild()
89 {
90 #if !ENABLE(OILPAN)
91     ASSERT(refCount());
92 #endif
93     if (!value().isEmpty()) {
94         RefPtrWillBeRawPtr<Text> textNode = document().createTextNode(value().string());
95
96         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
97         // but much more efficiently.
98         textNode->setParentOrShadowHostNode(this);
99         treeScope().adoptIfNeeded(*textNode);
100         setFirstChild(textNode.get());
101         setLastChild(textNode.get());
102     }
103 }
104
105 void Attr::setValue(const AtomicString& value)
106 {
107     EventQueueScope scope;
108     m_ignoreChildrenChanged++;
109     removeChildren();
110     if (m_element)
111         elementAttribute().setValue(value);
112     else
113         m_standaloneValueOrAttachedLocalName = value;
114     createTextChild();
115     m_ignoreChildrenChanged--;
116
117     QualifiedName name = qualifiedName();
118     invalidateNodeListCachesInAncestors(&name, m_element);
119 }
120
121 void Attr::setValueInternal(const AtomicString& value)
122 {
123     if (m_element)
124         m_element->willModifyAttribute(qualifiedName(), this->value(), value);
125
126     setValue(value);
127
128     if (m_element)
129         m_element->didModifyAttribute(qualifiedName(), value);
130 }
131
132 const AtomicString& Attr::valueForBindings() const
133 {
134     UseCounter::count(document(), UseCounter::AttrGetValue);
135     return value();
136 }
137
138 void Attr::setValueForBindings(const AtomicString& value)
139 {
140     UseCounter::count(document(), UseCounter::AttrSetValue);
141     if (m_element)
142         UseCounter::count(document(), UseCounter::AttrSetValueWithElement);
143     setValueInternal(value);
144 }
145
146 void Attr::setNodeValue(const String& v)
147 {
148     // Attr uses AtomicString type for its value to save memory as there
149     // is duplication among Elements' attributes values.
150     setValueInternal(AtomicString(v));
151 }
152
153 PassRefPtrWillBeRawPtr<Node> Attr::cloneNode(bool /*deep*/)
154 {
155     RefPtrWillBeRawPtr<Attr> clone = adoptRefWillBeNoop(new Attr(document(), m_name, value()));
156     cloneChildNodes(clone.get());
157     return clone.release();
158 }
159
160 // DOM Section 1.1.1
161 bool Attr::childTypeAllowed(NodeType type) const
162 {
163     return TEXT_NODE == type;
164 }
165
166 void Attr::childrenChanged(const ChildrenChange&)
167 {
168     if (m_ignoreChildrenChanged > 0)
169         return;
170
171     QualifiedName name = qualifiedName();
172     invalidateNodeListCachesInAncestors(&name, m_element);
173
174     StringBuilder valueBuilder;
175     for (Node *n = firstChild(); n; n = n->nextSibling()) {
176         if (n->isTextNode())
177             valueBuilder.append(toText(n)->data());
178     }
179
180     AtomicString newValue = valueBuilder.toAtomicString();
181     if (m_element)
182         m_element->willModifyAttribute(qualifiedName(), value(), newValue);
183
184     if (m_element)
185         elementAttribute().setValue(newValue);
186     else
187         m_standaloneValueOrAttachedLocalName = newValue;
188
189     if (m_element)
190         m_element->attributeChanged(qualifiedName(), newValue);
191 }
192
193 const AtomicString& Attr::value() const
194 {
195     if (m_element)
196         return m_element->getAttribute(qualifiedName());
197     return m_standaloneValueOrAttachedLocalName;
198 }
199
200 Attribute& Attr::elementAttribute()
201 {
202     ASSERT(m_element);
203     ASSERT(m_element->elementData());
204     return *m_element->ensureUniqueElementData().attributes().find(qualifiedName());
205 }
206
207 void Attr::detachFromElementWithValue(const AtomicString& value)
208 {
209     ASSERT(m_element);
210     m_standaloneValueOrAttachedLocalName = value;
211     m_element = nullptr;
212 }
213
214 void Attr::attachToElement(Element* element, const AtomicString& attachedLocalName)
215 {
216     ASSERT(!m_element);
217     m_element = element;
218     m_standaloneValueOrAttachedLocalName = attachedLocalName;
219 }
220
221 void Attr::trace(Visitor* visitor)
222 {
223     visitor->trace(m_element);
224     ContainerNode::trace(visitor);
225 }
226
227 }