Upstream version 7.36.149.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/v8/ExceptionState.h"
27 #include "bindings/v8/ExceptionStatePlaceholder.h"
28 #include "core/dom/Element.h"
29 #include "core/dom/Text.h"
30 #include "core/events/ScopedEventQueue.h"
31 #include "core/frame/UseCounter.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     ScriptWrappable::init(this);
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     ScriptWrappable::init(this);
56 }
57
58 PassRefPtr<Attr> Attr::create(Element& element, const QualifiedName& name)
59 {
60     RefPtr<Attr> attr = adoptRef(new Attr(element, name));
61     attr->createTextChild();
62     return attr.release();
63 }
64
65 PassRefPtr<Attr> Attr::create(Document& document, const QualifiedName& name, const AtomicString& value)
66 {
67     RefPtr<Attr> attr = adoptRef(new Attr(document, name, value));
68     attr->createTextChild();
69     return attr.release();
70 }
71
72 Attr::~Attr()
73 {
74 }
75
76 void Attr::createTextChild()
77 {
78 #if !ENABLE(OILPAN)
79     ASSERT(refCount());
80 #endif
81     if (!value().isEmpty()) {
82         RefPtr<Text> textNode = document().createTextNode(value().string());
83
84         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
85         // but much more efficiently.
86         textNode->setParentOrShadowHostNode(this);
87         treeScope().adoptIfNeeded(*textNode);
88         setFirstChild(textNode.get());
89         setLastChild(textNode.get());
90     }
91 }
92
93 void Attr::setValue(const AtomicString& value)
94 {
95     EventQueueScope scope;
96     m_ignoreChildrenChanged++;
97     removeChildren();
98     if (m_element)
99         elementAttribute().setValue(value);
100     else
101         m_standaloneValue = value;
102     createTextChild();
103     m_ignoreChildrenChanged--;
104
105     invalidateNodeListCachesInAncestors(&m_name, m_element);
106 }
107
108 void Attr::setValueInternal(const AtomicString& value)
109 {
110     if (m_element)
111         m_element->willModifyAttribute(qualifiedName(), this->value(), value);
112
113     setValue(value);
114
115     if (m_element)
116         m_element->didModifyAttribute(qualifiedName(), value);
117 }
118
119 const AtomicString& Attr::valueForBindings() const
120 {
121     UseCounter::count(document(), UseCounter::AttrGetValue);
122     return value();
123 }
124
125 void Attr::setValueForBindings(const AtomicString& value)
126 {
127     UseCounter::count(document(), UseCounter::AttrSetValue);
128     if (m_element)
129         UseCounter::count(document(), UseCounter::AttrSetValueWithElement);
130     setValueInternal(value);
131 }
132
133 void Attr::setNodeValue(const String& v)
134 {
135     // Attr uses AtomicString type for its value to save memory as there
136     // is duplication among Elements' attributes values.
137     setValueInternal(AtomicString(v));
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     return TEXT_NODE == type;
151 }
152
153 void Attr::childrenChanged(bool, Node*, Node*, int)
154 {
155     if (m_ignoreChildrenChanged > 0)
156         return;
157
158     invalidateNodeListCachesInAncestors(&qualifiedName(), m_element);
159
160     StringBuilder valueBuilder;
161     for (Node *n = firstChild(); n; n = n->nextSibling()) {
162         if (n->isTextNode())
163             valueBuilder.append(toText(n)->data());
164     }
165
166     AtomicString newValue = valueBuilder.toAtomicString();
167     if (m_element)
168         m_element->willModifyAttribute(qualifiedName(), value(), newValue);
169
170     if (m_element)
171         elementAttribute().setValue(newValue);
172     else
173         m_standaloneValue = newValue;
174
175     if (m_element)
176         m_element->attributeChanged(qualifiedName(), newValue);
177 }
178
179 const AtomicString& Attr::value() const
180 {
181     if (m_element)
182         return m_element->getAttribute(qualifiedName());
183     return m_standaloneValue;
184 }
185
186 Attribute& Attr::elementAttribute()
187 {
188     ASSERT(m_element);
189     ASSERT(m_element->elementData());
190     return *m_element->ensureUniqueElementData().getAttributeItem(qualifiedName());
191 }
192
193 void Attr::detachFromElementWithValue(const AtomicString& value)
194 {
195     ASSERT(m_element);
196     ASSERT(m_standaloneValue.isNull());
197     m_standaloneValue = value;
198     m_element = 0;
199 }
200
201 void Attr::attachToElement(Element* element)
202 {
203     ASSERT(!m_element);
204     m_element = element;
205     m_standaloneValue = nullAtom;
206 }
207
208 }