Don't invoke post resolution callbacks when resolving computed style
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Jun 2018 22:25:30 +0000 (22:25 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Jun 2018 22:25:30 +0000 (22:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187113
<rdar://problem/41365766>

Reviewed by Geoff Garen.

Source/WebCore:

Post-resolution callbacks should only be invoked when we resolve the full document style,
not when resolving computed style for a single element.

Tests: fast/dom/object-computed-style-event.html

* dom/Document.cpp:
(WebCore::Document::styleForElementIgnoringPendingStylesheets):
* dom/Element.cpp:
(WebCore::Element::resolveComputedStyle):

Also ref the ancestor stack to be safe.

* style/StyleTreeResolver.cpp:
(WebCore::Style::PostResolutionCallbackDisabler::PostResolutionCallbackDisabler):
(WebCore::Style::PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler):

Add an option to not drain the callback queue on destruction. In this mode we
just block network loads.

* style/StyleTreeResolver.h:

LayoutTests:

* fast/dom/object-computed-style-event-expected.txt: Added.
* fast/dom/object-computed-style-event.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233281 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/dom/object-computed-style-event-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/object-computed-style-event.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/style/StyleTreeResolver.cpp
Source/WebCore/style/StyleTreeResolver.h

index 2a259ef..c9bc968 100644 (file)
@@ -1,3 +1,14 @@
+2018-06-27  Antti Koivisto  <antti@apple.com>
+
+        Don't invoke post resolution callbacks when resolving computed style
+        https://bugs.webkit.org/show_bug.cgi?id=187113
+        <rdar://problem/41365766>
+
+        Reviewed by Geoff Garen.
+
+        * fast/dom/object-computed-style-event-expected.txt: Added.
+        * fast/dom/object-computed-style-event.html: Added.
+
 2018-06-27  Timothy Hatcher  <timothy@apple.com>
 
         Find on page selection color isn't adapted for dark mode.
diff --git a/LayoutTests/fast/dom/object-computed-style-event-expected.txt b/LayoutTests/fast/dom/object-computed-style-event-expected.txt
new file mode 100644 (file)
index 0000000..fe28933
--- /dev/null
@@ -0,0 +1 @@
+This test passes if there is no exception.
diff --git a/LayoutTests/fast/dom/object-computed-style-event.html b/LayoutTests/fast/dom/object-computed-style-event.html
new file mode 100644 (file)
index 0000000..2881baf
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+</script>
+<style>
+.class1 { -webkit-mask-box-image-source: url(#nonexistentURL); }
+</style>
+<script>
+function freememory() {
+    var a;
+    for(var i=0;i<100;i++) {
+        a = new Uint8Array(1024*1024);
+    }
+    document.implementation.createHTMLDocument("doc");
+}
+
+function createTestRange() {
+    var testRange = document.createRange();
+    testRange.setEndAfter(testSelectOption);
+    testRange.deleteContents();
+}
+
+function eventhandler1() {
+    var testDataList = document.createElement("datalist");
+    testSelect.appendChild(testObjectParam);
+    document.title = "foo";
+    testDataList.addEventListener("DOMNodeInsertedIntoDocument", createTestRange);
+    testObject.appendChild(testDataList);
+    freememory();
+}
+
+function eventhandler2() {
+    testObject.setAttribute("onbeforeload", "eventhandler1()");
+    testSelect.addEventListener("DOMNodeRemovedFromDocument", eventhandler1);
+    testSelect.replaceWith("This test passes if there is no exception.");
+}
+
+function runTest() {
+    var testSource = document.createElement("source");
+    testSource.addEventListener("DOMSubtreeModified", eventhandler2);
+    testSource.setAttribute("onsubmit", "");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+</script>
+</head>
+<body onload=runTest()>
+    <li class="class1">Test List</li>
+    <object id="testObject">
+        <param id="testObjectParam"></param>
+    </object>
+    <select id="testSelect">
+        <option id="testSelectOption">Test Option</option>
+    </select>
+</body>
+</html>
index 9187141..395f940 100644 (file)
@@ -1,3 +1,32 @@
+2018-06-27  Antti Koivisto  <antti@apple.com>
+
+        Don't invoke post resolution callbacks when resolving computed style
+        https://bugs.webkit.org/show_bug.cgi?id=187113
+        <rdar://problem/41365766>
+
+        Reviewed by Geoff Garen.
+
+        Post-resolution callbacks should only be invoked when we resolve the full document style,
+        not when resolving computed style for a single element.
+
+        Tests: fast/dom/object-computed-style-event.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::styleForElementIgnoringPendingStylesheets):
+        * dom/Element.cpp:
+        (WebCore::Element::resolveComputedStyle):
+
+        Also ref the ancestor stack to be safe.
+
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::PostResolutionCallbackDisabler::PostResolutionCallbackDisabler):
+        (WebCore::Style::PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler):
+
+        Add an option to not drain the callback queue on destruction. In this mode we
+        just block network loads.
+
+        * style/StyleTreeResolver.h:
+
 2018-06-27  Timothy Hatcher  <timothy@apple.com>
 
         Find on page selection color isn't adapted for dark mode.
index 22d495b..d764e75 100644 (file)
@@ -2021,7 +2021,7 @@ std::unique_ptr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets
     ASSERT(pseudoElementSpecifier == PseudoId::None || parentStyle);
 
     // On iOS request delegates called during styleForElement may result in re-entering WebKit and killing the style resolver.
-    Style::PostResolutionCallbackDisabler disabler(*this);
+    Style::PostResolutionCallbackDisabler disabler(*this, Style::PostResolutionCallbackDisabler::DrainCallbacks::No);
 
     SetForScope<bool> change(m_ignorePendingStylesheets, true);
     auto& resolver = element.styleResolver();
index 88ebd25..1dcf0e8 100644 (file)
@@ -2746,7 +2746,7 @@ const RenderStyle& Element::resolveComputedStyle()
     ASSERT(isConnected());
     ASSERT(!existingComputedStyle());
 
-    Deque<Element*, 32> elementsRequiringComputedStyle({ this });
+    Deque<RefPtr<Element>, 32> elementsRequiringComputedStyle({ this });
     const RenderStyle* computedStyle = nullptr;
 
     // Collect ancestors until we find one that has style.
@@ -2760,7 +2760,7 @@ const RenderStyle& Element::resolveComputedStyle()
     }
 
     // Resolve and cache styles starting from the most distant ancestor.
-    for (auto* element : elementsRequiringComputedStyle) {
+    for (auto& element : elementsRequiringComputedStyle) {
         auto style = document().styleForElementIgnoringPendingStylesheets(*element, computedStyle);
         computedStyle = style.get();
         ElementRareData& rareData = element->ensureElementRareData();
index 7083dd2..44f24c1 100644 (file)
@@ -600,7 +600,8 @@ static void suspendMemoryCacheClientCalls(Document& document)
 
 static unsigned resolutionNestingDepth;
 
-PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
+PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document, DrainCallbacks drainCallbacks)
+    : m_drainCallbacks(drainCallbacks)
 {
     ++resolutionNestingDepth;
 
@@ -614,12 +615,13 @@ PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& documen
 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
 {
     if (resolutionNestingDepth == 1) {
-        // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
-        auto& queue = postResolutionCallbackQueue();
-        for (size_t i = 0; i < queue.size(); ++i)
-            queue[i]();
-        queue.clear();
-
+        if (m_drainCallbacks == DrainCallbacks::Yes) {
+            // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
+            auto& queue = postResolutionCallbackQueue();
+            for (size_t i = 0; i < queue.size(); ++i)
+                queue[i]();
+            queue.clear();
+        }
         platformStrategies()->loaderStrategy()->resumePendingRequests();
     }
 
index 88af96f..899a9f6 100644 (file)
@@ -112,8 +112,11 @@ bool postResolutionCallbacksAreSuspended();
 
 class PostResolutionCallbackDisabler {
 public:
-    explicit PostResolutionCallbackDisabler(Document&);
+    enum class DrainCallbacks { Yes, No };
+    explicit PostResolutionCallbackDisabler(Document&, DrainCallbacks = DrainCallbacks::Yes);
     ~PostResolutionCallbackDisabler();
+private:
+    DrainCallbacks m_drainCallbacks;
 };
 
 }