Modified: trunk/Source/WebKit/ChangeLog (279244 => 279245)
--- trunk/Source/WebKit/ChangeLog 2021-06-24 21:38:52 UTC (rev 279244)
+++ trunk/Source/WebKit/ChangeLog 2021-06-24 21:41:25 UTC (rev 279245)
@@ -1,3 +1,63 @@
+2021-06-24 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [watchOS] Automatically apply system minimum layout margins as scroll view content insets
+ https://bugs.webkit.org/show_bug.cgi?id=227178
+ rdar://76784095
+
+ Reviewed by Tim Horton.
+
+ Respect `-[UIViewController systemMinimumLayoutMargins]` on watchOS by treating them in a similar way as safe
+ area insets, such that we avoid laying out parts of the web page within these margins unless the page's meta
+ viewport specifies `viewport-fit=cover`. On watch, avoiding these layout margins is crucial.
+
+ * UIProcess/API/ios/WKWebViewIOS.mm:
+ (-[WKWebView _computedObscuredInsetForSafeBrowsingWarning]):
+ (-[WKWebView _contentInsetsFromSystemMinimumLayoutMargins]):
+
+ Add a helper method to compute the amount of additional content inset we need to apply to the scroll view in
+ order for content to fit within WKWebView's view controller's `-systemMinimumLayoutMargins`. Note that this
+ accounts for cases where the web view's frame is already inset relative to the view controller's content view.
+
+ (-[WKWebView _computedObscuredInset]):
+ (-[WKWebView _computedContentInset]):
+
+ Unconditionalize a few codepaths that apply obscured and content insets by consulting
+ `-_scrollViewSystemContentInset`.
+
+ (-[WKWebView _computedUnobscuredSafeAreaInset]):
+
+ On watchOS, we augment safe area insets, such that they include `_contentInsetsFromSystemMinimumLayoutMargins`
+ as well.
+
+ (-[WKWebView activeViewLayoutSize:]):
+ (-[WKWebView _updateScrollViewContentInsetsIfNecessary]):
+
+ Add a helper method that (on watchOS only) updates WKScrollView's content scroll insets such that the web page
+ fits inside `-systemMinimumLayoutMargins`. See WKScrollView changes below for more details.
+
+ (-[WKWebView _updateVisibleContentRects]):
+ (-[WKWebView _setAvoidsUnsafeArea:]):
+
+ Update scroll view content insets on watchOS if the `viewport-fit` state changes. Additionally make sure that we
+ also update the active layout size if the insets actually change (without this tweak, when dynamically adding
+ `viewport-fit=cover`, we'll end up in a state where the content size is still narrow to account for the old
+ content scroll insets, but the new content scroll insets are set, so the web page apears misaligned relative to
+ the scroll view).
+
+ * UIProcess/ios/WKScrollView.h:
+ * UIProcess/ios/WKScrollView.mm:
+ (-[WKScrollView _setContentScrollInset:]):
+ (-[WKScrollView _setContentScrollInsetInternal:]):
+
+ Add an internal method for setting `-[UIScrollView _contentScrollInset]` that defers to the embedding client.
+ This means WKWebView clients that use `webView.scrollView.contentScrollInset = myInset;` will override the above
+ behavior in `-_updateScrollViewContentInsetsIfNecessary`, but otherwise, the content scroll insets will be
+ automatically computed and set in order to avoid minimum layout margins if needed.
+
+ Note that this also returns a `BOOL` indicating whether the inset was updated.
+
+ (-[WKScrollView _updateContentScrollInset]):
+
2021-06-24 Chris Dumez <cdu...@apple.com>
Improve release logging in WebProcessProxy
Modified: trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm (279244 => 279245)
--- trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm 2021-06-24 21:38:52 UTC (rev 279244)
+++ trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm 2021-06-24 21:41:25 UTC (rev 279245)
@@ -580,11 +580,33 @@
if (_haveSetObscuredInsets)
return _obscuredInsets;
-#if PLATFORM(IOS)
return UIEdgeInsetsAdd(UIEdgeInsetsZero, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
-#else
+}
+
+- (UIEdgeInsets)_contentInsetsFromSystemMinimumLayoutMargins
+{
+ if (auto controller = [UIViewController _viewControllerForFullScreenPresentationFromView:self]) {
+ auto margins = controller.systemMinimumLayoutMargins;
+ auto insets = UIEdgeInsetsMake(margins.top, margins.leading, margins.bottom, margins.trailing);
+ if (_page && _page->userInterfaceLayoutDirection() == WebCore::UserInterfaceLayoutDirection::RTL)
+ std::swap(insets.left, insets.right);
+
+ if (auto view = controller.viewIfLoaded) {
+ auto adjustInsetEdge = [](CGFloat& insetEdge, CGFloat distanceFromEdge) {
+ insetEdge -= std::max<CGFloat>(0, distanceFromEdge);
+ insetEdge = std::max<CGFloat>(0, insetEdge);
+ };
+
+ auto viewBounds = view.bounds;
+ auto webViewBoundsInView = [self convertRect:self.bounds toView:view];
+ adjustInsetEdge(insets.top, CGRectGetMinY(webViewBoundsInView) - CGRectGetMinY(viewBounds));
+ adjustInsetEdge(insets.left, CGRectGetMinX(webViewBoundsInView) - CGRectGetMinX(viewBounds));
+ adjustInsetEdge(insets.bottom, CGRectGetMaxY(viewBounds) - CGRectGetMaxY(webViewBoundsInView));
+ adjustInsetEdge(insets.right, CGRectGetMaxX(viewBounds) - CGRectGetMaxX(webViewBoundsInView));
+ }
+ return insets;
+ }
return UIEdgeInsetsZero;
-#endif
}
- (UIEdgeInsets)_computedObscuredInset
@@ -598,10 +620,8 @@
if (_haveSetObscuredInsets)
return _obscuredInsets;
-#if PLATFORM(IOS)
if (self._safeAreaShouldAffectObscuredInsets)
return UIEdgeInsetsAdd(UIEdgeInsetsZero, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
-#endif
return UIEdgeInsetsZero;
}
@@ -613,10 +633,8 @@
UIEdgeInsets insets = [_scrollView contentInset];
-#if PLATFORM(IOS)
if (self._safeAreaShouldAffectObscuredInsets)
insets = UIEdgeInsetsAdd(insets, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
-#endif
return insets;
}
@@ -626,10 +644,13 @@
if (_haveSetUnobscuredSafeAreaInsets)
return _unobscuredSafeAreaInsets;
-#if PLATFORM(IOS)
- if (!self._safeAreaShouldAffectObscuredInsets)
- return self.safeAreaInsets;
+ if (!self._safeAreaShouldAffectObscuredInsets) {
+ auto safeAreaInsets = self.safeAreaInsets;
+#if PLATFORM(WATCHOS)
+ safeAreaInsets = UIEdgeInsetsAdd(safeAreaInsets, self._contentInsetsFromSystemMinimumLayoutMargins, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
#endif
+ return safeAreaInsets;
+ }
return UIEdgeInsetsZero;
}
@@ -1808,12 +1829,7 @@
if (_viewLayoutSizeOverride)
return WebCore::FloatSize(_viewLayoutSizeOverride.value());
-// FIXME: Likely we can remove this special case for watchOS and tvOS.
-#if !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
return WebCore::FloatSize(UIEdgeInsetsInsetRect(CGRectMake(0, 0, bounds.size.width, bounds.size.height), self._scrollViewSystemContentInset).size);
-#else
- return WebCore::FloatSize { bounds.size };
-#endif
}
- (void)_dispatchSetViewLayoutSize:(WebCore::FloatSize)viewLayoutSize
@@ -1844,6 +1860,15 @@
_lastSentDeviceOrientation = deviceOrientation;
}
+- (BOOL)_updateScrollViewContentInsetsIfNecessary
+{
+#if PLATFORM(WATCHOS)
+ return [_scrollView _setContentScrollInsetInternal:self._safeAreaShouldAffectObscuredInsets ? self._contentInsetsFromSystemMinimumLayoutMargins : UIEdgeInsetsZero];
+#else
+ return NO;
+#endif
+}
+
- (void)_frameOrBoundsChanged
{
CGRect bounds = self.bounds;
@@ -2108,6 +2133,8 @@
_didDeferUpdateVisibleContentRectsForUnstableScrollView = NO;
_didDeferUpdateVisibleContentRectsForAnyReason = NO;
+ [self _updateScrollViewContentInsetsIfNecessary];
+
CGRect visibleRectInContentCoordinates = [self _visibleContentRect];
UIEdgeInsets computedContentInsetUnadjustedForKeyboard = [self _computedObscuredInset];
@@ -2472,6 +2499,9 @@
_avoidsUnsafeArea = avoidsUnsafeArea;
+ if ([self _updateScrollViewContentInsetsIfNecessary] && _dynamicViewportUpdateMode == WebKit::DynamicViewportUpdateMode::NotResizing && !_viewLayoutSizeOverride)
+ [self _dispatchSetViewLayoutSize:[self activeViewLayoutSize:self.bounds]];
+
[self _updateScrollViewInsetAdjustmentBehavior];
[self _scheduleVisibleContentRectUpdate];
Modified: trunk/Source/WebKit/UIProcess/ios/WKScrollView.h (279244 => 279245)
--- trunk/Source/WebKit/UIProcess/ios/WKScrollView.h 2021-06-24 21:38:52 UTC (rev 279244)
+++ trunk/Source/WebKit/UIProcess/ios/WKScrollView.h 2021-06-24 21:41:25 UTC (rev 279245)
@@ -36,6 +36,7 @@
- (void)_setContentSizePreservingContentOffsetDuringRubberband:(CGSize)contentSize;
- (void)_setScrollEnabledInternal:(BOOL)enabled;
- (void)_setZoomEnabledInternal:(BOOL)enabled;
+- (BOOL)_setContentScrollInsetInternal:(UIEdgeInsets)insets;
// FIXME: Likely we can remove this special case for watchOS and tvOS.
#if !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
Modified: trunk/Source/WebKit/UIProcess/ios/WKScrollView.mm (279244 => 279245)
--- trunk/Source/WebKit/UIProcess/ios/WKScrollView.mm 2021-06-24 21:38:52 UTC (rev 279244)
+++ trunk/Source/WebKit/UIProcess/ios/WKScrollView.mm 2021-06-24 21:41:25 UTC (rev 279245)
@@ -136,6 +136,8 @@
BOOL _scrollEnabledInternal;
BOOL _zoomEnabledByClient;
BOOL _zoomEnabledInternal;
+ std::optional<UIEdgeInsets> _contentScrollInsetFromClient;
+ std::optional<UIEdgeInsets> _contentScrollInsetInternal;
}
- (id)initWithFrame:(CGRect)frame
@@ -423,6 +425,35 @@
#endif // PLATFORM(WATCHOS)
+- (void)_setContentScrollInset:(UIEdgeInsets)insets
+{
+ _contentScrollInsetFromClient = insets;
+ [self _updateContentScrollInset];
+}
+
+- (BOOL)_setContentScrollInsetInternal:(UIEdgeInsets)insets
+{
+ if (_contentScrollInsetFromClient)
+ return NO;
+
+ if (_contentScrollInsetInternal && UIEdgeInsetsEqualToEdgeInsets(*_contentScrollInsetInternal, insets))
+ return NO;
+
+ _contentScrollInsetInternal = insets;
+ [self _updateContentScrollInset];
+ return YES;
+}
+
+- (void)_updateContentScrollInset
+{
+ if (auto insets = _contentScrollInsetFromClient)
+ super.contentScrollInset = *insets;
+ else if (auto insets = _contentScrollInsetInternal)
+ super.contentScrollInset = *insets;
+ else
+ ASSERT_NOT_REACHED();
+}
+
#if HAVE(PEPPER_UI_CORE)
- (void)_configureDigitalCrownScrolling