https://bugs.webkit.org/show_bug.cgi?id=74692
Reviewed by Sam Weinig.
Source/WebCore:
Call invalidateNodeListsCacheAfterAttributeChanged in Element::updateAfterAttributeChanged instead of
parsedMappedAttribute of various elements. Also make invalidateNodeListsCacheAfterAttributeChanged take
the qualified name of the changed attribute so that we can exit early when the changed attribute isn't
one of attributes we care.
In addition, added a missing call to invalidateNodeListsCacheAfterAttributeChanged in Attr::setValue.
Test: fast/dom/Attr/invalidate-nodelist-after-attr-setvalue.html
* dom/Attr.cpp:
(WebCore::Attr::childrenChanged):
* dom/Element.cpp:
(WebCore::Element::updateAfterAttributeChanged):
* dom/NamedNodeMap.cpp:
(WebCore::NamedNodeMap::addAttribute):
(WebCore::NamedNodeMap::removeAttribute):
* dom/Node.cpp:
(WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged):
* dom/Node.h:
* dom/StyledElement.cpp:
(WebCore::StyledElement::classAttributeChanged):
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parseMappedAttribute):
* html/HTMLAppletElement.cpp:
(WebCore::HTMLAppletElement::parseMappedAttribute):
* html/HTMLElement.cpp:
(WebCore::HTMLElement::parseMappedAttribute):
* html/HTMLEmbedElement.cpp:
(WebCore::HTMLEmbedElement::parseMappedAttribute):
* html/HTMLFormElement.cpp:
(WebCore::HTMLFormElement::parseMappedAttribute):
* html/HTMLFrameElementBase.cpp:
(WebCore::HTMLFrameElementBase::parseMappedAttribute):
* html/HTMLIFrameElement.cpp:
(WebCore::HTMLIFrameElement::parseMappedAttribute):
* html/HTMLImageElement.cpp:
(WebCore::HTMLImageElement::parseMappedAttribute):
* html/HTMLMapElement.cpp:
(WebCore::HTMLMapElement::parseMappedAttribute):
* html/HTMLMetaElement.cpp:
(WebCore::HTMLMetaElement::parseMappedAttribute):
* html/HTMLObjectElement.cpp:
(WebCore::HTMLObjectElement::parseMappedAttribute):
* html/HTMLParamElement.cpp:
(WebCore::HTMLParamElement::parseMappedAttribute):
LayoutTests:
Add a regression test for setting Attr's value. WebKit should invalidate the cache as needed.
* fast/dom/Attr/invalidate-nodelist-after-attr-setvalue-expected.txt: Added.
* fast/dom/Attr/invalidate-nodelist-after-attr-setvalue.html: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@103116
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-12-16 Ryosuke Niwa <rniwa@webkit.org>
+
+ invalidateNodeListsCacheAfterAttributeChanged has too many callers
+ https://bugs.webkit.org/show_bug.cgi?id=74692
+
+ Reviewed by Sam Weinig.
+
+ Add a regression test for setting Attr's value. WebKit should invalidate the cache as needed.
+
+ * fast/dom/Attr/invalidate-nodelist-after-attr-setvalue-expected.txt: Added.
+ * fast/dom/Attr/invalidate-nodelist-after-attr-setvalue.html: Added.
+
2011-12-16 Andreas Kling <kling@webkit.org>
Cache and reuse HTMLCollections exposed by Document.
--- /dev/null
+This tests setting the value of an attribute node after caching childNodes of the attribute node.
+The cache should be cleared and childNodes[0].data should return the new value.
+You should see PASS below:
+
+PASS nameAttrNode.childNodes.length is 1
+PASS nameAttrNode.childNodes[0] is oldValue
+PASS nameAttrNode.childNodes[0].data is "oldName"
+
+PASS nameAttrNode.value = 'newName'; nameAttrNode.value is "newName"
+PASS nameAttrNode.childNodes[0] is not oldValue
+PASS nameAttrNode.childNodes[0].data is "newName"
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests setting the value of an attribute node after caching childNodes of the attribute node.<br>
+The cache should be cleared and childNodes[0].data should return the new value.<br>
+You should see PASS below:</p>
+<div id="console"></div>
+<script src="../../js/resources/js-test-pre.js"></script>
+<script>
+
+var element = document.createElement('div');
+var nameAttrNode = document.createAttribute('name');
+var oldValue = document.createTextNode('oldName');
+nameAttrNode.appendChild(oldValue);
+element.setAttributeNode(nameAttrNode);
+document.body.appendChild(element);
+
+shouldBe("nameAttrNode.childNodes.length", '1');
+shouldBe('nameAttrNode.childNodes[0]', 'oldValue');
+shouldBe('nameAttrNode.childNodes[0].data', '"oldName"');
+
+debug('');
+shouldBe("nameAttrNode.value = 'newName'; nameAttrNode.value", '"newName"');
+shouldNotBe("nameAttrNode.childNodes[0]", 'oldValue');
+shouldBe("nameAttrNode.childNodes[0].data", '"newName"');
+
+</script>
+</body>
+</html>
+2011-12-16 Ryosuke Niwa <rniwa@webkit.org>
+
+ invalidateNodeListsCacheAfterAttributeChanged has too many callers
+ https://bugs.webkit.org/show_bug.cgi?id=74692
+
+ Reviewed by Sam Weinig.
+
+ Call invalidateNodeListsCacheAfterAttributeChanged in Element::updateAfterAttributeChanged instead of
+ parsedMappedAttribute of various elements. Also make invalidateNodeListsCacheAfterAttributeChanged take
+ the qualified name of the changed attribute so that we can exit early when the changed attribute isn't
+ one of attributes we care.
+
+ In addition, added a missing call to invalidateNodeListsCacheAfterAttributeChanged in Attr::setValue.
+
+ Test: fast/dom/Attr/invalidate-nodelist-after-attr-setvalue.html
+
+ * dom/Attr.cpp:
+ (WebCore::Attr::childrenChanged):
+ * dom/Element.cpp:
+ (WebCore::Element::updateAfterAttributeChanged):
+ * dom/NamedNodeMap.cpp:
+ (WebCore::NamedNodeMap::addAttribute):
+ (WebCore::NamedNodeMap::removeAttribute):
+ * dom/Node.cpp:
+ (WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged):
+ * dom/Node.h:
+ * dom/StyledElement.cpp:
+ (WebCore::StyledElement::classAttributeChanged):
+ * html/HTMLAnchorElement.cpp:
+ (WebCore::HTMLAnchorElement::parseMappedAttribute):
+ * html/HTMLAppletElement.cpp:
+ (WebCore::HTMLAppletElement::parseMappedAttribute):
+ * html/HTMLElement.cpp:
+ (WebCore::HTMLElement::parseMappedAttribute):
+ * html/HTMLEmbedElement.cpp:
+ (WebCore::HTMLEmbedElement::parseMappedAttribute):
+ * html/HTMLFormElement.cpp:
+ (WebCore::HTMLFormElement::parseMappedAttribute):
+ * html/HTMLFrameElementBase.cpp:
+ (WebCore::HTMLFrameElementBase::parseMappedAttribute):
+ * html/HTMLIFrameElement.cpp:
+ (WebCore::HTMLIFrameElement::parseMappedAttribute):
+ * html/HTMLImageElement.cpp:
+ (WebCore::HTMLImageElement::parseMappedAttribute):
+ * html/HTMLMapElement.cpp:
+ (WebCore::HTMLMapElement::parseMappedAttribute):
+ * html/HTMLMetaElement.cpp:
+ (WebCore::HTMLMetaElement::parseMappedAttribute):
+ * html/HTMLObjectElement.cpp:
+ (WebCore::HTMLObjectElement::parseMappedAttribute):
+ * html/HTMLParamElement.cpp:
+ (WebCore::HTMLParamElement::parseMappedAttribute):
+
2011-12-16 Andreas Kling <kling@webkit.org>
Cache and reuse HTMLCollections exposed by Document.
m_attribute->setValue(value);
createTextChild();
m_ignoreChildrenChanged--;
+
+ invalidateNodeListsCacheAfterAttributeChanged(m_attribute->name());
}
void Attr::setValue(const AtomicString& value, ExceptionCode&)
Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
- invalidateNodeListsCacheAfterAttributeChanged();
+ invalidateNodeListsCacheAfterAttributeChanged(m_attribute->name());
// FIXME: We should include entity references in the value
-
+
String val = "";
for (Node *n = firstChild(); n; n = n->nextSibling()) {
if (n->isTextNode())
void Element::updateAfterAttributeChanged(Attribute* attr)
{
+ invalidateNodeListsCacheAfterAttributeChanged(attr->name());
+
if (!AXObjectCache::accessibilityEnabled())
return;
m_element->attributeChanged(attribute.get());
// Because of our updateStyleAttribute() style modification events are never sent at the right time, so don't bother sending them.
if (attribute->name() != styleAttr) {
- m_element->invalidateNodeListsCacheAfterAttributeChanged();
m_element->dispatchAttrAdditionEvent(attribute.get());
m_element->dispatchSubtreeModifiedEvent();
}
attr->m_value = value;
}
if (m_element) {
- m_element->invalidateNodeListsCacheAfterAttributeChanged();
m_element->dispatchAttrRemovalEvent(attr.get());
m_element->dispatchSubtreeModifiedEvent();
}
removeNodeListCacheIfPossible(this, data);
}
-void Node::invalidateNodeListsCacheAfterAttributeChanged()
+void Node::invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName& attrName)
{
if (hasRareData() && isAttributeNode()) {
NodeRareData* data = rareData();
data->clearChildNodeListCache();
}
+ // This list should be sync'ed with NodeListsNodeData.
+ if (attrName != classAttr
+#if ENABLE(MICRODATA)
+ && attrName != itemscopeAttr
+ && attrName != itempropAttr
+#endif
+ && attrName != nameAttr)
+ return;
+
if (!treeScope()->hasNodeListCaches())
return;
void registerDynamicSubtreeNodeList(DynamicSubtreeNodeList*);
void unregisterDynamicSubtreeNodeList(DynamicSubtreeNodeList*);
- void invalidateNodeListsCacheAfterAttributeChanged();
+ void invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName&);
void invalidateNodeListsCacheAfterChildrenChanged();
void notifyLocalNodeListsLabelChanged();
void removeCachedClassNodeList(ClassNodeList*, const String&);
} else if (attributeMap())
attributeMap()->clearClass();
setNeedsStyleRecalc();
- invalidateNodeListsCacheAfterAttributeChanged();
dispatchSubtreeModifiedEvent();
}
}
}
invalidateCachedVisitedLinkHash();
- } else if (attr->name() == nameAttr) {
- invalidateNodeListsCacheAfterAttributeChanged();
- } else if (attr->name() == titleAttr) {
+ } else if (attr->name() == nameAttr || attr->name() == titleAttr) {
// Do nothing.
} else if (attr->name() == relAttr)
setRel(attr->value());
document->addNamedItem(newName);
}
m_name = newName;
- invalidateNodeListsCacheAfterAttributeChanged();
} else if (isIdAttributeName(attr->name())) {
const AtomicString& newId = attr->value();
if (inDocument() && document()->isHTMLDocument()) {
addCSSProperty(attr, CSSPropertyWebkitUserSelect, CSSValueNone);
} else if (equalIgnoringCase(value, "false"))
addCSSProperty(attr, CSSPropertyWebkitUserDrag, CSSValueNone);
- } else if (attr->name() == nameAttr) {
- invalidateNodeListsCacheAfterAttributeChanged();
#if ENABLE(MICRODATA)
} else if (attr->name() == itempropAttr) {
setItemProp(attr->value());
document->addNamedItem(value);
}
m_name = value;
- invalidateNodeListsCacheAfterAttributeChanged();
} else
HTMLPlugInImageElement::parseMappedAttribute(attr);
}
document->addNamedItem(newName);
}
m_name = newName;
- invalidateNodeListsCacheAfterAttributeChanged();
} else
HTMLElement::parseMappedAttribute(attr);
}
m_frameName = attr->value();
} else if (attr->name() == nameAttr) {
m_frameName = attr->value();
- invalidateNodeListsCacheAfterAttributeChanged();
// FIXME: If we are already attached, this doesn't actually change the frame's name.
// FIXME: If we are already attached, this doesn't check for frame name
// conflicts and generate a unique frame name.
document->addExtraNamedItem(newName);
}
m_name = newName;
- invalidateNodeListsCacheAfterAttributeChanged();
} else if (attr->name() == frameborderAttr) {
// Frame border doesn't really match the HTML4 spec definition for iframes. It simply adds
// a presentational hint that the border should be off if set to zero.
document->addNamedItem(newName);
}
m_name = newName;
- invalidateNodeListsCacheAfterAttributeChanged();
} else if (isIdAttributeName(attr->name())) {
const AtomicString& newId = attr->value();
if (inDocument() && document()->isHTMLDocument()) {
if (inDocument())
treeScope()->addImageMap(this);
- if (attrName == nameAttr)
- invalidateNodeListsCacheAfterAttributeChanged();
return;
}
else if (attr->name() == contentAttr)
process();
else if (attr->name() == nameAttr) {
- invalidateNodeListsCacheAfterAttributeChanged();
+ // Do nothing
} else
HTMLElement::parseMappedAttribute(attr);
}
document->addNamedItem(newName);
}
m_name = newName;
- invalidateNodeListsCacheAfterAttributeChanged();
} else if (attr->name() == borderAttr)
applyBorderAttribute(attr);
else if (isIdAttributeName(attr->name())) {
m_name = attr->value();
} else if (attr->name() == nameAttr) {
m_name = attr->value();
- invalidateNodeListsCacheAfterAttributeChanged();
} else if (attr->name() == valueAttr) {
m_value = attr->value();
} else