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