Make scrolling to the focused element async
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jan 2018 05:03:37 +0000 (05:03 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jan 2018 05:03:37 +0000 (05:03 +0000)
commitb99299602adeff35ff38a5700d7104c3daee509b
treebdfe8e951ebf790692cb61e5e53ffbe35a7369b4
parent7206e7938c0fc790b945d532c7901fc07ae431d0
Make scrolling to the focused element async
https://bugs.webkit.org/show_bug.cgi?id=181575
<rdar://problem/36459767>

Reviewed by Simon Fraser.

Source/WebCore:

Made the revealing of the focused element asynchronous in Element::focus. Like selection, schedule a timer when
a new element is focused, and only scroll to the focused element when the timer fires. If any other scrolling
happens meanwhile, we cancel this timer.

There are two Web exposed behavioral changes:
1. The scrolling position doesn't change immediately when calling Element::focus.
2. Only the last focused element will be revealed.

Both behavioral changes pose its own compatibility risks but we're making a conscious decision here since
the scrolling asynchronous has a clear performance benefit.

There is one edge case to cosnider: when the history controller restores the scrolling position, canceling the
timer results in a focused element in an overflow: hidden element to be never revealed. Expediate revealing of
the focused element in this one case instead of canceling.

Tests: fast/scrolling/scroll-to-focused-element-asynchronously.html
       fast/scrolling/scroll-to-focused-element-canceled-by-fragment-navigation.html

* dom/Element.cpp:
(WebCore::Element::focus): Call updateFocusAppearance on focusAppearanceUpdateTarget to handle HTMLAreaElement
which delegates the focus appearance update to its image element.
(WebCore::Element::focusAppearanceUpdateTarget): Extracted. Returns "this" element for all but HTMLAreaElement.
(WebCore::Element::updateFocusAppearance): Schedule the revealing of the focused element in FrameView instead of
synchronously scrolling to the focused element.
* dom/Element.h:
(WebCore::Element::defaultFocusTextStateChangeIntent):
* html/HTMLAreaElement.cpp:
(WebCore::HTMLAreaElement::focusAppearanceUpdateTarget): Extracted from updateFocusAppearance.
(WebCore::HTMLAreaElement::updateFocusAppearance): Deleted.
* html/HTMLAreaElement.h:
* loader/HistoryController.cpp:
(WebCore::HistoryController::restoreScrollPositionAndViewState): Reveal the focused element
prior to restoring the scrolling location of the fragment navigation. This is needed to reveal a focused element
inside overflow: hidden element which got focused.
* page/FrameView.cpp:
(WebCore::FrameView::FrameView): Added a boolean flag and a timer for scrolling to the focused element.
(WebCore::FrameView::reset): Stop the timer and clear the flag.
(WebCore::FrameView::maintainScrollPositionAtAnchor): Ditto when scrolling to an anchor.
(WebCore::FrameView::setScrollPosition): Ditto when some other programatic scroll or the user scrolls the view.
(WebCore::FrameView::scheduleScrollToFocusedElement): Added.
(WebCore::FrameView::scrollToFocusedElementImmediatelyIfNeeded): Added.
(WebCore::FrameView::scrollToFocusedElementTimerFired): Added.
(WebCore::FrameView::scrollToAnchor): Stop the timer and clear the flag when scrolling to an achor.
(WebCore::FrameView::setWasScrolledByUser): Ditto when the user scrolls.
* page/FrameView.h:

LayoutTests:

Updated the tests per the behavioral change and added two more tests for scrolling to the focused element.

* accessibility/mac/webkit-scrollarea-position.html: Wait for the focus scrolling to take effect.
* fast/events/reveal-link-when-focused.html: Ditto.
* fast/images/imagemap-scroll.html: Ditto.
* fast/overflow/scroll-nested-positioned-layer-in-overflow.html: Ditto.
* fast/overflow/scrollRevealButton.html: Ditto.
* fast/transforms/scrollIntoView-transformed.html: Ditto. We need to focus each element in a seperate task
since only the last focused element will be revealed otherwise.
* fast/scrolling/scroll-to-focused-element-asynchronously-expected.txt: Added.
* fast/scrolling/scroll-to-focused-element-asynchronously.html: Added.
* fast/scrolling/scroll-to-focused-element-canceled-by-fragment-navigation-expected.txt: Added.
* fast/scrolling/scroll-to-focused-element-canceled-by-fragment-navigation.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227664 268f45cc-cd09-0410-ab3c-d52691b4dbfc
19 files changed:
LayoutTests/ChangeLog
LayoutTests/accessibility/mac/webkit-scrollarea-position.html
LayoutTests/fast/events/reveal-link-when-focused.html
LayoutTests/fast/images/imagemap-scroll.html
LayoutTests/fast/overflow/scroll-nested-positioned-layer-in-overflow.html
LayoutTests/fast/overflow/scrollRevealButton.html
LayoutTests/fast/scrolling/scroll-to-focused-element-asynchronously-expected.txt [new file with mode: 0644]
LayoutTests/fast/scrolling/scroll-to-focused-element-asynchronously.html [new file with mode: 0644]
LayoutTests/fast/scrolling/scroll-to-focused-element-canceled-by-fragment-navigation-expected.txt [new file with mode: 0644]
LayoutTests/fast/scrolling/scroll-to-focused-element-canceled-by-fragment-navigation.html [new file with mode: 0644]
LayoutTests/fast/transforms/scrollIntoView-transformed.html
Source/WebCore/ChangeLog
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/html/HTMLAreaElement.cpp
Source/WebCore/html/HTMLAreaElement.h
Source/WebCore/loader/HistoryController.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h