[iOS] [WebKit2] Add support for honoring -[UIMenuItem dontDismiss]
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Apr 2019 03:34:10 +0000 (03:34 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Apr 2019 03:34:10 +0000 (03:34 +0000)
commit3ffc4050c32c125f1fc81a346cb2378368bd9441
tree5f30e3fce762fd17f7d69ebcb3f6c0784abcbc07
parent9b94df5d3cd08e18d98eecd6aac6d1743e3be33c
[iOS] [WebKit2] Add support for honoring -[UIMenuItem dontDismiss]
https://bugs.webkit.org/show_bug.cgi?id=196919
<rdar://problem/41630459>

Reviewed by Tim Horton.

Source/WebKit:

Adds modern WebKit support for -dontDismiss by implementing a couple of new platform hooks. Covered by a new
layout test: editing/selection/ios/selection-after-changing-text-with-callout-menu.html.

* Platform/spi/ios/UIKitSPI.h:

Declare the private -dontDismiss property of UIMenuItem.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView willFinishIgnoringCalloutBarFadeAfterPerformingAction]):

Additionally teach the web view (not just the content view) to respond to the hook. This matters in the case
where the WebKit client (most notably, Mail) overrides WKWebView methods to define custom actions in the menu
controller. This scenario is exercised by the new layout test.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView willFinishIgnoringCalloutBarFadeAfterPerformingAction]):

If an action was performed where callout bar fading was ignored, then in WebKit, don't allow selection changes
to fade the callout bar until after the next remote layer tree commit.

(-[WKContentView _updateChangedSelection:]):

Stop suppressing selection updates when showing B/I/U controls, now that we can properly honor the -dontDismiss
property. This was originally introduced in <rdar://problem/15199925>, presumably to ensure that B/I/U buttons
(which have -dontDismiss set to YES) don't trigger selection change and end up dismissing themselves; however,
if triggering B/I/U actually changes the selection rects, this also means that the selection rects on-screen
would be stale after triggering these actions. This effect is most noticeable when bolding text.

(-[WKContentView shouldAllowHidingSelectionCommands]):

Tools:

Add iOS support for several new testing hooks. See below for more detail.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::isDismissingMenu const):

Add a new script controller method to query whether the platform menu (on iOS, the callout bar) is done
dismissing. We consider the menu to be dismissing in between the `-WillHide` and `-DidHide` notifications sent
by UIKit when dismissing the callout bar (i.e. UIMenuController).

* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::isDismissingMenu const):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
(WTR::InjectedBundle::didReceiveMessageToPage):
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setAllowedMenuActions):

Add a new helper method to specify a list of allowed actions when bringing up the menu. On iOS, in the case of
actions supported by the platform, this matches against method selector names (for instance, "SelectAll", or
"Copy", or "Paste"). In the case of the custom actions installed via `installCustomMenuAction`, we instead match
against the name of the custom action.

(WTR::TestRunner::installCustomMenuAction):

Add a new helper method to install a custom action for the context menu (on iOS, this is the callout bar). This
takes the name of the action (which appears in a button in the callout bar), whether the action should cause
the callout bar to automatically dismiss, and finally, a JavaScript callback that is invoked when the action is
triggered.

(WTR::TestRunner::performCustomMenuAction):

Invoked when the custom menu action is triggered.

* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::installCustomMenuAction):
(WTR::TestController::setAllowedMenuActions):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
(WTR::TestInvocation::performCustomMenuAction):

Add plumbing to call back into the injected bundle when performing the custom action.

* WebKitTestRunner/TestInvocation.h:
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::installCustomMenuAction):
(WTR::TestController::setAllowedMenuActions):
* WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
* WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
(-[TestRunnerWKWebView initWithFrame:configuration:]):
(-[TestRunnerWKWebView becomeFirstResponder]):
(-[TestRunnerWKWebView _addCustomItemToMenuControllerIfNecessary]):

Helper method that converts web view's current custom menu action info into a UIMenuItem, and adds it to the
shared menu controller. This is also invoked when the web view becomes first responder, which matches behavior
in the Mail app on iOS.

(-[TestRunnerWKWebView installCustomMenuAction:dismissesAutomatically:callback:]):
(-[TestRunnerWKWebView setAllowedMenuActions:]):
(-[TestRunnerWKWebView resetCustomMenuAction]):
(-[TestRunnerWKWebView performCustomAction:]):
(-[TestRunnerWKWebView canPerformAction:withSender:]):
(-[TestRunnerWKWebView _willHideMenu]):
(-[TestRunnerWKWebView _didHideMenu]):
* WebKitTestRunner/ios/TestControllerIOS.mm:
(WTR::TestController::platformResetStateToConsistentValues):

Reset both any custom installed actions on the shared menu controller, as well as the list of allowed actions,
if specified.

* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::isDismissingMenu const):

LayoutTests:

Add a new iOS layout test that installs a custom, non-dismissing action in the callout menu that enlarges text.
The test then activates this custom menu item and checks that the selection rects after triggering this custom
action are updated, and the callout bar is still showing.

* editing/selection/ios/selection-after-changing-text-with-callout-menu-expected.txt: Added.
* editing/selection/ios/selection-after-changing-text-with-callout-menu.html: Added.

This test additionally suppresses all callout bar menu items except for the custom "Embiggen" action, to ensure
that the "Embiggen" option can be tapped from the layout test without having to navigate callout bar items by
tapping on the "Next" and "Show styles" buttons. This latter approach is very challenging to make reliable in
automation; when navigating submenus in the callout bar, the next button can't be tapped until the current
callout bar transition animation is complete, but there's no delegate method invoked or notification posted when
this happens.

* resources/ui-helper.js:
(window.UIHelper.isShowingMenu):
(window.UIHelper.isDismissingMenu):
(window.UIHelper.rectForMenuAction):
(window.UIHelper.async.chooseMenuAction):

Additionally add a few more UIHelper methods.

(window.UIHelper):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244370 268f45cc-cd09-0410-ab3c-d52691b4dbfc
27 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/selection/ios/selection-after-changing-text-with-callout-menu-expected.txt [new file with mode: 0644]
LayoutTests/editing/selection/ios/selection-after-changing-text-with-callout-menu.html [new file with mode: 0644]
LayoutTests/resources/ui-helper.js
Source/WebKit/ChangeLog
Source/WebKit/Platform/spi/ios/UIKitSPI.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h
Tools/WebKitTestRunner/TestInvocation.cpp
Tools/WebKitTestRunner/TestInvocation.h
Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm
Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.h
Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm
Tools/WebKitTestRunner/ios/TestControllerIOS.mm
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm