| /* |
| * Copyright (C) 2018 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" |
| |
| #if PLATFORM(IOS_FAMILY) |
| |
| #import "InstanceMethodSwizzler.h" |
| #import "PlatformUtilities.h" |
| #import "TestCocoa.h" |
| #import "TestNavigationDelegate.h" |
| #import "TestWKWebView.h" |
| #import "UIKitSPIForTesting.h" |
| #import "UserInterfaceSwizzler.h" |
| #import "WKBrowserEngineDefinitions.h" |
| #import <WebCore/ColorCocoa.h> |
| #import <WebCore/ColorSerialization.h> |
| #import <WebCore/WebEvent.h> |
| #import <WebKit/WKPreferencesPrivate.h> |
| #import <WebKit/WKWebViewPrivate.h> |
| #import <WebKit/WKWebViewPrivateForTesting.h> |
| #import <WebKit/_WKFeature.h> |
| #import <wtf/BlockPtr.h> |
| #import <wtf/darwin/DispatchExtras.h> |
| |
| constexpr CGFloat blackColorComponents[4] = { 0, 0, 0, 1 }; |
| constexpr CGFloat whiteColorComponents[4] = { 1, 1, 1, 1 }; |
| |
| @interface UIView (TestWebKitAPI) |
| - (BOOL)_appearsBeforeViewInSubviewOrder:(UIView *)view; |
| @end |
| |
| @implementation UIView (TestWebKitAPI) |
| |
| - (BOOL)_appearsBeforeViewInSubviewOrder:(UIView *)view |
| { |
| if (!view || view.superview != self.superview) |
| return false; |
| |
| RetainPtr subviews = [self.superview subviews]; |
| return [subviews count] && [subviews indexOfObject:self] < [subviews indexOfObject:view]; |
| } |
| |
| @end |
| |
| #if HAVE(LIQUID_GLASS) |
| |
| @interface ScrollEdgeEffectIsHiddenObserver : NSObject |
| @end |
| |
| @implementation ScrollEdgeEffectIsHiddenObserver { |
| __weak UIScrollEdgeEffect *_effect; |
| BlockPtr<void()> _callback; |
| } |
| |
| void *scrollEdgeEffectObservationContext = &scrollEdgeEffectObservationContext; |
| |
| - (instancetype)initWithScrollEdgeEffect:(UIScrollEdgeEffect *)effect callback:(void(^)())callback |
| { |
| if (!(self = [super init])) |
| return nil; |
| |
| _effect = effect; |
| _callback = makeBlockPtr(callback); |
| [effect addObserver:self forKeyPath:NSStringFromSelector(@selector(isHidden)) options:NSKeyValueObservingOptionNew context:scrollEdgeEffectObservationContext]; |
| return self; |
| } |
| |
| - (void)dealloc |
| { |
| [_effect removeObserver:self forKeyPath:NSStringFromSelector(@selector(isHidden))]; |
| |
| [super dealloc]; |
| } |
| |
| - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context |
| { |
| if (context == scrollEdgeEffectObservationContext) |
| _callback(); |
| } |
| |
| @end |
| |
| #endif // HAVE(LIQUID_GLASS) |
| |
| #if HAVE(UISCROLLVIEW_ASYNCHRONOUS_SCROLL_EVENT_HANDLING) |
| |
| #if USE(BROWSERENGINEKIT) |
| |
| @interface WKTestScrollViewScrollUpdate : NSObject |
| |
| - (instancetype)initWithScrollEvent:(UIScrollEvent *)scrollEvent phase:(BEScrollViewScrollUpdatePhase)phase; |
| - (CGPoint)locationInView:(UIView *)view; |
| - (CGPoint)translationInView:(UIView *)view; |
| |
| @property (nonatomic, readonly) NSTimeInterval timestamp; |
| @property (nonatomic, readonly) BEScrollViewScrollUpdatePhase phase; |
| |
| @end |
| |
| @implementation WKTestScrollViewScrollUpdate { |
| RetainPtr<UIScrollEvent> _scrollEvent; |
| BEScrollViewScrollUpdatePhase _phase; |
| } |
| |
| - (UIScrollEvent *)_scrollEvent |
| { |
| return _scrollEvent.get(); |
| } |
| |
| - (instancetype)initWithScrollEvent:(UIScrollEvent *)scrollEvent phase:(BEScrollViewScrollUpdatePhase)phase |
| { |
| if (!(self = [super init])) |
| return nil; |
| |
| _scrollEvent = scrollEvent; |
| _phase = phase; |
| return self; |
| } |
| |
| - (BEScrollViewScrollUpdatePhase)phase |
| { |
| return _phase; |
| } |
| |
| - (NSTimeInterval)timestamp |
| { |
| return [_scrollEvent timestamp]; |
| } |
| |
| - (CGPoint)locationInView:(UIView *)view |
| { |
| return [_scrollEvent locationInView:view]; |
| } |
| |
| - (CGPoint)translationInView:(UIView *)view |
| { |
| CGVector adjustedAcceleratedDelta = [_scrollEvent _adjustedAcceleratedDeltaInView:view]; |
| return CGPointMake(adjustedAcceleratedDelta.dx, adjustedAcceleratedDelta.dy); |
| } |
| |
| @end |
| |
| #endif // USE(BROWSERENGINEKIT) |
| |
| @interface WKUIScrollEvent : UIScrollEvent |
| |
| - (instancetype)initWithPhase:(UIScrollPhase)phase location:(CGPoint)location delta:(CGVector)delta; |
| |
| @end |
| |
| @implementation WKUIScrollEvent { |
| UIScrollPhase _phase; |
| CGPoint _location; |
| CGVector _delta; |
| } |
| |
| - (instancetype)initWithPhase:(UIScrollPhase)phase location:(CGPoint)location delta:(CGVector)delta |
| { |
| self = [super init]; |
| if (!self) |
| return nil; |
| |
| _phase = phase; |
| _location = location; |
| _delta = delta; |
| |
| return self; |
| } |
| |
| - (UIScrollPhase)phase |
| { |
| return _phase; |
| } |
| |
| - (CGPoint)locationInView:(UIView *)view |
| { |
| return _location; |
| } |
| |
| - (CGVector)_adjustedAcceleratedDeltaInView:(UIView *)view |
| { |
| return _delta; |
| } |
| |
| @end |
| |
| inline static UIScrollPhase legacyScrollPhase(WKBEScrollViewScrollUpdatePhase phase) |
| { |
| #if USE(BROWSERENGINEKIT) |
| switch (phase) { |
| case WKBEScrollViewScrollUpdatePhaseBegan: |
| return UIScrollPhaseBegan; |
| case WKBEScrollViewScrollUpdatePhaseChanged: |
| return UIScrollPhaseChanged; |
| case WKBEScrollViewScrollUpdatePhaseEnded: |
| return UIScrollPhaseEnded; |
| case WKBEScrollViewScrollUpdatePhaseCancelled: |
| return UIScrollPhaseCancelled; |
| } |
| ASSERT_NOT_REACHED(); |
| return UIScrollPhaseCancelled; |
| #else |
| return phase; |
| #endif |
| } |
| |
| inline static RetainPtr<WKBEScrollViewScrollUpdate> createScrollUpdate(WKBEScrollViewScrollUpdatePhase phase, CGPoint location, CGVector delta) |
| { |
| auto event = adoptNS([[WKUIScrollEvent alloc] initWithPhase:legacyScrollPhase(phase) location:location delta:delta]); |
| #if USE(BROWSERENGINEKIT) |
| return adoptNS(static_cast<BEScrollViewScrollUpdate *>([[WKTestScrollViewScrollUpdate alloc] initWithScrollEvent:event.get() phase:phase])); |
| #else |
| return event; |
| #endif |
| } |
| |
| @interface WKWebView (WKBEScrollViewDelegate) |
| - (void)scrollView:(UIScrollView *)scrollView handleScrollUpdate:(WKBEScrollViewScrollUpdate *)update completion:(void (^)(BOOL handled))completion; |
| @end |
| |
| @interface WKWebView (WKScrollViewTests) |
| - (BOOL)synchronouslyHandleScrollEventWithPhase:(WKBEScrollViewScrollUpdatePhase)phase location:(CGPoint)location delta:(CGVector)delta; |
| @end |
| |
| @implementation WKWebView (WKScrollViewTests) |
| |
| - (BOOL)synchronouslyHandleScrollEventWithPhase:(WKBEScrollViewScrollUpdatePhase)phase location:(CGPoint)location delta:(CGVector)delta |
| { |
| __block bool done = false; |
| __block BOOL scrollingPrevented; |
| |
| RetainPtr update = createScrollUpdate(phase, location, delta); |
| [self scrollView:self.scrollView handleScrollUpdate:update.get() completion:^(BOOL prevented) { |
| scrollingPrevented = prevented; |
| done = true; |
| }]; |
| |
| TestWebKitAPI::Util::run(&done); |
| return scrollingPrevented; |
| } |
| |
| @end |
| |
| #endif // HAVE(UISCROLLVIEW_ASYNCHRONOUS_SCROLL_EVENT_HANDLING) |
| |
| namespace TestWebKitAPI { |
| |
| static void traverseLayerTree(CALayer *layer, void(^block)(CALayer *)) |
| { |
| for (CALayer *child in layer.sublayers) |
| traverseLayerTree(child, block); |
| block(layer); |
| } |
| |
| TEST(WKScrollViewTests, PositionFixedLayerAfterScrolling) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); |
| [webView synchronouslyLoadTestPageNamed:@"fixed-nav-bar"]; |
| |
| __block bool done = false; |
| [webView _doAfterNextPresentationUpdate:^() { |
| done = true; |
| }]; |
| |
| [CATransaction begin]; |
| [webView scrollView].contentOffset = CGPointMake(0, 5000); |
| [CATransaction commit]; |
| |
| // Purposefully hang the main thread for a short while to give the remote layer tree transaction an |
| // opportunity to arrive in the UI process before dispatching the next visible content rect update. |
| usleep(USEC_PER_SEC * 0.25); |
| |
| Util::run(&done); |
| |
| bool foundLayerForFixedNavigationBar = false; |
| traverseLayerTree([webView layer], [&] (CALayer *layer) { |
| if (!CGSizeEqualToSize(layer.bounds.size, CGSizeMake(320, 50))) |
| return; |
| |
| auto boundsInWebViewCoordinates = [layer convertRect:layer.bounds toLayer:[webView layer]]; |
| EXPECT_EQ(CGRectGetMinX(boundsInWebViewCoordinates), 0); |
| EXPECT_EQ(CGRectGetMinY(boundsInWebViewCoordinates), 0); |
| foundLayerForFixedNavigationBar = true; |
| }); |
| EXPECT_TRUE(foundLayerForFixedNavigationBar); |
| } |
| |
| #if HAVE(UISCROLLVIEW_ASYNCHRONOUS_SCROLL_EVENT_HANDLING) |
| |
| TEST(WKScrollViewTests, AsynchronousWheelEventHandling) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); |
| [webView synchronouslyLoadHTMLString:@"" |
| "<style>#handler { width: 200px; height: 200px; }</style>" |
| "<div id='handler'></div>" |
| "<script>window.preventDefaultOnScrollEvents = false;" |
| "document.getElementById('handler').addEventListener('wheel', " |
| "function (e) {" |
| " window.lastWheelEvent = e;" |
| " if (window.preventDefaultOnScrollEvents)" |
| " e.preventDefault();" |
| "})</script>"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| BOOL scrollingPrevented; |
| // Don't preventDefault() at all. |
| #if !USE(BROWSERENGINEKIT) |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| #endif |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_FALSE(scrollingPrevented); |
| EXPECT_TRUE([[webView objectByEvaluatingJavaScript:@"window.lastWheelEvent.cancelable"] intValue]); |
| EXPECT_EQ(-10, [[webView objectByEvaluatingJavaScript:@"window.lastWheelEvent.deltaY"] intValue]); |
| EXPECT_EQ(30, [[webView objectByEvaluatingJavaScript:@"window.lastWheelEvent.wheelDeltaY"] intValue]); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_FALSE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| |
| // preventDefault() on all events. |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = true;"]; |
| #if !USE(BROWSERENGINEKIT) |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| #endif |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| |
| // preventDefault() on all but the begin event; it will be ignored. |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = false;"]; |
| #if !USE(BROWSERENGINEKIT) |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| #endif |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE([[webView objectByEvaluatingJavaScript:@"window.lastWheelEvent.cancelable"] intValue]); |
| EXPECT_FALSE(scrollingPrevented); |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = true;"]; |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_FALSE(scrollingPrevented); |
| EXPECT_FALSE([[webView objectByEvaluatingJavaScript:@"window.lastWheelEvent.cancelable"] intValue]); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| |
| // preventDefault() on the begin event, and some subsequent events. |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = true;"]; |
| #if !USE(BROWSERENGINEKIT) |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| #endif |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = false;"]; |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_FALSE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| |
| // preventDefault() on the first event with non-zero deltas, and some subsequent events. |
| // In this case, the begin event has zero delta, and is not dispatched to the page, so the |
| // first non-zero scroll event is actually the first preventable one. |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = true;"]; |
| #if !USE(BROWSERENGINEKIT) |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| #endif |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_TRUE(scrollingPrevented); |
| [webView stringByEvaluatingJavaScript:@"window.preventDefaultOnScrollEvents = false;"]; |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| EXPECT_FALSE(scrollingPrevented); |
| scrollingPrevented = [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]; |
| EXPECT_FALSE(scrollingPrevented); |
| } |
| |
| TEST(WKScrollViewTests, OverscrollBehaviorAndOverflowHiddenOnRootShouldNotPreventScrolling) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); |
| [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html>" |
| "<html>" |
| "<meta name='viewport' content='width=device-width, initial-scale=1'>" |
| "<head>" |
| " <style>" |
| " body, html { width: 100%; height: 100%; margin: 0; overscroll-behavior: contain; overflow: hidden; }" |
| " .scroller { width: 100%; height: 100%; overflow: scroll; }" |
| " .tall { width: 1px; height: 5000px; }" |
| " </style>" |
| "</head>" |
| "<body>" |
| " <div class='scroller'><div class='tall'></div></div>" |
| " <script>" |
| " window.preventWheelEvents = false;" |
| " document.querySelector('.scroller').addEventListener('wheel', (event) => {" |
| " if (window.preventWheelEvents) event.preventDefault();" |
| " });" |
| " </script>" |
| "</body>" |
| "</html>"]; |
| |
| EXPECT_FALSE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]); |
| EXPECT_FALSE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]); |
| EXPECT_FALSE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]); |
| |
| [webView stringByEvaluatingJavaScript:@"window.preventWheelEvents = true;"]; |
| |
| EXPECT_TRUE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]); |
| EXPECT_TRUE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseChanged location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]); |
| EXPECT_FALSE([webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseEnded location:CGPointMake(100, 100) delta:CGVectorMake(0, 0)]); |
| } |
| |
| TEST(WKScrollViewTests, WheelEventDispatchedToSubframe) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]); |
| [webView synchronouslyLoadHTMLString:@(R"( |
| <!DOCTYPE html> |
| <html> |
| <body style='margin: 0; padding: 0;'> |
| <iframe id='subframe' style='width: 200px; height: 400px;'></iframe> |
| </body> |
| <script> |
| window.addEventListener('load', () => { |
| window.subframeHit = 0; |
| let subframe = document.getElementById('subframe'); |
| subframe.srcdoc = `\<script\> document.addEventListener('wheel', (e) => { parent.window.subframeHit = 1; }); \</script\>`; |
| }); |
| </script> |
| </html> |
| )")]; |
| #if !USE(BROWSERENGINEKIT) |
| [webView synchronouslyHandleScrollEventWithPhase:UIScrollPhaseMayBegin location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| #else |
| [webView synchronouslyHandleScrollEventWithPhase:WKBEScrollViewScrollUpdatePhaseBegan location:CGPointMake(100, 100) delta:CGVectorMake(0, 10)]; |
| #endif |
| EXPECT_TRUE([[webView objectByEvaluatingJavaScript:@"window.subframeHit"] intValue]); |
| } |
| |
| #endif // HAVE(UISCROLLVIEW_ASYNCHRONOUS_SCROLL_EVENT_HANDLING) |
| |
| TEST(WKScrollViewTests, IndicatorStyleSetByClient) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 320, 500)]); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: black; } </style>"]; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleWhite); |
| |
| [webView scrollView].indicatorStyle = UIScrollViewIndicatorStyleBlack; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleBlack); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: black; } </style>"]; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleBlack); |
| |
| [webView scrollView].indicatorStyle = UIScrollViewIndicatorStyleDefault; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleWhite); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: white; } </style>"]; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleBlack); |
| |
| [webView scrollView].indicatorStyle = UIScrollViewIndicatorStyleWhite; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleWhite); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: white; } </style>"]; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleWhite); |
| |
| [webView scrollView].indicatorStyle = UIScrollViewIndicatorStyleDefault; |
| EXPECT_EQ([webView scrollView].indicatorStyle, UIScrollViewIndicatorStyleBlack); |
| } |
| |
| TEST(WKScrollViewTests, BackgroundColorSetByClient) |
| { |
| auto sRGBColorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); |
| auto blackColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), blackColorComponents)); |
| auto whiteColor = adoptCF(CGColorCreate(sRGBColorSpace.get(), whiteColorComponents)); |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 320, 500)]); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: black; } </style>"]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, blackColor.get())); |
| |
| [webView scrollView].backgroundColor = [UIColor colorWithCGColor:whiteColor.get()]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, whiteColor.get())); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: black; } </style>"]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, whiteColor.get())); |
| |
| [webView scrollView].backgroundColor = nil; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, blackColor.get())); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: white; } </style>"]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, whiteColor.get())); |
| |
| [webView scrollView].backgroundColor = [UIColor colorWithCGColor:blackColor.get()]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, blackColor.get())); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"<style> body { background-color: white; } </style>"]; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, blackColor.get())); |
| |
| [webView scrollView].backgroundColor = nil; |
| EXPECT_TRUE(CGColorEqualToColor([webView scrollView].backgroundColor.CGColor, whiteColor.get())); |
| } |
| |
| TEST(WKScrollViewTests, DecelerationSetByClient) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 320, 500)]); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"first"]; |
| EXPECT_FLOAT_EQ([webView scrollView].decelerationRate, UIScrollViewDecelerationRateNormal); |
| |
| [webView scrollView].decelerationRate = UIScrollViewDecelerationRateFast; |
| EXPECT_FLOAT_EQ([webView scrollView].decelerationRate, UIScrollViewDecelerationRateFast); |
| |
| [webView synchronouslyLoadHTMLStringAndWaitUntilAllImmediateChildFramesPaint:@"second"]; |
| EXPECT_FLOAT_EQ([webView scrollView].decelerationRate, UIScrollViewDecelerationRateFast); |
| } |
| |
| #if HAVE(UISCROLLVIEW_ALLOWS_KEYBOARD_SCROLLING) |
| TEST(WKScrollViewTests, AllowsKeyboardScrolling) |
| { |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]); |
| |
| [webView synchronouslyLoadTestPageNamed:@"simple-tall"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| auto pressSpacebar = ^(void(^completionHandler)(void)) { |
| auto firstWebEvent = adoptNS([[WebEvent alloc] initWithKeyEventType:WebEventKeyDown timeStamp:CFAbsoluteTimeGetCurrent() characters:@" " charactersIgnoringModifiers:@" " modifiers:0 isRepeating:NO withFlags:0 withInputManagerHint:nil keyCode:0 isTabKey:NO]); |
| |
| auto secondWebEvent = adoptNS([[WebEvent alloc] initWithKeyEventType:WebEventKeyUp timeStamp:CFAbsoluteTimeGetCurrent() characters:@" " charactersIgnoringModifiers:@" " modifiers:0 isRepeating:NO withFlags:0 withInputManagerHint:nil keyCode:0 isTabKey:NO]); |
| |
| [webView handleKeyEvent:firstWebEvent.get() completion:^(WebEvent *theEvent, BOOL wasHandled) { |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), mainDispatchQueueSingleton(), ^{ |
| [webView handleKeyEvent:secondWebEvent.get() completion:^(WebEvent *theEvent, BOOL wasHandled) { |
| completionHandler(); |
| }]; |
| }); |
| }]; |
| }; |
| |
| __block bool doneWaiting = false; |
| |
| [webView scrollView].allowsKeyboardScrolling = NO; |
| |
| pressSpacebar(^{ |
| NSInteger scrollY = [[webView stringByEvaluatingJavaScript:@"window.scrollY"] integerValue]; |
| EXPECT_EQ(scrollY, 0); |
| doneWaiting = true; |
| }); |
| |
| Util::run(&doneWaiting); |
| |
| doneWaiting = false; |
| |
| [webView scrollView].allowsKeyboardScrolling = YES; |
| |
| pressSpacebar(^{ |
| NSInteger scrollY = [[webView stringByEvaluatingJavaScript:@"window.scrollY"] integerValue]; |
| EXPECT_GT(scrollY, 0); |
| doneWaiting = true; |
| }); |
| |
| Util::run(&doneWaiting); |
| } |
| #endif |
| |
| #if HAVE(LIQUID_GLASS) |
| |
| TEST(WKScrollViewTests, ClientCanHideScrollEdgeEffects) |
| { |
| IPhoneUserInterfaceSwizzler swizzleUserInterface; |
| |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| |
| auto insets = UIEdgeInsetsMake(25, 0, 125, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_TRUE([scrollView topEdgeEffect].hidden); |
| EXPECT_FALSE([scrollView bottomEdgeEffect].hidden); |
| |
| [scrollView topEdgeEffect].hidden = YES; |
| [scrollView bottomEdgeEffect].hidden = YES; |
| |
| EXPECT_TRUE([scrollView topEdgeEffect].hidden); |
| EXPECT_TRUE([scrollView bottomEdgeEffect].hidden); |
| |
| [scrollView topEdgeEffect].hidden = NO; |
| [scrollView bottomEdgeEffect].hidden = NO; |
| |
| EXPECT_TRUE([scrollView topEdgeEffect].hidden); // Remains hidden, due to the top fixed color extension. |
| EXPECT_FALSE([scrollView bottomEdgeEffect].hidden); |
| |
| [webView stringByEvaluatingJavaScript:@"document.querySelector('header').remove()"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_FALSE([scrollView topEdgeEffect].hidden); |
| EXPECT_FALSE([scrollView bottomEdgeEffect].hidden); |
| } |
| |
| TEST(WKScrollViewTests, ColorExtensionViewsWhenZoomedIn) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 50, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| RetainPtr topColorExtension = [webView _colorExtensionViewForTesting:UIRectEdgeTop]; |
| EXPECT_EQ([topColorExtension frame], CGRectMake(0, -50, 400, 50)); |
| |
| [scrollView setZoomScale:1.5]; |
| [webView waitForNextVisibleContentRectUpdate]; |
| [webView waitForNextPresentationUpdate]; |
| EXPECT_EQ([topColorExtension frame], CGRectMake(0, 125, 600, 50)); |
| |
| [scrollView setContentOffset:CGPointMake(0, 0)]; |
| [webView waitForNextVisibleContentRectUpdate]; |
| [webView waitForNextPresentationUpdate]; |
| EXPECT_EQ([topColorExtension frame], CGRectMake(0, 0, 600, 50)); |
| } |
| |
| TEST(WKScrollViewTests, ColorExtensionViewsDuringAnimatedResize) |
| { |
| RetainPtr configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| RetainPtr preferences = [configuration preferences]; |
| for (_WKFeature *feature in WKPreferences._features) { |
| if ([feature.key isEqualToString:@"AutomaticLiveResizeEnabled"]) { |
| [preferences _setEnabled:YES forFeature:feature]; |
| break; |
| } |
| } |
| |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 300) configuration:configuration.get()]); |
| RetainPtr window = [webView window]; |
| |
| static CGSize windowSceneSize = CGSizeZero; |
| InstanceMethodSwizzler boundsSwizzler { |
| [window windowScene].effectiveGeometry.coordinateSpace.class, |
| @selector(bounds), |
| imp_implementationWithBlock(^{ |
| return CGRect { CGPointZero, windowSceneSize }; |
| }) |
| }; |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 0, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| auto targetSizes = std::array { |
| CGSizeMake(600, 400), |
| CGSizeMake(700, 500), |
| CGSizeMake(800, 600), |
| CGSizeMake(900, 700), |
| CGSizeMake(1000, 800), |
| }; |
| |
| RetainPtr topColorExtension = [webView _colorExtensionViewForTesting:UIRectEdgeTop]; |
| for (auto size : targetSizes) { |
| windowSceneSize = size; |
| auto newFrame = CGRectMake(0, 0, size.width, size.height); |
| [window setFrame:newFrame]; |
| [webView setFrame:newFrame]; |
| [webView waitForNextPresentationUpdate]; |
| EXPECT_EQ([topColorExtension frame], CGRectMake(0, -50, size.width, 50)); |
| } |
| } |
| |
| TEST(WKScrollViewTests, ShouldSuppressTopColorExtensionView) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 0, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView _setShouldSuppressTopColorExtensionView:YES]; |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_NULL([webView _colorExtensionViewForTesting:UIRectEdgeTop]); |
| |
| [webView _setShouldSuppressTopColorExtensionView:NO]; |
| RetainPtr topColorExtension = [webView _colorExtensionViewForTesting:UIRectEdgeTop]; |
| EXPECT_NOT_NULL(topColorExtension); |
| EXPECT_FALSE([topColorExtension isHidden]); |
| |
| [webView _setShouldSuppressTopColorExtensionView:YES]; |
| Util::waitForConditionWithLogging([topColorExtension] { |
| return [topColorExtension isHidden]; |
| }, 5, @"Color extension view failed to hide"); |
| } |
| |
| TEST(WKScrollViewTests, TopScrollEdgeEffectIsHiddenKVO) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 0, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| RetainPtr topScrollEdgeEffect = [scrollView topEdgeEffect]; |
| |
| __block bool isHiddenChanged = false; |
| RetainPtr observer = adoptNS([[ScrollEdgeEffectIsHiddenObserver alloc] initWithScrollEdgeEffect:topScrollEdgeEffect.get() callback:^{ |
| isHiddenChanged = true; |
| }]); |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| Util::run(&isHiddenChanged); |
| EXPECT_TRUE([topScrollEdgeEffect isHidden]); |
| isHiddenChanged = false; |
| |
| [webView synchronouslyLoadTestPageNamed:@"simple"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| Util::run(&isHiddenChanged); |
| EXPECT_FALSE([topScrollEdgeEffect isHidden]); |
| } |
| |
| TEST(WKScrollViewTests, TopColorExtensionViewAfterRemovingRefreshControl) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| RetainPtr contentView = [webView wkContentView]; |
| RetainPtr scrollView = [webView scrollView]; |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 0, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| RetainPtr refreshControl = adoptNS([[UIRefreshControl alloc] init]); |
| [scrollView setRefreshControl:refreshControl.get()]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| RetainPtr topColorExtension = [webView _colorExtensionViewForTesting:UIRectEdgeTop]; |
| |
| [scrollView setContentOffset:CGPointMake(0, -100)]; |
| [webView waitForNextVisibleContentRectUpdate]; |
| EXPECT_TRUE([topColorExtension _appearsBeforeViewInSubviewOrder:refreshControl.get()]); |
| |
| [scrollView setRefreshControl:nil]; |
| [scrollView setContentOffset:CGPointMake(0, 100)]; |
| [webView waitForNextVisibleContentRectUpdate]; |
| EXPECT_TRUE([contentView _appearsBeforeViewInSubviewOrder:topColorExtension.get()]); |
| } |
| |
| TEST(WKScrollViewTests, TopScrollPocketCaptureColorAfterSettingHardStyle) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 600, 400)]); |
| RetainPtr scrollView = [webView scrollView]; |
| |
| [scrollView topEdgeEffect].style = UIScrollEdgeEffectStyle.softStyle; |
| |
| auto insets = UIEdgeInsetsMake(50, 0, 0, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"top-fixed-element"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_NULL([scrollView _pocketColorForEdge:UIRectEdgeTop]); |
| EXPECT_FALSE([scrollView _prefersSolidColorHardPocketForEdge:UIRectEdgeTop]); |
| |
| [scrollView topEdgeEffect].style = UIScrollEdgeEffectStyle.hardStyle; |
| [webView waitForNextPresentationUpdate]; |
| |
| auto topHardPocketColor = WebCore::colorFromCocoaColor([scrollView _pocketColorForEdge:UIRectEdgeTop]); |
| EXPECT_WK_STREQ("rgb(255, 99, 71)", WebCore::serializationForCSS(topHardPocketColor)); |
| EXPECT_TRUE([scrollView _prefersSolidColorHardPocketForEdge:UIRectEdgeTop]); |
| |
| [scrollView topEdgeEffect].style = UIScrollEdgeEffectStyle.softStyle; |
| |
| // Removing the top fixed element should also remove the top color extension. |
| [webView objectByEvaluatingJavaScript:@"document.querySelector('header').remove()"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_NULL([scrollView _pocketColorForEdge:UIRectEdgeTop]); |
| } |
| |
| #endif // HAVE(LIQUID_GLASS) |
| |
| TEST(WKScrollViewTests, SafeAreaEnvironmentVariablesAccountForObscuredContentInsets) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| [webView setOverrideSafeAreaInset:UIEdgeInsetsMake(66, 10, 34, 10)]; |
| |
| RetainPtr scrollView = [webView scrollView]; |
| |
| auto insets = UIEdgeInsetsMake(100, 0, 20, 0); |
| [webView setObscuredContentInsets:insets]; |
| |
| [scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; |
| [scrollView setContentInset:insets]; |
| |
| [webView synchronouslyLoadTestPageNamed:@"safe-area-env"]; |
| [webView waitForNextPresentationUpdate]; |
| |
| auto computedBodyPadding = [&](NSString *side) { |
| return [webView stringByEvaluatingJavaScript:[NSString stringWithFormat:@"getComputedStyle(document.body).padding%@", side]]; |
| }; |
| EXPECT_WK_STREQ("0px", computedBodyPadding(@"Top")); |
| EXPECT_WK_STREQ("10px", computedBodyPadding(@"Left")); |
| EXPECT_WK_STREQ("14px", computedBodyPadding(@"Bottom")); |
| EXPECT_WK_STREQ("10px", computedBodyPadding(@"Right")); |
| } |
| |
| TEST(WKScrollViewTests, ContentInsetAdjustmentBehaviorChangeAfterViewportFitChange) |
| { |
| RetainPtr webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 800)]); |
| RetainPtr scrollView = [webView scrollView]; |
| |
| UIEdgeInsets insets = UIEdgeInsetsMake(0, 60, 0, 60); |
| [webView setOverrideSafeAreaInset:insets]; |
| |
| RetainPtr navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| [webView loadSimulatedRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://domain1.com"]] responseHTMLString:@"<html><head><meta name='viewport' content='width=device-width, initial-scale=1, viewport-fit=cover'></head></html>"]; |
| [navigationDelegate waitForDidFinishNavigation]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_EQ([scrollView contentInsetAdjustmentBehavior], UIScrollViewContentInsetAdjustmentNever); |
| EXPECT_EQ([scrollView adjustedContentInset], UIEdgeInsetsZero); |
| |
| EXPECT_WK_STREQ([webView stringByEvaluatingJavaScript:@"document.body.clientWidth"], "400"); |
| |
| [webView loadSimulatedRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://domain2.com"]] responseHTMLString:@"<html><head><meta name='viewport' content='width=device-width, initial-scale=1'></head></html>"]; |
| [navigationDelegate waitForDidFinishNavigation]; |
| [webView waitForNextPresentationUpdate]; |
| |
| EXPECT_EQ([scrollView contentInsetAdjustmentBehavior], UIScrollViewContentInsetAdjustmentAlways); |
| EXPECT_EQ([scrollView adjustedContentInset], insets); |
| |
| EXPECT_WK_STREQ([webView stringByEvaluatingJavaScript:@"document.body.clientWidth"], "280"); |
| } |
| |
| } // namespace TestWebKitAPI |
| |
| #endif // PLATFORM(IOS_FAMILY) |