/*
 * 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;

    if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged)
        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];
}

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;
}

- (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];
    [scrollView _flashScrollIndicatorsForAxes:axesForDelta(WebCore::FloatPoint(scrollView.contentOffset) - contentOffset) persistingPreviousFlashes:YES];
}

- (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)
