OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * (C) 2001 Peter Kelly (pmk@post.com) | 4 * (C) 2001 Peter Kelly (pmk@post.com) |
5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2012 Apple Inc. All rights
reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2012 Apple Inc. All rights
reserved. |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 20 matching lines...) Expand all Loading... |
31 #include "core/events/ScopedEventQueue.h" | 31 #include "core/events/ScopedEventQueue.h" |
32 #include "core/frame/UseCounter.h" | 32 #include "core/frame/UseCounter.h" |
33 #include "wtf/text/AtomicString.h" | 33 #include "wtf/text/AtomicString.h" |
34 #include "wtf/text/StringBuilder.h" | 34 #include "wtf/text/StringBuilder.h" |
35 | 35 |
36 namespace blink { | 36 namespace blink { |
37 | 37 |
38 using namespace HTMLNames; | 38 using namespace HTMLNames; |
39 | 39 |
40 Attr::Attr(Element& element, const QualifiedName& name) | 40 Attr::Attr(Element& element, const QualifiedName& name) |
41 : ContainerNode(&element.document()) | 41 : Node(&element.document(), CreateOther) |
42 , m_element(&element) | 42 , m_element(&element) |
43 , m_name(name) | 43 , m_name(name) |
44 , m_ignoreChildrenChanged(0) | |
45 { | 44 { |
46 } | 45 } |
47 | 46 |
48 Attr::Attr(Document& document, const QualifiedName& name, const AtomicString& st
andaloneValue) | 47 Attr::Attr(Document& document, const QualifiedName& name, const AtomicString& st
andaloneValue) |
49 : ContainerNode(&document) | 48 : Node(&document, CreateOther) |
50 , m_element(nullptr) | 49 , m_element(nullptr) |
51 , m_name(name) | 50 , m_name(name) |
52 , m_standaloneValueOrAttachedLocalName(standaloneValue) | 51 , m_standaloneValueOrAttachedLocalName(standaloneValue) |
53 , m_ignoreChildrenChanged(0) | |
54 { | 52 { |
55 } | 53 } |
56 | 54 |
57 PassRefPtrWillBeRawPtr<Attr> Attr::create(Element& element, const QualifiedName&
name) | 55 PassRefPtrWillBeRawPtr<Attr> Attr::create(Element& element, const QualifiedName&
name) |
58 { | 56 { |
59 RefPtrWillBeRawPtr<Attr> attr = adoptRefWillBeNoop(new Attr(element, name)); | 57 return adoptRefWillBeNoop(new Attr(element, name)); |
60 attr->createTextChild(); | |
61 return attr.release(); | |
62 } | 58 } |
63 | 59 |
64 PassRefPtrWillBeRawPtr<Attr> Attr::create(Document& document, const QualifiedNam
e& name, const AtomicString& value) | 60 PassRefPtrWillBeRawPtr<Attr> Attr::create(Document& document, const QualifiedNam
e& name, const AtomicString& value) |
65 { | 61 { |
66 RefPtrWillBeRawPtr<Attr> attr = adoptRefWillBeNoop(new Attr(document, name,
value)); | 62 return adoptRefWillBeNoop(new Attr(document, name, value)); |
67 attr->createTextChild(); | |
68 return attr.release(); | |
69 } | 63 } |
70 | 64 |
71 Attr::~Attr() | 65 Attr::~Attr() |
72 { | 66 { |
73 } | 67 } |
74 | 68 |
75 const QualifiedName Attr::qualifiedName() const | 69 const QualifiedName Attr::qualifiedName() const |
76 { | 70 { |
77 if (m_element && !m_standaloneValueOrAttachedLocalName.isNull()) { | 71 if (m_element && !m_standaloneValueOrAttachedLocalName.isNull()) { |
78 // In the unlikely case the Element attribute has a local name | 72 // In the unlikely case the Element attribute has a local name |
79 // that differs by case, construct the qualified name based on | 73 // that differs by case, construct the qualified name based on |
80 // it. This is the qualified name that must be used when | 74 // it. This is the qualified name that must be used when |
81 // looking up the attribute on the element. | 75 // looking up the attribute on the element. |
82 return QualifiedName(m_name.prefix(), m_standaloneValueOrAttachedLocalNa
me, m_name.namespaceURI()); | 76 return QualifiedName(m_name.prefix(), m_standaloneValueOrAttachedLocalNa
me, m_name.namespaceURI()); |
83 } | 77 } |
84 | 78 |
85 return m_name; | 79 return m_name; |
86 } | 80 } |
87 | 81 |
88 void Attr::createTextChild() | 82 const AtomicString& Attr::value() const |
89 { | 83 { |
90 #if !ENABLE(OILPAN) | 84 if (m_element) |
91 ASSERT(refCount()); | 85 return m_element->getAttribute(qualifiedName()); |
92 #endif | 86 return m_standaloneValueOrAttachedLocalName; |
93 if (!value().isEmpty()) { | |
94 RefPtrWillBeRawPtr<Text> textNode = document().createTextNode(value().st
ring()); | |
95 | |
96 // This does everything appendChild() would do in this situation (assumi
ng 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 } | 87 } |
104 | 88 |
105 void Attr::setValue(const AtomicString& value) | 89 void Attr::setValue(const AtomicString& value) |
106 { | 90 { |
107 EventQueueScope scope; | |
108 m_ignoreChildrenChanged++; | |
109 // We don't fire the DOMSubtreeModified event for Attr Nodes. This matches t
he behavior | |
110 // of IE and Firefox. This event is fired synchronously and is a source of t
rouble for | |
111 // attributes as the JS callback could alter the attributes and leave us in
a bad state. | |
112 removeChildren(OmitSubtreeModifiedEvent); | |
113 if (m_element) | 91 if (m_element) |
114 updateElementAttribute(value); | 92 m_element->setAttribute(qualifiedName(), value); |
115 else | 93 else |
116 m_standaloneValueOrAttachedLocalName = value; | 94 m_standaloneValueOrAttachedLocalName = value; |
117 createTextChild(); | |
118 m_ignoreChildrenChanged--; | |
119 | |
120 QualifiedName name = qualifiedName(); | |
121 invalidateNodeListCachesInAncestors(&name, m_element); | |
122 } | |
123 | |
124 void Attr::setValueInternal(const AtomicString& value) | |
125 { | |
126 if (m_element) | |
127 m_element->willModifyAttribute(qualifiedName(), this->value(), value); | |
128 | |
129 setValue(value); | |
130 | |
131 if (m_element) | |
132 m_element->didModifyAttribute(qualifiedName(), value); | |
133 } | 95 } |
134 | 96 |
135 const AtomicString& Attr::valueForBindings() const | 97 const AtomicString& Attr::valueForBindings() const |
136 { | 98 { |
137 UseCounter::count(document(), UseCounter::AttrGetValue); | 99 UseCounter::count(document(), UseCounter::AttrGetValue); |
138 return value(); | 100 return value(); |
139 } | 101 } |
140 | 102 |
141 void Attr::setValueForBindings(const AtomicString& value) | 103 void Attr::setValueForBindings(const AtomicString& value) |
142 { | 104 { |
143 UseCounter::count(document(), UseCounter::AttrSetValue); | 105 UseCounter::count(document(), UseCounter::AttrSetValue); |
144 if (m_element) | 106 if (m_element) |
145 UseCounter::count(document(), UseCounter::AttrSetValueWithElement); | 107 UseCounter::count(document(), UseCounter::AttrSetValueWithElement); |
146 setValueInternal(value); | 108 setValue(value); |
147 } | 109 } |
148 | 110 |
149 void Attr::setNodeValue(const String& v) | 111 void Attr::setNodeValue(const String& v) |
150 { | 112 { |
151 // Attr uses AtomicString type for its value to save memory as there | 113 // Attr uses AtomicString type for its value to save memory as there |
152 // is duplication among Elements' attributes values. | 114 // is duplication among Elements' attributes values. |
153 setValueInternal(AtomicString(v)); | 115 setValue(AtomicString(v)); |
154 } | 116 } |
155 | 117 |
156 PassRefPtrWillBeRawPtr<Node> Attr::cloneNode(bool /*deep*/) | 118 PassRefPtrWillBeRawPtr<Node> Attr::cloneNode(bool /*deep*/) |
157 { | 119 { |
158 RefPtrWillBeRawPtr<Attr> clone = adoptRefWillBeNoop(new Attr(document(), m_n
ame, value())); | 120 return adoptRefWillBeNoop(new Attr(document(), m_name, value())); |
159 cloneChildNodes(clone.get()); | |
160 return clone.release(); | |
161 } | |
162 | |
163 // DOM Section 1.1.1 | |
164 bool Attr::childTypeAllowed(NodeType type) const | |
165 { | |
166 return TEXT_NODE == type; | |
167 } | |
168 | |
169 void Attr::childrenChanged(const ChildrenChange&) | |
170 { | |
171 if (m_ignoreChildrenChanged > 0) | |
172 return; | |
173 | |
174 UseCounter::countDeprecation(document(), UseCounter::AttrChildChange); | |
175 | |
176 QualifiedName name = qualifiedName(); | |
177 invalidateNodeListCachesInAncestors(&name, m_element); | |
178 | |
179 StringBuilder valueBuilder; | |
180 for (Node *n = firstChild(); n; n = n->nextSibling()) { | |
181 if (n->isTextNode()) | |
182 valueBuilder.append(toText(n)->data()); | |
183 } | |
184 | |
185 AtomicString newValue = valueBuilder.toAtomicString(); | |
186 if (m_element) | |
187 m_element->willModifyAttribute(qualifiedName(), value(), newValue); | |
188 | |
189 if (m_element) | |
190 updateElementAttribute(newValue); | |
191 else | |
192 m_standaloneValueOrAttachedLocalName = newValue; | |
193 | |
194 if (m_element) | |
195 m_element->attributeChanged(qualifiedName(), newValue); | |
196 } | |
197 | |
198 const AtomicString& Attr::value() const | |
199 { | |
200 if (m_element) | |
201 return m_element->getAttribute(qualifiedName()); | |
202 return m_standaloneValueOrAttachedLocalName; | |
203 } | |
204 | |
205 void Attr::updateElementAttribute(const AtomicString& value) | |
206 { | |
207 ASSERT(m_element); | |
208 ASSERT(m_element->elementData()); | |
209 MutableAttributeCollection attributes = m_element->ensureUniqueElementData()
.attributes(); | |
210 size_t index = attributes.findIndex(qualifiedName()); | |
211 if (index == kNotFound) { | |
212 // Element attributes with null values are not stored. | |
213 if (!value.isNull()) | |
214 attributes.append(qualifiedName(), value); | |
215 return; | |
216 } | |
217 return attributes[index].setValue(value); | |
218 } | 121 } |
219 | 122 |
220 void Attr::detachFromElementWithValue(const AtomicString& value) | 123 void Attr::detachFromElementWithValue(const AtomicString& value) |
221 { | 124 { |
222 ASSERT(m_element); | 125 ASSERT(m_element); |
223 m_standaloneValueOrAttachedLocalName = value; | 126 m_standaloneValueOrAttachedLocalName = value; |
224 m_element = nullptr; | 127 m_element = nullptr; |
225 } | 128 } |
226 | 129 |
227 void Attr::attachToElement(Element* element, const AtomicString& attachedLocalNa
me) | 130 void Attr::attachToElement(Element* element, const AtomicString& attachedLocalNa
me) |
228 { | 131 { |
229 ASSERT(!m_element); | 132 ASSERT(!m_element); |
230 m_element = element; | 133 m_element = element; |
231 m_standaloneValueOrAttachedLocalName = attachedLocalName; | 134 m_standaloneValueOrAttachedLocalName = attachedLocalName; |
232 } | 135 } |
233 | 136 |
234 DEFINE_TRACE(Attr) | 137 DEFINE_TRACE(Attr) |
235 { | 138 { |
236 visitor->trace(m_element); | 139 visitor->trace(m_element); |
237 ContainerNode::trace(visitor); | 140 Node::trace(visitor); |
238 } | 141 } |
239 | 142 |
240 } | 143 } |
OLD | NEW |