Title: [264627] trunk
Revision
264627
Author
[email protected]
Date
2020-07-20 15:53:59 -0700 (Mon, 20 Jul 2020)

Log Message

REGRESSION (r261874): Typing near the bottom of a scrollable document causes the scroll position to jump
https://bugs.webkit.org/show_bug.cgi?id=214426
<rdar://problem/65302701>

Reviewed by Simon Fraser.

Source/WebCore:

After the changes in r261874, any content size changes that trigger `FrameView::adjustViewSize` cause the scroll
position to be clamped to its minimum and maximum limits after the next layout pass. In the context of edit
commands, this means that the scroll position may jump erratically, since many edit commands can temporarily
leave the DOM in a state where the content size is unstable.

For example, in the test case below, deleting the only character in a div element on its own line first involves
emptying the text node underneath the div (causing it to have no height), before inserting a BR element in its
place (which restores a nonzero height). After the text node is emptied (but before we insert the BR element),
the content size of view changes due to a layout update while creating visible positions (under
`VisiblePosition::canonicalPosition`). If we happen to be scrolled all the way to the bottom of the main frame,
this means we'll scroll up, due to the maximum scroll position temporarily decreasing. A similar effect happens
when inserting the first character on a line, wherein the div is empty after BR element is removed but before it
is replaced with a text node.

To mitigate this, introduce a mechanism to temporarily avoid updating the scroll position, and use it when
executing edit commands. See below for more details.

Test: editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html

* editing/CompositeEditCommand.cpp:
(WebCore::EditCommandComposition::unapply):
(WebCore::EditCommandComposition::reapply):
(WebCore::CompositeEditCommand::apply):
* editing/Editor.cpp:
(WebCore::Editor::willApplyEditing const):
(WebCore::Editor::appliedEditing):

Add logic to specifically handle typing commands here, since we handle typing commands by adding them to the
latest "open" typing command, rather than go through the more standard codepaths in EditCommandComposition
above.

* editing/Editor.h:
* page/FrameView.cpp:
(WebCore::FrameView::reset):
(WebCore::FrameView::topContentDirectionDidChange):
(WebCore::FrameView::handleDeferredScrollbarsUpdate):
(WebCore::FrameView::handleDeferredPositionScrollbarLayers):

Split existing logic for handling deferred scrollbar updates and deferred calls to `positionScrollbarLayers`
into two separate methods, with separate boolean flags. `topContentDirectionDidChange` sets both of these flags
(which preserves existing behavior), while `decrementProhibitsScrollingWhenChangingContentSizeCount` just
requests a scrollbar update.

(WebCore::FrameView::didLayout):
(WebCore::FrameView::didFinishProhibitingScrollingWhenChangingContentSize):

After decrementing `m_prohibitsScrollingWhenChangingContentSizeCount` back to zero, ensure that the scroll
position ultimately remains clamped to the minimum and maximum values by either immediately calling
`updateScrollbars` with the current scroll position if layout and style are up to date, or by scheduling a
deferred scrollbar update if that is not the case.

(WebCore::FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange): Deleted.

Rename this to just `handleDeferredScrollbarsUpdate`.

* page/FrameView.h:
* platform/ScrollView.cpp:
(WebCore::ScrollView::setContentsSize):
(WebCore::ScrollView::prohibitScrollingWhenChangingContentSizeForScope):
(WebCore::ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::ProhibitScrollingWhenChangingContentSizeForScope):
(WebCore::ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::~ProhibitScrollingWhenChangingContentSizeForScope):

Introduce a new token object, `ProhibitScrollingWhenChangingContentSizeForScope`, which increments a count on
`ScrollView` when created and decrements the count when destroyed. While this counter is greater than zero, we
will avoid scrolling as a result of changing content size.

* platform/ScrollView.h:
(WebCore::ScrollView::incrementProhibitsScrollingWhenChangingContentSizeCount):
(WebCore::ScrollView::decrementProhibitsScrollingWhenChangingContentSizeCount):

LayoutTests:

Add a test to verify that the scroll position doesn't change when deleting and then reinserting the only
character on a line (i.e. `div` element) in a contenteditable element. This test also verifies that deleting
lines in a way that decreases the height of the document still clamps the scroll position by scrolling up.

* editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible-expected.txt: Added.
* editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html: Added.
* platform/mac-wk1/TestExpectations:

Mark the test as failing in WebKit1 for now, which will require some additional work.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (264626 => 264627)


--- trunk/LayoutTests/ChangeLog	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/LayoutTests/ChangeLog	2020-07-20 22:53:59 UTC (rev 264627)
@@ -1,3 +1,21 @@
+2020-07-20  Wenson Hsieh  <[email protected]>
+
+        REGRESSION (r261874): Typing near the bottom of a scrollable document causes the scroll position to jump
+        https://bugs.webkit.org/show_bug.cgi?id=214426
+        <rdar://problem/65302701>
+
+        Reviewed by Simon Fraser.
+
+        Add a test to verify that the scroll position doesn't change when deleting and then reinserting the only
+        character on a line (i.e. `div` element) in a contenteditable element. This test also verifies that deleting
+        lines in a way that decreases the height of the document still clamps the scroll position by scrolling up.
+
+        * editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible-expected.txt: Added.
+        * editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html: Added.
+        * platform/mac-wk1/TestExpectations:
+
+        Mark the test as failing in WebKit1 for now, which will require some additional work.
+
 2020-07-20  Hector Lopez  <[email protected]>
 
         [ iOS ] css3/blending/blend-mode-clip-accelerated-blending-canvas.html is passing and expectations need to be removed

Added: trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible-expected.txt (0 => 264627)


--- trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible-expected.txt	2020-07-20 22:53:59 UTC (rev 264627)
@@ -0,0 +1,16 @@
+This test verifies that typing text, then undoing, and then redoing does not cause the scroll position of the document to jump around. To run the test manually, load the page and wait for the test to complete.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS scrollTopAfterTyping is scrollTopBeforeTyping
+PASS scrollTopAfterDeleting is scrollTopAfterTyping
+PASS scrollTopAfterUndoing is scrollTopAfterDeleting
+PASS scrollTopAfterRedoing is scrollTopAfterUndoing
+PASS scrollTopAfterDeletingAgain < scrollTopAfterRedoing is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Try to delete the letters below.
+A
+B
+C

Added: trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html (0 => 264627)


--- trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html	                        (rev 0)
+++ trunk/LayoutTests/editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html	2020-07-20 22:53:59 UTC (rev 264627)
@@ -0,0 +1,81 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src=""
+<script src=""
+<script src=""
+<style>
+div[contenteditable] {
+    margin-top: 2000px;
+    font-size: 20px;
+    border: solid black 1px;
+    outline: none;
+}
+</style>
+</head>
+<body>
+<div id="output">
+    <div id="description"></div>
+    <div id="console"></div>
+</div>
+<div contenteditable>
+    <div>Try to delete the letters below.</div>
+    <div>A</div>
+    <div>B</div>
+    <div>C</div>
+    <div id="target"><br></div>
+</div>
+<script>
+description("This test verifies that typing text, then undoing, and then redoing does not cause the scroll position of the document to jump around. To run the test manually, load the page and wait for the test to complete.");
+jsTestIsAsync = true;
+
+async function presentationUpdate()
+{
+    if (window.testRunner)
+        await UIHelper.ensurePresentationUpdate();
+    else
+        await new Promise(resolve => setTimeout(resolve, 250));
+}
+
+addEventListener("load", async () => {
+    getSelection().setPosition(target, 1);
+    await presentationUpdate();
+
+    target.scrollIntoView();
+    await presentationUpdate();
+    scrollTopBeforeTyping = document.scrollingElement.scrollTop;
+
+    typeCharacterCommand("D");
+    await presentationUpdate();
+    scrollTopAfterTyping = document.scrollingElement.scrollTop;
+
+    deleteCommand();
+    await presentationUpdate();
+    scrollTopAfterDeleting = document.scrollingElement.scrollTop;
+
+    undoCommand();
+    await presentationUpdate();
+    scrollTopAfterUndoing = document.scrollingElement.scrollTop;
+
+    redoCommand();
+    await presentationUpdate();
+    scrollTopAfterRedoing = document.scrollingElement.scrollTop;
+
+    deleteCommand();
+    await presentationUpdate();
+    scrollTopAfterDeletingAgain = document.scrollingElement.scrollTop;
+
+    shouldBe("scrollTopAfterTyping", "scrollTopBeforeTyping");
+    shouldBe("scrollTopAfterDeleting", "scrollTopAfterTyping");
+    shouldBe("scrollTopAfterUndoing", "scrollTopAfterDeleting");
+    shouldBe("scrollTopAfterRedoing", "scrollTopAfterUndoing");
+    shouldBeTrue("scrollTopAfterDeletingAgain < scrollTopAfterRedoing");
+
+    document.scrollingElement.scrollTo(0, 0);
+    finishJSTest();
+});
+</script>
+</body>
+</html>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (264626 => 264627)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2020-07-20 22:53:59 UTC (rev 264627)
@@ -882,6 +882,8 @@
 
 webkit.org/b/207066 editing/execCommand/insert-nested-lists.html [ Pass Failure ]
 
+webkit.org/b/214558 editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html [ Failure ]
+
 webkit.org/b/207125 transitions/start-transform-transition.html [ Pass Failure ]
 
 webkit.org/b/181085 svg/custom/object-sizing-explicit-width.xhtml [ Pass Failure ]

Modified: trunk/Source/WebCore/ChangeLog (264626 => 264627)


--- trunk/Source/WebCore/ChangeLog	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/ChangeLog	2020-07-20 22:53:59 UTC (rev 264627)
@@ -1,3 +1,81 @@
+2020-07-20  Wenson Hsieh  <[email protected]>
+
+        REGRESSION (r261874): Typing near the bottom of a scrollable document causes the scroll position to jump
+        https://bugs.webkit.org/show_bug.cgi?id=214426
+        <rdar://problem/65302701>
+
+        Reviewed by Simon Fraser.
+
+        After the changes in r261874, any content size changes that trigger `FrameView::adjustViewSize` cause the scroll
+        position to be clamped to its minimum and maximum limits after the next layout pass. In the context of edit
+        commands, this means that the scroll position may jump erratically, since many edit commands can temporarily
+        leave the DOM in a state where the content size is unstable.
+
+        For example, in the test case below, deleting the only character in a div element on its own line first involves
+        emptying the text node underneath the div (causing it to have no height), before inserting a BR element in its
+        place (which restores a nonzero height). After the text node is emptied (but before we insert the BR element),
+        the content size of view changes due to a layout update while creating visible positions (under
+        `VisiblePosition::canonicalPosition`). If we happen to be scrolled all the way to the bottom of the main frame,
+        this means we'll scroll up, due to the maximum scroll position temporarily decreasing. A similar effect happens
+        when inserting the first character on a line, wherein the div is empty after BR element is removed but before it
+        is replaced with a text node.
+
+        To mitigate this, introduce a mechanism to temporarily avoid updating the scroll position, and use it when
+        executing edit commands. See below for more details.
+
+        Test: editing/execCommand/typing-should-not-trigger-scrolling-when-selection-is-visible.html
+
+        * editing/CompositeEditCommand.cpp:
+        (WebCore::EditCommandComposition::unapply):
+        (WebCore::EditCommandComposition::reapply):
+        (WebCore::CompositeEditCommand::apply):
+        * editing/Editor.cpp:
+        (WebCore::Editor::willApplyEditing const):
+        (WebCore::Editor::appliedEditing):
+
+        Add logic to specifically handle typing commands here, since we handle typing commands by adding them to the
+        latest "open" typing command, rather than go through the more standard codepaths in EditCommandComposition
+        above.
+
+        * editing/Editor.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::reset):
+        (WebCore::FrameView::topContentDirectionDidChange):
+        (WebCore::FrameView::handleDeferredScrollbarsUpdate):
+        (WebCore::FrameView::handleDeferredPositionScrollbarLayers):
+
+        Split existing logic for handling deferred scrollbar updates and deferred calls to `positionScrollbarLayers`
+        into two separate methods, with separate boolean flags. `topContentDirectionDidChange` sets both of these flags
+        (which preserves existing behavior), while `decrementProhibitsScrollingWhenChangingContentSizeCount` just
+        requests a scrollbar update.
+
+        (WebCore::FrameView::didLayout):
+        (WebCore::FrameView::didFinishProhibitingScrollingWhenChangingContentSize):
+
+        After decrementing `m_prohibitsScrollingWhenChangingContentSizeCount` back to zero, ensure that the scroll
+        position ultimately remains clamped to the minimum and maximum values by either immediately calling
+        `updateScrollbars` with the current scroll position if layout and style are up to date, or by scheduling a
+        deferred scrollbar update if that is not the case.
+
+        (WebCore::FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange): Deleted.
+
+        Rename this to just `handleDeferredScrollbarsUpdate`.
+
+        * page/FrameView.h:
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::setContentsSize):
+        (WebCore::ScrollView::prohibitScrollingWhenChangingContentSizeForScope):
+        (WebCore::ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::ProhibitScrollingWhenChangingContentSizeForScope):
+        (WebCore::ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::~ProhibitScrollingWhenChangingContentSizeForScope):
+
+        Introduce a new token object, `ProhibitScrollingWhenChangingContentSizeForScope`, which increments a count on
+        `ScrollView` when created and decrements the count when destroyed. While this counter is greater than zero, we
+        will avoid scrolling as a result of changing content size.
+
+        * platform/ScrollView.h:
+        (WebCore::ScrollView::incrementProhibitsScrollingWhenChangingContentSizeCount):
+        (WebCore::ScrollView::decrementProhibitsScrollingWhenChangingContentSizeCount):
+
 2020-07-20  Said Abou-Hallawa  <[email protected]>
 
         CSS clip-path is applied to the <svg> root element in the view-box coordinates

Modified: trunk/Source/WebCore/editing/CompositeEditCommand.cpp (264626 => 264627)


--- trunk/Source/WebCore/editing/CompositeEditCommand.cpp	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/editing/CompositeEditCommand.cpp	2020-07-20 22:53:59 UTC (rev 264627)
@@ -231,6 +231,7 @@
     m_document->editor().cancelComposition();
 #endif
 
+    auto prohibitScrollingForScope = m_document->view() ? m_document->view()->prohibitScrollingWhenChangingContentSizeForScope() : nullptr;
     if (!m_document->editor().willUnapplyEditing(*this))
         return;
 
@@ -258,6 +259,7 @@
     // if one is necessary (like for the creation of VisiblePositions).
     m_document->updateLayoutIgnorePendingStylesheets();
 
+    auto prohibitScrollingForScope = m_document->view() ? m_document->view()->prohibitScrollingWhenChangingContentSizeForScope() : nullptr;
     if (!m_document->editor().willReapplyEditing(*this))
         return;
 
@@ -364,6 +366,7 @@
     // if one is necessary (like for the creation of VisiblePositions).
     document().updateLayoutIgnorePendingStylesheets();
 
+    auto prohibitScrollingForScope = document().view() ? document().view()->prohibitScrollingWhenChangingContentSizeForScope() : nullptr;
     if (!willApplyCommand())
         return;
 

Modified: trunk/Source/WebCore/editing/Editor.cpp (264626 => 264627)


--- trunk/Source/WebCore/editing/Editor.cpp	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/editing/Editor.cpp	2020-07-20 22:53:59 UTC (rev 264627)
@@ -1108,6 +1108,9 @@
     if (!composition)
         return true;
 
+    if (command.isTopLevelCommand() && command.isTypingCommand() && document().view())
+        m_prohibitScrollingDueToContentSizeChangesWhileTyping = document().view()->prohibitScrollingWhenChangingContentSizeForScope();
+
     return dispatchBeforeInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), command.inputEventTypeName(),
         command.inputEventData(), command.inputEventDataTransfer(), targetRanges, command.isBeforeInputEventCancelable() ? Event::IsCancelable::Yes : Event::IsCancelable::No);
 }
@@ -1155,6 +1158,9 @@
                 client()->registerUndoStep(m_lastEditCommand->ensureComposition());
         }
         respondToChangedContents(newSelection);
+
+        if (command.isTypingCommand())
+            m_prohibitScrollingDueToContentSizeChangesWhileTyping = nullptr;
     }
 }
 

Modified: trunk/Source/WebCore/editing/Editor.h (264626 => 264627)


--- trunk/Source/WebCore/editing/Editor.h	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/editing/Editor.h	2020-07-20 22:53:59 UTC (rev 264627)
@@ -35,6 +35,7 @@
 #include "Frame.h"
 #include "FrameSelection.h"
 #include "PasteboardWriterData.h"
+#include "ScrollView.h"
 #include "TextChecking.h"
 #include "TextEventInputType.h"
 #include "TextIteratorBehavior.h"
@@ -669,6 +670,8 @@
     Vector<SimpleRange> m_detectedTelephoneNumberRanges;
 #endif
 
+    mutable std::unique_ptr<ScrollView::ProhibitScrollingWhenChangingContentSizeForScope> m_prohibitScrollingDueToContentSizeChangesWhileTyping;
+
     bool m_isGettingDictionaryPopupInfo { false };
     HashSet<RefPtr<HTMLImageElement>> m_imageElementsToLoadBeforeRevealingSelection;
 };

Modified: trunk/Source/WebCore/page/FrameView.cpp (264626 => 264627)


--- trunk/Source/WebCore/page/FrameView.cpp	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/page/FrameView.cpp	2020-07-20 22:53:59 UTC (rev 264627)
@@ -258,6 +258,7 @@
     m_paintBehavior = PaintBehavior::Normal;
     m_isPainting = false;
     m_needsDeferredScrollbarsUpdate = false;
+    m_needsDeferredPositionScrollbarLayers = false;
     m_maintainScrollPositionAnchor = nullptr;
     resetLayoutMilestones();
     layoutContext().reset();
@@ -1092,16 +1093,24 @@
 void FrameView::topContentDirectionDidChange()
 {
     m_needsDeferredScrollbarsUpdate = true;
+    m_needsDeferredPositionScrollbarLayers = true;
 }
 
-void FrameView::handleDeferredScrollbarsUpdateAfterDirectionChange()
+void FrameView::handleDeferredScrollbarsUpdate()
 {
     if (!m_needsDeferredScrollbarsUpdate)
         return;
 
     m_needsDeferredScrollbarsUpdate = false;
+    updateScrollbars(scrollPosition());
+}
 
-    updateScrollbars(scrollPosition());
+void FrameView::handleDeferredPositionScrollbarLayers()
+{
+    if (!m_needsDeferredPositionScrollbarLayers)
+        return;
+
+    m_needsDeferredPositionScrollbarLayers = false;
     positionScrollbarLayers();
 }
 
@@ -1265,7 +1274,8 @@
 
     handleDeferredScrollUpdateAfterContentSizeChange();
 
-    handleDeferredScrollbarsUpdateAfterDirectionChange();
+    handleDeferredScrollbarsUpdate();
+    handleDeferredPositionScrollbarLayers();
 
     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
         updateOverflowStatus(layoutWidth() < contentsWidth(), layoutHeight() < contentsHeight());
@@ -5469,6 +5479,16 @@
     return ts;
 }
 
+void FrameView::didFinishProhibitingScrollingWhenChangingContentSize()
+{
+    if (auto* document = frame().document()) {
+        if (!document->needsStyleRecalc() && !needsLayout() && !layoutContext().isInLayout())
+            updateScrollbars(scrollPosition());
+        else
+            m_needsDeferredScrollbarsUpdate = true;
+    }
+}
+
 } // namespace WebCore
 
 #undef PAGE_ID

Modified: trunk/Source/WebCore/page/FrameView.h (264626 => 264627)


--- trunk/Source/WebCore/page/FrameView.h	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/page/FrameView.h	2020-07-20 22:53:59 UTC (rev 264627)
@@ -775,7 +775,8 @@
 
     void adjustScrollbarsForLayout(bool firstLayout);
 
-    void handleDeferredScrollbarsUpdateAfterDirectionChange();
+    void handleDeferredScrollbarsUpdate();
+    void handleDeferredPositionScrollbarLayers();
 
     void updateScrollableAreaSet();
     void updateLayoutViewport();
@@ -834,6 +835,8 @@
     void overrideViewportWidthForCSSViewportUnits(int);
     void resetOverriddenViewportWidthForCSSViewportUnits();
 
+    void didFinishProhibitingScrollingWhenChangingContentSize() final;
+
     static MonotonicTime sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache
 
     const Ref<Frame> m_frame;
@@ -945,6 +948,7 @@
     bool m_hasReachedSignificantRenderedTextThreshold { false };
 
     bool m_needsDeferredScrollbarsUpdate { false };
+    bool m_needsDeferredPositionScrollbarLayers { false };
     bool m_speculativeTilingEnabled { false };
     bool m_visualUpdatesAllowedByClient { true };
     bool m_hasFlippedBlockRenderers { false };

Modified: trunk/Source/WebCore/platform/ScrollView.cpp (264626 => 264627)


--- trunk/Source/WebCore/platform/ScrollView.cpp	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/platform/ScrollView.cpp	2020-07-20 22:53:59 UTC (rev 264627)
@@ -398,7 +398,7 @@
     m_contentsSize = newSize;
     if (platformWidget())
         platformSetContentsSize();
-    else
+    else if (!m_prohibitsScrollingWhenChangingContentSizeCount)
         updateScrollbars(scrollPosition());
     updateOverhangAreas();
 }
@@ -1538,6 +1538,23 @@
     return result;
 }
 
+std::unique_ptr<ScrollView::ProhibitScrollingWhenChangingContentSizeForScope> ScrollView::prohibitScrollingWhenChangingContentSizeForScope()
+{
+    return makeUnique<ProhibitScrollingWhenChangingContentSizeForScope>(*this);
+}
+
+ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::ProhibitScrollingWhenChangingContentSizeForScope(ScrollView& scrollView)
+    : m_scrollView(makeWeakPtr(scrollView))
+{
+    scrollView.incrementProhibitsScrollingWhenChangingContentSizeCount();
+}
+
+ScrollView::ProhibitScrollingWhenChangingContentSizeForScope::~ProhibitScrollingWhenChangingContentSizeForScope()
+{
+    if (m_scrollView)
+        m_scrollView->decrementProhibitsScrollingWhenChangingContentSizeCount();
+}
+
 String ScrollView::debugDescription() const
 {
     return makeString("ScrollView 0x", hex(reinterpret_cast<uintptr_t>(this), Lowercase));

Modified: trunk/Source/WebCore/platform/ScrollView.h (264626 => 264627)


--- trunk/Source/WebCore/platform/ScrollView.h	2020-07-20 22:38:40 UTC (rev 264626)
+++ trunk/Source/WebCore/platform/ScrollView.h	2020-07-20 22:53:59 UTC (rev 264627)
@@ -146,6 +146,18 @@
     void setProhibitsScrolling(bool b) { m_prohibitsScrolling = b; }
     bool prohibitsScrolling() const { return m_prohibitsScrolling; }
 
+    class ProhibitScrollingWhenChangingContentSizeForScope {
+        WTF_MAKE_FAST_ALLOCATED;
+    public:
+        ProhibitScrollingWhenChangingContentSizeForScope(ScrollView&);
+        ~ProhibitScrollingWhenChangingContentSizeForScope();
+
+    private:
+        WeakPtr<ScrollView> m_scrollView;
+    };
+
+    std::unique_ptr<ProhibitScrollingWhenChangingContentSizeForScope> prohibitScrollingWhenChangingContentSizeForScope();
+
     // Whether or not a scroll view will blit visible contents when it is scrolled. Blitting is disabled in situations
     // where it would cause rendering glitches (such as with fixed backgrounds or when the view is partially transparent).
     void setCanBlitOnScroll(bool);
@@ -431,6 +443,8 @@
 
     virtual void unobscuredContentSizeChanged() = 0;
 
+    virtual void didFinishProhibitingScrollingWhenChangingContentSize() = 0;
+
 #if PLATFORM(COCOA) && defined __OBJC__
 public:
     WEBCORE_EXPORT NSView* documentView() const;
@@ -493,6 +507,18 @@
     void calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect);
     void updateOverhangAreas();
 
+    void incrementProhibitsScrollingWhenChangingContentSizeCount() { ++m_prohibitsScrollingWhenChangingContentSizeCount; }
+    void decrementProhibitsScrollingWhenChangingContentSizeCount()
+    {
+        if (!m_prohibitsScrollingWhenChangingContentSizeCount) {
+            ASSERT_NOT_REACHED();
+            return;
+        }
+
+        if (!--m_prohibitsScrollingWhenChangingContentSizeCount)
+            didFinishProhibitingScrollingWhenChangingContentSize();
+    }
+
     HashSet<Ref<Widget>> m_children;
 
     RefPtr<Scrollbar> m_horizontalScrollbar;
@@ -524,6 +550,7 @@
     IntPoint m_panScrollIconPoint;
 
     unsigned m_updateScrollbarsPass { 0 };
+    unsigned m_prohibitsScrollingWhenChangingContentSizeCount { 0 };
 
     bool m_horizontalScrollbarLock { false };
     bool m_verticalScrollbarLock { false };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to