Diff
Modified: trunk/LayoutTests/ChangeLog (284653 => 284654)
--- trunk/LayoutTests/ChangeLog 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/LayoutTests/ChangeLog 2021-10-21 23:58:35 UTC (rev 284654)
@@ -1,3 +1,15 @@
+2021-10-21 Simon Fraser <[email protected]>
+
+ Content offset in this codepen when switching tabs
+ https://bugs.webkit.org/show_bug.cgi?id=231989
+
+ Reviewed by Tim Horton.
+
+ New baselines.
+
+ * tiled-drawing/scrolling/clamp-out-of-bounds-scrolls-expected.txt:
+ * tiled-drawing/scrolling/scrolling-tree-after-scroll-expected.txt:
+
2021-10-21 John Wilander <[email protected]>
PCM: Change expectation to pass so we can investigate http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window.html
Modified: trunk/LayoutTests/tiled-drawing/scrolling/clamp-out-of-bounds-scrolls-expected.txt (284653 => 284654)
--- trunk/LayoutTests/tiled-drawing/scrolling/clamp-out-of-bounds-scrolls-expected.txt 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/LayoutTests/tiled-drawing/scrolling/clamp-out-of-bounds-scrolls-expected.txt 2021-10-21 23:58:35 UTC (rev 284654)
@@ -55,6 +55,7 @@
Attempted scroll to 10000, 0
(Frame scrolling node
+ (scroll position 4223 0)
(scrollable area size 785 585)
(contents size 5008 5021)
(requested scroll position 4223 0)
@@ -75,7 +76,7 @@
Attempted scroll to 0, 10000
(Frame scrolling node
- (scroll position 4223 0)
+ (scroll position 0 4436)
(scrollable area size 785 585)
(contents size 5008 5021)
(requested scroll position 0 4436)
@@ -96,7 +97,7 @@
Attempted scroll to 10000, 10000
(Frame scrolling node
- (scroll position 0 4436)
+ (scroll position 4223 4436)
(scrollable area size 785 585)
(contents size 5008 5021)
(requested scroll position 4223 4436)
Modified: trunk/LayoutTests/tiled-drawing/scrolling/scrolling-tree-after-scroll-expected.txt (284653 => 284654)
--- trunk/LayoutTests/tiled-drawing/scrolling/scrolling-tree-after-scroll-expected.txt 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scrolling-tree-after-scroll-expected.txt 2021-10-21 23:58:35 UTC (rev 284654)
@@ -1,5 +1,6 @@
(Frame scrolling node
+ (scroll position 0 3000)
(scrollable area size 785 600)
(contents size 785 5021)
(requested scroll position 0 3000)
Modified: trunk/Source/WebCore/ChangeLog (284653 => 284654)
--- trunk/Source/WebCore/ChangeLog 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/ChangeLog 2021-10-21 23:58:35 UTC (rev 284654)
@@ -1,3 +1,51 @@
+2021-10-21 Simon Fraser <[email protected]>
+
+ Content offset in this codepen when switching tabs
+ https://bugs.webkit.org/show_bug.cgi?id=231989
+
+ Reviewed by Tim Horton.
+
+ There were two problems that occurred with async-scrollable iframes when their associated
+ WKWebView was removed and re-added to the view hierarchy (e.g. when switching tabs).
+ These resulted in misplaced position:fixed content, and the first user scroll in the
+ iframe causing the scroll position to jump back to the top.
+
+ The positon:fixed issue was caused by an ordering problem in
+ ScrollingTreeFrameScrollingNode::commitStateBeforeChildren() which resulted in the layout
+ viewport being computed incorrectly; we called updateViewportForCurrentScrollPosition()
+ before setting the min and max scroll position, so we'd always clamp the layout viewport to
+ a location of 0,0.
+
+ The second scroll position reset issue was caused by the ScrollingTreeScrollingNode's
+ m_currentScrollPosition reverting to a stale after re-attaching the iframe's scrolling
+ subtree. ScrollingTreeScrollingNode::commitStateBeforeChildren() has code to set
+ m_currentScrollPosition from the state tree node's scroll position on first commit;
+ the issue was that ScrollingStateScrollingNode's scrollPosition() was not updated on every
+ scroll, only when something triggered a scrolling tree commit.
+
+ Fix by silently updating ScrollingStateScrollingNode's scrollPosition() when we get
+ notifications back from the scrolling thread that a scroll happened.
+
+ Both fixes are tested by the ScrollingCoordinatorTests.ScrollingTreeAfterDetachReattach API test.
+
+ * page/scrolling/AsyncScrollingCoordinator.cpp:
+ (WebCore::AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll):
+ * page/scrolling/ScrollingStateScrollingNode.cpp:
+ (WebCore::ScrollingStateScrollingNode::syncScrollPosition):
+ (WebCore::ScrollingStateScrollingNode::hasScrollPositionRequest const):
+ * page/scrolling/ScrollingStateScrollingNode.h:
+ * page/scrolling/ScrollingStateTree.cpp:
+ (WebCore::ScrollingStateTree::insertNode):
+ * page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
+ (WebCore::ScrollingTreeFrameScrollingNode::commitStateBeforeChildren): We need to check
+ state.hasScrollPositionRequest(), otherwise the "cancel animated scroll request" that comes
+ out of Page::stopKeyboardScrollAnimation() prevents scroll position restoration.
+ * page/scrolling/ScrollingTreeScrollingNode.cpp:
+ (WebCore::ScrollingTreeScrollingNode::commitStateBeforeChildren):
+ (WebCore::ScrollingTreeScrollingNode::dumpProperties const):
+ * page/scrolling/mac/ScrollingCoordinatorMac.mm:
+ (WebCore::ScrollingCoordinatorMac::commitTreeStateIfNeeded):
+
2021-10-21 Sihui Liu <[email protected]>
FileSystemSyncAccessHandle should close platform file handle on close()
Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp 2021-10-21 23:58:35 UTC (rev 284654)
@@ -451,6 +451,12 @@
m_page->editorClient().subFrameScrollPositionChanged();
}
+ auto* node = m_scrollingStateTree->stateNodeForID(scrollingNodeID);
+ if (is<ScrollingStateScrollingNode>(node)) {
+ auto& scrollingNode = downcast<ScrollingStateScrollingNode>(*node);
+ scrollingNode.syncScrollPosition(scrollPosition);
+ }
+
if (scrollingNodeID == frameView.scrollingNodeID()) {
reconcileScrollingState(frameView, scrollPosition, layoutViewportOrigin, scrollType, ViewportRectStability::Stable, scrollingLayerPositionAction);
return;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp 2021-10-21 23:58:35 UTC (rev 284654)
@@ -143,6 +143,11 @@
setPropertyChanged(Property::ScrollPosition);
}
+void ScrollingStateScrollingNode::syncScrollPosition(const FloatPoint& scrollPosition)
+{
+ m_scrollPosition = scrollPosition;
+}
+
void ScrollingStateScrollingNode::setScrollOrigin(const IntPoint& scrollOrigin)
{
if (m_scrollOrigin == scrollOrigin)
@@ -206,6 +211,11 @@
setPropertyChanged(Property::RequestedScrollPosition);
}
+bool ScrollingStateScrollingNode::hasScrollPositionRequest() const
+{
+ return hasChangedProperty(Property::RequestedScrollPosition) && m_requestedScrollData.requestType == ScrollRequestType::PositionUpdate;
+}
+
void ScrollingStateScrollingNode::setIsMonitoringWheelEvents(bool isMonitoringWheelEvents)
{
if (isMonitoringWheelEvents == m_isMonitoringWheelEvents)
Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h 2021-10-21 23:58:35 UTC (rev 284654)
@@ -54,6 +54,9 @@
const FloatPoint& scrollPosition() const { return m_scrollPosition; }
WEBCORE_EXPORT void setScrollPosition(const FloatPoint&);
+ // Does not trigger a scrolling tree commit.
+ WEBCORE_EXPORT void syncScrollPosition(const FloatPoint&);
+
const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
WEBCORE_EXPORT void setScrollOrigin(const IntPoint&);
@@ -78,6 +81,8 @@
const RequestedScrollData& requestedScrollData() const { return m_requestedScrollData; }
WEBCORE_EXPORT void setRequestedScrollData(const RequestedScrollData&);
+ WEBCORE_EXPORT bool hasScrollPositionRequest() const;
+
bool isMonitoringWheelEvents() const { return m_isMonitoringWheelEvents; }
WEBCORE_EXPORT void setIsMonitoringWheelEvents(bool);
Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateTree.cpp (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/ScrollingStateTree.cpp 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateTree.cpp 2021-10-21 23:58:35 UTC (rev 284654)
@@ -176,7 +176,7 @@
if (parentID) {
if (auto unparentedNode = m_unparentedNodes.take(newNodeID)) {
- LOG_WITH_STREAM(ScrollingTree, stream << "ScrollingStateTree " << this << " insertNode " << newNodeID << " getting node from unparented nodes");
+ LOG_WITH_STREAM(ScrollingTree, stream << "ScrollingStateTree " << this << " insertNode reattaching node " << newNodeID);
newNode = unparentedNode.get();
nodeWasReattachedRecursive(*unparentedNode);
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeFrameScrollingNode.cpp 2021-10-21 23:58:35 UTC (rev 284654)
@@ -72,10 +72,8 @@
if (state.hasChangedProperty(ScrollingStateNode::Property::FixedElementsLayoutRelativeToFrame))
m_fixedElementsLayoutRelativeToFrame = state.fixedElementsLayoutRelativeToFrame();
- if (state.hasChangedProperty(ScrollingStateNode::Property::LayoutViewport)) {
+ if (state.hasChangedProperty(ScrollingStateNode::Property::LayoutViewport))
m_layoutViewport = state.layoutViewport();
- updateViewportForCurrentScrollPosition({ });
- }
if (state.hasChangedProperty(ScrollingStateNode::Property::MinLayoutViewportOrigin))
m_minLayoutViewportOrigin = state.minLayoutViewportOrigin();
@@ -85,6 +83,11 @@
if (state.hasChangedProperty(ScrollingStateNode::Property::OverrideVisualViewportSize))
m_overrideVisualViewportSize = state.overrideVisualViewportSize();
+
+ if (state.hasChangedProperty(ScrollingStateNode::Property::LayoutViewport)) {
+ // This requires that minLayoutViewportOrigin and maxLayoutViewportOrigin have been updated.
+ updateViewportForCurrentScrollPosition({ });
+ }
}
bool ScrollingTreeFrameScrollingNode::scrollPositionAndLayoutViewportMatch(const FloatPoint& position, std::optional<FloatRect> overrideLayoutViewport)
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp 2021-10-21 23:58:35 UTC (rev 284654)
@@ -67,7 +67,7 @@
if (state.hasChangedProperty(ScrollingStateNode::Property::ScrollPosition)) {
m_lastCommittedScrollPosition = state.scrollPosition();
- if (m_isFirstCommit && !state.hasChangedProperty(ScrollingStateNode::Property::RequestedScrollPosition))
+ if (m_isFirstCommit && !state.hasScrollPositionRequest())
m_currentScrollPosition = m_lastCommittedScrollPosition;
}
@@ -336,7 +336,10 @@
ts.dumpProperty("reachable content size", m_reachableContentsSize);
ts.dumpProperty("last committed scroll position", m_lastCommittedScrollPosition);
- if (m_scrollOrigin != IntPoint())
+ if (!m_currentScrollPosition.isZero())
+ ts.dumpProperty("scroll position", m_currentScrollPosition);
+
+ if (!m_scrollOrigin.isZero())
ts.dumpProperty("scroll origin", m_scrollOrigin);
if (m_snapOffsetsInfo.horizontalSnapOffsets.size())
Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (284653 => 284654)
--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2021-10-21 23:58:35 UTC (rev 284654)
@@ -114,7 +114,7 @@
if (!scrollingStateTree()->hasChangedProperties())
return;
- LOG_WITH_STREAM(ScrollingTree, stream << scrollingStateTreeAsText(debugScrollingStateTreeAsTextBehaviors));
+ LOG_WITH_STREAM(ScrollingTree, stream << "ScrollingCoordinatorMac::commitTreeState: state tree " << scrollingStateTreeAsText(debugScrollingStateTreeAsTextBehaviors));
auto stateTree = scrollingStateTree()->commit(LayerRepresentation::PlatformLayerRepresentation);
scrollingTree()->commitTreeState(WTFMove(stateTree));
Modified: trunk/Tools/ChangeLog (284653 => 284654)
--- trunk/Tools/ChangeLog 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Tools/ChangeLog 2021-10-21 23:58:35 UTC (rev 284654)
@@ -1,3 +1,30 @@
+2021-10-21 Simon Fraser <[email protected]>
+
+ Content offset in this codepen when switching tabs
+ https://bugs.webkit.org/show_bug.cgi?id=231989
+
+ Reviewed by Tim Horton.
+
+ API test that scrolls an iframe via wheel events, then detached and re-attaches the view.
+
+ The two wheel scrolls are necessary to exercise the "stale ScrollingStateScrollingNode
+ scroll position" issue.
+
+ The scrolling tree dumps validate the layout viewport part of the fix.
+
+ Also correct some functions where the sense of 'isWaitingForJavaScript' was flipped.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/mac/ScrollingCoordinatorTests.mm: Added.
+ (TestWebKitAPI::synthesizeWheelEvents):
+ (TestWebKitAPI::waitForScrollEventAndReturnScrollY):
+ (TestWebKitAPI::scrollingTreeElidingLastCommittedScrollPosition):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/cocoa/TestWKWebView.mm:
+ (-[WKWebView objectByEvaluatingJavaScript:]):
+ (-[WKWebView objectByEvaluatingJavaScriptWithUserGesture:]):
+ (-[WKWebView objectByCallingAsyncFunction:withArguments:error:]):
+
2021-10-21 Fujii Hironori <[email protected]>
[Win] TestWTF.FileSystemTest.* are timing out if run-api-tests is run by a normal user
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (284653 => 284654)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-10-21 23:58:35 UTC (rev 284654)
@@ -86,6 +86,7 @@
0F4FFA9E1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F4FFA9D1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm */; };
0F5651F71FCE4DDC00310FBC /* NoHistoryItemScrollToFragment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F5651F61FCE4DDB00310FBC /* NoHistoryItemScrollToFragment.mm */; };
0F5651F91FCE513500310FBC /* scroll-to-anchor.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 0F5651F81FCE50E800310FBC /* scroll-to-anchor.html */; };
+ 0FEFAF64271FC2CD005704D7 /* ScrollingCoordinatorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FEFAF63271FC2CD005704D7 /* ScrollingCoordinatorTests.mm */; };
0FF1134E22D68679009A81DA /* ScrollViewScrollabilityTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FF1134D22D68679009A81DA /* ScrollViewScrollabilityTests.mm */; };
115EB3431EE0BA03003C2C0A /* ViewportSizeForViewportUnits.mm in Sources */ = {isa = PBXBuildFile; fileRef = 115EB3421EE0B720003C2C0A /* ViewportSizeForViewportUnits.mm */; };
1171B24F219F49CD00CB897D /* FirstMeaningfulPaintMilestone_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11B7FD21219F46DD0069B27F /* FirstMeaningfulPaintMilestone_Bundle.cpp */; };
@@ -1860,6 +1861,7 @@
0FC6C4CE141034AD005B7F0C /* MetaAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MetaAllocator.cpp; sourceTree = "<group>"; };
0FE447971B76F1E3009498EB /* ParkingLot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParkingLot.cpp; sourceTree = "<group>"; };
0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Condition.cpp; sourceTree = "<group>"; };
+ 0FEFAF63271FC2CD005704D7 /* ScrollingCoordinatorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingCoordinatorTests.mm; sourceTree = "<group>"; };
0FF1134D22D68679009A81DA /* ScrollViewScrollabilityTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewScrollabilityTests.mm; sourceTree = "<group>"; };
0FFC45A41B73EBE20085BD62 /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = "<group>"; };
115EB3421EE0B720003C2C0A /* ViewportSizeForViewportUnits.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewportSizeForViewportUnits.mm; sourceTree = "<group>"; };
@@ -3092,7 +3094,6 @@
F44A530F21B8976900DBB99C /* ClassMethodSwizzler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClassMethodSwizzler.h; path = ../TestRunnerShared/cocoa/ClassMethodSwizzler.h; sourceTree = "<group>"; };
F44A531021B8976900DBB99C /* InstanceMethodSwizzler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InstanceMethodSwizzler.mm; path = ../TestRunnerShared/cocoa/InstanceMethodSwizzler.mm; sourceTree = "<group>"; };
F44A7D1F268D5C6900B49BB8 /* ImageAnalysisTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImageAnalysisTests.mm; sourceTree = "<group>"; };
- F44A9AF52649BBDD00E7CB16 /* ImmediateActionTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImmediateActionTests.h; sourceTree = "<group>"; };
F44A9AF62649BBDD00E7CB16 /* ImmediateActionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImmediateActionTests.mm; sourceTree = "<group>"; };
F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ParserYieldTokenPlugIn.mm; sourceTree = "<group>"; };
F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserYieldTokenTests.h; sourceTree = "<group>"; };
@@ -4828,7 +4829,6 @@
51EB125824C68589000CB030 /* HIDGamepads.mm */,
9B4F8FA3159D52B1002D9F94 /* HTMLCollectionNamedItem.mm */,
9B26FC6B159D061000CC3765 /* HTMLFormCollectionNamedItem.mm */,
- F44A9AF52649BBDD00E7CB16 /* ImmediateActionTests.h */,
F44A9AF62649BBDD00E7CB16 /* ImmediateActionTests.mm */,
C507E8A614C6545B005D6B3B /* InspectorBar.mm */,
57F10D921C7E7B3800ECDF30 /* IsNavigationActionTrusted.mm */,
@@ -4848,6 +4848,7 @@
A57A34EF16AF677200C2501F /* PageVisibilityStateWithWindowChanges.mm */,
37C784DE197C8F2E0010A496 /* RenderedImageFromDOMNode.mm */,
3722C8681461E03E00C45D00 /* RenderedImageFromDOMRange.mm */,
+ 0FEFAF63271FC2CD005704D7 /* ScrollingCoordinatorTests.mm */,
261516D515B0E60500A2C201 /* SetAndUpdateCacheModel.mm */,
52B8CF9515868CF000281053 /* SetDocumentURI.mm */,
C540F775152E4DA000A40C8C /* SimplifyMarkup.mm */,
@@ -5845,6 +5846,7 @@
95095F20262FFFA50000D920 /* SampledPageTopColor.mm in Sources */,
CDCFA7AA1E45183200C2433D /* SampleMap.cpp in Sources */,
CE0947372063223B003C9BA0 /* SchemeRegistry.mm in Sources */,
+ 0FEFAF64271FC2CD005704D7 /* ScrollingCoordinatorTests.mm in Sources */,
CDC0932B21C872C10030C4B0 /* ScrollingDoesNotPauseMedia.mm in Sources */,
7CCE7F121A411AE600447C4C /* ScrollPinningBehaviors.cpp in Sources */,
F434CA1A22E65BCA005DDB26 /* ScrollToRevealSelection.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/mac/ScrollingCoordinatorTests.mm (0 => 284654)
--- trunk/Tools/TestWebKitAPI/Tests/mac/ScrollingCoordinatorTests.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/ScrollingCoordinatorTests.mm 2021-10-21 23:58:35 UTC (rev 284654)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#import "config.h"
+#import "Test.h"
+
+#if PLATFORM(MAC)
+
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import "WKWebViewConfigurationExtras.h"
+#import <WebKit/WKWebViewPrivate.h>
+#import <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static float waitForScrollEventAndReturnScrollY(WKWebView* webView, const std::function<void(WKWebView*)>& scrollTrigger)
+{
+ bool receivedScrollEvent = false;
+ RetainPtr<id> evalResult;
+ RetainPtr<NSError> strongError;
+
+ NSString *scriptString = @"return new Promise((resolve) => {" \
+ " let iframe = document.getElementsByTagName('iframe')[0];" \
+ " iframe.contentWindow.addEventListener(\"scroll\", (event) => resolve(iframe.contentWindow.scrollY)); " \
+ "})";
+
+ [webView callAsyncJavaScript:scriptString arguments:nil inFrame:nil inContentWorld:WKContentWorld.pageWorld completionHandler:[&] (id result, NSError *error) {
+ evalResult = result;
+ strongError = error;
+ receivedScrollEvent = true;
+ }];
+
+ scrollTrigger(webView);
+
+ TestWebKitAPI::Util::run(&receivedScrollEvent);
+
+ return [evalResult floatValue];
+}
+
+// Remove "last committed scroll position" for the iframe's node, which we expect to be different.
+static NSString *scrollingTreeElidingLastCommittedScrollPosition(NSString *scrollingTree)
+{
+ NSMutableArray *lines = [[[scrollingTree componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] mutableCopy] autorelease];
+
+ NSIndexSet* lastCommittedLineIndices = [lines indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ return [obj hasPrefix:@" (last committed scroll position"];
+ }];
+ [lines removeObjectsAtIndexes:lastCommittedLineIndices];
+ return [lines componentsJoinedByString:@"\n"];
+}
+
+TEST(ScrollingCoordinatorTests, ScrollingTreeAfterDetachReattach)
+{
+ WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500) configuration:configuration addToWindow:YES]);
+
+ NSString *documentString = @"<style>body { height: 5000px; }</style>" \
+ "<iframe srcdoc=\"<style>body { height: 5000px; }</style><div style='position:fixed; width: 100px; height: 50px; background: blue'></div>\"></iframe>";
+
+ [webView synchronouslyLoadHTMLString:documentString];
+ [webView waitForNextPresentationUpdate];
+
+ CGPoint eventLocationInWindow = [webView convertPoint:CGPointMake(50, 50) toView:nil];
+
+ auto scrollY = waitForScrollEventAndReturnScrollY(webView.get(), [eventLocationInWindow](TestWKWebView *webView) {
+ [webView wheelEventAtPoint:eventLocationInWindow wheelDelta:CGSizeMake(0, -100)];
+ });
+ EXPECT_EQ(scrollY, 100);
+
+ // Send a second wheel event to trigger reconcileScrollingState() that does not end up in setScrollingNodeScrollableAreaGeometry() (some compositing code early returns).
+ // This would leave the scrolling state tree with a stale m_scrollPosition.
+ scrollY = waitForScrollEventAndReturnScrollY(webView.get(), [eventLocationInWindow](TestWKWebView *webView) {
+ [webView wheelEventAtPoint:eventLocationInWindow wheelDelta:CGSizeMake(0, -100)];
+ });
+ EXPECT_EQ(scrollY, 200);
+
+ [webView waitForNextPresentationUpdate];
+
+ NSString *scrollingTreeBefore = scrollingTreeElidingLastCommittedScrollPosition([webView stringByEvaluatingJavaScript:@"internals.scrollingTreeAsText()"]);
+
+ NSWindow *hostWindow = [webView window];
+ [webView removeFromSuperview];
+ [webView waitForNextPresentationUpdate];
+ [[hostWindow contentView] addSubview:webView.get()];
+ [webView waitForNextPresentationUpdate];
+
+ NSString *scrollingTreeAfter = scrollingTreeElidingLastCommittedScrollPosition([webView stringByEvaluatingJavaScript:@"internals.scrollingTreeAsText()"]);
+
+ EXPECT_TRUE([scrollingTreeBefore isEqualToString:scrollingTreeAfter]);
+
+ scrollY = waitForScrollEventAndReturnScrollY(webView.get(), [eventLocationInWindow](TestWKWebView *webView) {
+ [webView wheelEventAtPoint:eventLocationInWindow wheelDelta:CGSizeMake(0, -101)];
+ });
+ EXPECT_EQ(scrollY, 301);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // PLATFORM(MAC)
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (284653 => 284654)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h 2021-10-21 23:58:35 UTC (rev 284654)
@@ -139,6 +139,7 @@
- (void)mouseMoveToPoint:(NSPoint)pointInWindow withFlags:(NSEventModifierFlags)flags;
- (void)sendClicksAtPoint:(NSPoint)pointInWindow numberOfClicks:(NSUInteger)numberOfClicks;
- (void)sendClickAtPoint:(NSPoint)pointInWindow;
+- (void)wheelEventAtPoint:(CGPoint)pointInWindow wheelDelta:(CGSize)delta;
- (NSWindow *)hostWindow;
- (void)typeCharacter:(char)character modifiers:(NSEventModifierFlags)modifiers;
- (void)typeCharacter:(char)character;
Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (284653 => 284654)
--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2021-10-21 23:46:00 UTC (rev 284653)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm 2021-10-21 23:58:35 UTC (rev 284654)
@@ -204,37 +204,37 @@
- (id)objectByEvaluatingJavaScript:(NSString *)script
{
- bool isWaitingForJavaScript = false;
+ bool callbackComplete = false;
RetainPtr<id> evalResult;
[self _evaluateJavaScriptWithoutUserGesture:script completionHandler:[&] (id result, NSError *error) {
evalResult = result;
- isWaitingForJavaScript = true;
+ callbackComplete = true;
EXPECT_TRUE(!error);
if (error)
NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
}];
- TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+ TestWebKitAPI::Util::run(&callbackComplete);
return evalResult.autorelease();
}
- (id)objectByEvaluatingJavaScriptWithUserGesture:(NSString *)script
{
- bool isWaitingForJavaScript = false;
+ bool callbackComplete = false;
RetainPtr<id> evalResult;
[self evaluateJavaScript:script completionHandler:[&] (id result, NSError *error) {
evalResult = result;
- isWaitingForJavaScript = true;
+ callbackComplete = true;
EXPECT_TRUE(!error);
if (error)
NSLog(@"Encountered error: %@ while evaluating script: %@", error, script);
}];
- TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+ TestWebKitAPI::Util::run(&callbackComplete);
return evalResult.autorelease();
}
- (id)objectByCallingAsyncFunction:(NSString *)script withArguments:(NSDictionary *)arguments error:(NSError **)errorOut
{
- bool isWaitingForJavaScript = false;
+ bool callbackComplete = false;
if (errorOut)
*errorOut = nil;
@@ -243,9 +243,9 @@
[self callAsyncJavaScript:script arguments:arguments inFrame:nil inContentWorld:WKContentWorld.pageWorld completionHandler:[&] (id result, NSError *error) {
evalResult = result;
strongError = error;
- isWaitingForJavaScript = true;
+ callbackComplete = true;
}];
- TestWebKitAPI::Util::run(&isWaitingForJavaScript);
+ TestWebKitAPI::Util::run(&callbackComplete);
if (errorOut)
*errorOut = strongError.autorelease();
@@ -862,6 +862,18 @@
}
}
+- (void)wheelEventAtPoint:(CGPoint)pointInWindow wheelDelta:(CGSize)delta
+{
+ RetainPtr<CGEventRef> cgScrollEvent = adoptCF(CGEventCreateScrollWheelEvent(nullptr, kCGScrollEventUnitPixel, 2, delta.height, delta.width, 0));
+
+ CGPoint locationInGlobalScreenCoordinates = [[self window] convertPointToScreen:pointInWindow];
+ locationInGlobalScreenCoordinates.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - locationInGlobalScreenCoordinates.y;
+ CGEventSetLocation(cgScrollEvent.get(), locationInGlobalScreenCoordinates);
+
+ NSEvent* event = [NSEvent eventWithCGEvent:cgScrollEvent.get()];
+ [self scrollWheel:event];
+}
+
- (NSWindow *)hostWindow
{
return _hostWindow.get();