/*
 * 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"
#import "WKKeyboardScrollingAnimator.h"

#if PLATFORM(IOS_FAMILY)

#import "AccessibilitySupportSPI.h"
#import "UIKitSPI.h"
#import <QuartzCore/CADisplayLink.h>
#import <WebCore/FloatPoint.h>
#import <WebCore/KeyEventCodesIOS.h>
#import <WebCore/RectEdges.h>
#import <WebCore/WebEvent.h>
#import <WebKit/UIKitSPI.h>
#import <algorithm>
#import <wtf/RetainPtr.h>
#import <wtf/WeakObjCPtr.h>

namespace WebKit {

struct KeyboardScroll {
    WebCore::FloatSize offset; // Points per increment.
    WebCore::FloatSize maximumVelocity; // Points per second.
    WebCore::FloatSize force;

    WebKit::ScrollingIncrement increment;
    WebKit::ScrollingDirection direction;
};

struct KeyboardScrollParameters {
    CGFloat springMass { 1 };
    CGFloat springStiffness { 109 };
    CGFloat springDamping { 20 };

    CGFloat maximumVelocityMultiplier { 25 };
    CGFloat timeToMaximumVelocity { 1 };

    CGFloat rubberBandForce { 5000 };
};

}

@protocol WKKeyboardScrollableInternal <NSObject>
@required
- (BOOL)isKeyboardScrollable;
- (CGFloat)distanceForIncrement:(WebKit::ScrollingIncrement)increment inDirection:(WebKit::ScrollingDirection)direction;
- (void)scrollToContentOffset:(WebCore::FloatPoint)offset animated:(BOOL)animated;
- (void)scrollWithScrollToExtentAnimationTo:(CGPoint)offset;
- (CGPoint)contentOffset;
- (CGSize)interactiveScrollVelocity;
- (CGPoint)boundedContentOffset:(CGPoint)offset;
- (WebCore::RectEdges<bool>)scrollableDirectionsFromOffset:(CGPoint)offset;
- (WebCore::RectEdges<bool>)rubberbandableDirections;
- (void)didFinishScrolling;

@end

@interface WKKeyboardScrollingAnimator : NSObject

- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithScrollable:(id <WKKeyboardScrollableInternal>)scrollable;

- (void)invalidate;

- (void)willStartInteractiveScroll;

- (BOOL)beginWithEvent:(::WebEvent *)event;
- (void)handleKeyEvent:(::WebEvent *)event;

@end

@implementation WKKeyboardScrollingAnimator {
    id <WKKeyboardScrollableInternal> _scrollable;
    RetainPtr<CADisplayLink> _displayLink;

    Optional<WebKit::KeyboardScroll> _currentScroll;

    BOOL _scrollTriggeringKeyIsPressed;

    WebCore::FloatSize _velocity; // Points per second.

    WebCore::FloatPoint _idealPosition;
    WebCore::FloatPoint _currentPosition;
    WebCore::FloatPoint _idealPositionForMinimumTravel;
}

- (instancetype)init
{
    return nil;
}

- (instancetype)initWithScrollable:(id <WKKeyboardScrollableInternal>)scrollable
{
    self = [super init];
    if (!self)
        return nil;

    _scrollable = scrollable;

    return self;
}

- (const WebKit::KeyboardScrollParameters &)parameters
{
    static const WebKit::KeyboardScrollParameters parameters;
    return parameters;
}

- (void)invalidate
{
    [self stopAnimatedScroll];
    [self stopDisplayLink];
    _scrollable = nil;
}

static WebCore::FloatSize unitVector(WebKit::ScrollingDirection direction)
{
    switch (direction) {
    case WebKit::ScrollingDirection::Up:
        return { 0, -1 };
    case WebKit::ScrollingDirection::Down:
        return { 0, 1 };
    case WebKit::ScrollingDirection::Left:
        return { -1, 0 };
    case WebKit::ScrollingDirection::Right:
        return { 1, 0 };
    }
}

static WebCore::FloatSize perpendicularAbsoluteUnitVector(WebKit::ScrollingDirection direction)
{
    switch (direction) {
    case WebKit::ScrollingDirection::Up:
    case WebKit::ScrollingDirection::Down:
        return { 1, 0 };
    case WebKit::ScrollingDirection::Left:
    case WebKit::ScrollingDirection::Right:
        return { 0, 1 };
    }
}

static WebCore::PhysicalBoxSide boxSide(WebKit::ScrollingDirection direction)
{
    switch (direction) {
    case WebKit::ScrollingDirection::Up:
        return WebCore::PhysicalBoxSide::Top;
    case WebKit::ScrollingDirection::Down:
        return WebCore::PhysicalBoxSide::Bottom;
    case WebKit::ScrollingDirection::Left:
        return WebCore::PhysicalBoxSide::Left;
    case WebKit::ScrollingDirection::Right:
        return WebCore::PhysicalBoxSide::Right;
    }
}

- (Optional<WebKit::KeyboardScroll>)keyboardScrollForEvent:(::WebEvent *)event
{
    static const unsigned kWebSpaceKey = 0x20;

    if (![_scrollable isKeyboardScrollable])
        return WTF::nullopt;

    NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers;
    if (!charactersIgnoringModifiers.length)
        return WTF::nullopt;

    enum class Key : uint8_t { Other, LeftArrow, RightArrow, UpArrow, DownArrow, PageUp, PageDown, Space };
    
    auto key = ^{
        auto firstCharacter = [charactersIgnoringModifiers characterAtIndex:0];
        switch (firstCharacter) {
        case NSLeftArrowFunctionKey:
            return Key::LeftArrow;
        case NSRightArrowFunctionKey:
            return Key::RightArrow;
        case NSUpArrowFunctionKey:
            return Key::UpArrow;
        case NSDownArrowFunctionKey:
            return Key::DownArrow;
        case NSPageDownFunctionKey:
            return Key::PageDown;
        case NSPageUpFunctionKey:
            return Key::PageUp;
        case kWebSpaceKey:
            return Key::Space;
        default:
            return Key::Other;
        };
    }();
    
    if (key == Key::Other)
        return WTF::nullopt;
    
    BOOL shiftPressed = event.modifierFlags & WebEventFlagMaskShiftKey;
    BOOL altPressed = event.modifierFlags & WebEventFlagMaskOptionKey;
    BOOL cmdPressed = event.modifierFlags & WebEventFlagMaskCommandKey;

    // No shortcuts include more than one modifier; we should not eat key events
    // that contain more than one modifier because they might be used for other shortcuts.
    if (shiftPressed + altPressed + cmdPressed > 1)
        return WTF::nullopt;

    auto allowedModifiers = ^ WebEventFlags {
        switch (key) {
        case Key::LeftArrow:
        case Key::RightArrow:
            return WebEventFlagMaskOptionKey;
        case Key::UpArrow:
        case Key::DownArrow:
            return WebEventFlagMaskOptionKey | WebEventFlagMaskCommandKey;
        case Key::PageUp:
        case Key::PageDown:
            return 0;
        case Key::Space:
            return WebEventFlagMaskShiftKey;
        case Key::Other:
            ASSERT_NOT_REACHED();
            return 0;
        };
    }();

    auto relevantModifierFlags = WebEventFlagMaskOptionKey | WebEventFlagMaskCommandKey | WebEventFlagMaskShiftKey;
    if (event.modifierFlags & relevantModifierFlags & ~allowedModifiers)
        return WTF::nullopt;

    auto increment = ^{
        switch (key) {
        case Key::LeftArrow:
        case Key::RightArrow:
            if (altPressed)
                return WebKit::ScrollingIncrement::Page;
            return WebKit::ScrollingIncrement::Line;
        case Key::UpArrow:
        case Key::DownArrow:
            if (altPressed)
                return WebKit::ScrollingIncrement::Page;
            if (cmdPressed)
                return WebKit::ScrollingIncrement::Document;
            return WebKit::ScrollingIncrement::Line;
        case Key::PageUp:
        case Key::PageDown:
        case Key::Space:
            return WebKit::ScrollingIncrement::Page;
        case Key::Other:
            ASSERT_NOT_REACHED();
            return WebKit::ScrollingIncrement::Line;
        };
    }();

    auto direction = ^() {
        switch (key) {
        case Key::LeftArrow:
            return WebKit::ScrollingDirection::Left;
        case Key::RightArrow:
            return WebKit::ScrollingDirection::Right;
        case Key::UpArrow:
        case Key::PageUp:
            return WebKit::ScrollingDirection::Up;
        case Key::DownArrow:
        case Key::PageDown:
            return WebKit::ScrollingDirection::Down;
        case Key::Space:
            return shiftPressed ? WebKit::ScrollingDirection::Up : WebKit::ScrollingDirection::Down;
        case Key::Other:
            ASSERT_NOT_REACHED();
            return WebKit::ScrollingDirection::Down;
        };
    }();

    CGFloat scrollDistance = [_scrollable distanceForIncrement:increment inDirection:direction];

    WebKit::KeyboardScroll scroll;
    scroll.offset = unitVector(direction).scaled(scrollDistance);
    scroll.increment = increment;
    scroll.direction = direction;
    scroll.maximumVelocity = scroll.offset.scaled(self.parameters.maximumVelocityMultiplier);

    // Apply a constant force to achieve Vmax in timeToMaximumVelocity seconds.
    // F_constant = m * Vmax / t
    scroll.force = scroll.maximumVelocity.scaled(self.parameters.springMass / self.parameters.timeToMaximumVelocity);
    
    return scroll;
}

- (BOOL)beginWithEvent:(::WebEvent *)event
{
    if (event.type != WebEventKeyDown)
        return NO;

    auto scroll = [self keyboardScrollForEvent:event];
    if (!scroll)
        return NO;

    if (_scrollTriggeringKeyIsPressed)
        return NO;

    if (![_scrollable rubberbandableDirections].at(boxSide(scroll->direction)))
        return NO;

    _scrollTriggeringKeyIsPressed = YES;
    _currentScroll = scroll;

    if (scroll->increment == WebKit::ScrollingIncrement::Document) {
        _velocity = { };
        [self stopAnimatedScroll];
        [self stopDisplayLink];
        [_scrollable scrollWithScrollToExtentAnimationTo:[_scrollable boundedContentOffset:_currentPosition + scroll->offset]];
        return YES;
    }

    [self startDisplayLinkIfNeeded];

    _currentPosition = WebCore::FloatPoint([_scrollable contentOffset]);
    _velocity += WebCore::FloatSize([_scrollable interactiveScrollVelocity]);
    _idealPositionForMinimumTravel = _currentPosition + _currentScroll->offset;

    return YES;
}

- (void)handleKeyEvent:(::WebEvent *)event
{
    if (!_scrollTriggeringKeyIsPressed)
        return;

    auto scroll = [self keyboardScrollForEvent:event];

    // UIKit does not emit a keyup event when the Command key is down. See <rdar://problem/49523065>.
    // For recognized key commands that include the Command key (e.g. Command + Arrow Up) we reset our
    // state on keydown.
    if (!scroll || event.type == WebEventKeyUp || (event.modifierFlags & WebEventFlagMaskCommandKey)) {
        [self stopAnimatedScroll];
        _scrollTriggeringKeyIsPressed = NO;
    }
}

static WebCore::FloatPoint farthestPointInDirection(WebCore::FloatPoint a, WebCore::FloatPoint b, WebKit::ScrollingDirection direction)
{
    switch (direction) {
    case WebKit::ScrollingDirection::Up:
        return WebCore::FloatPoint(a.x(), std::min(a.y(), b.y()));
    case WebKit::ScrollingDirection::Down:
        return WebCore::FloatPoint(a.x(), std::max(a.y(), b.y()));
    case WebKit::ScrollingDirection::Left:
        return WebCore::FloatPoint(std::min(a.x(), b.x()), a.y());
    case WebKit::ScrollingDirection::Right:
        return WebCore::FloatPoint(std::max(a.x(), b.x()), a.y());
    }

    ASSERT_NOT_REACHED();
    return { };
}

- (void)stopAnimatedScroll
{
    if (!_currentScroll)
        return;

    // Determine the settling position of the spring, conserving the system's current energy.
    // Kinetic = elastic potential
    // 1/2 * m * v^2 = 1/2 * k * x^2
    // x = sqrt(v^2 * m / k)
    auto displacementMagnitudeSquared = (_velocity * _velocity).scaled(self.parameters.springMass / self.parameters.springStiffness);
    WebCore::FloatSize displacement = {
        std::copysign(sqrt(displacementMagnitudeSquared.width()), _velocity.width()),
        std::copysign(sqrt(displacementMagnitudeSquared.height()), _velocity.height())
    };

    // If the spring would settle before the minimum travel distance
    // for an instantaneous tap, move the settling position of the spring
    // out to that point.
    _idealPosition = [_scrollable boundedContentOffset:farthestPointInDirection(_currentPosition + displacement, _idealPositionForMinimumTravel, _currentScroll->direction)];

    _currentScroll = WTF::nullopt;
}

- (BOOL)scrollTriggeringKeyIsPressed
{
    return _scrollTriggeringKeyIsPressed;
}

- (void)willStartInteractiveScroll
{
    // If the user touches the screen to start an interactive scroll, stop everything.
    _velocity = { };
    [self stopAnimatedScroll];
    [self stopDisplayLink];
}

- (void)startDisplayLinkIfNeeded
{
    if (_displayLink)
        return;

    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)];
    [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)stopDisplayLink
{
    [_displayLink invalidate];
    _displayLink = nil;
}

- (void)displayLinkFired:(CADisplayLink *)sender
{
    WebCore::FloatSize force;
    WebCore::FloatSize axesToApplySpring = { 1, 1 };

    if (_currentScroll) {
        auto scrollableDirections = [_scrollable scrollableDirectionsFromOffset:_currentPosition];
        auto direction = _currentScroll->direction;

        if (scrollableDirections.at(boxSide(direction))) {
            // Apply the scrolling force. Only apply the spring in the perpendicular axis,
            // otherwise it drags against the direction of motion.
            axesToApplySpring = perpendicularAbsoluteUnitVector(direction);
            force = _currentScroll->force;
        } else {
            // The scroll view cannot scroll in this direction, and is rubber-banding.
            // Apply a constant and significant force; otherwise, the force for a
            // single-line increment is not strong enough to rubber-band perceptibly.
            force = unitVector(direction).scaled(self.parameters.rubberBandForce);
        }

        // If we've reached or exceeded the maximum velocity, stop applying any force.
        // However, we won't let the spring snap, we'll just keep going at the same
        // velocity until the user raises their finger or we hit an edge.
        if (fabs(_velocity.width()) >= fabs(_currentScroll->maximumVelocity.width()))
            force.setWidth(0);
        if (fabs(_velocity.height()) >= fabs(_currentScroll->maximumVelocity.height()))
            force.setHeight(0);
    }

    WebCore::FloatPoint idealPosition = [_scrollable boundedContentOffset:_currentScroll ? _currentPosition : _idealPosition];
    WebCore::FloatSize displacement = _currentPosition - idealPosition;

    // Compute the spring's force, and apply it in allowed directions.
    // F_spring = -k * x - c * v
    auto springForce = - displacement.scaled(self.parameters.springStiffness) - _velocity.scaled(self.parameters.springDamping);
    force += springForce * axesToApplySpring;

    // Integrate acceleration -> velocity -> position for this time step.
    CFTimeInterval frameDuration = sender.targetTimestamp - sender.timestamp;
    WebCore::FloatSize acceleration = force.scaled(1. / self.parameters.springMass);
    _velocity += acceleration.scaled(frameDuration);
    _currentPosition += _velocity.scaled(frameDuration);

    [_scrollable scrollToContentOffset:_currentPosition animated:NO];

    // If we've effectively stopped scrolling, and no key is pressed,
    // shut down the display link.
    if (!_scrollTriggeringKeyIsPressed && _velocity.diagonalLengthSquared() < 1) {
        [_scrollable didFinishScrolling];
        [self stopDisplayLink];
        _velocity = { };
    }
}

@end

@interface WKKeyboardScrollViewAnimator () <WKKeyboardScrollableInternal>
@end

@implementation WKKeyboardScrollViewAnimator {
    WeakObjCPtr<UIScrollView> _scrollView;
    RetainPtr<WKKeyboardScrollingAnimator> _animator;

    BOOL _delegateRespondsToIsKeyboardScrollable;
    BOOL _delegateRespondsToDistanceForIncrement;
    BOOL _delegateRespondsToWillScroll;
    BOOL _delegateRespondsToDidFinishScrolling;
}

- (instancetype)init
{
    return nil;
}

- (instancetype)initWithScrollView:(UIScrollView *)scrollView
{
    self = [super init];
    if (!self)
        return nil;

    _scrollView = scrollView;
    _animator = adoptNS([[WKKeyboardScrollingAnimator alloc] initWithScrollable:self]);

    return self;
}

- (void)dealloc
{
    [_animator invalidate];
    [super dealloc];
}

- (void)invalidate
{
    _scrollView = nil;

    [_animator invalidate];
    _animator = nil;
}

- (void)setDelegate:(id <WKKeyboardScrollViewAnimatorDelegate>)delegate
{
    _delegate = delegate;

    _delegateRespondsToIsKeyboardScrollable = [_delegate respondsToSelector:@selector(isScrollableForKeyboardScrollViewAnimator:)];
    _delegateRespondsToDistanceForIncrement = [_delegate respondsToSelector:@selector(keyboardScrollViewAnimator:distanceForIncrement:inDirection:)];
    _delegateRespondsToWillScroll = [_delegate respondsToSelector:@selector(keyboardScrollViewAnimatorWillScroll:)];
    _delegateRespondsToDidFinishScrolling = [_delegate respondsToSelector:@selector(keyboardScrollViewAnimatorDidFinishScrolling:)];
}

- (void)willStartInteractiveScroll
{
    [_animator willStartInteractiveScroll];
}

- (BOOL)beginWithEvent:(::WebEvent *)event
{
    return [_animator beginWithEvent:event];
}

- (void)handleKeyEvent:(::WebEvent *)event
{
    return [_animator handleKeyEvent:event];
}

- (BOOL)scrollTriggeringKeyIsPressed
{
    return [_animator scrollTriggeringKeyIsPressed];
}

- (BOOL)isKeyboardScrollable
{
    if (!_delegateRespondsToIsKeyboardScrollable)
        return YES;
    return [_delegate isScrollableForKeyboardScrollViewAnimator:self];
}

- (CGFloat)distanceForIncrement:(WebKit::ScrollingIncrement)increment inDirection:(WebKit::ScrollingDirection)direction
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return 0;

    const CGFloat defaultPageScrollFraction = 0.8;
    const CGFloat defaultLineScrollHeight = 40;

    BOOL directionIsHorizontal = direction == WebKit::ScrollingDirection::Left || direction == WebKit::ScrollingDirection::Right;

    if (!_delegateRespondsToDistanceForIncrement) {
        switch (increment) {
        case WebKit::ScrollingIncrement::Document:
            return directionIsHorizontal ? scrollView.contentSize.width : scrollView.contentSize.height;
        case WebKit::ScrollingIncrement::Page:
            return (directionIsHorizontal ? scrollView.frame.size.width : scrollView.frame.size.height) * defaultPageScrollFraction;
        case WebKit::ScrollingIncrement::Line:
            return defaultLineScrollHeight * scrollView.zoomScale;
        }
        ASSERT_NOT_REACHED();
        return 0;
    }

    return [_delegate keyboardScrollViewAnimator:self distanceForIncrement:increment inDirection:direction];
}

#if HAVE(UI_SCROLL_VIEW_INDICATOR_FLASHING_SPI)
static UIAxis axesForDelta(WebCore::FloatSize delta)
{
    UIAxis axes = UIAxisNeither;
    if (delta.width())
        axes = static_cast<UIAxis>(axes | UIAxisHorizontal);
    if (delta.height())
        axes = static_cast<UIAxis>(axes | UIAxisVertical);
    return axes;
}
#endif

- (void)scrollToContentOffset:(WebCore::FloatPoint)contentOffset animated:(BOOL)animated
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return;
    if (_delegateRespondsToWillScroll)
        [_delegate keyboardScrollViewAnimatorWillScroll:self];
    [scrollView setContentOffset:contentOffset animated:animated];
#if HAVE(UI_SCROLL_VIEW_INDICATOR_FLASHING_SPI)
    [scrollView _flashScrollIndicatorsForAxes:axesForDelta(WebCore::FloatPoint(scrollView.contentOffset) - contentOffset) persistingPreviousFlashes:YES];
#else
    [scrollView _flashScrollIndicatorsPersistingPreviousFlashes:YES];
#endif
}

- (void)scrollWithScrollToExtentAnimationTo:(CGPoint)offset
{
    auto scrollView = _scrollView.getAutoreleased();
    [scrollView _setContentOffsetWithDecelerationAnimation:offset];
    [scrollView flashScrollIndicators];
}

- (CGPoint)contentOffset
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return CGPointZero;

    return [scrollView contentOffset];
}

- (CGPoint)boundedContentOffset:(CGPoint)offset
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return CGPointZero;

    return [scrollView _adjustedContentOffsetForContentOffset:offset];
}

- (CGSize)interactiveScrollVelocity
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return CGSizeZero;

    const NSTimeInterval millisecondsPerSecond = 1000;
    return CGSizeMake(scrollView._horizontalVelocity * millisecondsPerSecond, scrollView._verticalVelocity * millisecondsPerSecond);
}

- (WebCore::RectEdges<bool>)scrollableDirectionsFromOffset:(CGPoint)offset
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return { };

    UIEdgeInsets contentInsets = scrollView.adjustedContentInset;

    CGSize contentSize = scrollView.contentSize;
    CGSize scrollViewSize = scrollView.bounds.size;

    CGPoint minimumContentOffset = CGPointMake(-contentInsets.left, -contentInsets.top);
    CGPoint maximumContentOffset = CGPointMake(std::max(minimumContentOffset.x, contentSize.width + contentInsets.right - scrollViewSize.width), std::max(minimumContentOffset.y, contentSize.height + contentInsets.bottom - scrollViewSize.height));

    WebCore::RectEdges<bool> edges;

    edges.setTop(offset.y > minimumContentOffset.y);
    edges.setBottom(offset.y < maximumContentOffset.y);
    edges.setLeft(offset.x > minimumContentOffset.x);
    edges.setRight(offset.x < maximumContentOffset.x);

    return edges;
}

- (WebCore::RectEdges<bool>)rubberbandableDirections
{
    auto scrollView = _scrollView.getAutoreleased();
    if (!scrollView)
        return { };

    WebCore::RectEdges<bool> edges;

    edges.setTop(scrollView._canScrollWithoutBouncingY);
    edges.setBottom(edges.top());
    edges.setLeft(scrollView._canScrollWithoutBouncingX);
    edges.setRight(edges.left());

    return edges;
}

- (void)didFinishScrolling
{
    if (_delegateRespondsToDidFinishScrolling)
        [_delegate keyboardScrollViewAnimatorDidFinishScrolling:self];
}

@end

#endif // PLATFORM(IOS_FAMILY)
