Changeset 255054 in webkit


Ignore:
Timestamp:
Jan 23, 2020 9:55:54 PM (4 years ago)
Author:
Wenson Hsieh
Message:

[iOS] Support setting minimum effective device width during dynamic viewport size updates
https://bugs.webkit.org/show_bug.cgi?id=206709
<rdar://problem/58713872>

Reviewed by Tim Horton.

Source/WebKit:

Changes to minimum effective device width are currently always propagated to the web process via out-of-band
updates to the web process. During animated resize, Safari currently changes the minimum effective device width
prior to updating the view size; this causes the viewport configuration to temporarily be in a state where the
new value for minimum effective device width is used, but the old viewport width and height are still used.

This subsequently breaks existing logic in WebPage::dynamicViewportSizeUpdate that attempts to keep the portion
of the unobscured content width that is visible consistent before and after rotation (see
visibleHorizontalFraction), since that code will be mislead into believing that the wrong fraction of content
width is visible.

To fix this, we roll minimum effective device width changes along with view size (and other attributes) in
dynamic viewport size updates.

Test: WebKit.ChangeFrameAndMinimumEffectiveDeviceWidthDuringAnimatedResize

  • UIProcess/API/Cocoa/WKWebView.mm:

(-[WKWebView _setViewScale:]):
(-[WKWebView _setMinimumEffectiveDeviceWidth:]):

During animated resize, just set m_minimumEffectiveDeviceWidth without notifying the web process; if the value
changed during the update block, we send the new minimum effective device width to the web page as a part of
the dynamic viewport size update.

Also, make a drive-by adjustment to use _page->viewLayoutSize() instead of recomputing the active layout
bounds when we know that only the minimum effective device width is changing. We also apply the same adjustment
above, in -_setViewScale:.

  • UIProcess/API/ios/WKWebViewIOS.mm:

(-[WKWebView _beginAnimatedResizeWithUpdates:]):

  • UIProcess/WebPageProxy.h:

(WebKit::WebPageProxy::viewLayoutSize const):
(WebKit::WebPageProxy::setMinimumEffectiveDeviceWidthWithoutViewportConfigurationUpdate):

Add a helper method to update the minimum effective device width without updating the viewport configuration in
the web process. This is only used when the minimum effective device width is specified in the middle of a
dynamic viewport size update (i.e. animated resize).

  • UIProcess/ios/WebPageProxyIOS.mm:

(WebKit::WebPageProxy::dynamicViewportSizeUpdate):

Plumb the new minimum effective device width over to the web process as a part of the dynamic viewport size
update, and update both the new view size and minimum effective device width on the viewport configuration at
the same time.

  • WebProcess/WebPage/WebPage.h:
  • WebProcess/WebPage/WebPage.messages.in:
  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::dynamicViewportSizeUpdate):

Tools:

Adds a new API test that changes both the effective minimum device width and view size during animated resize.

  • TestWebKitAPI/Tests/WebKitCocoa/AnimatedResize.mm:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r255050 r255054  
     12020-01-23  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS] Support setting minimum effective device width during dynamic viewport size updates
     4        https://bugs.webkit.org/show_bug.cgi?id=206709
     5        <rdar://problem/58713872>
     6
     7        Reviewed by Tim Horton.
     8
     9        Changes to minimum effective device width are currently always propagated to the web process via out-of-band
     10        updates to the web process. During animated resize, Safari currently changes the minimum effective device width
     11        prior to updating the view size; this causes the viewport configuration to temporarily be in a state where the
     12        new value for minimum effective device width is used, but the old viewport width and height are still used.
     13
     14        This subsequently breaks existing logic in WebPage::dynamicViewportSizeUpdate that attempts to keep the portion
     15        of the unobscured content width that is visible consistent before and after rotation (see
     16        visibleHorizontalFraction), since that code will be mislead into believing that the wrong fraction of content
     17        width is visible.
     18
     19        To fix this, we roll minimum effective device width changes along with view size (and other attributes) in
     20        dynamic viewport size updates.
     21
     22        Test: WebKit.ChangeFrameAndMinimumEffectiveDeviceWidthDuringAnimatedResize
     23
     24        * UIProcess/API/Cocoa/WKWebView.mm:
     25        (-[WKWebView _setViewScale:]):
     26        (-[WKWebView _setMinimumEffectiveDeviceWidth:]):
     27
     28        During animated resize, just set m_minimumEffectiveDeviceWidth without notifying the web process; if the value
     29        changed during the update block, we send the new minimum effective device width to the web page as a part of
     30        the dynamic viewport size update.
     31
     32        Also, make a drive-by adjustment to use `_page->viewLayoutSize()` instead of recomputing the active layout
     33        bounds when we know that only the minimum effective device width is changing. We also apply the same adjustment
     34        above, in -_setViewScale:.
     35
     36        * UIProcess/API/ios/WKWebViewIOS.mm:
     37        (-[WKWebView _beginAnimatedResizeWithUpdates:]):
     38        * UIProcess/WebPageProxy.h:
     39        (WebKit::WebPageProxy::viewLayoutSize const):
     40        (WebKit::WebPageProxy::setMinimumEffectiveDeviceWidthWithoutViewportConfigurationUpdate):
     41
     42        Add a helper method to update the minimum effective device width without updating the viewport configuration in
     43        the web process. This is only used when the minimum effective device width is specified in the middle of a
     44        dynamic viewport size update (i.e. animated resize).
     45
     46        * UIProcess/ios/WebPageProxyIOS.mm:
     47        (WebKit::WebPageProxy::dynamicViewportSizeUpdate):
     48
     49        Plumb the new minimum effective device width over to the web process as a part of the dynamic viewport size
     50        update, and update both the new view size and minimum effective device width on the viewport configuration at
     51        the same time.
     52
     53        * WebProcess/WebPage/WebPage.h:
     54        * WebProcess/WebPage/WebPage.messages.in:
     55        * WebProcess/WebPage/ios/WebPageIOS.mm:
     56        (WebKit::WebPage::dynamicViewportSizeUpdate):
     57
    1582020-01-23  Per Arne Vollan  <pvollan@apple.com>
    259
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

    r254711 r255054  
    27072707        return;
    27082708
    2709     _page->setViewportConfigurationViewLayoutSize([self activeViewLayoutSize:self.bounds], viewScale, _page->minimumEffectiveDeviceWidth());
     2709    _page->setViewportConfigurationViewLayoutSize(_page->viewLayoutSize(), viewScale, _page->minimumEffectiveDeviceWidth());
    27102710#endif
    27112711}
     
    27172717        return;
    27182718
    2719     _page->setViewportConfigurationViewLayoutSize([self activeViewLayoutSize:self.bounds], _page->layoutSizeScaleFactor(), minimumEffectiveDeviceWidth);
     2719    if (_dynamicViewportUpdateMode == WebKit::DynamicViewportUpdateMode::NotResizing)
     2720        _page->setViewportConfigurationViewLayoutSize(_page->viewLayoutSize(), _page->layoutSizeScaleFactor(), minimumEffectiveDeviceWidth);
     2721    else
     2722        _page->setMinimumEffectiveDeviceWidthWithoutViewportConfigurationUpdate(minimumEffectiveDeviceWidth);
    27202723#endif
    27212724}
  • trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm

    r255038 r255054  
    27122712    _dynamicViewportUpdateMode = WebKit::DynamicViewportUpdateMode::ResizingWithAnimation;
    27132713
     2714    auto oldMinimumEffectiveDeviceWidth = [self _minimumEffectiveDeviceWidth];
    27142715    auto oldViewLayoutSize = [self activeViewLayoutSize:self.bounds];
    27152716    auto oldMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, oldBounds);
     
    27202721
    27212722    CGRect newBounds = self.bounds;
     2723    auto newMinimumEffectiveDeviceWidth = [self _minimumEffectiveDeviceWidth];
    27222724    auto newViewLayoutSize = [self activeViewLayoutSize:newBounds];
    27232725    auto newMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, newBounds);
     
    27452747        && oldMaximumUnobscuredSize == newMaximumUnobscuredSize
    27462748        && oldOrientation == newOrientation
     2749        && oldMinimumEffectiveDeviceWidth == newMinimumEffectiveDeviceWidth
    27472750        && UIEdgeInsetsEqualToEdgeInsets(oldObscuredInsets, newObscuredInsets)) {
    27482751        [self _cancelAnimatedResize];
     
    28122815    _lastSentDeviceOrientation = newOrientation;
    28132816
    2814     _page->dynamicViewportSizeUpdate(newViewLayoutSize, newMaximumUnobscuredSize, visibleRectInContentCoordinates, unobscuredRectInContentCoordinates, futureUnobscuredRectInSelfCoordinates, unobscuredSafeAreaInsetsExtent, targetScale, newOrientation, ++_currentDynamicViewportSizeUpdateID);
     2817    _page->dynamicViewportSizeUpdate(newViewLayoutSize, newMaximumUnobscuredSize, visibleRectInContentCoordinates, unobscuredRectInContentCoordinates, futureUnobscuredRectInSelfCoordinates, unobscuredSafeAreaInsetsExtent, targetScale, newOrientation, newMinimumEffectiveDeviceWidth, ++_currentDynamicViewportSizeUpdateID);
    28152818    if (WebKit::DrawingAreaProxy* drawingArea = _page->drawingArea())
    28162819        drawingArea->setSize(WebCore::IntSize(newBounds.size));
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r255038 r255054  
    715715    void scrollingNodeScrollDidEndScroll();
    716716
    717     void dynamicViewportSizeUpdate(const WebCore::FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID);
     717    void dynamicViewportSizeUpdate(const WebCore::FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, double minimumEffectiveDeviceWidth, DynamicViewportSizeUpdateID);
    718718
    719719    void setViewportConfigurationViewLayoutSize(const WebCore::FloatSize&, double scaleFactor, double minimumEffectiveDeviceWidth);
     
    776776    bool forceAlwaysUserScalable() const { return m_forceAlwaysUserScalable; }
    777777    double layoutSizeScaleFactor() const { return m_viewportConfigurationLayoutSizeScaleFactor; }
     778    WebCore::FloatSize viewLayoutSize() const { return m_viewportConfigurationViewLayoutSize; }
    778779    double minimumEffectiveDeviceWidth() const { return m_viewportConfigurationMinimumEffectiveDeviceWidth; }
     780    void setMinimumEffectiveDeviceWidthWithoutViewportConfigurationUpdate(double minimumEffectiveDeviceWidth) { m_viewportConfigurationMinimumEffectiveDeviceWidth = minimumEffectiveDeviceWidth; }
    779781    void setIsScrollingOrZooming(bool);
    780782    void requestRectsForGranularityWithSelectionOffset(WebCore::TextGranularity, uint32_t offset, WTF::Function<void(const Vector<WebCore::SelectionRect>&, CallbackBase::Error)>&&);
  • trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm

    r255038 r255054  
    313313}
    314314
    315 void WebPageProxy::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
     315void WebPageProxy::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& unobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, double minimumEffectiveDeviceWidth, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
    316316{
    317317    if (!hasRunningProcess())
     
    324324        maximumUnobscuredSize, targetExposedContentRect, targetUnobscuredRect,
    325325        targetUnobscuredRectInScrollViewCoordinates, unobscuredSafeAreaInsets,
    326         targetScale, deviceOrientation, dynamicViewportSizeUpdateID), m_webPageID);
     326        targetScale, deviceOrientation, minimumEffectiveDeviceWidth, dynamicViewportSizeUpdateID), m_webPageID);
    327327}
    328328
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r254886 r255054  
    971971    void setMaximumUnobscuredSize(const WebCore::FloatSize&);
    972972    void setDeviceOrientation(int32_t);
    973     void dynamicViewportSizeUpdate(const WebCore::FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, DynamicViewportSizeUpdateID);
     973    void dynamicViewportSizeUpdate(const WebCore::FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, double minimumEffectiveDeviceWidth, DynamicViewportSizeUpdateID);
    974974    bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; }
    975975    void willStartUserTriggeredZooming();
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in

    r254886 r255054  
    5252    SetDeviceOrientation(int32_t deviceOrientation)
    5353    SetOverrideViewportArguments(Optional<WebCore::ViewportArguments> arguments)
    54     DynamicViewportSizeUpdate(WebCore::FloatSize viewLayoutSize, WebCore::FloatSize maximumUnobscuredSize, WebCore::FloatRect targetExposedContentRect, WebCore::FloatRect targetUnobscuredRect, WebCore::FloatRect targetUnobscuredRectInScrollViewCoordinates, WebCore::RectEdges<float> targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID)
     54    DynamicViewportSizeUpdate(WebCore::FloatSize viewLayoutSize, WebCore::FloatSize maximumUnobscuredSize, WebCore::FloatRect targetExposedContentRect, WebCore::FloatRect targetUnobscuredRect, WebCore::FloatRect targetUnobscuredRectInScrollViewCoordinates, WebCore::RectEdges<float> targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, double minimumEffectiveDeviceWidth, uint64_t dynamicViewportSizeUpdateID)
    5555
    5656    HandleTap(WebCore::IntPoint point, OptionSet<WebKit::WebEvent::Modifier> modifiers, WebKit::TransactionID lastLayerTreeTransactionId)
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r255046 r255054  
    31663166}
    31673167
    3168 void WebPage::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
     3168void WebPage::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, double minimumEffectiveDeviceWidth, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
    31693169{
    31703170    SetForScope<bool> dynamicSizeUpdateGuard(m_inDynamicSizeUpdate, true);
     
    32053205    LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting view layout size to " << viewLayoutSize);
    32063206    bool viewportChanged = m_viewportConfiguration.setIsKnownToLayOutWiderThanViewport(false);
    3207     viewportChanged |= m_viewportConfiguration.setViewLayoutSize(viewLayoutSize);
     3207    viewportChanged |= m_viewportConfiguration.setViewLayoutSize(viewLayoutSize, WTF::nullopt, minimumEffectiveDeviceWidth);
    32083208    if (viewportChanged)
    32093209        viewportConfigurationChanged();
  • trunk/Tools/ChangeLog

    r255050 r255054  
     12020-01-23  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS] Support setting minimum effective device width during dynamic viewport size updates
     4        https://bugs.webkit.org/show_bug.cgi?id=206709
     5        <rdar://problem/58713872>
     6
     7        Reviewed by Tim Horton.
     8
     9        Adds a new API test that changes both the effective minimum device width and view size during animated resize.
     10
     11        * TestWebKitAPI/Tests/WebKitCocoa/AnimatedResize.mm:
     12
    1132020-01-23  Per Arne Vollan  <pvollan@apple.com>
    214
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AnimatedResize.mm

    r253465 r255054  
    3131#import "TestWKWebView.h"
    3232#import <WebKit/WKPreferences.h>
     33#import <WebKit/WKPreferencesPrivate.h>
    3334#import <WebKit/WKProcessPoolPrivate.h>
    3435#import <WebKit/WKWebView.h>
     
    288289        didReadLayoutSize = true;
    289290    }];
     291    TestWebKitAPI::Util::run(&didReadLayoutSize);
     292}
     293
     294TEST(WebKit, ChangeFrameAndMinimumEffectiveDeviceWidthDuringAnimatedResize)
     295{
     296    auto webView = createAnimatedResizeWebView();
     297    [[webView configuration] preferences]._shouldIgnoreMetaViewport = YES;
     298    [webView setUIDelegate:webView.get()];
     299    [webView loadHTMLString:@"<body>Hello world</body>" baseURL:nil];
     300
     301    auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
     302    [webView setNavigationDelegate:navigationDelegate.get()];
     303    [navigationDelegate waitForDidFinishNavigation];
     304
     305    auto window = adoptNS([[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]);
     306    [window addSubview:webView.get()];
     307    [window setHidden:NO];
     308
     309    [webView _beginAnimatedResizeWithUpdates:^{
     310        [webView _setMinimumEffectiveDeviceWidth:1000];
     311        [webView setFrame:CGRectMake(0, 0, 500, 375)];
     312    }];
     313
     314    [webView _endAnimatedResize];
     315
     316    __block bool didReadLayoutSize = false;
     317    [webView _doAfterNextPresentationUpdate:^{
     318        [webView evaluateJavaScript:@"[window.innerWidth, window.innerHeight, visualViewport.scale]" completionHandler:^(NSArray<NSNumber *> *value, NSError *error) {
     319            CGFloat innerWidth = value[0].floatValue;
     320            CGFloat innerHeight = value[1].floatValue;
     321            CGFloat scale = value[2].floatValue;
     322            EXPECT_EQ(innerWidth, 1000);
     323            EXPECT_EQ(innerHeight, 750);
     324            EXPECT_EQ(scale, 0.5);
     325            didReadLayoutSize = true;
     326        }];
     327    }];
     328
    290329    TestWebKitAPI::Util::run(&didReadLayoutSize);
    291330}
Note: See TracChangeset for help on using the changeset viewer.