Title: [292947] trunk
Revision
292947
Author
[email protected]
Date
2022-04-17 01:08:00 -0700 (Sun, 17 Apr 2022)

Log Message

Make release assertion in Document::updateLayout more precise for FrameSelection::setSelection
https://bugs.webkit.org/show_bug.cgi?id=239431

Reviewed by Alan Bujtas.

Source/WebCore:

Avoid the assertion failure by allowing no-op layout updates within FrameSelection::setSelection.

To do this, this patch introduces a new RAII object, UpToDateLayoutScope, which denotes when when the layout
is up-to-date and therefore does not require a new layout update. When this scope exists in the stack frame,
we allow calls to Document::updateLayout even inside ScriptDisallowedScope. We also assert that nobody attempts
to schedule a new style resolution or layout when this object exists.

Test: fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html

* WebCore.xcodeproj/project.pbxproj:
* dom/Document.cpp:
(WebCore::Document::scheduleStyleRecalc):
(WebCore::Document::updateLayout):
* dom/Document.h:
(WebCore::Document::upToDateLayoutScopeCount const):
(WebCore::Document::incrementUpToDateLayoutScopeCount):
(WebCore::Document::decrementUpToDateLayoutScopeCount):
* editing/FrameSelection.cpp:
(WebCore::FrameSelection::setSelection):
* page/FrameViewLayoutContext.cpp:
(WebCore::FrameViewLayoutContext::scheduleLayout):
* rendering/RenderObject.h:
(WebCore::RenderObject::isSetNeedsLayoutForbidden const):
* rendering/UpToDateLayoutScope.h: Added.
(WebCore::UpToDateLayoutScope::UpToDateLayoutScope):
(WebCore::UpToDateLayoutScope::~UpToDateLayoutScope):
(WebCore::UpToDateLayoutScope::scopeIfLayoutIsUpToUpdate):
(WebCore::UpToDateLayoutScope::needsLayout):

LayoutTests:

Add a regression test, and fix existing accessibility tests which were mutating DOM inside setSelection
via should* functions. In production, this will never happen since accessibility notification will be sent
to UI process asynchronously and accesssibility code won't try to mutate DOM synchronously.

* accessibility/mac/focus-setting-selection-syncronizing-not-clearing-expected.txt: Rebaselined.
* accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html: Delay DOM mutations in should*
until the notification is over.
* accessibility/mac/selection-change-userinfo.html: Ditto.
* accessibility/mac/selection-sync.html: Ditto.
* accessibility/mac/selection-value-changes-for-aria-textbox.html: Ditto.
* fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash-expected.txt: Added.
* fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (292946 => 292947)


--- trunk/LayoutTests/ChangeLog	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/ChangeLog	2022-04-17 08:08:00 UTC (rev 292947)
@@ -1,3 +1,23 @@
+2022-04-16  Ryosuke Niwa  <[email protected]>
+
+        Make release assertion in Document::updateLayout more precise for FrameSelection::setSelection
+        https://bugs.webkit.org/show_bug.cgi?id=239431
+
+        Reviewed by Alan Bujtas.
+
+        Add a regression test, and fix existing accessibility tests which were mutating DOM inside setSelection
+        via should* functions. In production, this will never happen since accessibility notification will be sent
+        to UI process asynchronously and accesssibility code won't try to mutate DOM synchronously.
+
+        * accessibility/mac/focus-setting-selection-syncronizing-not-clearing-expected.txt: Rebaselined.
+        * accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html: Delay DOM mutations in should*
+        until the notification is over.
+        * accessibility/mac/selection-change-userinfo.html: Ditto.
+        * accessibility/mac/selection-sync.html: Ditto.
+        * accessibility/mac/selection-value-changes-for-aria-textbox.html: Ditto.
+        * fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash-expected.txt: Added.
+        * fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html: Added.
+
 2022-04-15  Matteo Flores  <[email protected]>
 
         REBASLINE: [ Monterey wk2 ] 7 /paymentrequest/* tests are constant text failures

Modified: trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing-expected.txt (292946 => 292947)


--- trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing-expected.txt	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing-expected.txt	2022-04-17 08:08:00 UTC (rev 292947)
@@ -7,9 +7,9 @@
 
 
 PASS addedNotification is true
+PASS accessibilityController.focusedElement.isEqual(accessibilityController.accessibleElementById("1")) is true
 PASS axTextStateSyncOne is undefined
-PASS accessibilityController.accessibleElementById("1").isFocusable is true
-PASS accessibilityController.focusedElement.isEqual(accessibilityController.accessibleElementById("1")) is true
+PASS accessibleElement1WasFocusable is true
 PASS axTextStateSyncTwo is undefined
 PASS successfullyParsed is true
 

Modified: trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html (292946 => 292947)


--- trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/accessibility/mac/focus-setting-selection-syncronizing-not-clearing.html	2022-04-17 08:08:00 UTC (rev 292947)
@@ -26,6 +26,7 @@
 
     var webArea = 0;
     var axTextStateSyncOne = 0;
+    var accessibleElement1WasFocusable = false;
     var axTextStateSyncTwo = 0;
     var selectCount = 0;
     var focusCount = 0;
@@ -39,13 +40,10 @@
             selectCount++;
             if (selectCount == 1) {
                 axTextStateSyncOne = userInfo["AXTextStateSync"];
-                shouldBe("axTextStateSyncOne", "undefined");
-
-                shouldBe("accessibilityController.accessibleElementById(\"1\").isFocusable", "true");
+                accessibleElement1WasFocusable = accessibilityController.accessibleElementById("1").isFocusable;
                 accessibilityController.accessibleElementById("1").takeFocus();
             } else if (selectCount == 2) {
                 axTextStateSyncTwo = userInfo["AXTextStateSync"];
-                shouldBe("axTextStateSyncTwo", "undefined");
             }
         } else if (notification == "AXFocusChanged") {
             focusCount++;
@@ -55,7 +53,12 @@
         }
         if (selectCount == 2 && focusCount == 3) {
             webArea.removeNotificationListener();
-            finishJSTest();
+            setTimeout(() => {
+                shouldBe("axTextStateSyncOne", "undefined");
+                shouldBe("accessibleElement1WasFocusable", "true");
+                shouldBe("axTextStateSyncTwo", "undefined");
+                finishJSTest();
+            }, 0);
         }
     }
 

Modified: trunk/LayoutTests/accessibility/mac/selection-change-userinfo.html (292946 => 292947)


--- trunk/LayoutTests/accessibility/mac/selection-change-userinfo.html	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/accessibility/mac/selection-change-userinfo.html	2022-04-17 08:08:00 UTC (rev 292947)
@@ -43,7 +43,12 @@
             count++;
             if (userInfo)
                 results.push(userInfo);
-            if (count == gran.length * 4) {
+            if (count != gran.length * 4)
+                return;
+
+            webArea.removeNotificationListener();
+
+            setTimeout(() => {
                 resultIndex++;
                 shouldBe("results[resultIndex][\"AXTextStateChangeType\"]", "AXTextStateChangeTypeSelectionMove");
                 shouldBe("results[resultIndex][\"AXTextSelectionGranularity\"]", "AXTextSelectionGranularityCharacter");
@@ -179,9 +184,8 @@
                 shouldBe("results[resultIndex][\"AXTextSelectionGranularity\"]", "AXTextSelectionGranularityDocument");
                 shouldBe("results[resultIndex][\"AXTextSelectionDirection\"]", "AXTextSelectionDirectionEnd");
 
-                webArea.removeNotificationListener();
                 finishJSTest();
-            }
+            }, 0);
         }
     }
 

Modified: trunk/LayoutTests/accessibility/mac/selection-sync.html (292946 => 292947)


--- trunk/LayoutTests/accessibility/mac/selection-sync.html	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/accessibility/mac/selection-sync.html	2022-04-17 08:08:00 UTC (rev 292947)
@@ -31,7 +31,12 @@
             count++;
             if (userInfo)
                 results.push(userInfo);
-            if (count == 5) {
+            if (count != 5)
+                return;
+
+            webArea.removeNotificationListener();
+
+            setTimeout(() => {
                 shouldBe("results[resultIndex][\"AXTextStateChangeType\"]", "AXTextStateChangeTypeSelectionMove");
                 shouldBe("results[resultIndex][\"AXTextSelectionDirection\"]", "AXTextSelectionDirectionDiscontiguous");
                 shouldBe("results[resultIndex][\"AXTextStateSync\"]", "true");
@@ -56,9 +61,8 @@
                 shouldBe("results[resultIndex][\"AXTextSelectionDirection\"]", "AXTextSelectionDirectionDiscontiguous");
                 shouldBe("results[resultIndex][\"AXTextStateSync\"]", "true");
 
-                webArea.removeNotificationListener();
                 finishJSTest();
-            }
+            }, 0);
         }
     }
 

Modified: trunk/LayoutTests/accessibility/mac/selection-value-changes-for-aria-textbox.html (292946 => 292947)


--- trunk/LayoutTests/accessibility/mac/selection-value-changes-for-aria-textbox.html	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/LayoutTests/accessibility/mac/selection-value-changes-for-aria-textbox.html	2022-04-17 08:08:00 UTC (rev 292947)
@@ -18,14 +18,18 @@
     description("This tests that ARIA removing an element from a live region sends the correct notification.");
 
     var axTextbox = 0;
+    var result = '';
     function notificationCallback(notification) {
         if (notification == "AXValueChanged") {
-           document.getElementById("notifications").innerHTML += "Successfully received " + notification + "<br>";
+           result += "Successfully received " + notification + "<br>";
            axTextbox.removeNotificationListener();
-           finishJSTest();
+           setTimeout(() => {
+               document.getElementById("notifications").innerHTML += result;
+              finishJSTest();
+           }, 0);
         }
         else if (notification == "AXSelectedTextChanged") {
-           document.getElementById("notifications").innerHTML += "Successfully received " + notification + "<br>";
+           result += "Successfully received " + notification + "<br>";
         }
     }
 

Added: trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash-expected.txt (0 => 292947)


--- trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash-expected.txt	2022-04-17 08:08:00 UTC (rev 292947)
@@ -0,0 +1,3 @@
+This tests updating selection within DOMNodeRemoved. WebKit should not hit any release assertions.
+
+PASS

Added: trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html (0 => 292947)


--- trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html	2022-04-17 08:08:00 UTC (rev 292947)
@@ -0,0 +1,33 @@
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+setTimeout(() => {
+    textarea1.selectionStart = 1;
+
+    span2.appendChild(textarea1);
+    document.documentElement.appendChild(canvas1);
+
+    textarea1.addEventListener("DOMNodeRemoved", () => {
+        other1.appendChild(span1);
+        textarea1.selectionStart = -1;
+        document.getSelection().collapse(span1);
+    });
+
+    textarea1.innerHTML = '';
+
+    document.body.innerHTML = '<p>This tests updating selection within DOMNodeRemoved. WebKit should not hit any release assertions.</p>PASS';
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}, 0);
+</script>
+<textarea id="textarea1">hello</textarea>
+<canvas id="canvas1"><other-element id="other1"></other-element></canvas>
+<span id="span1">
+    <audio controls="controls" src=""
+        <span id="span2">G&#x27;lzKsb6[Xava</span>
+    </audio>
+</span>

Modified: trunk/Source/WebCore/ChangeLog (292946 => 292947)


--- trunk/Source/WebCore/ChangeLog	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/ChangeLog	2022-04-17 08:08:00 UTC (rev 292947)
@@ -1,3 +1,39 @@
+2022-04-16  Ryosuke Niwa  <[email protected]>
+
+        Make release assertion in Document::updateLayout more precise for FrameSelection::setSelection
+        https://bugs.webkit.org/show_bug.cgi?id=239431
+
+        Reviewed by Alan Bujtas.
+
+        Avoid the assertion failure by allowing no-op layout updates within FrameSelection::setSelection.
+
+        To do this, this patch introduces a new RAII object, UpToDateLayoutScope, which denotes when when the layout
+        is up-to-date and therefore does not require a new layout update. When this scope exists in the stack frame,
+        we allow calls to Document::updateLayout even inside ScriptDisallowedScope. We also assert that nobody attempts
+        to schedule a new style resolution or layout when this object exists.
+
+        Test: fast/forms/textarea-selection-update-during-DOMNodeRemoved-crash.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/Document.cpp:
+        (WebCore::Document::scheduleStyleRecalc):
+        (WebCore::Document::updateLayout):
+        * dom/Document.h:
+        (WebCore::Document::upToDateLayoutScopeCount const):
+        (WebCore::Document::incrementUpToDateLayoutScopeCount):
+        (WebCore::Document::decrementUpToDateLayoutScopeCount):
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::setSelection):
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::FrameViewLayoutContext::scheduleLayout):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isSetNeedsLayoutForbidden const):
+        * rendering/UpToDateLayoutScope.h: Added.
+        (WebCore::UpToDateLayoutScope::UpToDateLayoutScope):
+        (WebCore::UpToDateLayoutScope::~UpToDateLayoutScope):
+        (WebCore::UpToDateLayoutScope::scopeIfLayoutIsUpToUpdate):
+        (WebCore::UpToDateLayoutScope::needsLayout):
+
 2022-04-16  Chris Dumez  <[email protected]>
 
         Drop String::truncate() and use String::left() instead

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (292946 => 292947)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-04-17 08:08:00 UTC (rev 292947)
@@ -3281,6 +3281,7 @@
 		9B27FC60234D9ADB00394A46 /* WindowEventLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B27FC5E234D9ADA00394A46 /* WindowEventLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B2D8A7914997CCF00ECEF3E /* UndoStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B2D8A7814997CCF00ECEF3E /* UndoStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B32CDA913DF7FA900F34D13 /* RenderedPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B32CDA713DF7FA900F34D13 /* RenderedPosition.h */; };
+		9B33DF8628090B5600ECFAE7 /* UpToDateLayoutScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B33DF8428090B5600ECFAE7 /* UpToDateLayoutScope.h */; };
 		9B417064125662B3006B28FC /* ApplyBlockElementCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */; };
 		9B50B1DE17CD4C0F0087F63C /* FormNamedItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B50B1DC17CD4C0F0087F63C /* FormNamedItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B532EA41BA928570038A827 /* SlotAssignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B532EA21BA928570038A827 /* SlotAssignment.h */; };
@@ -13466,6 +13467,7 @@
 		9B2D8A7814997CCF00ECEF3E /* UndoStep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UndoStep.h; sourceTree = "<group>"; };
 		9B32CDA713DF7FA900F34D13 /* RenderedPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderedPosition.h; sourceTree = "<group>"; };
 		9B32CDA813DF7FA900F34D13 /* RenderedPosition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderedPosition.cpp; sourceTree = "<group>"; };
+		9B33DF8428090B5600ECFAE7 /* UpToDateLayoutScope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UpToDateLayoutScope.h; sourceTree = "<group>"; };
 		9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyBlockElementCommand.h; sourceTree = "<group>"; };
 		9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; };
 		9B4376EF2117E872009D03A0 /* ThrowOnDynamicMarkupInsertionCountIncrementer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThrowOnDynamicMarkupInsertionCountIncrementer.h; sourceTree = "<group>"; };
@@ -32421,6 +32423,7 @@
 				1C18DA57181AF6A500C4EF22 /* TextPainter.h */,
 				E4C91A0F1802343900A17F6D /* TextPaintStyle.cpp */,
 				E4C91A0D1802343100A17F6D /* TextPaintStyle.h */,
+				9B33DF8428090B5600ECFAE7 /* UpToDateLayoutScope.h */,
 				BCA257141293C010007A263D /* VerticalPositionCache.h */,
 			);
 			path = rendering;
@@ -38040,6 +38043,7 @@
 				C18CC0A42580EFB1003D75FB /* UniversalAccessZoom.h in Headers */,
 				D086FE9809D53AAB005BC74D /* UnlinkCommand.h in Headers */,
 				FD1762E0176686D900D836A8 /* UpSampler.h in Headers */,
+				9B33DF8628090B5600ECFAE7 /* UpToDateLayoutScope.h in Headers */,
 				93D437A21D57B3FE00AB85EA /* URLDecomposition.h in Headers */,
 				267726051A5DF6F2003C24DD /* URLFilterParser.h in Headers */,
 				F55B3DDE1251F12D003EF269 /* URLInputType.h in Headers */,

Modified: trunk/Source/WebCore/dom/Document.cpp (292946 => 292947)


--- trunk/Source/WebCore/dom/Document.cpp	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/dom/Document.cpp	2022-04-17 08:08:00 UTC (rev 292947)
@@ -252,6 +252,7 @@
 #include "TransformSource.h"
 #include "TreeWalker.h"
 #include "UndoManager.h"
+#include "UpToDateLayoutScope.h"
 #include "UserGestureIndicator.h"
 #include "ValidationMessageClient.h"
 #include "VisibilityChangeClient.h"
@@ -1977,6 +1978,7 @@
     if (m_styleRecalcTimer.isActive() || backForwardCacheState() != NotInBackForwardCache)
         return;
 
+    RELEASE_ASSERT(!m_upToDateLayoutScopeCount);
     ASSERT(childNeedsStyleRecalc() || m_needsFullStyleRebuild);
 
     m_styleRecalcTimer.startOneShot(0_s);
@@ -2224,8 +2226,10 @@
         ASSERT_NOT_REACHED();
         return;
     }
-    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(isSafeToUpdateStyleOrLayout(*this));
 
+    bool safeToUpdateStyleOrLayout = isSafeToUpdateStyleOrLayout(*this);
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(safeToUpdateStyleOrLayout || (m_upToDateLayoutScopeCount && !UpToDateLayoutScope::needsLayout(*this)));
+
     RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
 
     if (RefPtr owner = ownerElement())
@@ -2240,6 +2244,9 @@
     if (!frameView->layoutContext().isLayoutPending() && !renderView()->needsLayout())
         return;
 
+    // needsLayout may have changed.
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(safeToUpdateStyleOrLayout);
+
     frameView->layoutContext().layout();
 
     Style::Scope::QueryContainerUpdateContext queryContainerUpdateContext;

Modified: trunk/Source/WebCore/dom/Document.h (292946 => 292947)


--- trunk/Source/WebCore/dom/Document.h	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/dom/Document.h	2022-04-17 08:08:00 UTC (rev 292947)
@@ -621,7 +621,11 @@
     unsigned lastStyleUpdateSizeForTesting() const { return m_lastStyleUpdateSizeForTesting; }
 
     WEBCORE_EXPORT void updateLayout();
-    
+
+    unsigned upToDateLayoutScopeCount() const { return m_upToDateLayoutScopeCount; }
+    void incrementUpToDateLayoutScopeCount() { ++m_upToDateLayoutScopeCount; }
+    void decrementUpToDateLayoutScopeCount() { ASSERT(m_upToDateLayoutScopeCount); --m_upToDateLayoutScopeCount; }
+
     // updateLayoutIgnorePendingStylesheets() forces layout even if we are waiting for pending stylesheet loads,
     // so calling this may cause a flash of unstyled content (FOUC).
     enum class RunPostLayoutTasks { Asynchronously, Synchronously };
@@ -2107,6 +2111,8 @@
 
     unsigned m_writeRecursionDepth { 0 };
 
+    unsigned m_upToDateLayoutScopeCount { 0 };
+
     InheritedBool m_designMode { inherit };
     MediaProducerMediaStateFlags m_mediaState;
     bool m_userHasInteractedWithMediaElement { false };

Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (292946 => 292947)


--- trunk/Source/WebCore/editing/FrameSelection.cpp	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp	2022-04-17 08:08:00 UTC (rev 292947)
@@ -73,6 +73,7 @@
 #include "StyleProperties.h"
 #include "StyleTreeResolver.h"
 #include "TypingCommand.h"
+#include "UpToDateLayoutScope.h"
 #include "VisibleUnits.h"
 #include <stdio.h>
 #include <wtf/text/CString.h>
@@ -447,13 +448,10 @@
     m_selectionRevealIntent = intent;
     m_pendingSelectionUpdate = true;
 
-    if (protectedDocument->hasPendingStyleRecalc())
+    auto layoutScope = UpToDateLayoutScope::scopeIfLayoutIsUpToUpdate(*protectedDocument);
+    if (!layoutScope)
         return;
 
-    auto frameView = protectedDocument->view();
-    if (frameView && frameView->layoutContext().isLayoutPending())
-        return;
-
     updateAndRevealSelection(intent, options.contains(SmoothScroll) ? ScrollBehavior::Smooth : ScrollBehavior::Instant, options.contains(RevealSelectionBounds) ? RevealExtentOption::DoNotRevealExtent : RevealExtentOption::RevealExtent);
 
     if (options & IsUserTriggered) {

Modified: trunk/Source/WebCore/page/FrameViewLayoutContext.cpp (292946 => 292947)


--- trunk/Source/WebCore/page/FrameViewLayoutContext.cpp	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/page/FrameViewLayoutContext.cpp	2022-04-17 08:08:00 UTC (rev 292947)
@@ -373,6 +373,8 @@
     // too many false assertions. See <rdar://problem/7218118>.
     ASSERT(frame().view() == &view());
 
+    RELEASE_ASSERT(!frame().document()->upToDateLayoutScopeCount());
+
     if (subtreeLayoutRoot())
         convertSubtreeLayoutToFullLayout();
     if (!isLayoutSchedulingEnabled())

Modified: trunk/Source/WebCore/rendering/RenderObject.h (292946 => 292947)


--- trunk/Source/WebCore/rendering/RenderObject.h	2022-04-17 04:22:20 UTC (rev 292946)
+++ trunk/Source/WebCore/rendering/RenderObject.h	2022-04-17 08:08:00 UTC (rev 292947)
@@ -1166,7 +1166,7 @@
 inline bool RenderObject::isSetNeedsLayoutForbidden() const
 {
 #if ASSERT_ENABLED
-    return m_setNeedsLayoutForbidden;
+    return m_setNeedsLayoutForbidden || document().upToDateLayoutScopeCount();
 #else
     return false;
 #endif

Added: trunk/Source/WebCore/rendering/UpToDateLayoutScope.h (0 => 292947)


--- trunk/Source/WebCore/rendering/UpToDateLayoutScope.h	                        (rev 0)
+++ trunk/Source/WebCore/rendering/UpToDateLayoutScope.h	2022-04-17 08:08:00 UTC (rev 292947)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Document.h"
+#include "FrameView.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+class UpToDateLayoutScope {
+    WTF_MAKE_NONCOPYABLE(UpToDateLayoutScope);
+public:
+    UpToDateLayoutScope(Document& document)
+        : m_document { &document }
+    {
+        m_document->incrementUpToDateLayoutScopeCount();
+        RELEASE_ASSERT(!needsLayout(document));
+    }
+    
+    UpToDateLayoutScope(UpToDateLayoutScope&& source)
+        : m_document { std::exchange(source.m_document, nullptr) }
+    {
+    }
+
+    ~UpToDateLayoutScope()
+    {
+        if (m_document)
+            m_document->decrementUpToDateLayoutScopeCount();
+    }
+
+    static std::optional<UpToDateLayoutScope> scopeIfLayoutIsUpToUpdate(Document& document)
+    {
+        if (needsLayout(document))
+            return std::nullopt;
+        return UpToDateLayoutScope { document };
+    }
+
+    static bool needsLayout(Document& document)
+    {
+        if (document.needsStyleRecalc())
+            return true;
+        RefPtr frameView = document.view();
+        return frameView && frameView->layoutContext().needsLayout();
+    }
+
+private:
+    RefPtr<Document> m_document;
+};
+
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to