WebKit Bugzilla
Attachment 346312 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-20180801162447.patch (text/plain), 32.15 KB, created by
Tim Horton
on 2018-08-01 16:24:47 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tim Horton
Created:
2018-08-01 16:24:47 PDT
Size:
32.15 KB
patch
obsolete
>Subversion Revision: 234460 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 7b97a4fcc8f735414c08c33fea1b3c86d16ced06..62fc974f08cb1c6bc78c2fe5c30840e349b152da 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 Simon Fraser. >+ >+ 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 non-scrolling keydown), 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/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..023ab010e3b9f4f316f73ad1195a498b33925ff1 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 NO; >+ >+ if (_assistedNodeInformation.elementType == InputType::Select) >+ return NO; >+ >+ return YES; >+} >+ >+- (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..960a85ab255c063c8427de376f73a676c310f255 >--- /dev/null >+++ b/Source/WebKit/UIProcess/ios/WKKeyboardScrollingAnimator.mm >@@ -0,0 +1,246 @@ >+/* >+ * 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 Direction : uint8_t { Up, Down, Left, Right }; >+ enum class Key : uint8_t { Other, LeftArrow, RightArrow, UpArrow, DownArrow, PageUp, PageDown, Space }; >+ >+ auto key = ^{ >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputLeftArrow]) >+ return Key::LeftArrow; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputRightArrow]) >+ return Key::RightArrow; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputUpArrow]) >+ return Key::UpArrow; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputDownArrow]) >+ return Key::DownArrow; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageDown]) >+ return Key::PageDown; >+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageUp]) >+ return Key::PageUp; >+ if ([charactersIgnoringModifiers characterAtIndex:0] == kWebSpaceKey) >+ return Key::Space; >+ return Key::Other; >+ }(); >+ >+ if (key == Key::Other) >+ return std::nullopt; >+ >+ BOOL shiftPressed = event.modifierFlags & WebEventFlagMaskShift; >+ BOOL altPressed = event.modifierFlags & WebEventFlagMaskAlternate; >+ BOOL cmdPressed = event.modifierFlags & WebEventFlagMaskCommand; >+ >+ auto increment = ^{ >+ switch (key) { >+ case Key::LeftArrow: >+ case Key::RightArrow: >+ return ScrollingIncrement::Line; >+ case Key::UpArrow: >+ case Key::DownArrow: >+ if (altPressed) >+ return ScrollingIncrement::Page; >+ if (cmdPressed) >+ return ScrollingIncrement::Document; >+ return ScrollingIncrement::Line; >+ case Key::PageUp: >+ case Key::PageDown: >+ case Key::Space: >+ return ScrollingIncrement::Page; >+ case Key::Other: >+ ASSERT_NOT_REACHED(); >+ return ScrollingIncrement::Line; >+ }; >+ }(); >+ >+ auto direction = ^() { >+ switch (key) { >+ case Key::LeftArrow: >+ return Direction::Left; >+ case Key::RightArrow: >+ return Direction::Right; >+ case Key::UpArrow: >+ case Key::PageUp: >+ return Direction::Up; >+ case Key::DownArrow: >+ case Key::PageDown: >+ return Direction::Down; >+ case Key::Space: >+ return shiftPressed ? Direction::Up : Direction::Down; >+ case Key::Other: >+ ASSERT_NOT_REACHED(); >+ return Direction::Down; >+ }; >+ }(); >+ >+ bool isHorizontal = direction == Direction::Left || direction == Direction::Right; >+ CGFloat scrollDistance = [_scrollable distanceForScrollingIncrement:increment]; >+ >+ if (direction == Direction::Up || direction == Direction::Left) >+ scrollDistance = -scrollDistance; >+ >+ return isHorizontal ? WebCore::FloatPoint(scrollDistance, 0) : WebCore::FloatPoint(0, scrollDistance); >+} >+ >+- (BOOL)beginWithEvent:(::WebEvent *)event >+{ >+ if (_state != KeyboardScrollingAnimatorState::WaitingForFirstEvent) >+ return NO; >+ >+ if (event.type != WebEventKeyDown) >+ return NO; >+ >+ auto offset = [self _scrollOffsetForEvent:event]; >+ if (!offset) >+ return NO; >+ >+ _state = KeyboardScrollingAnimatorState::WaitingForRepeat; >+ _scrollOffsetPerIncrement = offset.value(); >+ >+ // 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 || 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 CFTimeInterval 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:std::min<CFTimeInterval>(timeFromAnimationStart, accelerationDuration) / 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