WebKit Bugzilla
Attachment 346304 Details for
Bug 188239
: Using the keyboard arrow keys to scroll a webpage is very slow, not smooth, takes too long
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188239-20180801145901.patch (text/plain), 32.75 KB, created by
Tim Horton
on 2018-08-01 14:59:02 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tim Horton
Created:
2018-08-01 14:59:02 PDT
Size:
32.75 KB
patch
obsolete
>Subversion Revision: 234460 >diff --git a/Source/WebCore/PAL/ChangeLog b/Source/WebCore/PAL/ChangeLog >index d7bbd969f070ee808326da3344a138addb9bed99..154c78341e683fe7334d2abf32ad1918d9d65b13 100644 >--- a/Source/WebCore/PAL/ChangeLog >+++ b/Source/WebCore/PAL/ChangeLog >@@ -1,3 +1,14 @@ >+2018-08-01 Tim Horton <timothy_horton@apple.com> >+ >+ Using the keyboard arrow keys to scroll a webpage is very slow, not smooth, takes too long >+ https://bugs.webkit.org/show_bug.cgi?id=188239 >+ <rdar://problem/22997654> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * pal/spi/cocoa/QuartzCoreSPI.h: >+ Add a piece of SPI. >+ > 2018-07-30 Sihui Liu <sihui_liu@apple.com> > > Add support for fetching and remove type _WKWebsiteDataTypeHSTSCache >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 7b97a4fcc8f735414c08c33fea1b3c86d16ced06..db033da983fc4dcbfba0ba4f0bf7a39333fe1497 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,94 @@ >+2018-08-01 Tim Horton <timothy_horton@apple.com> >+ >+ Using the keyboard arrow keys to scroll a webpage is very slow, not smooth, takes too long >+ https://bugs.webkit.org/show_bug.cgi?id=188239 >+ <rdar://problem/22997654> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Instead of depending on key repeat to drive scrolling with arrow keys held down, >+ run a display link that animates the scroll. We still do a single discrete scroll >+ first (so that you can tap the key and shift by line/page), but then on the first >+ repeat we ramp up to a constant velocity determined by the desired increment, >+ stopping when the key is lifted or a different key is pressed. >+ >+ * UIProcess/API/Cocoa/WKWebView.mm: >+ (-[WKWebView _scrollByContentOffset:animated:]): >+ (-[WKWebView _scrollByContentOffset:]): Deleted. >+ * UIProcess/API/Cocoa/WKWebViewInternal.h: >+ Add animated parameter to scrollByContentOffset, and plumb it through to UIScrollView. >+ >+ * UIProcess/ios/WKContentViewInteraction.h: >+ Add a WKKeyboardScrollingAnimator member. >+ Conform to WKKeyboardScrollable. >+ >+ * UIProcess/ios/WKContentViewInteraction.mm: >+ (-[WKContentView setupInteraction]): >+ Install the WKKeyboardScrollingAnimator. >+ >+ (-[WKContentView cleanupInteraction]): >+ Uninstall the WKKeyboardScrollingAnimator. >+ >+ (-[WKContentView unscaledView]): >+ Fix a stupid style nit. >+ >+ (-[WKContentView handleKeyWebEvent:]): >+ Give WKKeyboardScrollingAnimator the first shot at incoming keyboard events. >+ It will only consume events here if it's already performing a scrolling animation >+ (because otherwise they should go straight through to the page). >+ >+ (-[WKContentView _interpretKeyEvent:isCharEvent:]): >+ Give WKKeyboardScrollingAnimator a shot at handling keyboard events that >+ the web content did not handle. We will only start a scrolling animation >+ if the page did not handle an event that would start a scroll. >+ >+ (-[WKContentView isKeyboardScrollable]): >+ Part of WKKeyboardScrollable; only report ourselves as scrollable if >+ we would previously have allowed scrolling from keyboard events (if >+ we're not in contenteditable, and don't have a <select> focused). >+ >+ (-[WKContentView distanceForScrollingIncrement:]): >+ Part of WKKeyboardScrollable; compute the distance for each scrolling increment. >+ >+ (-[WKContentView scrollByContentOffset:animated:]): >+ Part of WKKeyboardScrollable; plumb scrolls up to WKWebView. >+ >+ (-[WKContentView _scrollOffsetForEvent:]): Moved to WKKeyboardScrollingAnimator.mm. >+ >+ * UIProcess/ios/WKKeyboardScrollingAnimator.h: Added. >+ * UIProcess/ios/WKKeyboardScrollingAnimator.mm: Added. >+ (-[WKKeyboardScrollingAnimator init]): >+ (-[WKKeyboardScrollingAnimator initWithScrollable:]): >+ (-[WKKeyboardScrollingAnimator invalidate]): >+ (-[WKKeyboardScrollingAnimator _scrollOffsetForEvent:]): >+ Compute the scroll offset given a particular event. This is moved from WKContentView; >+ otherwise the primary change is that it now asks the WKKeyboardScrollable >+ for the distance instead of computing it directly. >+ >+ (-[WKKeyboardScrollingAnimator beginWithEvent:]): >+ If we're currently in the initial state (WaitingForFirstEvent), and >+ a given event should start a scroll, transition into WaitingForRepeat, >+ and do a single animated scroll of the appropriate distance. >+ >+ (-[WKKeyboardScrollingAnimator handleKeyEvent:]): >+ If this key event should terminate a scroll (because it is either a keyup >+ or a different key than the current scroll), shut down any running animations. >+ >+ If this is the first key repeat after the initial scroll, start a scrolling >+ animation. >+ >+ Eat the event if it either started or continued a scroll. >+ >+ (-[WKKeyboardScrollingAnimator startAnimatedScroll]): >+ (-[WKKeyboardScrollingAnimator stopAnimatedScroll]): >+ Helpers to start and stop the display link and do some bookkeeping. >+ >+ (-[WKKeyboardScrollingAnimator displayLinkFired:]): >+ Ask the WKKeyboardScrollable to scroll the content based on the frame time, >+ an acceleration curve, and the current animation's scrolling increment. >+ >+ * WebKit.xcodeproj/project.pbxproj: >+ > 2018-08-01 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r234443 and r234445. >diff --git a/Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h b/Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h >index 67e08d5182ba4074db06e8674b3bc99112afdb89..6a0eca0ab50aebfabaf561f1e532b7f4436391d9 100644 >--- a/Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h >+++ b/Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h >@@ -41,6 +41,7 @@ > #import <QuartzCore/CAContext.h> > #import <QuartzCore/CALayerHost.h> > #import <QuartzCore/CALayerPrivate.h> >+#import <QuartzCore/CAMediaTimingFunctionPrivate.h> > #import <QuartzCore/QuartzCorePrivate.h> > > #if PLATFORM(MAC) >@@ -153,6 +154,10 @@ typedef enum { > @property CGFloat velocity; > @end > >+@interface CAMediaTimingFunction () >+- (float)_solveForInput:(float)t; >+@end >+ > #endif // __OBJC__ > > #endif >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >index 53df915717dca340fc7ca36616a735f7419ffeec..b10a01c04a7180012de9c651d07461a4424bca17 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >@@ -2113,7 +2113,7 @@ - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint > return true; > } > >-- (void)_scrollByContentOffset:(WebCore::FloatPoint)contentOffsetDelta >+- (void)_scrollByContentOffset:(WebCore::FloatPoint)contentOffsetDelta animated:(BOOL)animated > { > WebCore::FloatPoint scaledOffsetDelta = contentOffsetDelta; > CGFloat zoomScale = contentZoomScale(self); >@@ -2128,7 +2128,7 @@ - (void)_scrollByContentOffset:(WebCore::FloatPoint)contentOffsetDelta > > LOG_WITH_STREAM(VisibleRects, stream << "_scrollByContentOffset: scrolling to " << WebCore::FloatPoint(boundedOffset)); > >- [_scrollView setContentOffset:boundedOffset animated:YES]; >+ [_scrollView setContentOffset:boundedOffset animated:animated]; > } > > - (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >index aab3010f5d831f190b9a944af2676f871c57d0be..3a0541c410417cb0cb8dddde69eee2244cf9da1c 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >@@ -91,7 +91,7 @@ struct PrintInfo; > > - (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin; > - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance; >-- (void)_scrollByContentOffset:(WebCore::FloatPoint)offset; >+- (void)_scrollByContentOffset:(WebCore::FloatPoint)offset animated:(BOOL)animated; > - (void)_zoomToFocusRect:(WebCore::FloatRect)focusedElementRect selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll; > - (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance; > - (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated; >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >index f8e4584ebefc8d8b8e7262eb8fc400b61dcd1457..31a6283b28c11f0e7d9428c2589cf5966f3d3807 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >@@ -37,6 +37,7 @@ > #import "WKAirPlayRoutePicker.h" > #import "WKFileUploadPanel.h" > #import "WKFormPeripheral.h" >+#import "WKKeyboardScrollingAnimator.h" > #import "WKSyntheticClickTapGestureRecognizer.h" > #import <UIKit/UIView.h> > #import <WebCore/Color.h> >@@ -215,6 +216,8 @@ struct WKAutoCorrectionData { > > std::unique_ptr<WebKit::InputViewUpdateDeferrer> _inputViewUpdateDeferrer; > >+ RetainPtr<WKKeyboardScrollingAnimator> _keyboardScrollingAnimator; >+ > BOOL _isEditable; > BOOL _showingTextStyleOptions; > BOOL _hasValidPositionInformation; >@@ -260,7 +263,7 @@ struct WKAutoCorrectionData { > > @end > >-@interface WKContentView (WKInteraction) <UIGestureRecognizerDelegate, UITextAutoscrolling, UITextInputMultiDocument, UITextInputPrivate, UIWebFormAccessoryDelegate, UIWebTouchEventsGestureRecognizerDelegate, UIWKInteractionViewProtocol, WKActionSheetAssistantDelegate, WKFileUploadPanelDelegate >+@interface WKContentView (WKInteraction) <UIGestureRecognizerDelegate, UITextAutoscrolling, UITextInputMultiDocument, UITextInputPrivate, UIWebFormAccessoryDelegate, UIWebTouchEventsGestureRecognizerDelegate, UIWKInteractionViewProtocol, WKActionSheetAssistantDelegate, WKFileUploadPanelDelegate, WKKeyboardScrollable > #if ENABLE(DATA_INTERACTION) > , UIDragInteractionDelegate, UIDropInteractionDelegate > #endif >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >index a1a4dc8b6056a8fe6d69430d0d4669e1ce670082..4199cf2d9777b230dcb4d3c9b95c42d1e1a0ee80 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >@@ -622,6 +622,8 @@ - (void)setupInteraction > [self.superview addSubview:_interactionViewsContainerView.get()]; > } > >+ _keyboardScrollingAnimator = adoptNS([[WKKeyboardScrollingAnimator alloc] initWithScrollable:self]); >+ > [self.layer addObserver:self forKeyPath:@"transform" options:NSKeyValueObservingOptionInitial context:nil]; > > _touchEventGestureRecognizer = adoptNS([[UIWebTouchEventsGestureRecognizer alloc] initWithTarget:self action:@selector(_webTouchEventsRecognized:) touchDelegate:self]); >@@ -778,6 +780,9 @@ - (void)cleanupInteraction > > _inputViewUpdateDeferrer = nullptr; > _assistedNodeInformation = { }; >+ >+ [_keyboardScrollingAnimator invalidate]; >+ _keyboardScrollingAnimator = nil; > } > > - (void)_removeDefaultGestureRecognizers >@@ -808,7 +813,7 @@ - (void)_addDefaultGestureRecognizers > #endif > } > >-- (UIView*)unscaledView >+- (UIView *)unscaledView > { > return _interactionViewsContainerView.get(); > } >@@ -3638,6 +3643,9 @@ - (void)handleKeyEvent:(::UIEvent *)event > > - (void)handleKeyWebEvent:(::WebEvent *)theEvent > { >+ if ([_keyboardScrollingAnimator handleKeyEvent:theEvent]) >+ return; >+ > _page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent)); > } > >@@ -3676,73 +3684,6 @@ - (void)_didHandleKeyEvent:(::WebEvent *)event eventWasHandled:(BOOL)eventWasHan > _uiEventBeingResent = nil; > } > >-- (std::optional<FloatPoint>)_scrollOffsetForEvent:(::WebEvent *)event >-{ >- static const unsigned kWebSpaceKey = 0x20; >- >- if (_page->editorState().isContentEditable) >- return std::nullopt; >- >- if (_assistedNodeInformation.elementType == InputType::Select) >- return std::nullopt; >- >- NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers; >- if (!charactersIgnoringModifiers.length) >- return std::nullopt; >- >- enum ScrollingIncrement { Document, Page, Line }; >- enum ScrollingDirection { Up, Down, Left, Right }; >- >- auto computeOffset = ^(ScrollingIncrement increment, ScrollingDirection direction) { >- bool isHorizontal = (direction == Left || direction == Right); >- >- CGFloat scrollDistance = ^ CGFloat { >- switch (increment) { >- case Document: >- ASSERT(!isHorizontal); >- return self.bounds.size.height; >- case Page: >- ASSERT(!isHorizontal); >- return Scrollbar::pageStep(_page->unobscuredContentRect().height(), self.bounds.size.height); >- case Line: >- return Scrollbar::pixelsPerLineStep(); >- } >- ASSERT_NOT_REACHED(); >- return 0; >- }(); >- >- if (direction == Up || direction == Left) >- scrollDistance = -scrollDistance; >- >- return (isHorizontal ? FloatPoint(scrollDistance, 0) : FloatPoint(0, scrollDistance)); >- }; >- >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputLeftArrow]) >- return computeOffset(Line, Left); >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputRightArrow]) >- return computeOffset(Line, Right); >- >- ScrollingIncrement incrementForVerticalArrowKey = Line; >- if (event.modifierFlags & WebEventFlagMaskAlternate) >- incrementForVerticalArrowKey = Page; >- else if (event.modifierFlags & WebEventFlagMaskCommand) >- incrementForVerticalArrowKey = Document; >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputUpArrow]) >- return computeOffset(incrementForVerticalArrowKey, Up); >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputDownArrow]) >- return computeOffset(incrementForVerticalArrowKey, Down); >- >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageDown]) >- return computeOffset(Page, Down); >- if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageUp]) >- return computeOffset(Page, Up); >- >- if ([charactersIgnoringModifiers characterAtIndex:0] == kWebSpaceKey) >- return computeOffset(Page, (event.modifierFlags & WebEventFlagMaskShift) ? Up : Down); >- >- return std::nullopt; >-} >- > - (BOOL)_interpretKeyEvent:(::WebEvent *)event isCharEvent:(BOOL)isCharEvent > { > static const unsigned kWebEnterKey = 0x0003; >@@ -3757,10 +3698,8 @@ - (BOOL)_interpretKeyEvent:(::WebEvent *)event isCharEvent:(BOOL)isCharEvent > if (!contentEditable && event.isTabKey) > return NO; > >- if (std::optional<FloatPoint> scrollOffset = [self _scrollOffsetForEvent:event]) { >- [_webView _scrollByContentOffset:*scrollOffset]; >+ if ([_keyboardScrollingAnimator beginWithEvent:event]) > return YES; >- } > > UIKeyboardImpl *keyboard = [UIKeyboardImpl sharedInstance]; > NSString *characters = event.characters; >@@ -3808,6 +3747,36 @@ - (BOOL)_interpretKeyEvent:(::WebEvent *)event isCharEvent:(BOOL)isCharEvent > return NO; > } > >+- (BOOL)isKeyboardScrollable >+{ >+ if (_page->editorState().isContentEditable) >+ return false; >+ >+ if (_assistedNodeInformation.elementType == InputType::Select) >+ return false; >+ >+ return true; >+} >+ >+- (CGFloat)distanceForScrollingIncrement:(ScrollingIncrement)increment >+{ >+ switch (increment) { >+ case ScrollingIncrement::Document: >+ return self.bounds.size.height; >+ case ScrollingIncrement::Page: >+ return WebCore::Scrollbar::pageStep(_page->unobscuredContentRect().height(), self.bounds.size.height); >+ case ScrollingIncrement::Line: >+ return WebCore::Scrollbar::pixelsPerLineStep(); >+ } >+ ASSERT_NOT_REACHED(); >+ return 0; >+} >+ >+- (void)scrollByContentOffset:(WebCore::FloatPoint)offset animated:(BOOL)animated >+{ >+ [_webView _scrollByContentOffset:offset animated:animated]; >+} >+ > - (void)executeEditCommandWithCallback:(NSString *)commandName > { > [self beginSelectionChange]; >diff --git a/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.h b/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.h >new file mode 100644 >index 0000000000000000000000000000000000000000..a539ad720991e0beb766208c033c583fb54ddf2c >--- /dev/null >+++ b/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.h >@@ -0,0 +1,64 @@ >+/* >+ * 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. >+ */ >+ >+#if PLATFORM(IOS) >+ >+namespace WebCore { >+class FloatPoint; >+} >+ >+namespace WebKit { >+ >+enum class ScrollingIncrement : uint8_t { >+ Document, >+ Page, >+ Line >+}; >+ >+} >+ >+@class WebEvent; >+@protocol WKKeyboardScrollable; >+ >+@interface WKKeyboardScrollingAnimator : NSObject >+ >+- (instancetype)init NS_UNAVAILABLE; >+- (instancetype)initWithScrollable:(id <WKKeyboardScrollable>)scrollable; >+ >+- (void)invalidate; >+ >+- (BOOL)beginWithEvent:(::WebEvent *)event; >+- (BOOL)handleKeyEvent:(::WebEvent *)event; >+ >+@end >+ >+@protocol WKKeyboardScrollable <NSObject> >+@required >+- (BOOL)isKeyboardScrollable; >+- (CGFloat)distanceForScrollingIncrement:(WebKit::ScrollingIncrement)increment; >+- (void)scrollByContentOffset:(WebCore::FloatPoint)offset animated:(BOOL)animated; >+@end >+ >+#endif // PLATFORM(IOS) >diff --git a/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm b/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm >new file mode 100644 >index 0000000000000000000000000000000000000000..eb756b649eb05b40a04235ecf8a8640f3bd85f84 >--- /dev/null >+++ b/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm >@@ -0,0 +1,204 @@ >+/* >+ * 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) >+ >+#import "UIKitSPI.h" >+#import <WebCore/FloatPoint.h> >+#import <WebCore/WebEvent.h> >+#import <algorithm> >+#import <pal/spi/cocoa/QuartzCoreSPI.h> >+#import <wtf/RetainPtr.h> >+ >+using namespace WebKit; >+ >+namespace WebKit { >+ >+enum class KeyboardScrollingAnimatorState : uint8_t { >+ WaitingForFirstEvent, >+ WaitingForRepeat, >+ Animating >+}; >+ >+}; >+ >+@implementation WKKeyboardScrollingAnimator { >+ id <WKKeyboardScrollable> _scrollable; >+ CFTimeInterval _startTime; >+ WebCore::FloatPoint _scrollOffsetPerIncrement; >+ RetainPtr<CADisplayLink> _displayLink; >+ KeyboardScrollingAnimatorState _state; >+} >+ >+- (instancetype)init >+{ >+ return nil; >+} >+ >+- (instancetype)initWithScrollable:(id <WKKeyboardScrollable>)scrollable >+{ >+ self = [super init]; >+ if (!self) >+ return nil; >+ >+ _scrollable = scrollable; >+ >+ return self; >+} >+ >+- (void)invalidate >+{ >+ [self stopAnimatedScroll]; >+ _scrollable = nil; >+} >+ >+- (std::optional<WebCore::FloatPoint>)_scrollOffsetForEvent:(::WebEvent *)event >+{ >+ static const unsigned kWebSpaceKey = 0x20; >+ >+ if (![_scrollable isKeyboardScrollable]) >+ return std::nullopt; >+ >+ NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers; >+ if (!charactersIgnoringModifiers.length) >+ return std::nullopt; >+ >+ enum class ScrollingDirection : uint8_t { Up, Down, Left, Right }; >+ >+ auto computeOffset = ^(ScrollingIncrement increment, ScrollingDirection direction) { >+ bool isHorizontal = (direction == ScrollingDirection::Left || direction == ScrollingDirection::Right); >+ >+ CGFloat scrollDistance = [_scrollable distanceForScrollingIncrement:increment]; >+ >+ if (direction == ScrollingDirection::Up || direction == ScrollingDirection::Left) >+ scrollDistance = -scrollDistance; >+ >+ return (isHorizontal ? WebCore::FloatPoint(scrollDistance, 0) : WebCore::FloatPoint(0, scrollDistance)); >+ }; >+ >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputLeftArrow]) >+ return computeOffset(ScrollingIncrement::Line, ScrollingDirection::Left); >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputRightArrow]) >+ return computeOffset(ScrollingIncrement::Line, ScrollingDirection::Right); >+ >+ ScrollingIncrement incrementForVerticalArrowKey = ScrollingIncrement::Line; >+ if (event.modifierFlags & WebEventFlagMaskAlternate) >+ incrementForVerticalArrowKey = ScrollingIncrement::Page; >+ else if (event.modifierFlags & WebEventFlagMaskCommand) >+ incrementForVerticalArrowKey = ScrollingIncrement::Document; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputUpArrow]) >+ return computeOffset(incrementForVerticalArrowKey, ScrollingDirection::Up); >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputDownArrow]) >+ return computeOffset(incrementForVerticalArrowKey, ScrollingDirection::Down); >+ >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageDown]) >+ return computeOffset(ScrollingIncrement::Page, ScrollingDirection::Down); >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageUp]) >+ return computeOffset(ScrollingIncrement::Page, ScrollingDirection::Up); >+ >+ if ([charactersIgnoringModifiers characterAtIndex:0] == kWebSpaceKey) >+ return computeOffset(ScrollingIncrement::Page, (event.modifierFlags & WebEventFlagMaskShift) ? ScrollingDirection::Up : ScrollingDirection::Down); >+ >+ return std::nullopt; >+} >+ >+- (BOOL)beginWithEvent:(::WebEvent *)event >+{ >+ if (_state != KeyboardScrollingAnimatorState::WaitingForFirstEvent) >+ return NO; >+ >+ auto offset = [self _scrollOffsetForEvent:event]; >+ >+ if (!offset) >+ return NO; >+ >+ _state = KeyboardScrollingAnimatorState::WaitingForRepeat; >+ _scrollOffsetPerIncrement = *offset; >+ >+ // The first keyboard event that starts scrolling performs its own >+ // discrete animated scroll. Continuously animated scrolling starts >+ // when the key repeats. >+ [_scrollable scrollByContentOffset:_scrollOffsetPerIncrement animated:YES]; >+ >+ return YES; >+} >+ >+- (BOOL)handleKeyEvent:(::WebEvent *)event >+{ >+ if (_state == KeyboardScrollingAnimatorState::WaitingForFirstEvent) >+ return NO; >+ >+ auto offset = [self _scrollOffsetForEvent:event]; >+ if (!offset || offset != _scrollOffsetPerIncrement || event.type == WebEventKeyUp) { >+ [self stopAnimatedScroll]; >+ return NO; >+ } >+ >+ if (_state == KeyboardScrollingAnimatorState::WaitingForRepeat) >+ [self startAnimatedScroll]; >+ >+ return YES; >+} >+ >+- (void)startAnimatedScroll >+{ >+ ASSERT(!_displayLink); >+ >+ _state = KeyboardScrollingAnimatorState::Animating; >+ _startTime = CACurrentMediaTime(); >+ _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)]; >+ [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; >+} >+ >+- (void)stopAnimatedScroll >+{ >+ _state = KeyboardScrollingAnimatorState::WaitingForFirstEvent; >+ [_displayLink invalidate]; >+ _displayLink = nil; >+} >+ >+- (void)displayLinkFired:(CADisplayLink *)sender >+{ >+ const CFTimeInterval secondsPerScrollIncrement = 0.05; // Seconds it should take to cover one increment when at full speed. >+ const float maximumVelocity = 2000; // Maximum velocity in pixels per second. Empirically determined. >+ const float accelerationDuration = 0.3; // Duration of acceleration in seconds. This matches UIScrollView. >+ >+ auto velocity = _scrollOffsetPerIncrement.scaled(1. / secondsPerScrollIncrement); >+ velocity = velocity.constrainedBetween({ -maximumVelocity, -maximumVelocity }, { maximumVelocity, maximumVelocity }); >+ >+ CFTimeInterval frameDuration = sender.targetTimestamp - sender.timestamp; >+ CFTimeInterval timeFromAnimationStart = sender.timestamp - _startTime; >+ float accelerationFactor = [[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] _solveForInput:timeFromAnimationStart / accelerationDuration]; >+ >+ auto contentOffset = velocity.scaled(accelerationFactor * frameDuration); >+ [_scrollable scrollByContentOffset:contentOffset animated:NO]; >+} >+ >+@end >+ >+#endif // PLATFORM(IOS) >diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >index 6f86e045b576d1b626220f0959566399afbdb2e9..a2da24976da283e2117a308a3b52371e912bc878 100644 >--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj >+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >@@ -618,6 +618,7 @@ > 2D1087601D2C573E00B85F82 /* LoadParameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D10875E1D2C573E00B85F82 /* LoadParameters.cpp */; }; > 2D1087611D2C573E00B85F82 /* LoadParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D10875F1D2C573E00B85F82 /* LoadParameters.h */; }; > 2D1087631D2C641B00B85F82 /* LoadParametersCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D1087621D2C641B00B85F82 /* LoadParametersCocoa.mm */; }; >+ 2D11BD1F21125BE8009D99E3 /* WKKeyboardScrollingAnimator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DD5E126210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.mm */; }; > 2D125C5E1857EA05003BA3CB /* ViewGestureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D125C5C1857EA05003BA3CB /* ViewGestureController.h */; }; > 2D125C5F1857EA05003BA3CB /* ViewGestureControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */; }; > 2D12DAB520662C73006F00FB /* WKAnimationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D12DAB420662C73006F00FB /* WKAnimationDelegate.h */; }; >@@ -717,6 +718,7 @@ > 2DD45ADF1E5F8972006C355F /* InputViewUpdateDeferrer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DD45ADD1E5F8972006C355F /* InputViewUpdateDeferrer.mm */; }; > 2DD5A7291EBF08D5009BA597 /* VisibleWebPageCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD5A7281EBF08D5009BA597 /* VisibleWebPageCounter.h */; }; > 2DD5A72B1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */; }; >+ 2DD5E129210ADC7B00DB6012 /* WKKeyboardScrollingAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD5E127210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.h */; }; > 2DD67A2E1BD819730053B251 /* APIFindMatchesClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD67A2D1BD819730053B251 /* APIFindMatchesClient.h */; }; > 2DD67A351BD861060053B251 /* WKTextFinderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD67A331BD861060053B251 /* WKTextFinderClient.h */; }; > 2DD67A361BD861060053B251 /* WKTextFinderClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DD67A341BD861060053B251 /* WKTextFinderClient.mm */; }; >@@ -3190,6 +3192,8 @@ > 2DD45ADD1E5F8972006C355F /* InputViewUpdateDeferrer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InputViewUpdateDeferrer.mm; path = ios/InputViewUpdateDeferrer.mm; sourceTree = "<group>"; }; > 2DD5A7281EBF08D5009BA597 /* VisibleWebPageCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisibleWebPageCounter.h; sourceTree = "<group>"; }; > 2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HiddenPageThrottlingAutoIncreasesCounter.h; sourceTree = "<group>"; }; >+ 2DD5E126210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKKeyboardScrollingAnimator.mm; path = ios/WKKeyboardScrollingAnimator.mm; sourceTree = "<group>"; }; >+ 2DD5E127210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKKeyboardScrollingAnimator.h; path = ios/WKKeyboardScrollingAnimator.h; sourceTree = "<group>"; }; > 2DD67A2D1BD819730053B251 /* APIFindMatchesClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIFindMatchesClient.h; sourceTree = "<group>"; }; > 2DD67A331BD861060053B251 /* WKTextFinderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKTextFinderClient.h; sourceTree = "<group>"; }; > 2DD67A341BD861060053B251 /* WKTextFinderClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKTextFinderClient.mm; sourceTree = "<group>"; }; >@@ -5984,6 +5988,8 @@ > 0F3C7257196F5F5000AEDD0C /* WKInspectorHighlightView.mm */, > A54293A2195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.h */, > A54293A3195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.mm */, >+ 2DD5E127210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.h */, >+ 2DD5E126210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.mm */, > 2DA1E4FC18C02B6A00DBC929 /* WKLegacyPDFView.h */, > 2DA1E4FD18C02B6A00DBC929 /* WKLegacyPDFView.mm */, > A15EEDE41E301CEE000069B0 /* WKPasswordView.h */, >@@ -9789,6 +9795,7 @@ > 994BADF41F7D781400B571E7 /* WKInspectorViewController.h in Headers */, > A5C0F0AB2000658200536536 /* WKInspectorWindow.h in Headers */, > A518B5D21FE1D55B00F9FA28 /* WKInspectorWKWebView.h in Headers */, >+ 2DD5E129210ADC7B00DB6012 /* WKKeyboardScrollingAnimator.h in Headers */, > 51A9E10B1315CD18009E7031 /* WKKeyValueStorageManager.h in Headers */, > 2D790A9F1AD7164900AB90B3 /* WKLayoutMode.h in Headers */, > 2DA1E4FE18C02B6A00DBC929 /* WKLegacyPDFView.h in Headers */, >@@ -11633,6 +11640,7 @@ > 994BADF31F7D781100B571E7 /* WKInspectorViewController.mm in Sources */, > A5C0F0AC2000658500536536 /* WKInspectorWindow.mm in Sources */, > A518B5D31FE1D55B00F9FA28 /* WKInspectorWKWebView.mm in Sources */, >+ 2D11BD1F21125BE8009D99E3 /* WKKeyboardScrollingAnimator.mm in Sources */, > 51A9E10A1315CD18009E7031 /* WKKeyValueStorageManager.cpp in Sources */, > 2DA1E4FF18C02B6A00DBC929 /* WKLegacyPDFView.mm in Sources */, > C98C48A91B6FD5B500145103 /* WKMediaSessionFocusManager.cpp in Sources */,
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188239
:
346302
|
346304
|
346312
|
346313