WKWebView Find-in-page API.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Nov 2019 04:06:58 +0000 (04:06 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Nov 2019 04:06:58 +0000 (04:06 +0000)
<rdar://problem/46971112> and https://bugs.webkit.org/show_bug.cgi?id=203872

Reviewed by Tim Horton.

Source/WebKit:

Covered by API tests.

- Promote _findString:
- Add a completion handler for it.

* SourcesCocoa.txt:

* UIProcess/API/Cocoa/WKFindConfiguration.h: Added.
* UIProcess/API/Cocoa/WKFindConfiguration.mm: Added.
(-[WKFindConfiguration init]):
(-[WKFindConfiguration copyWithZone:]):

* UIProcess/API/Cocoa/WKFindResult.h: Added.
* UIProcess/API/Cocoa/WKFindResult.mm: Added.
(-[WKFindResult init]):
(-[WKFindResult _initWithMatchFound:]):
(-[WKFindResult copyWithZone:]):
* UIProcess/API/Cocoa/WKFindResultInternal.h: Added.

* UIProcess/API/Cocoa/WKWebView.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(toFindOptions):
(-[WKWebView findString:withConfiguration:completionHandler:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:

* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:

* UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h:
* UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm:

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::findString):
(WebKit::WebPageProxy::findStringCallback):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:

* WebKit.xcodeproj/project.pbxproj:

* WebProcess/WebPage/FindController.cpp:
(WebKit::FindController::findString):
* WebProcess/WebPage/FindController.h:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::findString):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/FindInPageAPI.mm: Added.
(TEST):
* TestWebKitAPI/cocoa/TestWKWebView.h:
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[TestWKWebView selectionRangeHasStartOffset:endOffset:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252303 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
Source/WebKit/ChangeLog
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.mm [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/WKFindResult.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/WKFindResult.mm [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/WKFindResultInternal.h [new file with mode: 0644]
Source/WebKit/UIProcess/API/Cocoa/WKWebView.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h
Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/WebPage/FindController.cpp
Source/WebKit/WebProcess/WebPage/FindController.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPageAPI.mm [new file with mode: 0644]
Tools/TestWebKitAPI/cocoa/TestWKWebView.h
Tools/TestWebKitAPI/cocoa/TestWKWebView.mm

index 486af35..be01b4c 100644 (file)
@@ -1,3 +1,57 @@
+2019-11-08  Brady Eidson  <beidson@apple.com>
+
+        WKWebView Find-in-page API.
+        <rdar://problem/46971112> and https://bugs.webkit.org/show_bug.cgi?id=203872
+
+        Reviewed by Tim Horton.
+
+        Covered by API tests.
+
+        - Promote _findString:
+        - Add a completion handler for it.
+
+        * SourcesCocoa.txt:
+        
+        * UIProcess/API/Cocoa/WKFindConfiguration.h: Added.
+        * UIProcess/API/Cocoa/WKFindConfiguration.mm: Added.
+        (-[WKFindConfiguration init]):
+        (-[WKFindConfiguration copyWithZone:]):
+
+        * UIProcess/API/Cocoa/WKFindResult.h: Added.
+        * UIProcess/API/Cocoa/WKFindResult.mm: Added.
+        (-[WKFindResult init]):
+        (-[WKFindResult _initWithMatchFound:]):
+        (-[WKFindResult copyWithZone:]):
+        * UIProcess/API/Cocoa/WKFindResultInternal.h: Added.
+
+        * UIProcess/API/Cocoa/WKWebView.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (toFindOptions):
+        (-[WKWebView findString:withConfiguration:completionHandler:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+
+        * UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h:
+        * UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm:
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::findString):
+        (WebKit::WebPageProxy::findStringCallback):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+
+        * WebKit.xcodeproj/project.pbxproj:
+
+        * WebProcess/WebPage/FindController.cpp:
+        (WebKit::FindController::findString):
+        * WebProcess/WebPage/FindController.h:
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::findString):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2019-11-08  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthn] Add quirk needed to support legacy Google NFC Titan security keys
index b077542..63c4dfa 100644 (file)
@@ -290,6 +290,8 @@ UIProcess/API/Cocoa/WKContentRuleList.mm
 UIProcess/API/Cocoa/WKContentRuleListStore.mm
 UIProcess/API/Cocoa/WKContextMenuElementInfo.mm
 UIProcess/API/Cocoa/WKError.mm
+UIProcess/API/Cocoa/WKFindConfiguration.mm
+UIProcess/API/Cocoa/WKFindResult.mm
 UIProcess/API/Cocoa/WKFrameInfo.mm
 UIProcess/API/Cocoa/WKHTTPCookieStore.mm
 UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.h
new file mode 100644 (file)
index 0000000..0b20239
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+* Copyright (C) 2019 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 <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
+@interface WKFindConfiguration : NSObject <NSCopying>
+
+/* @abstract The direction to search from the current selection
+ @discussion The search will respect the writing direction of the document.
+ The initial value is NO.
+*/
+@property (nonatomic) BOOL backwards;
+
+/* @abstract Whether or not the search should be case sensitive
+ @discussion The initial value is NO.
+*/
+@property (nonatomic) BOOL caseSensitive;
+
+/* @abstract Whether the search should start at the beginning of the document once it reaches the end
+ @discussion The initial value is YES.
+*/
+@property (nonatomic) BOOL wraps;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/WKFindConfiguration.mm
new file mode 100644 (file)
index 0000000..016bd72
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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 "WKFindConfiguration.h"
+
+@implementation WKFindConfiguration
+
+- (instancetype)init
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _backwards = NO;
+    _caseSensitive = NO;
+    _wraps = YES;
+    return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    WKFindConfiguration *findConfiguration = [(WKFindConfiguration *)[[self class] allocWithZone:zone] init];
+
+    findConfiguration.backwards = _backwards;
+    findConfiguration.caseSensitive = _caseSensitive;
+    findConfiguration.wraps = _wraps;
+
+    return findConfiguration;
+}
+
+@end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKFindResult.h b/Source/WebKit/UIProcess/API/Cocoa/WKFindResult.h
new file mode 100644 (file)
index 0000000..9ee1a4f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+* Copyright (C) 2019 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 <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
+@interface WKFindResult : NSObject <NSCopying>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/* @abstract Whether or not a match was found during the find operation */
+@property (nonatomic, readonly) BOOL matchFound;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKFindResult.mm b/Source/WebKit/UIProcess/API/Cocoa/WKFindResult.mm
new file mode 100644 (file)
index 0000000..36ede9d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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 "WKFindResultInternal.h"
+
+@implementation WKFindResult
+
+- (instancetype)init
+{
+    return nil;
+}
+
+- (instancetype)_initWithMatchFound:(BOOL)matchFound
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _matchFound = matchFound;
+
+    return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    WKFindResult *findResult = [(WKFindResult *)[[self class] allocWithZone:zone] _initWithMatchFound:_matchFound];
+
+    return findResult;
+}
+
+@end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKFindResultInternal.h b/Source/WebKit/UIProcess/API/Cocoa/WKFindResultInternal.h
new file mode 100644 (file)
index 0000000..b028d7b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+* Copyright (C) 2019 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 "WKFindResult.h"
+
+@interface WKFindResult ()
+
+- (instancetype)_initWithMatchFound:(BOOL)matchFound;
+
+@end
index dd6f87b..46d324f 100644 (file)
@@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @class WKBackForwardList;
 @class WKBackForwardListItem;
+@class WKFindConfiguration;
+@class WKFindResult;
 @class WKNavigation;
 @class WKPDFConfiguration;
 @class WKSnapshotConfiguration;
@@ -303,6 +305,16 @@ The uniform type identifier kUTTypeWebArchive can be used get the related pasteb
 */
 @property (nonatomic) CGFloat pageZoom WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+/* @abstract Searches the page contents for the given string.
+ @param string The string to search for.
+ @param configuration A set of options configuring the search.
+ @param completionHandler A block to invoke when the search completes.
+ @discussion If the WKFindConfiguration is nil, all of the default WKFindConfiguration values will be used.
+  A match found by the search is selected and the page is scrolled to reveal the selection.
+  The completion handler is called after the search completes.
+*/
+- (void)findString:(NSString *)string withConfiguration:(nullable WKFindConfiguration *)configuration completionHandler:(void (^)(WKFindResult *result))completionHandler NS_REFINED_FOR_SWIFT WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 /* @abstract Checks whether or not WKWebViews handle the given URL scheme by default.
  @param scheme The URL scheme to check.
  */
@@ -351,6 +363,10 @@ The uniform type identifier kUTTypeWebArchive can be used get the related pasteb
 
 @end
 
+WK_API_AVAILABLE(macos(WK_MAC_TBA))
+@interface WKWebView (WKNSTextFinderClient) <NSTextFinderClient>
+@end
+
 #endif
 
 @interface WKWebView (WKDeprecated)
index 0cc1c86..500db5c 100644 (file)
@@ -59,6 +59,8 @@
 #import "WKBackForwardListItemInternal.h"
 #import "WKBrowsingContextHandleInternal.h"
 #import "WKErrorInternal.h"
+#import "WKFindConfiguration.h"
+#import "WKFindResultInternal.h"
 #import "WKHistoryDelegatePrivate.h"
 #import "WKLayoutMode.h"
 #import "WKNSData.h"
@@ -4746,6 +4748,32 @@ ALLOW_DEPRECATED_IMPLEMENTATIONS_END
     });
 }
 
+inline WebKit::FindOptions toFindOptions(WKFindConfiguration *configuration)
+{
+    unsigned findOptions = 0;
+
+    if (!configuration.caseSensitive)
+        findOptions |= WebKit::FindOptionsCaseInsensitive;
+    if (configuration.backwards)
+        findOptions |= WebKit::FindOptionsBackwards;
+    if (configuration.wraps)
+        findOptions |= WebKit::FindOptionsWrapAround;
+
+    return static_cast<WebKit::FindOptions>(findOptions);
+}
+
+- (void)findString:(NSString *)string withConfiguration:(WKFindConfiguration *)configuration completionHandler:(void (^)(WKFindResult *result))completionHandler
+{
+    if (!string.length) {
+        completionHandler([[[WKFindResult alloc] _initWithMatchFound:NO] autorelease]);
+        return;
+    }
+
+    _page->findString(string, toFindOptions(configuration), 1, [handler = makeBlockPtr(completionHandler)](bool found, WebKit::CallbackBase::Error error) {
+        handler([[[WKFindResult alloc] _initWithMatchFound:(error == WebKit::CallbackBase::Error::None && found)] autorelease]);
+    });
+}
+
 @end
 
 @implementation WKWebView (WKPrivate)
index 72944d5..2f0d5bd 100644 (file)
@@ -37,6 +37,7 @@
 #import "WKWebView.h"
 #import "WKWebViewContentProviderRegistry.h"
 #import "WebKit2Initialize.h"
+#import "WebPreferencesDefaultValues.h"
 #import "WebURLSchemeHandlerCocoa.h"
 #import "_WKApplicationManifestInternal.h"
 #import "_WKVisitedLinkStore.h"
index 2d3b9ef..fd91910 100644 (file)
@@ -450,11 +450,6 @@ typedef NS_OPTIONS(NSUInteger, _WKRectEdge) {
 @interface WKWebView () <UIResponderStandardEditActions>
 @end
 
-#else
-
-@interface WKWebView (WKNSTextFinderClient) <NSTextFinderClient>
-@end
-
 #endif
 
 @interface WKWebView (WKTesting)
index b6694fe..454c61f 100644 (file)
@@ -28,6 +28,7 @@
 #if HAVE(APP_SSO)
 
 #include "SOAuthorizationSession.h"
+#include <wtf/CompletionHandler.h>
 
 OBJC_CLASS WKSOSecretDelegate;
 OBJC_CLASS WKWebView;
index 076cfaa..0f18038 100644 (file)
@@ -33,6 +33,7 @@
 #import "WKUIDelegate.h"
 #import "WKWebViewConfigurationPrivate.h"
 #import "WKWebViewInternal.h"
+#import "WebPageProxy.h"
 #import <WebCore/ResourceResponse.h>
 #import <wtf/BlockPtr.h>
 
index 8ec8fae..fd9d354 100644 (file)
@@ -3699,9 +3699,22 @@ void WebPageProxy::findStringMatches(const String& string, FindOptions options,
     m_process->send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount), m_webPageID);
 }
 
-void WebPageProxy::findString(const String& string, FindOptions options, unsigned maxMatchCount)
+void WebPageProxy::findString(const String& string, FindOptions options, unsigned maxMatchCount, Function<void (bool, CallbackBase::Error)>&& callbackFunction)
 {
-    m_process->send(Messages::WebPage::FindString(string, options, maxMatchCount), m_webPageID);
+    Optional<CallbackID> callbackID;
+    if (callbackFunction)
+        callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivity("WebPageProxy::findString"_s));
+
+    m_process->send(Messages::WebPage::FindString(string, options, maxMatchCount, callbackID), m_webPageID);
+}
+
+void WebPageProxy::findStringCallback(bool found, CallbackID callbackID)
+{
+    auto callback = m_callbacks.take<BoolCallback>(callbackID);
+    if (!callback)
+        return;
+
+    callback->performCallbackWithReturnValue(found);
 }
 
 void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
index b84fb9e..c6c36f3 100644 (file)
@@ -337,6 +337,7 @@ typedef GenericCallback<const String&> StringCallback;
 typedef GenericCallback<API::SerializedScriptValue*, bool, const WebCore::ExceptionDetails&> ScriptValueCallback;
 typedef GenericCallback<const WebCore::FontAttributes&> FontAttributesCallback;
 typedef GenericCallback<const String&, const String&, const String&> SelectionContextCallback;
+typedef GenericCallback<bool> BoolCallback;
 
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
 using LayerHostingContextID = uint32_t;
@@ -1019,7 +1020,7 @@ public:
     void pluginZoomFactorDidChange(double);
 
     // Find.
-    void findString(const String&, FindOptions, unsigned maxMatchCount);
+    void findString(const String&, FindOptions, unsigned maxMatchCount, Function<void (bool, CallbackBase::Error)>&& = nullptr);
     void findStringMatches(const String&, FindOptions, unsigned maxMatchCount);
     void getImageForFindMatch(int32_t matchIndex);
     void selectFindMatch(int32_t matchIndex);
@@ -1032,6 +1033,8 @@ public:
     void setTextIndicator(const WebCore::TextIndicatorData&, uint64_t /* WebCore::TextIndicatorWindowLifetime */ lifetime = 0 /* Permanent */);
     void setTextIndicatorAnimationProgress(float);
     void clearTextIndicator();
+
+    void findStringCallback(bool found, CallbackID);
     void didFindString(const String&, const Vector<WebCore::IntRect>&, uint32_t matchCount, int32_t matchIndex, bool didWrapAround);
     void didFailToFindString(const String&);
     void didFindStringMatches(const String&, const Vector<Vector<WebCore::IntRect>>& matchRects, int32_t firstIndexAfterSelection);
index 2269aa6..5d8392b 100644 (file)
@@ -209,6 +209,7 @@ messages -> WebPageProxy {
     MachSendRightCallback(MachSendRight sendRight, WebKit::CallbackID callbackID)
     NowPlayingInfoCallback(bool active, bool registeredAsNowPlayingApplication, String title, double duration, double elapsedTime, uint64_t uniqueIdentifier, WebKit::CallbackID callbackID)
 #endif
+    FindStringCallback(bool found, WebKit::CallbackID callbackID)
 
     PageScaleFactorDidChange(double scaleFactor)
     PluginScaleFactorDidChange(double zoomFactor)
index 859c8fa..5e3ea3b 100644 (file)
                513FFB8D201459B0002596EA /* UIMessagePortChannelProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 513FFB8B201459A7002596EA /* UIMessagePortChannelProvider.h */; };
                513FFB91201459C6002596EA /* WebMessagePortChannelProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 513FFB8F201459C2002596EA /* WebMessagePortChannelProvider.h */; };
                514129941C6428BB0059E714 /* WebIDBConnectionToServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 514129921C6428100059E714 /* WebIDBConnectionToServer.h */; };
+               51489CC32370DBFA0044E68A /* WKFindResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 51489CC12370DACC0044E68A /* WKFindResult.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               51489CC7237237800044E68A /* WKFindResultInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 51489CC6237237780044E68A /* WKFindResultInternal.h */; };
+               514AB9F02360D2A900EDC396 /* WKFindConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 514AB9EF235FA59B00EDC396 /* WKFindConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
                514BDED316C98EDD00E4E25E /* StatisticsRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 514BDED216C98EDD00E4E25E /* StatisticsRequest.h */; };
                514D9F5719119D35000063A7 /* ServicesController.h in Headers */ = {isa = PBXBuildFile; fileRef = 514D9F5519119D35000063A7 /* ServicesController.h */; };
                515262BC1FB9515D0070E579 /* WebSWServerToContextConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 515262BB1FB951310070E579 /* WebSWServerToContextConnectionMessages.h */; };
                514129921C6428100059E714 /* WebIDBConnectionToServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebIDBConnectionToServer.h; sourceTree = "<group>"; };
                5143B25E1DDCDFD10014FAC6 /* _WKIconLoadingDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKIconLoadingDelegate.h; sourceTree = "<group>"; };
                5143B2611DDD0DA00014FAC6 /* APIIconLoadingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIIconLoadingClient.h; sourceTree = "<group>"; };
+               51489CC12370DACC0044E68A /* WKFindResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKFindResult.h; sourceTree = "<group>"; };
+               51489CC22370DACC0044E68A /* WKFindResult.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKFindResult.mm; sourceTree = "<group>"; };
+               51489CC6237237780044E68A /* WKFindResultInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKFindResultInternal.h; sourceTree = "<group>"; };
+               514AB9EF235FA59B00EDC396 /* WKFindConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKFindConfiguration.h; sourceTree = "<group>"; };
+               514AB9F12360E83D00EDC396 /* WKFindConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKFindConfiguration.mm; sourceTree = "<group>"; };
                514BDED216C98EDD00E4E25E /* StatisticsRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatisticsRequest.h; sourceTree = "<group>"; };
                514D9F5519119D35000063A7 /* ServicesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServicesController.h; sourceTree = "<group>"; };
                514D9F5619119D35000063A7 /* ServicesController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ServicesController.mm; sourceTree = "<group>"; };
                                1AF4592C19464B2000F9D4A2 /* WKError.mm */,
                                1A2D252A194688FD004537B0 /* WKErrorInternal.h */,
                                37B5045119EEF31300CE2CF8 /* WKErrorPrivate.h */,
+                               514AB9EF235FA59B00EDC396 /* WKFindConfiguration.h */,
+                               514AB9F12360E83D00EDC396 /* WKFindConfiguration.mm */,
+                               51489CC12370DACC0044E68A /* WKFindResult.h */,
+                               51489CC22370DACC0044E68A /* WKFindResult.mm */,
+                               51489CC6237237780044E68A /* WKFindResultInternal.h */,
                                1A4D664A18A3030E00D82E21 /* WKFrameInfo.h */,
                                1A4D664918A3030E00D82E21 /* WKFrameInfo.mm */,
                                2DF9EEE71A78245500B6CFBE /* WKFrameInfoInternal.h */,
                                BC4075FC124FF0270068F20A /* WKErrorRef.h in Headers */,
                                BC40783D1250FADD0068F20A /* WKEvent.h in Headers */,
                                A58B6F0818FCA733008CBA53 /* WKFileUploadPanel.h in Headers */,
+                               514AB9F02360D2A900EDC396 /* WKFindConfiguration.h in Headers */,
                                37F623B812A57B6200E3FDF6 /* WKFindOptions.h in Headers */,
+                               51489CC32370DBFA0044E68A /* WKFindResult.h in Headers */,
+                               51489CC7237237800044E68A /* WKFindResultInternal.h in Headers */,
                                2E16B6CF2017B7AD008996D6 /* WKFocusedFormControlView.h in Headers */,
                                E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */,
                                E548EBD121015F0E00BE3C32 /* WKFormColorPicker.h in Headers */,
index 0762d00..c6cc38a 100644 (file)
@@ -224,7 +224,7 @@ void FindController::updateFindUIAfterPageScroll(bool found, const String& strin
         hideFindIndicator();
 }
 
-void FindController::findString(const String& string, FindOptions options, unsigned maxMatchCount)
+void FindController::findString(const String& string, FindOptions options, unsigned maxMatchCount, Optional<CallbackID> callbackID)
 {
     auto* pluginView = WebPage::pluginViewForFrame(m_webPage->mainFrame());
 
@@ -277,6 +277,9 @@ void FindController::findString(const String& string, FindOptions options, unsig
     m_webPage->drawingArea()->dispatchAfterEnsuringUpdatedScrollPosition([protectedWebPage, found, string, options, maxMatchCount, didWrap] () {
         protectedWebPage->findController().updateFindUIAfterPageScroll(found, string, options, maxMatchCount, didWrap, FindUIOriginator::FindString);
     });
+
+    if (callbackID)
+        m_webPage->send(Messages::WebPageProxy::FindStringCallback(found, *callbackID));
 }
 
 void FindController::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
index b32d53f..44059a1 100644 (file)
@@ -56,7 +56,7 @@ public:
     explicit FindController(WebPage*);
     virtual ~FindController();
 
-    void findString(const String&, FindOptions, unsigned maxMatchCount);
+    void findString(const String&, FindOptions, unsigned maxMatchCount, Optional<CallbackID>);
     void findStringMatches(const String&, FindOptions, unsigned maxMatchCount);
     void getImageForFindMatch(uint32_t matchIndex);
     void selectFindMatch(uint32_t matchIndex);
index 8247480..0c58804 100644 (file)
@@ -4047,9 +4047,9 @@ void WebPage::replaceStringMatchesFromInjectedBundle(const Vector<uint32_t>& mat
     findController().replaceMatches(matchIndices, replacementText, selectionOnly);
 }
 
-void WebPage::findString(const String& string, uint32_t options, uint32_t maxMatchCount)
+void WebPage::findString(const String& string, uint32_t options, uint32_t maxMatchCount, Optional<CallbackID> callbackID)
 {
-    findController().findString(string, static_cast<FindOptions>(options), maxMatchCount);
+    findController().findString(string, static_cast<FindOptions>(options), maxMatchCount, callbackID);
 }
 
 void WebPage::findStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
index 44c7f48..62308dc 100644 (file)
@@ -1472,7 +1472,7 @@ private:
     void reapplyEditCommand(WebUndoStepID commandID);
     void didRemoveEditCommand(WebUndoStepID commandID);
 
-    void findString(const String&, uint32_t findOptions, uint32_t maxMatchCount);
+    void findString(const String&, uint32_t findOptions, uint32_t maxMatchCount, Optional<CallbackID>);
     void findStringMatches(const String&, uint32_t findOptions, uint32_t maxMatchCount);
     void getImageForFindMatch(uint32_t matchIndex);
     void selectFindMatch(uint32_t matchIndex);
index 36e3d28..da1c755 100644 (file)
@@ -284,7 +284,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
     PostInjectedBundleMessage(String messageName, WebKit::UserData messageBody)
 
     # Find.
-    FindString(String string, uint32_t findOptions, unsigned maxMatchCount)
+    FindString(String string, uint32_t findOptions, unsigned maxMatchCount, Optional<WebKit::CallbackID> callbackID)
     FindStringMatches(String string, uint32_t findOptions, unsigned maxMatchCount)
     GetImageForFindMatch(uint32_t matchIndex)
     SelectFindMatch(uint32_t matchIndex)
index 788150d..7210032 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-08  Brady Eidson  <beidson@apple.com>
+
+        WKWebView Find-in-page API.
+        <rdar://problem/46971112> and https://bugs.webkit.org/show_bug.cgi?id=203872
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/FindInPageAPI.mm: Added.
+        (TEST):
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[TestWKWebView selectionRangeHasStartOffset:endOffset:]):
+
 2019-11-08  Jonathan Bedard  <jbedard@apple.com>
 
         Simulators having trouble launching apps after booting
index 59135ae..589c08b 100644 (file)
                5110FCFA1E01CDB8006F8D0B /* IDBIndexUpgradeToV2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5110FCEF1E01CBAA006F8D0B /* IDBIndexUpgradeToV2.mm */; };
                5120C83D1E6751290025B250 /* WebsiteDataStoreCustomPaths.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5120C83C1E6750790025B250 /* WebsiteDataStoreCustomPaths.mm */; };
                5120C83E1E67678F0025B250 /* WebsiteDataStoreCustomPaths.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5120C83B1E674E350025B250 /* WebsiteDataStoreCustomPaths.html */; };
+               51242CD52374E62500EED9C1 /* FindInPageAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51242CD42374E61E00EED9C1 /* FindInPageAPI.mm */; };
                512C4C9E20EAA40D004945EA /* ResponsivenessTimerCrash.mm in Sources */ = {isa = PBXBuildFile; fileRef = 512C4C9D20EAA405004945EA /* ResponsivenessTimerCrash.mm */; };
                51393E221523952D005F39C5 /* DOMWindowExtensionBasic_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51393E1D1523944A005F39C5 /* DOMWindowExtensionBasic_Bundle.cpp */; };
                51396E1A222E516000A42FCE /* LoadFileURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51396E19222E4E8600A42FCE /* LoadFileURL.mm */; };
                5110FCF31E01CD77006F8D0B /* IndexUpgrade.sqlite3 */ = {isa = PBXFileReference; lastKnownFileType = file; path = IndexUpgrade.sqlite3; sourceTree = "<group>"; };
                5120C83B1E674E350025B250 /* WebsiteDataStoreCustomPaths.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = WebsiteDataStoreCustomPaths.html; sourceTree = "<group>"; };
                5120C83C1E6750790025B250 /* WebsiteDataStoreCustomPaths.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebsiteDataStoreCustomPaths.mm; sourceTree = "<group>"; };
+               51242CD42374E61E00EED9C1 /* FindInPageAPI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FindInPageAPI.mm; sourceTree = "<group>"; };
                512C4C9D20EAA405004945EA /* ResponsivenessTimerCrash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ResponsivenessTimerCrash.mm; sourceTree = "<group>"; };
                51393E1D1523944A005F39C5 /* DOMWindowExtensionBasic_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionBasic_Bundle.cpp; sourceTree = "<group>"; };
                51393E1E1523944A005F39C5 /* DOMWindowExtensionBasic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionBasic.cpp; sourceTree = "<group>"; };
                                F44D06461F395C4D001A0E29 /* EditorStateTests.mm */,
                                CDA29B2820FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm */,
                                2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
+                               51242CD42374E61E00EED9C1 /* FindInPageAPI.mm */,
                                118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm */,
                                2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
                                2E92B8F8216490EA005B64F0 /* FontAttributes.mm */,
                                7A32D74A1F02151500162C44 /* FileMonitor.cpp in Sources */,
                                7CCE7EF31A411AE600447C4C /* Find.cpp in Sources */,
                                7C83E0BB1D0A650000FEBCF3 /* FindInPage.mm in Sources */,
+                               51242CD52374E62500EED9C1 /* FindInPageAPI.mm in Sources */,
                                7CCE7EF41A411AE600447C4C /* FindMatches.mm in Sources */,
                                11B7FD28219F47110069B27F /* FirstMeaningfulPaintMilestone.cpp in Sources */,
                                7C83E0401D0A63E300FEBCF3 /* FirstResponderScrollingPosition.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPageAPI.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/FindInPageAPI.mm
new file mode 100644 (file)
index 0000000..6042052
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "config.h"
+
+#import "PlatformUtilities.h"
+#import "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKFindConfiguration.h>
+#import <WebKit/WKFindResult.h>
+#import <WebKit/WKWebView.h>
+#import <wtf/RetainPtr.h>
+
+
+TEST(WKWebView, FindAPIForwardsNoMatch)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+
+    EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+    static bool done;
+    [webView findString:@"foobar" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_FALSE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
+TEST(WKWebView, FindAPIForwardsWrap)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+
+    static bool done;
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
+TEST(WKWebView, FindAPIForwardsNoWrap)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+    configuration.get().wraps = NO;
+
+    static bool done;
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_FALSE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
+TEST(WKWebView, FindAPIBackwardsWrap)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+    configuration.get().backwards = YES;
+
+    EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+    static bool done;
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
+TEST(WKWebView, FindAPIBackwardsNoWrap)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+    configuration.get().backwards = YES;
+    configuration.get().wraps = NO;
+
+    EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+    static bool done;
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_FALSE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:0]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
+TEST(WKWebView, FindAPIForwardsCaseSensitive)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadHTMLString:@"word Word word" baseURL:nil];
+
+    // The default find configuration is "forwards, case insensitive, wrapping"
+    auto configuration = adoptNS([[WKFindConfiguration alloc] init]);
+    configuration.get().caseSensitive = YES;
+
+    static bool done;
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:10 endOffset:14]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:0 endOffset:4]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView findString:@"Word" withConfiguration:configuration.get() completionHandler:^(WKFindResult *result) {
+        EXPECT_TRUE(result.matchFound);
+        EXPECT_TRUE([webView selectionRangeHasStartOffset:5 endOffset:9]);
+
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
index ab25039..1543e2f 100644 (file)
@@ -83,6 +83,7 @@
 - (void)collapseToStart;
 - (void)collapseToEnd;
 - (void)addToTestWindow;
+- (BOOL)selectionRangeHasStartOffset:(int)start endOffset:(int)end;
 @end
 
 #if PLATFORM(IOS_FAMILY)
index 3b83c92..603cb73 100644 (file)
@@ -459,6 +459,24 @@ static UICalloutBar *suppressUICalloutBar()
     [self evaluateJavaScript:@"getSelection().collapseToEnd()" completionHandler:nil];
 }
 
+- (BOOL)selectionRangeHasStartOffset:(int)start endOffset:(int)end
+{
+    __block bool isDone = false;
+    __block bool matches = true;
+    [self evaluateJavaScript:@"window.getSelection().getRangeAt(0).startOffset" completionHandler:^(id result, NSError *error) {
+        if ([(NSNumber *)result intValue] != start)
+            matches = false;
+    }];
+    [self evaluateJavaScript:@"window.getSelection().getRangeAt(0).endOffset" completionHandler:^(id result, NSError *error) {
+        if ([(NSNumber *)result intValue] != end)
+            matches = false;
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&isDone);
+
+    return matches;
+}
+
 #if PLATFORM(IOS_FAMILY)
 
 - (void)didStartFormControlInteraction