Skip to content

Commit

Permalink
Stop using -_canScrollWithoutBouncing(X|Y) and -_adjustedContentOffse…
Browse files Browse the repository at this point in the history
…tForContentOffset: on UIScrollView

https://bugs.webkit.org/show_bug.cgi?id=262973

Reviewed by Richard Robinson.

Remove uses of these three SPI methods and properties on `UIScrollView`, which are currently just
used for smooth keyboard scrolling on iOS:

```
-_canScrollWithoutBouncingX
-_canScrollWithoutBouncingY
-_adjustedContentOffsetForContentOffset:
```

Instead, we use a combination `-adjustedContentInset`, `-contentSize` and `-bounds` to both compute
the scroll extents and total content dimensions of the content scroll view, and to adjust a given
content offset to fit within the extents.

* Source/WebKit/Platform/spi/ios/UIKitSPI.h:

Remove the now-unnecessary SPI declarations.

* Source/WebKit/UIProcess/ios/UIKitUtilities.h:
* Source/WebKit/UIProcess/ios/UIKitUtilities.mm:
(-[UIScrollView _wk_contentWidthIncludingInsets]):
(-[UIScrollView _wk_contentHeightIncludingInsets]):
(-[UIScrollView _wk_isScrolledBeyondExtents]):
(-[UIScrollView _wk_clampToScrollExtents:]):
(-[UIScrollView _wk_canScrollHorizontallyWithoutBouncing]):
(-[UIScrollView _wk_canScrollVerticallyWithoutBouncing]):
* Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm:
(-[WKKeyboardScrollViewAnimator boundedContentOffset:]):
(-[WKKeyboardScrollViewAnimator rubberbandableDirections]):
* Source/WebKit/UIProcess/ios/WKVelocityTrackingScrollView.mm:

Drive-by fix: remove an unnecessary header import for `FixedVector.h`.
Canonical link: https://commits.webkit.org/269186@main
  • Loading branch information
whsieh committed Oct 11, 2023
1 parent 80c45a1 commit a609e0d
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 12 deletions.
3 changes: 0 additions & 3 deletions Source/WebKit/Platform/spi/ios/UIKitSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -1112,10 +1112,7 @@ typedef NS_ENUM(NSUInteger, _UIScrollDeviceCategory) {
@interface UIScrollView (IPI)
- (void)_adjustForAutomaticKeyboardInfo:(NSDictionary *)info animated:(BOOL)animated lastAdjustment:(CGFloat*)lastAdjustment;
- (BOOL)_isScrollingToTop;
- (BOOL)_canScrollWithoutBouncingX;
- (BOOL)_canScrollWithoutBouncingY;
- (void)_setContentOffsetWithDecelerationAnimation:(CGPoint)contentOffset;
- (CGPoint)_adjustedContentOffsetForContentOffset:(CGPoint)contentOffset;

@property (nonatomic) BOOL tracksImmediatelyWhileDecelerating;
@property (nonatomic, getter=_avoidsJumpOnInterruptedBounce, setter=_setAvoidsJumpOnInterruptedBounce:) BOOL _avoidsJumpOnInterruptedBounce;
Expand Down
6 changes: 6 additions & 0 deletions Source/WebKit/UIProcess/ios/UIKitUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
@interface UIScrollView (WebKitInternal)
@property (readonly, nonatomic) BOOL _wk_isInterruptingDeceleration;
@property (readonly, nonatomic) BOOL _wk_isScrolledBeyondExtents;
@property (readonly, nonatomic) BOOL _wk_canScrollHorizontallyWithoutBouncing;
@property (readonly, nonatomic) BOOL _wk_canScrollVerticallyWithoutBouncing;
@property (readonly, nonatomic) CGFloat _wk_contentWidthIncludingInsets;
@property (readonly, nonatomic) CGFloat _wk_contentHeightIncludingInsets;

- (CGPoint)_wk_clampToScrollExtents:(CGPoint)contentOffset;
@end

@interface UIView (WebKitInternal)
Expand Down
57 changes: 55 additions & 2 deletions Source/WebKit/UIProcess/ios/UIKitUtilities.mm
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ - (BOOL)_wk_isInterruptingDeceleration
return self.decelerating && self.tracking;
}

- (CGFloat)_wk_contentWidthIncludingInsets
{
auto inset = self.adjustedContentInset;
return self.contentSize.width + inset.left + inset.right;
}

- (CGFloat)_wk_contentHeightIncludingInsets
{
auto inset = self.adjustedContentInset;
return self.contentSize.height + inset.top + inset.bottom;
}

- (BOOL)_wk_isScrolledBeyondExtents
{
auto contentOffset = self.contentOffset;
Expand All @@ -47,12 +59,53 @@ - (BOOL)_wk_isScrolledBeyondExtents
auto contentSize = self.contentSize;
auto boundsSize = self.bounds.size;
auto maxScrollExtent = CGPointMake(
contentSize.width + inset.right - std::min<CGFloat>(boundsSize.width, contentSize.width + inset.left + inset.right),
contentSize.height + inset.bottom - std::min<CGFloat>(boundsSize.height, contentSize.height + inset.top + inset.bottom)
contentSize.width + inset.right - std::min<CGFloat>(boundsSize.width, self._wk_contentWidthIncludingInsets),
contentSize.height + inset.bottom - std::min<CGFloat>(boundsSize.height, self._wk_contentHeightIncludingInsets)
);
return contentOffset.x > maxScrollExtent.x || contentOffset.y > maxScrollExtent.y;
}

- (CGPoint)_wk_clampToScrollExtents:(CGPoint)contentOffset
{
// See also: -[UIScrollView _adjustedContentOffsetForContentOffset:].
auto bounds = CGRect { contentOffset, self.bounds.size };
auto effectiveInset = self.adjustedContentInset;

if (!self.zoomBouncing && self.zooming)
return contentOffset;

auto contentMinX = -effectiveInset.left;
auto contentMinY = -effectiveInset.top;
auto contentSize = self.contentSize;
auto contentMaxX = contentSize.width + effectiveInset.right;
auto contentMaxY = contentSize.height + effectiveInset.bottom;

if (CGRectGetWidth(bounds) >= self._wk_contentWidthIncludingInsets || CGRectGetMinX(bounds) < contentMinX)
contentOffset.x = contentMinX;
else if (CGRectGetMaxX(bounds) > contentMaxX)
contentOffset.x = contentMaxX - CGRectGetWidth(bounds);

if (CGRectGetHeight(bounds) >= self._wk_contentHeightIncludingInsets || CGRectGetMinY(bounds) < contentMinY)
contentOffset.y = contentMinY;
else if (CGRectGetMaxY(bounds) > contentMaxY)
contentOffset.y = contentMaxY - CGRectGetHeight(bounds);

return contentOffset;
}

// Consistent with the value of `_UISmartEpsilon` in UIKit.
static constexpr auto epsilonForComputingScrollability = 0.0001;

- (BOOL)_wk_canScrollHorizontallyWithoutBouncing
{
return self._wk_contentWidthIncludingInsets - CGRectGetWidth(self.bounds) > epsilonForComputingScrollability;
}

- (BOOL)_wk_canScrollVerticallyWithoutBouncing
{
return self._wk_contentHeightIncludingInsets - CGRectGetHeight(self.bounds) > epsilonForComputingScrollability;
}

@end

@implementation UIView (WebKitInternal)
Expand Down
10 changes: 4 additions & 6 deletions Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#import "AccessibilitySupportSPI.h"
#import "UIKitSPI.h"
#import "UIKitUtilities.h"
#import "WKVelocityTrackingScrollView.h"
#import <QuartzCore/CADisplayLink.h>
#import <WebCore/FloatPoint.h>
Expand Down Expand Up @@ -611,10 +612,7 @@ - (CGPoint)contentOffset

- (CGPoint)boundedContentOffset:(CGPoint)offset
{
if (!_scrollView)
return CGPointZero;

return [_scrollView _adjustedContentOffsetForContentOffset:offset];
return [_scrollView _wk_clampToScrollExtents:offset];
}

- (CGSize)interactiveScrollVelocity
Expand Down Expand Up @@ -652,9 +650,9 @@ - (CGSize)interactiveScrollVelocity

WebCore::RectEdges<bool> edges;

edges.setTop(_scrollView._canScrollWithoutBouncingY);
edges.setTop(_scrollView._wk_canScrollVerticallyWithoutBouncing);
edges.setBottom(edges.top());
edges.setLeft(_scrollView._canScrollWithoutBouncingX);
edges.setLeft(_scrollView._wk_canScrollHorizontallyWithoutBouncing);
edges.setRight(edges.left());

return edges;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#if PLATFORM(IOS_FAMILY)

#import <wtf/ApproximateTime.h>
#import <wtf/FixedVector.h>

template <size_t windowSize>
struct ScrollingDeltaWindow {
Expand Down

0 comments on commit a609e0d

Please sign in to comment.