Title: [124485] trunk
Revision
124485
Author
[email protected]
Date
2012-08-02 12:36:04 -0700 (Thu, 02 Aug 2012)

Log Message

Do not dispatch modification events in SVG attribute synchronization
https://bugs.webkit.org/show_bug.cgi?id=92604

Reviewed by Ryosuke Niwa.

Source/WebCore:

Previously, calling hasAttribute() during layout could hit a
layout-during-layout bug because calling hasAttribute() could dispatch a
subtree modification event which could synchronously force a layout. hasAttribute()
exhibits this behavior because property synchronization is done lazily.

This patch skips dispatching subtree modification events during attribute
synchronization.

Additionally, this patch contains a refactoring of lazy attribute setting. We
now have a single place where lazy attributes are set (setSynchronizedLazyAttribute)
and lazy attribute flags have been moved to just Element and ElementAttributeData.

Test: svg/custom/path-domsubtreemodified-crash.html

* dom/Element.cpp:
(WebCore::Element::setAttribute):
(WebCore::Element::setSynchronizedLazyAttribute):
(WebCore):
(WebCore::Element::setAttributeInternal):
* dom/Element.h:
(Element):
* dom/ElementAttributeData.cpp:
(WebCore::ElementAttributeData::addAttribute):
(WebCore::ElementAttributeData::removeAttribute):
* dom/ElementAttributeData.h:
(ElementAttributeData):
* dom/StyledElement.cpp:
(WebCore::StyledElement::updateStyleAttribute):
* svg/properties/SVGAnimatedPropertyMacros.h:
(WebCore::SVGSynchronizableAnimatedProperty::synchronize):

LayoutTests:

* svg/custom/path-domsubtreemodified-crash-expected.txt: Added.
* svg/custom/path-domsubtreemodified-crash.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (124484 => 124485)


--- trunk/LayoutTests/ChangeLog	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/LayoutTests/ChangeLog	2012-08-02 19:36:04 UTC (rev 124485)
@@ -1,3 +1,13 @@
+2012-08-02  Philip Rogers  <[email protected]>
+
+        Do not dispatch modification events in SVG attribute synchronization
+        https://bugs.webkit.org/show_bug.cgi?id=92604
+
+        Reviewed by Ryosuke Niwa.
+
+        * svg/custom/path-domsubtreemodified-crash-expected.txt: Added.
+        * svg/custom/path-domsubtreemodified-crash.html: Added.
+
 2012-08-02  Konrad Piascik  <[email protected]>
 
         Web Inspector: Override the DeviceOrientation

Added: trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash-expected.txt (0 => 124485)


--- trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash-expected.txt	2012-08-02 19:36:04 UTC (rev 124485)
@@ -0,0 +1 @@
+This test passes if no crash occurs and PASS is printed. PASS

Added: trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash.html (0 => 124485)


--- trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash.html	                        (rev 0)
+++ trunk/LayoutTests/svg/custom/path-domsubtreemodified-crash.html	2012-08-02 19:36:04 UTC (rev 124485)
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!-- Test for WK92604 - Passes if no crash occurs and "PASS" is printed. -->
+<body id="body">
+<svg xmlns="http://www.w3.org/2000/svg">
+    <line stroke="green" vector-effect="non-scaling-stroke" y2="1"/>
+    <defs id="defs"></defs>
+</svg>
+<script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    var body = document.getElementById("body");
+    var defs = document.getElementById("defs");
+    document.addEventListener("DOMContentLoaded", doCrash, false);
+
+    body.addEventListener("DOMSubtreeModified", function() {
+        // Prevent infinite loop of modification events.
+        this.removeEventListener("DOMSubtreeModified", arguments.callee);
+
+        document.write("This test passes if no crash occurs and PASS is printed. PASS");
+
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, false);
+
+    function doCrash() {
+        var farthestViewportElement = defs["farthestViewportElement"];
+        var externalResourcesRequired = farthestViewportElement["externalResourcesRequired"];
+        externalResourcesRequired["baseVal"] = undefined;
+        body.offsetWidth;
+        body.innerHTML = "FAIL";
+    }
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (124484 => 124485)


--- trunk/Source/WebCore/ChangeLog	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/ChangeLog	2012-08-02 19:36:04 UTC (rev 124485)
@@ -1,3 +1,41 @@
+2012-08-02  Philip Rogers  <[email protected]>
+
+        Do not dispatch modification events in SVG attribute synchronization
+        https://bugs.webkit.org/show_bug.cgi?id=92604
+
+        Reviewed by Ryosuke Niwa.
+
+        Previously, calling hasAttribute() during layout could hit a
+        layout-during-layout bug because calling hasAttribute() could dispatch a 
+        subtree modification event which could synchronously force a layout. hasAttribute()
+        exhibits this behavior because property synchronization is done lazily.
+
+        This patch skips dispatching subtree modification events during attribute
+        synchronization.
+
+        Additionally, this patch contains a refactoring of lazy attribute setting. We
+        now have a single place where lazy attributes are set (setSynchronizedLazyAttribute)
+        and lazy attribute flags have been moved to just Element and ElementAttributeData.
+
+        Test: svg/custom/path-domsubtreemodified-crash.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::setAttribute):
+        (WebCore::Element::setSynchronizedLazyAttribute):
+        (WebCore):
+        (WebCore::Element::setAttributeInternal):
+        * dom/Element.h:
+        (Element):
+        * dom/ElementAttributeData.cpp:
+        (WebCore::ElementAttributeData::addAttribute):
+        (WebCore::ElementAttributeData::removeAttribute):
+        * dom/ElementAttributeData.h:
+        (ElementAttributeData):
+        * dom/StyledElement.cpp:
+        (WebCore::StyledElement::updateStyleAttribute):
+        * svg/properties/SVGAnimatedPropertyMacros.h:
+        (WebCore::SVGSynchronizableAnimatedProperty::synchronize):
+
 2012-08-02  Konrad Piascik  <[email protected]>
 
         Web Inspector: Override the DeviceOrientation

Modified: trunk/Source/WebCore/dom/Element.cpp (124484 => 124485)


--- trunk/Source/WebCore/dom/Element.cpp	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/dom/Element.cpp	2012-08-02 19:36:04 UTC (rev 124485)
@@ -656,31 +656,36 @@
 
     size_t index = ensureUpdatedAttributeData()->getAttributeItemIndex(localName, false);
     const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom);
-    setAttributeInternal(index, qName, value, NotInUpdateStyleAttribute);
+    setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
 }
 
-void Element::setAttribute(const QualifiedName& name, const AtomicString& value, EInUpdateStyleAttribute inUpdateStyleAttribute)
+void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
 {
-    setAttributeInternal(ensureUpdatedAttributeData()->getAttributeItemIndex(name), name, value, inUpdateStyleAttribute);
+    setAttributeInternal(ensureUpdatedAttributeData()->getAttributeItemIndex(name), name, value, NotInSynchronizationOfLazyAttribute);
 }
 
-inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& value, EInUpdateStyleAttribute inUpdateStyleAttribute)
+void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
 {
+    setAttributeInternal(mutableAttributeData()->getAttributeItemIndex(name), name, value, InSynchronizationOfLazyAttribute);
+}
+
+inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
+{
     ElementAttributeData* attributeData = mutableAttributeData();
 
     Attribute* old = index != notFound ? attributeData->attributeItem(index) : 0;
     if (value.isNull()) {
         if (old)
-            attributeData->removeAttribute(index, this, inUpdateStyleAttribute);
+            attributeData->removeAttribute(index, this, inSynchronizationOfLazyAttribute);
         return;
     }
 
     if (!old) {
-        attributeData->addAttribute(Attribute(name, value), this, inUpdateStyleAttribute);
+        attributeData->addAttribute(Attribute(name, value), this, inSynchronizationOfLazyAttribute);
         return;
     }
 
-    if (inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         willModifyAttribute(name, old->value(), value);
 
     if (RefPtr<Attr> attrNode = attrIfExists(name))
@@ -688,7 +693,7 @@
     else
         old->setValue(value);
 
-    if (inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         didModifyAttribute(Attribute(old->name(), old->value()));
 }
 

Modified: trunk/Source/WebCore/dom/Element.h (124484 => 124485)


--- trunk/Source/WebCore/dom/Element.h	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/dom/Element.h	2012-08-02 19:36:04 UTC (rev 124485)
@@ -113,7 +113,8 @@
 
     bool hasAttribute(const QualifiedName&) const;
     const AtomicString& getAttribute(const QualifiedName&) const;
-    void setAttribute(const QualifiedName&, const AtomicString& value, EInUpdateStyleAttribute = NotInUpdateStyleAttribute);
+    void setAttribute(const QualifiedName&, const AtomicString& value);
+    void setSynchronizedLazyAttribute(const QualifiedName&, const AtomicString& value);
     void removeAttribute(const QualifiedName&);
     void removeAttribute(size_t index);
 
@@ -479,7 +480,7 @@
     virtual NodeType nodeType() const;
     virtual bool childTypeAllowed(NodeType) const;
 
-    void setAttributeInternal(size_t index, const QualifiedName&, const AtomicString& value, EInUpdateStyleAttribute);
+    void setAttributeInternal(size_t index, const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
 
 #ifndef NDEBUG
     virtual void formatForDebugger(char* buffer, unsigned length) const;

Modified: trunk/Source/WebCore/dom/ElementAttributeData.cpp (124484 => 124485)


--- trunk/Source/WebCore/dom/ElementAttributeData.cpp	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/dom/ElementAttributeData.cpp	2012-08-02 19:36:04 UTC (rev 124485)
@@ -218,20 +218,20 @@
     m_inlineStyleDecl = 0;
 }
 
-void ElementAttributeData::addAttribute(const Attribute& attribute, Element* element, EInUpdateStyleAttribute inUpdateStyleAttribute)
+void ElementAttributeData::addAttribute(const Attribute& attribute, Element* element, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
 {
     ASSERT(isMutable());
 
-    if (element && inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (element && inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         element->willModifyAttribute(attribute.name(), nullAtom, attribute.value());
 
     m_mutableAttributeVector->append(attribute);
 
-    if (element && inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (element && inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         element->didAddAttribute(attribute);
 }
 
-void ElementAttributeData::removeAttribute(size_t index, Element* element, EInUpdateStyleAttribute inUpdateStyleAttribute)
+void ElementAttributeData::removeAttribute(size_t index, Element* element, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
 {
     ASSERT(isMutable());
     ASSERT(index < length());
@@ -239,7 +239,7 @@
     Attribute& attribute = m_mutableAttributeVector->at(index);
     QualifiedName name = attribute.name();
 
-    if (element && inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (element && inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         element->willRemoveAttribute(name, attribute.value());
 
     if (RefPtr<Attr> attr = attrIfExists(element, name))
@@ -247,7 +247,7 @@
 
     m_mutableAttributeVector->remove(index);
 
-    if (element && inUpdateStyleAttribute == NotInUpdateStyleAttribute)
+    if (element && inSynchronizationOfLazyAttribute == NotInSynchronizationOfLazyAttribute)
         element->didRemoveAttribute(name);
 }
 

Modified: trunk/Source/WebCore/dom/ElementAttributeData.h (124484 => 124485)


--- trunk/Source/WebCore/dom/ElementAttributeData.h	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/dom/ElementAttributeData.h	2012-08-02 19:36:04 UTC (rev 124485)
@@ -37,7 +37,7 @@
 class Element;
 class MemoryObjectInfo;
 
-enum EInUpdateStyleAttribute { NotInUpdateStyleAttribute, InUpdateStyleAttribute };
+enum SynchronizationOfLazyAttribute { NotInSynchronizationOfLazyAttribute, InSynchronizationOfLazyAttribute };
 
 class ElementAttributeData {
     WTF_MAKE_FAST_ALLOCATED;
@@ -78,9 +78,9 @@
     size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
 
     // These functions do no error checking.
-    void addAttribute(const Attribute&, Element*, EInUpdateStyleAttribute = NotInUpdateStyleAttribute);
+    void addAttribute(const Attribute&, Element*, SynchronizationOfLazyAttribute = NotInSynchronizationOfLazyAttribute);
     void removeAttribute(const QualifiedName&, Element*);
-    void removeAttribute(size_t index, Element*, EInUpdateStyleAttribute = NotInUpdateStyleAttribute);
+    void removeAttribute(size_t index, Element*, SynchronizationOfLazyAttribute = NotInSynchronizationOfLazyAttribute);
     PassRefPtr<Attr> takeAttribute(size_t index, Element*);
 
     bool hasID() const { return !m_idForStyleResolution.isNull(); }

Modified: trunk/Source/WebCore/dom/StyledElement.cpp (124484 => 124485)


--- trunk/Source/WebCore/dom/StyledElement.cpp	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/dom/StyledElement.cpp	2012-08-02 19:36:04 UTC (rev 124485)
@@ -127,7 +127,7 @@
     ASSERT(!isStyleAttributeValid());
     setIsStyleAttributeValid();
     if (const StylePropertySet* inlineStyle = this->inlineStyle())
-        const_cast<StyledElement*>(this)->setAttribute(styleAttr, inlineStyle->asText(), InUpdateStyleAttribute);
+        const_cast<StyledElement*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
 }
 
 StyledElement::StyledElement(const QualifiedName& name, Document* document, ConstructionType type)

Modified: trunk/Source/WebCore/svg/properties/SVGAnimatedPropertyMacros.h (124484 => 124485)


--- trunk/Source/WebCore/svg/properties/SVGAnimatedPropertyMacros.h	2012-08-02 19:29:26 UTC (rev 124484)
+++ trunk/Source/WebCore/svg/properties/SVGAnimatedPropertyMacros.h	2012-08-02 19:36:04 UTC (rev 124485)
@@ -55,18 +55,7 @@
 
     void synchronize(SVGElement* ownerElement, const QualifiedName& attrName, const AtomicString& value)
     {
-        // If the attribute already exists on the element, we change the
-        // Attribute directly to avoid a call to Element::attributeChanged
-        // that could cause the SVGElement to erroneously reset its properties.
-        // svg/dom/SVGStringList-basics.xhtml exercises this behavior.
-        ElementAttributeData* attributeData = ownerElement->mutableAttributeData();
-        Attribute* old = attributeData->getAttributeItem(attrName);
-        if (old && value.isNull())
-            attributeData->removeAttribute(old->name(), ownerElement);
-        else if (!old && !value.isNull())
-            attributeData->addAttribute(Attribute(attrName, value), ownerElement);
-        else if (old && !value.isNull())
-            old->setValue(value);
+        ownerElement->setSynchronizedLazyAttribute(attrName, value);
     }
 
     PropertyType value;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to