| 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 |