WebKit Bugzilla
Attachment 349354 Details for
Bug 189475
: [iOS] Unable to change the value of select elements while preserving focus state
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for landing
bug-189475-20180910163039.patch (text/plain), 26.61 KB, created by
Wenson Hsieh
on 2018-09-10 16:30:40 PDT
(
hide
)
Description:
Patch for landing
Filename:
MIME Type:
Creator:
Wenson Hsieh
Created:
2018-09-10 16:30:40 PDT
Size:
26.61 KB
patch
obsolete
>Subversion Revision: 235819 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 77cce9454dfedeb8ffede17a17161e0f1934a6b9..f077393d53dac11d48e59790f33c057d3f455d23 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,75 @@ >+2018-09-10 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [iOS] Unable to change the value of select elements while preserving focus state >+ https://bugs.webkit.org/show_bug.cgi?id=189475 >+ <rdar://problem/41125764> >+ >+ Reviewed by Tim Horton. >+ >+ With UITextInputMultiDocument support in WebKit (r226911), WKContentView may enter a state where the user is >+ able to interact with web content, but focus state is being preserved on WKWebView. This prevents keyboard and >+ input view dismissal from blurring the focused element (which, in turn, means that the value of certain form >+ controls, such as select elements, cannot be changed). This can happen in the following scenario: >+ >+ 1. Suppose we have a web view embedded inside of a view controller (let's call it `A`). >+ 2. Another view controller (let's call this one `B`) is modally presented over `A`. >+ 3. The web view is removed from `A`'s view hierarchy and reparented under `B`'s view. >+ 4. The user taps a form control in the web view, interacts with the keyboard, and taps the Done button. >+ >+ After step 2, WKContentView gets a call to `-_preserveFocusWithToken:destructively:`, which increments its focus >+ retain count to 1. Thus, in step 3, resigning first responder using the Done button fails to blur the element. >+ To fix this, we split the existing `_activeFocusedStateRetainCount` into two values: `_focusPreservationCount`, >+ which is safe to reset and resets to 0 when changing the focused element, and `_activeFocusedStateRetainCount`, >+ which always increments and decrements, and only does so when using `-_retainActiveFocusedState`. >+ >+ This also fixes a bug wherein `-_restoreFocusWithToken:` is implemented as returning `void` in WebKit, even >+ though its declaration in UIKit returns a `BOOL`. UIKit currently calls this selector on WKContentView and >+ stores the result within a `BOOL`; this results in the return value of `-_restoreFocusWithToken:` effectively >+ becoming the last byte of the most recent value stored in `$rax` when exiting `-_restoreFocusWithToken:`. From >+ debugging a release build of WebKit, this turns out to just be 0x0, becoming NO, which is correct given that >+ WKContentView does not attempt to become first responder within `_restoreFocusWithToken:`. >+ >+ Tests: FocusPreservationTests.PreserveAndRestoreFocus >+ FocusPreservationTests.ChangingFocusedNodeResetsFocusPreservationState >+ >+ * Platform/spi/ios/UIKitSPI.h: >+ * UIProcess/API/Cocoa/WKWebView.mm: >+ (-[WKWebView _incrementFocusPreservationCount]): >+ (-[WKWebView _decrementFocusPreservationCount]): >+ (-[WKWebView _resetFocusPreservationCount]): >+ (-[WKWebView _isRetainingActiveFocusedState]): >+ >+ Active focus state is retained if either the focus preservation count or active focus state count is non-zero. >+ Splitting this into two variables ensures that SPI clients of `-_retainActiveFocusedState` won't have active >+ focus state reset from underneath them, and additionally prevents WKContentView from retaining active focus due >+ to UITextInputMultiDocument protocol methods while the user is still interacting with it. >+ >+ * UIProcess/API/Cocoa/WKWebViewInternal.h: >+ >+ Move _activeFocusedStateRetainCount to the implementation of WKContentView; instead of directly manipulating the >+ variable, add helper methods to increment, decrement, or reset the focus preservation count. >+ >+ * UIProcess/ios/PageClientImplIOS.mm: >+ (WebKit::PageClientImpl::isViewWindowActive): >+ (WebKit::PageClientImpl::isViewFocused): >+ * UIProcess/ios/WKContentViewInteraction.h: >+ * UIProcess/ios/WKContentViewInteraction.mm: >+ (-[WKContentView resignFirstResponderForWebView]): >+ (-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:]): >+ >+ Reset the focus preservation count. >+ >+ (-[WKContentView addFocusedFormControlOverlay]): >+ (-[WKContentView removeFocusedFormControlOverlay]): >+ >+ Use `-_retainActiveFocusedState` instead of incrementing and decrementing the counter directly. >+ >+ (-[WKContentView _restoreFocusWithToken:]): >+ (-[WKContentView _preserveFocusWithToken:destructively:]): >+ >+ Use `_incrementFocusPreservationCount` and `_decrementFocusPreservationCount` instead of manipulating counter >+ variables directly. >+ > 2018-09-07 Brent Fulgham <bfulgham@apple.com> > > Allow WebContent access to AVCSupported IOKit property in sandbox >diff --git a/Source/WebKit/Platform/spi/ios/UIKitSPI.h b/Source/WebKit/Platform/spi/ios/UIKitSPI.h >index a8857abc35684f2213c66439d35344f36a87451e..5d663b5b9a0059b372c6340c35e32b9069c6c186 100644 >--- a/Source/WebKit/Platform/spi/ios/UIKitSPI.h >+++ b/Source/WebKit/Platform/spi/ios/UIKitSPI.h >@@ -1028,7 +1028,7 @@ typedef NSInteger UICompositingMode; > #else > @protocol UITextInputMultiDocument <NSObject> > @optional >-- (void)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token completion:(void (^)(BOOL didRestore))completion; >+- (BOOL)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token; > - (void)_preserveFocusWithToken:(id <NSCopying, NSSecureCoding>)token destructively:(BOOL)destructively; > @end > #endif >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >index 66c28ebffcd523b7045c15adb2754f42a0cd8243..d579f6c3357c0b7d3aea62ac4622aefbf896c3d0 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >@@ -359,6 +359,9 @@ static std::optional<WebCore::ScrollbarOverlayStyle> toCoreScrollbarStyle(_WKOve > // For release-logging for <rdar://problem/39281269>. > MonotonicTime _timeOfRequestForVisibleContentRectUpdate; > MonotonicTime _timeOfLastVisibleContentRectUpdate; >+ >+ NSUInteger _focusPreservationCount; >+ NSUInteger _activeFocusedStateRetainCount; > #endif > #if PLATFORM(MAC) > std::unique_ptr<WebKit::WebViewImpl> _impl; >@@ -433,6 +436,31 @@ static bool shouldAllowSettingAnyXHRHeaderFromFileURLs() > return shouldAllowSettingAnyXHRHeaderFromFileURLs; > } > >+- (void)_incrementFocusPreservationCount >+{ >+ ++_focusPreservationCount; >+} >+ >+- (void)_decrementFocusPreservationCount >+{ >+ if (_focusPreservationCount) >+ --_focusPreservationCount; >+} >+ >+- (void)_resetFocusPreservationCount >+{ >+ _focusPreservationCount = 0; >+} >+ >+- (BOOL)_isRetainingActiveFocusedState >+{ >+ // Focus preservation count fulfills the same role as active focus state count. >+ // However, unlike active focus state, it may be reset to 0 without impacting the >+ // behavior of -_retainActiveFocusedState, and it's harmless to invoke >+ // -_decrementFocusPreservationCount after resetting the count to 0. >+ return _focusPreservationCount || _activeFocusedStateRetainCount; >+} >+ > #endif > > static bool shouldRequireUserGestureToLoadVideo() >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >index 4f3abbcce58f84f3597c1e3ce3d7428349a0e9d4..74e9a2770ba27b98994471f40acad349b41eb845 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h >@@ -73,10 +73,6 @@ struct PrintInfo; > RetainPtr<WKWebViewConfiguration> _configuration; > > RefPtr<WebKit::WebPageProxy> _page; >- >-#if PLATFORM(IOS) >- NSUInteger _activeFocusedStateRetainCount; >-#endif > } > > #if PLATFORM(IOS) >@@ -142,6 +138,10 @@ struct PrintInfo; > - (void)_transliterateChinese:(id)sender; > - (void)replace:(id)sender; > >+- (void)_incrementFocusPreservationCount; >+- (void)_decrementFocusPreservationCount; >+- (void)_resetFocusPreservationCount; >+ > @property (nonatomic, readonly) WKPasswordView *_passwordView; > > @property (nonatomic, readonly) BOOL _isBackground; >@@ -154,6 +154,7 @@ struct PrintInfo; > @property (nonatomic, readonly) BOOL _haveSetObscuredInsets; > @property (nonatomic, readonly) UIEdgeInsets _computedObscuredInset; > @property (nonatomic, readonly) UIEdgeInsets _computedUnobscuredSafeAreaInset; >+@property (nonatomic, readonly, getter=_isRetainingActiveFocusedState) BOOL _retainingActiveFocusedState; > #endif > > #if ENABLE(ACCESSIBILITY_EVENTS) >diff --git a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >index d1cb445adaff1a59e2b2d6347842c42e7e4ebf84..0d32ee22f52f74a977ada047c6e6327d08649a97 100644 >--- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >+++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm >@@ -161,13 +161,13 @@ IntSize PageClientImpl::viewSize() > bool PageClientImpl::isViewWindowActive() > { > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098 >- return isViewVisible() || (m_webView && m_webView->_activeFocusedStateRetainCount); >+ return isViewVisible() || (m_webView && [m_webView _isRetainingActiveFocusedState]); > } > > bool PageClientImpl::isViewFocused() > { > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098 >- return isViewWindowActive() || (m_webView && m_webView->_activeFocusedStateRetainCount); >+ return isViewWindowActive() || (m_webView && [m_webView _isRetainingActiveFocusedState]); > } > > bool PageClientImpl::isViewVisible() >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >index 4cf49cc3c2e5b46a2c7476decba5b1d6abaed30f..d71562c55679e2311ccc7534b6abce90ca744749 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >@@ -277,6 +277,7 @@ struct WKAutoCorrectionData { > RetainPtr<UINavigationController> _inputNavigationViewControllerForFullScreenInputs; > > BOOL _shouldRestoreFirstResponderStatusAfterLosingFocus; >+ BlockPtr<void()> _activeFocusedStateRetainBlock; > #endif > } > >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >index 938d4a9df48915bc92ecf7f88bee52060b508f8d..878738bddd4fde8caed8f38a1bd76a8a5426e8ad 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >@@ -1011,7 +1011,7 @@ static inline bool hasAssistedNode(WebKit::AssistedNodeInformation assistedNodeI > // and do nothing if the return value is NO. > > _resigningFirstResponder = YES; >- if (!_webView->_activeFocusedStateRetainCount) { >+ if (!_webView._retainingActiveFocusedState) { > // We need to complete the editing operation before we blur the element. > [_inputPeripheral endEditing]; > [_formInputSession endEditing]; >@@ -4210,6 +4210,8 @@ static bool isAssistableInputType(InputType type) > if (_assistedNodeInformation.elementType == information.elementType && _assistedNodeInformation.elementRect == information.elementRect) > return; > >+ [_webView _resetFocusPreservationCount]; >+ > _focusRequiresStrongPasswordAssistance = NO; > if ([inputDelegate respondsToSelector:@selector(_webView:focusRequiresStrongPasswordAssistance:)]) > _focusRequiresStrongPasswordAssistance = [inputDelegate _webView:_webView focusRequiresStrongPasswordAssistance:focusedElementInfo.get()]; >@@ -4340,7 +4342,7 @@ static bool isAssistableInputType(InputType type) > if (_focusedFormControlView) > return; > >- ++_webView->_activeFocusedStateRetainCount; >+ _activeFocusedStateRetainBlock = makeBlockPtr(_webView._retainActiveFocusedState); > > _focusedFormControlView = adoptNS([[WKFocusedFormControlView alloc] initWithFrame:_webView.bounds delegate:self]); > [_focusedFormControlView hide:NO]; >@@ -4353,7 +4355,8 @@ static bool isAssistableInputType(InputType type) > if (!_focusedFormControlView) > return; > >- --_webView->_activeFocusedStateRetainCount; >+ if (auto releaseActiveFocusState = WTFMove(_activeFocusedStateRetainBlock)) >+ releaseActiveFocusState(); > > [_focusedFormControlView removeFromSuperview]; > _focusedFormControlView = nil; >@@ -4760,20 +4763,26 @@ static bool isAssistableInputType(InputType type) > > #pragma mark - UITextInputMultiDocument > >-- (void)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token >+- (BOOL)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token > { >- ASSERT(!_focusStateStack.isEmpty()); >- >- if (_focusStateStack.takeLast()) { >- ASSERT(_webView->_activeFocusedStateRetainCount); >- --_webView->_activeFocusedStateRetainCount; >+ if (_focusStateStack.isEmpty()) { >+ ASSERT_NOT_REACHED(); >+ return NO; > } >+ >+ if (_focusStateStack.takeLast()) >+ [_webView _decrementFocusPreservationCount]; >+ >+ // FIXME: Our current behavior in -_restoreFocusWithToken: does not force the web view to become first responder >+ // by refocusing the currently focused element. As such, we return NO here so that UIKit will tell WKContentView >+ // to become first responder in the future. >+ return NO; > } > > - (void)_preserveFocusWithToken:(id <NSCopying, NSSecureCoding>)token destructively:(BOOL)destructively > { > if (!_inputPeripheral) { >- ++_webView->_activeFocusedStateRetainCount; >+ [_webView _incrementFocusPreservationCount]; > _focusStateStack.append(true); > } else > _focusStateStack.append(false); >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index b0f05d58c95bc861d05364781669cca3680c8220..8ad3f01c9711569e14d452dea19c6599008f1542 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,24 @@ >+2018-09-10 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ [iOS] Unable to change the value of select elements while preserving focus state >+ https://bugs.webkit.org/show_bug.cgi?id=189475 >+ <rdar://problem/41125764> >+ >+ Reviewed by Tim Horton. >+ >+ Adds a pair of new API tests to verify that (1) resigning first responder while preserving focus does not blur >+ the focused element, and (2) if another element is focused and presents an input view while preserving focus, >+ then we reset preservation state and allow first responder resignation to blur the focused element. >+ >+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: >+ * TestWebKitAPI/Tests/ios/FocusPreservationTests.mm: Added. >+ (webViewForTestingFocusPreservation): >+ (TestWebKitAPI::TEST): >+ * TestWebKitAPI/cocoa/TestWKWebView.h: >+ * TestWebKitAPI/cocoa/TestWKWebView.mm: >+ (-[TestWKWebView textInputContentView]): >+ * TestWebKitAPI/ios/UIKitSPI.h: >+ > 2018-09-07 Daniel Bates <dabates@apple.com> > > [iOS] uiController.typeCharacterUsingHardwareKeyboard("`", ...) dispatches DOM key events for ~ >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 4cb5ecca4c4a7190cd1e34eac6f1441c9b7d15c4..716b3c8f677c50165e5acdc64a5faa59b9ac2df7 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -833,6 +833,7 @@ > F4AB578A1F65165400DB0DA1 /* custom-draggable-div.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */; }; > F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4B825D61EF4DBD4006E417F /* compressed-files.zip */; }; > F4B86D4F20BCD5B20099A7E6 /* paint-significant-area-milestone.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4B86D4E20BCD5970099A7E6 /* paint-significant-area-milestone.html */; }; >+ F4BC0B142146C849002A0478 /* FocusPreservationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BC0B132146C849002A0478 /* FocusPreservationTests.mm */; }; > F4BFA68E1E4AD08000154298 /* LegacyDragAndDropTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BFA68C1E4AD08000154298 /* LegacyDragAndDropTests.mm */; }; > F4C2AB221DD6D95E00E06D5B /* enormous-video-with-sound.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */; }; > F4C8797F2059D8D3009CD00B /* ScrollViewInsetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */; }; >@@ -2085,6 +2086,7 @@ > F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "custom-draggable-div.html"; sourceTree = "<group>"; }; > F4B825D61EF4DBD4006E417F /* compressed-files.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "compressed-files.zip"; sourceTree = "<group>"; }; > F4B86D4E20BCD5970099A7E6 /* paint-significant-area-milestone.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "paint-significant-area-milestone.html"; sourceTree = "<group>"; }; >+ F4BC0B132146C849002A0478 /* FocusPreservationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FocusPreservationTests.mm; sourceTree = "<group>"; }; > F4BFA68C1E4AD08000154298 /* LegacyDragAndDropTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LegacyDragAndDropTests.mm; sourceTree = "<group>"; }; > F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "enormous-video-with-sound.html"; sourceTree = "<group>"; }; > F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewInsetTests.mm; sourceTree = "<group>"; }; >@@ -2545,6 +2547,7 @@ > 2E205BA31F527746005952DD /* AccessibilityTestsIOS.mm */, > F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */, > F4D4F3B71E4E36E400BB2767 /* DragAndDropTestsIOS.mm */, >+ F4BC0B132146C849002A0478 /* FocusPreservationTests.mm */, > F45E15722112CE2900307E82 /* KeyboardInputTestsIOS.mm */, > 574F55CE204D3763002948C6 /* LocalAuthenticator.mm */, > 7560917719259C59009EF06E /* MemoryCacheAddImageToCacheIOS.mm */, >@@ -3781,6 +3784,7 @@ > 7A909A7E1D877480007E10F8 /* FloatPoint.cpp in Sources */, > 7A909A7F1D877480007E10F8 /* FloatRect.cpp in Sources */, > 7A909A801D877480007E10F8 /* FloatSize.cpp in Sources */, >+ F4BC0B142146C849002A0478 /* FocusPreservationTests.mm in Sources */, > 1CAD1F861E5CE7DA00AF2C2C /* FontCache.cpp in Sources */, > F456AB1C213EDBA300CB2CEF /* FontManagerTests.mm in Sources */, > 7CCE7EF51A411AE600447C4C /* ForceRepaint.cpp in Sources */, >diff --git a/Tools/TestWebKitAPI/Tests/ios/FocusPreservationTests.mm b/Tools/TestWebKitAPI/Tests/ios/FocusPreservationTests.mm >new file mode 100644 >index 0000000000000000000000000000000000000000..5a17bcd2542e661fc91209076df0f8770975a801 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/ios/FocusPreservationTests.mm >@@ -0,0 +1,108 @@ >+/* >+ * 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 "Test.h" >+ >+#if PLATFORM(IOS) >+ >+#import "PlatformUtilities.h" >+#import "TestInputDelegate.h" >+#import "TestWKWebView.h" >+#import "UIKitSPI.h" >+#import <WebKit/WKWebViewPrivate.h> >+#import <WebKit/_WKInputDelegate.h> >+#import <wtf/BlockPtr.h> >+ >+static std::pair<RetainPtr<TestWKWebView>, RetainPtr<TestInputDelegate>> webViewForTestingFocusPreservation(void(^focusHandler)(id <_WKFocusedElementInfo>)) >+{ >+ auto inputDelegate = adoptNS([[TestInputDelegate alloc] init]); >+ [inputDelegate setFocusStartsInputSessionPolicyHandler:[&, focusHandler = makeBlockPtr(focusHandler)] (WKWebView *, id<_WKFocusedElementInfo> info) { >+ focusHandler(info); >+ return _WKFocusStartsInputSessionPolicyAllow; >+ }]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]); >+ [webView _setInputDelegate:inputDelegate.get()]; >+ [webView synchronouslyLoadHTMLString:@"<input></input><select><option selected>foo</option><option>bar</option></select>"]; >+ return { webView, inputDelegate }; >+} >+ >+namespace TestWebKitAPI { >+ >+TEST(FocusPreservationTests, PreserveAndRestoreFocus) >+{ >+ bool inputFocused = false; >+ auto webViewAndDelegate = webViewForTestingFocusPreservation([&inputFocused] (id <_WKFocusedElementInfo> info) { >+ inputFocused = true; >+ }); >+ >+ TestWKWebView *webView = webViewAndDelegate.first.get(); >+ [webView evaluateJavaScript:@"document.querySelector('input').focus()" completionHandler:nil]; >+ Util::run(&inputFocused); >+ >+ NSUUID *focusToken = NSUUID.UUID; >+ [webView.textInputContentView _preserveFocusWithToken:focusToken destructively:YES]; >+ >+ EXPECT_TRUE([webView resignFirstResponder]); >+ EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"document.activeElement == document.querySelector('input')"].boolValue); >+ >+ [webView.textInputContentView _restoreFocusWithToken:focusToken]; >+ EXPECT_TRUE([webView becomeFirstResponder]); >+} >+ >+TEST(FocusPreservationTests, ChangingFocusedNodeResetsFocusPreservationState) >+{ >+ bool inputFocused = false; >+ bool selectFocused = false; >+ auto webViewAndDelegate = webViewForTestingFocusPreservation([&inputFocused, &selectFocused] (id <_WKFocusedElementInfo> info) { >+ if (info.type == WKInputTypeSelect) >+ selectFocused = true; >+ else >+ inputFocused = true; >+ }); >+ >+ TestWKWebView *webView = webViewAndDelegate.first.get(); >+ [webView evaluateJavaScript:@"document.querySelector('input').focus()" completionHandler:nil]; >+ Util::run(&inputFocused); >+ >+ NSUUID *focusToken = NSUUID.UUID; >+ [webView.textInputContentView _preserveFocusWithToken:focusToken destructively:YES]; >+ >+ [webView evaluateJavaScript:@"document.querySelector('select').focus()" completionHandler:nil]; >+ Util::run(&selectFocused); >+ >+ EXPECT_NOT_NULL(webView.textInputContentView.inputView); >+ [webView selectFormAccessoryPickerRow:1]; >+ EXPECT_TRUE([webView resignFirstResponder]); >+ EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"document.activeElement == document.querySelector('select')"].boolValue); >+ EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"document.querySelector('select').selectedIndex"].intValue); >+ >+ [webView.textInputContentView _restoreFocusWithToken:focusToken]; >+} >+ >+} // namespace TestWebKitAPI >+ >+#endif // PLATFORM(IOS) >diff --git a/Tools/TestWebKitAPI/cocoa/TestWKWebView.h b/Tools/TestWebKitAPI/cocoa/TestWKWebView.h >index 5f169d9b4d74da5713e3ea3c8185a2a72a8ad591..96cc8d5261c9845dfc82c251ccac824f2cdb1abc 100644 >--- a/Tools/TestWebKitAPI/cocoa/TestWKWebView.h >+++ b/Tools/TestWebKitAPI/cocoa/TestWKWebView.h >@@ -32,6 +32,7 @@ > > #if PLATFORM(IOS) > @class _WKActivatedElementInfo; >+@protocol UITextInputMultiDocument; > #endif > > @interface WKWebView (AdditionalDeclarations) >@@ -63,7 +64,7 @@ > > #if PLATFORM(IOS) > @interface TestWKWebView (IOSOnly) >-@property (nonatomic, readonly) UIView <UITextInput> *textInputContentView; >+@property (nonatomic, readonly) UIView <UITextInput, UITextInputMultiDocument> *textInputContentView; > @property (nonatomic, readonly) RetainPtr<NSArray> selectionRectsAfterPresentationUpdate; > @property (nonatomic, readonly) CGRect caretViewRectInContentCoordinates; > @property (nonatomic, readonly) NSArray<NSValue *> *selectionViewRectsInContentCoordinates; >diff --git a/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm b/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm >index 5f2ca53bd0629c1dff2cc408f1f52b29b9dcee1e..add013f32868506929216fea485d84fc5eed8138 100644 >--- a/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm >+++ b/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm >@@ -45,7 +45,7 @@ > #endif > > #if PLATFORM(IOS) >-#import <UIKit/UIKit.h> >+#import "UIKitSPI.h" > #import <wtf/SoftLinking.h> > SOFT_LINK_FRAMEWORK(UIKit) > SOFT_LINK_CLASS(UIKit, UIWindow) >@@ -321,9 +321,9 @@ NSEventMask __simulated_forceClickAssociatedEventsMask(id self, SEL _cmd) > > @implementation TestWKWebView (IOSOnly) > >-- (UIView <UITextInput> *)textInputContentView >+- (UIView <UITextInput, UITextInputMultiDocument> *)textInputContentView > { >- return (UIView <UITextInput> *)[self valueForKey:@"_currentContentView"]; >+ return (UIView <UITextInput, UITextInputMultiDocument> *)[self valueForKey:@"_currentContentView"]; > } > > - (RetainPtr<NSArray>)selectionRectsAfterPresentationUpdate >diff --git a/Tools/TestWebKitAPI/ios/UIKitSPI.h b/Tools/TestWebKitAPI/ios/UIKitSPI.h >index 522880407803afc7f04b22e3fc5006e1c2ca13ba..6bd3cb6927eee9d5215100ba5fe3fdadc881d3c9 100644 >--- a/Tools/TestWebKitAPI/ios/UIKitSPI.h >+++ b/Tools/TestWebKitAPI/ios/UIKitSPI.h >@@ -31,6 +31,7 @@ > > #import <UIKit/UIApplication_Private.h> > #import <UIKit/UIResponder_Private.h> >+#import <UIKit/UITextInputMultiDocument.h> > #import <UIKit/UITextInputTraits_Private.h> > #import <UIKit/UITextInput_Private.h> > #import <UIKit/UIViewController_Private.h> >@@ -79,6 +80,12 @@ WTF_EXTERN_C_END > - (void)handleKeyWebEvent:(WebEvent *)theEvent withCompletionHandler:(void (^)(WebEvent *, BOOL))completionHandler; > @end > >+@protocol UITextInputMultiDocument <NSObject> >+@optional >+- (void)_preserveFocusWithToken:(id <NSCopying, NSSecureCoding>)token destructively:(BOOL)destructively; >+- (BOOL)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token; >+@end >+ > #if ENABLE(DRAG_SUPPORT) > > @interface NSURL ()
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 189475
:
349332
| 349354