[Cherry-pick] Add a new set of WebKit2 APIs for text search and search results manage...
authorenrica@apple.com <enrica@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Jan 2013 23:00:59 +0000 (23:00 +0000)
committerJinwoo Song <jinwoo7.song@samsung.com>
Mon, 25 Mar 2013 05:32:55 +0000 (14:32 +0900)
[Title] [Cherry-pick] Add a new set of WebKit2 APIs for text search and search results management.
[Issue] https://tizendev.org/bugs/browse/N_SE-25811
[Problem] Find string is not working in the page with the CSS style, '--webkit-user-select: none'.
[Solution] We need to expand the text search implementation with the new WebKit2 APIs in the open source.
           So I cherry-pick this patch in the open source.
[Cherry-Picker] Jinwoo Song <jinwoo7.song@samsung.com>

Add a new set of WebKit2 APIs for text search and search results management.
https://bugs.webkit.org/show_bug.cgi?id=106834.
<rdar://problem/12597159>

Source/WebCore:

Reviewed by Simon Fraser.

Adding new API to perform text search in WebKit2 without using
the stock UI. The new interface provides all the information
necessary to write a custom UI for search.

Added new TextWebKitAPI test.

* WebCore.exp.in: Added new exported methods.
* editing/Editor.cpp:
(WebCore::Editor::countMatchesForText): Added new parameter to store
all the ranges relative to the matches found.
* editing/Editor.h: Modified the interface of countMatchesForText and removed
the other definition of countMatchesForText with a different signature.
* page/Page.cpp:
(WebCore::Page::findStringMatchingRanges): Added.
(WebCore::Page::markAllMatchesForText): Changed to use the new unified
countMatchesForText.
* page/Page.h:

Source/WebKit/mac:

Reviewed by Simon Fraser.

Adding new API to perform text search in WebKit2 without using
the stock UI. The new interface provides all the information
necessary to write a custom UI for search.

Added new TextWebKitAPI test.

* WebView/WebHTMLView.mm:
(-[WebHTMLView countMatchesForText:inDOMRange:options:limit:markMatches:]):
Modified to reflect the changes to Editor::countMatchesForText interface.

Source/WebKit2:

Reviewed by Simon Fraser.

Adding new API to perform text search in WebKit2 without using
the stock UI. The new interface provides all the information
necessary to write a custom UI for search. The main logic is
implemented in the new functions added to FindController.

Added new TextWebKitAPI test.

* UIProcess/API/C/WKPage.cpp:
(WKPageFindStringMatches): Added.
(WKPageGetImageForFindMatch): Added.
(WKPageSelectFindMatch): Added.
(WKPageSetPageFindMatchesClient): Added.
* UIProcess/API/C/WKPage.h: Added the new API definitions.
* UIProcess/WebFindClient.cpp: Added new client callbacks.
(WebKit::WebFindMatchesClient::didFindStringMatches):
(WebKit::WebFindMatchesClient::didGetImageForMatchResult):
* UIProcess/WebFindClient.h:
(WebFindMatchesClient): Added.
* UIProcess/WebPageProxy.cpp: Added proxy methods.
(WebKit::WebPageProxy::initializeFindMatchesClient):
(WebKit::WebPageProxy::findStringMatches):
(WebKit::WebPageProxy::getImageForFindMatch):
(WebKit::WebPageProxy::selectFindMatch):
(WebKit::WebPageProxy::didGetImageForFindMatch):
(WebKit::WebPageProxy::didFindStringMatches):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* WebProcess/WebPage/FindController.cpp:
(WebKit::FindController::findStringMatches): Finds all the matching
text according to the find options. All the matching text ranges are
stored in a vector until the next call to findStringMatches or until
hideFindUI is called. The message that is sent back to the UI process
contains a vector containing an entry for each find match (i.e. for each
range) and each entry is represented by a vector of the corresponding
text rects. It also returns the index in the vector of matches corresponding
to the first match after the user selection.
If there is no selection the index is always 0 and if there are no
matches after the user selection, the index returned is -1.
(WebKit::FindController::getFindIndicatorBitmapAndRect): Helper function
to share code between updateFindIndicator and getImageForFindMatch.
(WebKit::FindController::getImageForFindMatch): Creates the image corresponding
to the text matched at the given match index.
(WebKit::FindController::selectFindMatch): creates a selection for the range
corresponding to the given match index.
(WebKit::FindController::hideFindUI): Added logic to clear the vector
of matched ranges.
(WebKit::FindController::updateFindIndicator): Updated to use the
new helper function getFindIndicatorBitmapAndRect.
* WebProcess/WebPage/FindController.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::findStringMatches):
(WebKit::WebPage::getImageForFindMatch):
(WebKit::WebPage::selectFindMatch):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Added new test for the new WebKit2 API for
text search.

Reviewed by Simon Fraser.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2/FindMatches.mm: Added.

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

Conflicts:
Source/WebCore/ChangeLog
Source/WebKit/mac/ChangeLog
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/WebProcess/WebPage/FindController.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

Change-Id: I50c151a32ebbc2cbaa1ce2c973afb25d7e99db78

20 files changed:
Source/WebCore/WebCore.exp.in
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/Editor.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebKit/mac/WebView/WebHTMLView.mm
Source/WebKit2/UIProcess/API/C/WKPage.cpp
Source/WebKit2/UIProcess/API/C/WKPage.h
Source/WebKit2/UIProcess/WebFindClient.cpp
Source/WebKit2/UIProcess/WebFindClient.h
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/WebProcess/WebPage/FindController.cpp
Source/WebKit2/WebProcess/WebPage/FindController.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKit2/FindMatches.mm [new file with mode: 0644]

index a8f3860..aa05880 100644 (file)
@@ -675,6 +675,7 @@ __ZN7WebCore4Page20unmarkAllTextMatchesEv
 __ZN7WebCore4Page21markAllMatchesForTextERKN3WTF6StringEjbj
 __ZN7WebCore4Page22allVisitedStateChangedEPNS_9PageGroupE
 __ZN7WebCore4Page23clearUndoRedoOperationsEv
+__ZN7WebCore4Page24findStringMatchingRangesERKN3WTF6StringEjiPNS1_6VectorINS1_6RefPtrINS_5RangeEEELm0EEERi
 __ZN7WebCore4Page24resumeScriptedAnimationsEv
 __ZN7WebCore4Page25suspendScriptedAnimationsEv
 __ZN7WebCore4Page27setJavaScriptURLsAreAllowedEb
@@ -743,7 +744,6 @@ __ZN7WebCore6Editor17insertOrderedListEv
 __ZN7WebCore6Editor18confirmCompositionERKN3WTF6StringE
 __ZN7WebCore6Editor18confirmCompositionEv
 __ZN7WebCore6Editor18insertDictatedTextERKN3WTF6StringERKNS1_6VectorINS_20DictationAlternativeELm0EEEPNS_5EventE
-__ZN7WebCore6Editor19countMatchesForTextERKN3WTF6StringEPNS_5RangeEjjb
 __ZN7WebCore6Editor19deleteWithDirectionENS_18SelectionDirectionENS_15TextGranularityEbb
 __ZN7WebCore6Editor19insertUnorderedListEv
 __ZN7WebCore6Editor21applyStyleToSelectionEPNS_16StylePropertySetENS_10EditActionE
@@ -774,6 +774,7 @@ __ZN7WebCore6Editor6indentEv
 __ZN7WebCore6Editor7CommandC1Ev
 __ZN7WebCore6Editor7commandERKN3WTF6StringE
 __ZN7WebCore6Editor7outdentEv
+__ZN7WebCore6Editor19countMatchesForTextERKN3WTF6StringEPNS_5RangeEjjbPNS1_6VectorINS1_6RefPtrIS5_EELm0EEE
 __ZN7WebCore6JSNode6s_infoE
 __ZN7WebCore6Region5uniteERKS0_
 __ZN7WebCore6Region8subtractERKS0_
index edbe82c..b59bbb9 100644 (file)
@@ -2716,12 +2716,7 @@ static bool isFrameInRange(Frame* frame, Range* range)
     return inRange;
 }
 
-unsigned Editor::countMatchesForText(const String& target, FindOptions options, unsigned limit, bool markMatches)
-{
-    return countMatchesForText(target, 0, options, limit, markMatches);
-}
-
-unsigned Editor::countMatchesForText(const String& target, Range* range, FindOptions options, unsigned limit, bool markMatches)
+unsigned Editor::countMatchesForText(const String& target, Range* range, FindOptions options, unsigned limit, bool markMatches, Vector<RefPtr<Range> >* matches)
 {
     if (target.isEmpty())
         return 0;
@@ -2753,6 +2748,9 @@ unsigned Editor::countMatchesForText(const String& target, Range* range, FindOpt
         }
 
         ++matchCount;
+        if (matches)
+            matches->append(resultRange);
+        
         if (markMatches)
             m_frame->document()->markers()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
 
@@ -2771,7 +2769,7 @@ unsigned Editor::countMatchesForText(const String& target, Range* range, FindOpt
             searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);
     } while (true);
 
-    if (markMatches) {
+    if (markMatches || matches) {
         // Do a "fake" paint in order to execute the code that computes the rendered rect for each text match.
         if (m_frame->view() && m_frame->contentRenderer()) {
             m_frame->document()->updateLayout(); // Ensure layout is up to date.
index 21ebc32..97dc734 100644 (file)
@@ -369,8 +369,7 @@ public:
 
     void respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions);
     bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const;
-    unsigned countMatchesForText(const String&, FindOptions, unsigned limit, bool markMatches);
-    unsigned countMatchesForText(const String&, Range*, FindOptions, unsigned limit, bool markMatches);
+    unsigned countMatchesForText(const String&, Range*, FindOptions, unsigned limit, bool markMatches, Vector<RefPtr<Range> >*);
     bool markedTextMatchesAreHighlighted() const;
     void setMarkedTextMatchesAreHighlighted(bool);
 
index 75c76fc..5aa15e7 100644 (file)
@@ -529,6 +529,37 @@ bool Page::findString(const String& target, FindOptions options)
     return false;
 }
 
+void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
+{
+    indexForSelection = 0;
+    if (!mainFrame())
+        return;
+
+    Frame* frame = mainFrame();
+    Frame* frameWithSelection = 0;
+    do {
+        frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges);
+        if (frame->selection()->isRange())
+            frameWithSelection = frame;
+        frame = incrementFrame(frame, true, false);
+    } while (frame);
+
+    if (matchRanges->isEmpty())
+        return;
+
+    if (frameWithSelection) {
+        indexForSelection = NoMatchBeforeUserSelection;
+        RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange();
+        for (size_t i = 0; i < matchRanges->size(); ++i) {
+            ExceptionCode ec;
+            if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), ec) < 0) {
+                indexForSelection = i;
+                break;
+            }
+        }
+    }
+}
+
 PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
 {
     if (target.isEmpty() || !mainFrame())
@@ -572,7 +603,7 @@ unsigned int Page::markAllMatchesForText(const String& target, FindOptions optio
     Frame* frame = mainFrame();
     do {
         frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
-        matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
+        matches += frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matches) : 0, true, 0);
         frame = incrementFrame(frame, true, false);
     } while (frame);
 
index c90bcd0..00f3ad9 100644 (file)
@@ -221,6 +221,13 @@ namespace WebCore {
         unsigned markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);
         void unmarkAllTextMatches();
 
+        // find all the Ranges for the matching text.
+        // Upon return, indexForSelection will be one of the following:
+        // 0 if there is no user selection
+        // the index of the first range after the user selection
+        // NoMatchBeforeUserSelection if there is no matching text after the user selection.
+        enum { NoMatchBeforeUserSelection = -1 };
+        void findStringMatchingRanges(const String&, FindOptions, int maxCount, Vector<RefPtr<Range> >*, int& indexForSelection);
 #if PLATFORM(MAC)
         void addSchedulePair(PassRefPtr<SchedulePair>);
         void removeSchedulePair(PassRefPtr<SchedulePair>);
index 505db53..abda81e 100644 (file)
@@ -6213,7 +6213,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
     if (!coreFrame)
         return 0;
 
-    return coreFrame->editor()->countMatchesForText(string, core(range), coreOptions(options), limit, markMatches);
+    return coreFrame->editor()->countMatchesForText(string, core(range), coreOptions(options), limit, markMatches, 0);
 }
 
 - (void)setMarkedTextMatchesAreHighlighted:(BOOL)newValue
index c8f1543..6ccb839 100755 (executable)
@@ -455,6 +455,21 @@ void WKPageCenterSelectionInVisibleArea(WKPageRef pageRef)
     return toImpl(pageRef)->centerSelectionInVisibleArea();
 }
 
+void WKPageFindStringMatches(WKPageRef pageRef, WKStringRef string, WKFindOptions options, unsigned maxMatchCount)
+{
+    toImpl(pageRef)->findStringMatches(toImpl(string)->string(), toFindOptions(options), maxMatchCount);
+}
+
+void WKPageGetImageForFindMatch(WKPageRef pageRef, int32_t matchIndex)
+{
+    toImpl(pageRef)->getImageForFindMatch(matchIndex);
+}
+
+void WKPageSelectFindMatch(WKPageRef pageRef, int32_t matchIndex)
+{
+    toImpl(pageRef)->selectFindMatch(matchIndex);
+}
+
 void WKPageFindString(WKPageRef pageRef, WKStringRef string, WKFindOptions options, unsigned maxMatchCount)
 {
     toImpl(pageRef)->findString(toImpl(string)->string(), toFindOptions(options), maxMatchCount);
@@ -482,6 +497,11 @@ void WKPageSetPageFindClient(WKPageRef pageRef, const WKPageFindClient* wkClient
     toImpl(pageRef)->initializeFindClient(wkClient);
 }
 
+void WKPageSetPageFindMatchesClient(WKPageRef pageRef, const WKPageFindMatchesClient* wkClient)
+{
+    toImpl(pageRef)->initializeFindMatchesClient(wkClient);
+}
+
 void WKPageSetPageFormClient(WKPageRef pageRef, const WKPageFormClient* wkClient)
 {
     toImpl(pageRef)->initializeFormClient(wkClient);
index 8787be3..9a334e9 100755 (executable)
@@ -343,6 +343,20 @@ enum {
     kWKMoreThanMaximumMatchCount = -1
 };
 
+// Find match client.
+typedef void (*WKPageDidFindStringMatchesCallback)(WKPageRef page, WKStringRef string, WKArrayRef matches, int firstIndex, const void* clientInfo);
+typedef void (*WKPageDidGetImageForMatchResultCallback)(WKPageRef page, WKImageRef image, uint32_t index, const void* clientInfo);
+
+struct WKPageFindMatchesClient {
+    int                                                                 version;
+    const void *                                                        clientInfo;
+    WKPageDidFindStringMatchesCallback                                  didFindStringMatches;
+    WKPageDidGetImageForMatchResultCallback                             didGetImageForMatchResult;
+};
+typedef struct WKPageFindMatchesClient WKPageFindMatchesClient;
+
+enum { kWKPageFindMatchesClientCurrentVersion = 0 };
+
 // ContextMenu client
 typedef void (*WKPageGetContextMenuFromProposedContextMenuCallback)(WKPageRef page, WKArrayRef proposedMenu, WKArrayRef* newMenu, WKHitTestResultRef hitTestResult, WKTypeRef userData, const void* clientInfo);
 typedef void (*WKPageCustomContextMenuItemSelectedCallback)(WKPageRef page, WKContextMenuItemRef contextMenuItem, const void* clientInfo);
@@ -472,9 +486,13 @@ WK_EXPORT void WKPageCenterSelectionInVisibleArea(WKPageRef page);
 WK_EXPORT void WKPageFindString(WKPageRef page, WKStringRef string, WKFindOptions findOptions, unsigned maxMatchCount);
 WK_EXPORT void WKPageHideFindUI(WKPageRef page);
 WK_EXPORT void WKPageCountStringMatches(WKPageRef page, WKStringRef string, WKFindOptions findOptions, unsigned maxMatchCount);
+WK_EXPORT void WKPageFindStringMatches(WKPageRef page, WKStringRef string, WKFindOptions findOptions, unsigned maxMatchCount);
+WK_EXPORT void WKPageGetImageForFindMatch(WKPageRef page, int32_t matchIndex);
+WK_EXPORT void WKPageSelectFindMatch(WKPageRef page, int32_t matchIndex);
 
 WK_EXPORT void WKPageSetPageContextMenuClient(WKPageRef page, const WKPageContextMenuClient* client);
 WK_EXPORT void WKPageSetPageFindClient(WKPageRef page, const WKPageFindClient* client);
+WK_EXPORT void WKPageSetPageFindMatchesClient(WKPageRef page, const WKPageFindMatchesClient* client);
 WK_EXPORT void WKPageSetPageFormClient(WKPageRef page, const WKPageFormClient* client);
 WK_EXPORT void WKPageSetPageLoaderClient(WKPageRef page, const WKPageLoaderClient* client);
 WK_EXPORT void WKPageSetPagePolicyClient(WKPageRef page, const WKPagePolicyClient* client);
index c8df91d..702d187 100644 (file)
@@ -55,5 +55,20 @@ void WebFindClient::didCountStringMatches(WebPageProxy* page, const String& stri
     m_client.didCountStringMatches(toAPI(page), toAPI(string.impl()), matchCount, m_client.clientInfo);
 }
 
+void WebFindMatchesClient::didFindStringMatches(WebPageProxy* page, const String& string, ImmutableArray* matches, int firstIndex)
+{
+    if (!m_client.didFindStringMatches)
+        return;
+
+    m_client.didFindStringMatches(toAPI(page), toAPI(string.impl()), toAPI(matches), firstIndex, m_client.clientInfo);
+}
+
+void WebFindMatchesClient::didGetImageForMatchResult(WebPageProxy* page, WebImage* image, uint32_t index)
+{
+    if (!m_client.didGetImageForMatchResult)
+        return;
+    m_client.didGetImageForMatchResult(toAPI(page), toAPI(image), index, m_client.clientInfo);
+}
+
 } // namespace WebKit
 
index 82380ab..605f3d5 100644 (file)
@@ -32,7 +32,9 @@
 
 namespace WebKit {
 
+class ImmutableArray;
 class WebPageProxy;
+class WebImage;
 
 class WebFindClient : public APIClient<WKPageFindClient, kWKPageFindClientCurrentVersion> {
 public:
@@ -41,6 +43,12 @@ public:
     void didCountStringMatches(WebPageProxy*, const String&, uint32_t matchCount);
 };
 
+class WebFindMatchesClient : public APIClient<WKPageFindMatchesClient, kWKPageFindMatchesClientCurrentVersion> {
+public:
+    void didFindStringMatches(WebPageProxy*, const String&, ImmutableArray*, int);
+    void didGetImageForMatchResult(WebPageProxy*, WebImage*, uint32_t);
+};
+
 } // namespace WebKit
 
 #endif // WebFindClient_h
index 1d4dedc..10ce9d9 100755 (executable)
@@ -34,6 +34,7 @@
 #include "DrawingAreaProxy.h"
 #include "EventDispatcherMessages.h"
 #include "FindIndicator.h"
+#include "ImmutableArray.h"
 #include "Logging.h"
 #include "MessageID.h"
 #include "NativeWebKeyboardEvent.h"
@@ -341,6 +342,11 @@ void WebPageProxy::initializeFindClient(const WKPageFindClient* client)
     m_findClient.initialize(client);
 }
 
+void WebPageProxy::initializeFindMatchesClient(const WKPageFindMatchesClient* client)
+{
+    m_findMatchesClient.initialize(client);
+}
+
 #if ENABLE(CONTEXT_MENUS)
 void WebPageProxy::initializeContextMenuClient(const WKPageContextMenuClient* client)
 {
@@ -1713,6 +1719,16 @@ void WebPageProxy::setMemoryCacheClientCallsEnabled(bool memoryCacheClientCallsE
     process()->send(Messages::WebPage::SetMemoryCacheMessagesEnabled(memoryCacheClientCallsEnabled), m_pageID);
 }
 
+void WebPageProxy::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
+{
+    if (string.isEmpty()) {
+        didFindStringMatches(string, Vector<Vector<WebCore::IntRect> > (), 0);
+        return;
+    }
+
+    m_process->send(Messages::WebPage::FindStringMatches(string, options, maxMatchCount), m_pageID);
+}
+
 void WebPageProxy::findString(const String& string, FindOptions options, unsigned maxMatchCount)
 {
     if (m_mainFrameHasCustomRepresentation)
@@ -1721,6 +1737,16 @@ void WebPageProxy::findString(const String& string, FindOptions options, unsigne
         process()->send(Messages::WebPage::FindString(string, options, maxMatchCount), m_pageID);
 }
 
+void WebPageProxy::getImageForFindMatch(int32_t matchIndex)
+{
+    m_process->send(Messages::WebPage::GetImageForFindMatch(matchIndex), m_pageID);
+}
+
+void WebPageProxy::selectFindMatch(int32_t matchIndex)
+{
+    m_process->send(Messages::WebPage::SelectFindMatch(matchIndex), m_pageID);
+}
+
 void WebPageProxy::hideFindUI()
 {
     process()->send(Messages::WebPage::HideFindUI(), m_pageID);
@@ -3244,6 +3270,11 @@ void WebPageProxy::didCountStringMatches(const String& string, uint32_t matchCou
     m_findClient.didCountStringMatches(this, string, matchCount);
 }
 
+void WebPageProxy::didGetImageForFindMatch(const ShareableBitmap::Handle& contentImageHandle, uint32_t matchIndex)
+{
+    m_findMatchesClient.didGetImageForMatchResult(this, WebImage::create(ShareableBitmap::create(contentImageHandle)).get(), matchIndex);
+}
+
 void WebPageProxy::setFindIndicator(const FloatRect& selectionRectInWindowCoordinates, const Vector<FloatRect>& textRectsInSelectionRectCoordinates, float contentImageScaleFactor, const ShareableBitmap::Handle& contentImageHandle, bool fadeOut, bool animate)
 {
     RefPtr<FindIndicator> findIndicator = FindIndicator::create(selectionRectInWindowCoordinates, textRectsInSelectionRectCoordinates, contentImageScaleFactor, contentImageHandle);
@@ -3255,6 +3286,24 @@ void WebPageProxy::didFindString(const String& string, uint32_t matchCount)
     m_findClient.didFindString(this, string, matchCount);
 }
 
+void WebPageProxy::didFindStringMatches(const String& string, Vector<Vector<WebCore::IntRect> > matchRects, int32_t firstIndexAfterSelection)
+{
+    Vector<RefPtr<APIObject> > matches;
+    matches.reserveInitialCapacity(matchRects.size());
+
+    for (size_t i = 0; i < matchRects.size(); ++i) {
+        const Vector<WebCore::IntRect>& rects = matchRects[i];
+        size_t numRects = matchRects[i].size();
+        Vector<RefPtr<APIObject> > apiRects;
+        apiRects.reserveInitialCapacity(numRects);
+
+        for (size_t i = 0; i < numRects; ++i)
+            apiRects.uncheckedAppend(WebRect::create(toAPI(rects[i])));
+        matches.uncheckedAppend(ImmutableArray::adopt(apiRects));
+    }
+    m_findMatchesClient.didFindStringMatches(this, string, ImmutableArray::adopt(matches).get(), firstIndexAfterSelection);
+}
+
 void WebPageProxy::didFailToFindString(const String& string)
 {
     m_findClient.didFailToFindString(this, string);
index ba03ba6..e18efbf 100755 (executable)
@@ -319,6 +319,7 @@ public:
     void initializeContextMenuClient(const WKPageContextMenuClient*);
 #endif
     void initializeFindClient(const WKPageFindClient*);
+    void initializeFindMatchesClient(const WKPageFindMatchesClient*);
     void initializeFormClient(const WKPageFormClient*);
     void initializeLoaderClient(const WKPageLoaderClient*);
     void initializePolicyClient(const WKPagePolicyClient*);
@@ -665,12 +666,17 @@ public:
 
     // Find.
     void findString(const String&, FindOptions, unsigned maxMatchCount);
+    void findStringMatches(const String&, FindOptions, unsigned maxMatchCount);
+    void getImageForFindMatch(int32_t matchIndex);
+    void selectFindMatch(int32_t matchIndex);
+    void didGetImageForFindMatch(const ShareableBitmap::Handle& contentImageHandle, uint32_t matchIndex);
     void hideFindUI();
     void countStringMatches(const String&, FindOptions, unsigned maxMatchCount);
     void didCountStringMatches(const String&, uint32_t matchCount);
     void setFindIndicator(const WebCore::FloatRect& selectionRectInWindowCoordinates, const Vector<WebCore::FloatRect>& textRectsInSelectionRectCoordinates, float contentImageScaleFactor, const ShareableBitmap::Handle& contentImageHandle, bool fadeOut, bool animate);
     void didFindString(const String&, uint32_t matchCount);
     void didFailToFindString(const String&);
+    void didFindStringMatches(const String&, Vector<Vector<WebCore::IntRect> > matchRects, int32_t firstIndexAfterSelection);
 #if PLATFORM(WIN)
     void didInstallOrUninstallPageOverlay(bool);
 #endif
@@ -1370,6 +1376,7 @@ private:
     WebResourceLoadClient m_resourceLoadClient;
     WebUIClient m_uiClient;
     WebFindClient m_findClient;
+    WebFindMatchesClient m_findMatchesClient;
 #if ENABLE(CONTEXT_MENUS)
     WebPageContextMenuClient m_contextMenuClient;
 #endif
index f427a21..822ef4e 100755 (executable)
@@ -274,6 +274,8 @@ messages -> WebPageProxy {
     SetFindIndicator(WebCore::FloatRect selectionRect, Vector<WebCore::FloatRect> textRects, float contentImageScaleFactor, WebKit::ShareableBitmap::Handle contentImageHandle, bool fadeOut, bool animate)
     DidFindString(WTF::String string, uint32_t matchCount)
     DidFailToFindString(WTF::String string)
+    DidFindStringMatches(WTF::String string, Vector<Vector<WebCore::IntRect> > matches, int32_t firstIndexAfterSelection)
+    DidGetImageForFindMatch(WebKit::ShareableBitmap::Handle contentImageHandle, uint32_t matchIndex)
 #if PLATFORM(WIN)
     DidInstallOrUninstallPageOverlay(bool didInstall)
 #endif
index be2cf18..405de24 100644 (file)
@@ -160,32 +160,31 @@ void FindController::findString(const String& string, FindOptions options, unsig
     m_webPage->drawingArea()->dispatchAfterEnsuringUpdatedScrollPosition(WTF::bind(&FindController::updateFindUIAfterPageScroll, this, found, string, options, maxMatchCount));
 }
 
-void FindController::hideFindUI()
+void FindController::findStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
 {
-    if (m_findPageOverlay)
-        m_webPage->uninstallPageOverlay(m_findPageOverlay, false);
+    m_findMatches.clear();
+    int indexForSelection;
 
-    m_webPage->corePage()->unmarkAllTextMatches();
-    hideFindIndicator();
+    m_webPage->corePage()->findStringMatchingRanges(string, core(options), maxMatchCount, &m_findMatches, indexForSelection);
+
+    Vector<Vector<IntRect> > matchRects;
+    for (size_t i = 0; i < m_findMatches.size(); ++i) {
+        Vector<IntRect> rects;
+        m_findMatches[i]->textRects(rects);
+        matchRects.append(rects);
+    }
+
+    m_webPage->send(Messages::WebPageProxy::DidFindStringMatches(string, matchRects, indexForSelection));
 }
 
-bool FindController::updateFindIndicator(Frame* selectedFrame, bool isShowingOverlay, bool shouldAnimate)
+bool FindController::getFindIndicatorBitmapAndRect(Frame* frame, ShareableBitmap::Handle& handle, IntRect& selectionRect)
 {
-    if (!selectedFrame)
-        return false;
+    selectionRect = enclosingIntRect(frame->selection()->bounds());
 
-    IntRect selectionRect = enclosingIntRect(selectedFrame->selection()->bounds());
-    
     // Selection rect can be empty for matches that are currently obscured from view.
     if (selectionRect.isEmpty())
         return false;
 
-    // We want the selection rect in window coordinates.
-    IntRect selectionRectInWindowCoordinates = selectedFrame->view()->contentsToWindow(selectionRect);
-    
-    Vector<FloatRect> textRects;
-    selectedFrame->selection()->getClippedVisibleTextRectangles(textRects);
-
     IntSize backingStoreSize = selectionRect.size();
     backingStoreSize.scale(m_webPage->corePage()->deviceScaleFactor());
 
@@ -193,24 +192,81 @@ bool FindController::updateFindIndicator(Frame* selectedFrame, bool isShowingOve
     RefPtr<ShareableBitmap> findIndicatorTextBackingStore = ShareableBitmap::createShareable(backingStoreSize, ShareableBitmap::SupportsAlpha);
     if (!findIndicatorTextBackingStore)
         return false;
-    
+
     OwnPtr<GraphicsContext> graphicsContext = findIndicatorTextBackingStore->createGraphicsContext();
     graphicsContext->scale(FloatSize(m_webPage->corePage()->deviceScaleFactor(), m_webPage->corePage()->deviceScaleFactor()));
 
     IntRect paintRect = selectionRect;
-    paintRect.move(selectedFrame->view()->frameRect().x(), selectedFrame->view()->frameRect().y());
-    paintRect.move(-selectedFrame->view()->scrollOffset());
+    paintRect.move(frame->view()->frameRect().x(), frame->view()->frameRect().y());
+    paintRect.move(-frame->view()->scrollOffset());
 
     graphicsContext->translate(-paintRect.x(), -paintRect.y());
-    selectedFrame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorForceBlackText | PaintBehaviorFlattenCompositingLayers);
-    selectedFrame->document()->updateLayout();
+    frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorForceBlackText | PaintBehaviorFlattenCompositingLayers);
+    frame->document()->updateLayout();
+
+    frame->view()->paint(graphicsContext.get(), paintRect);
+    frame->view()->setPaintBehavior(PaintBehaviorNormal);
 
-    selectedFrame->view()->paint(graphicsContext.get(), paintRect);
-    selectedFrame->view()->setPaintBehavior(PaintBehaviorNormal);
-    
-    ShareableBitmap::Handle handle;
     if (!findIndicatorTextBackingStore->createHandle(handle))
         return false;
+    return true;
+}
+
+void FindController::getImageForFindMatch(uint32_t matchIndex)
+{
+    if (matchIndex >= m_findMatches.size())
+        return;
+    Frame* frame = m_findMatches[matchIndex]->startContainer()->document()->frame();
+    if (!frame)
+        return;
+
+    VisibleSelection oldSelection = frame->selection()->selection();
+    frame->selection()->setSelection(VisibleSelection(m_findMatches[matchIndex].get()));
+
+    IntRect selectionRect;
+    ShareableBitmap::Handle handle;
+    getFindIndicatorBitmapAndRect(frame, handle, selectionRect);
+
+    frame->selection()->setSelection(oldSelection);
+
+    m_webPage->send(Messages::WebPageProxy::DidGetImageForFindMatch(handle, matchIndex));
+}
+
+void FindController::selectFindMatch(uint32_t matchIndex)
+{
+    if (matchIndex >= m_findMatches.size())
+        return;
+    Frame* frame = m_findMatches[matchIndex]->startContainer()->document()->frame();
+    if (!frame)
+        return;
+    frame->selection()->setSelection(VisibleSelection(m_findMatches[matchIndex].get()));
+}
+
+void FindController::hideFindUI()
+{
+    m_findMatches.clear();
+    if (m_findPageOverlay)
+        m_webPage->uninstallPageOverlay(m_findPageOverlay, false);
+
+    m_webPage->corePage()->unmarkAllTextMatches();
+    hideFindIndicator();
+}
+
+bool FindController::updateFindIndicator(Frame* selectedFrame, bool isShowingOverlay, bool shouldAnimate)
+{
+    if (!selectedFrame)
+        return false;
+
+    IntRect selectionRect;
+    ShareableBitmap::Handle handle;
+    if (!getFindIndicatorBitmapAndRect(selectedFrame, handle, selectionRect))
+        return false;
+
+    // We want the selection rect in window coordinates.
+    IntRect selectionRectInWindowCoordinates = selectedFrame->view()->contentsToWindow(selectionRect);
+
+    Vector<FloatRect> textRects;
+    selectedFrame->selection()->getClippedVisibleTextRectangles(textRects);
 
     // We want the text rects in selection rect coordinates.
     Vector<FloatRect> textRectsInSelectionRectCoordinates;
index e070b6b..ba5e771 100644 (file)
@@ -27,6 +27,7 @@
 #define FindController_h
 
 #include "PageOverlay.h"
+#include "ShareableBitmap.h"
 #include "WebFindOptions.h"
 #include <WebCore/IntRect.h>
 #include <wtf/Forward.h>
@@ -35,6 +36,7 @@
 
 namespace WebCore {
     class Frame;
+    class Range;
 }
 
 namespace WebKit {
@@ -49,6 +51,9 @@ public:
     virtual ~FindController();
 
     void findString(const String&, FindOptions, unsigned maxMatchCount);
+    void findStringMatches(const String&, FindOptions, unsigned maxMatchCount);
+    void getImageForFindMatch(uint32_t matchIndex);
+    void selectFindMatch(uint32_t matchIndex);
     void hideFindUI();
     void countStringMatches(const String&, FindOptions, unsigned maxMatchCount);
     
@@ -68,6 +73,7 @@ private:
     virtual void drawRect(PageOverlay*, WebCore::GraphicsContext&, const WebCore::IntRect& dirtyRect);
 
     Vector<WebCore::IntRect> rectsForTextMatches();
+    bool getFindIndicatorBitmapAndRect(WebCore::Frame*, ShareableBitmap::Handle&, WebCore::IntRect& selectionRect);
     bool updateFindIndicator(WebCore::Frame* selectedFrame, bool isShowingOverlay, bool shouldAnimate = true);
 
     void updateFindUIAfterPageScroll(bool found, const String&, FindOptions, unsigned maxMatchCount);
@@ -79,6 +85,7 @@ private:
     // the find indicator isn't showing, but it will never be false when it is showing.
     bool m_isShowingFindIndicator;
     WebCore::IntRect m_findIndicatorRect;
+    Vector<RefPtr<WebCore::Range> > m_findMatches;
 };
 
 } // namespace WebKit
index 31841a1..60f45c5 100755 (executable)
@@ -2774,6 +2774,21 @@ void WebPage::findString(const String& string, uint32_t options, uint32_t maxMat
     m_findController.findString(string, static_cast<FindOptions>(options), maxMatchCount);
 }
 
+void WebPage::findStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
+{
+    m_findController.findStringMatches(string, static_cast<FindOptions>(options), maxMatchCount);
+}
+
+void WebPage::getImageForFindMatch(uint32_t matchIndex)
+{
+    m_findController.getImageForFindMatch(matchIndex);
+}
+
+void WebPage::selectFindMatch(uint32_t matchIndex)
+{
+    m_findController.selectFindMatch(matchIndex);
+}
+
 void WebPage::hideFindUI()
 {
     m_findController.hideFindUI();
index 686f0ad..f39ea2a 100755 (executable)
@@ -906,6 +906,9 @@ private:
     void didRemoveEditCommand(uint64_t commandID);
 
     void findString(const String&, uint32_t findOptions, uint32_t maxMatchCount);
+    void findStringMatches(const String&, uint32_t findOptions, uint32_t maxMatchCount);
+    void getImageForFindMatch(uint32_t matchIndex);
+    void selectFindMatch(uint32_t matchIndex);
     void hideFindUI();
     void countStringMatches(const String&, uint32_t findOptions, uint32_t maxMatchCount);
 
index 07dafbb..2d10c5e 100755 (executable)
@@ -183,6 +183,9 @@ messages -> WebPage {
 
     # Find.
     FindString(WTF::String string, uint32_t findOptions, unsigned maxMatchCount)
+    FindStringMatches(WTF::String string, uint32_t findOptions, unsigned maxMatchCount)
+    GetImageForFindMatch(uint32_t matchIndex)
+    SelectFindMatch(uint32_t matchIndex)
     HideFindUI()
     CountStringMatches(WTF::String string, uint32_t findOptions, unsigned maxMatchCount)
 
index d86f4b9..2e5f106 100644 (file)
                C0C5D3BE14598B6F00A802A6 /* GetBackingScaleFactor.mm in Sources */ = {isa = PBXBuildFile; fileRef = C0C5D3BC14598B6F00A802A6 /* GetBackingScaleFactor.mm */; };
                C0C5D3C61459912900A802A6 /* GetBackingScaleFactor_Bundle.mm in Sources */ = {isa = PBXBuildFile; fileRef = C0C5D3BD14598B6F00A802A6 /* GetBackingScaleFactor_Bundle.mm */; };
                C507E8A714C6545B005D6B3B /* InspectorBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = C507E8A614C6545B005D6B3B /* InspectorBar.mm */; };
+               C51AFB99169F49FF009CCF66 /* FindMatches.mm in Sources */ = {isa = PBXBuildFile; fileRef = C51AFB98169F49FF009CCF66 /* FindMatches.mm */; };
                C540F776152E4DA000A40C8C /* SimplifyMarkup.mm in Sources */ = {isa = PBXBuildFile; fileRef = C540F775152E4DA000A40C8C /* SimplifyMarkup.mm */; };
                C540F784152E5A9A00A40C8C /* verboseMarkup.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C540F783152E5A7800A40C8C /* verboseMarkup.html */; };
                E1220DA0155B25480013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1220D9F155B25480013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.mm */; };
                C0C5D3BC14598B6F00A802A6 /* GetBackingScaleFactor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetBackingScaleFactor.mm; sourceTree = "<group>"; };
                C0C5D3BD14598B6F00A802A6 /* GetBackingScaleFactor_Bundle.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetBackingScaleFactor_Bundle.mm; sourceTree = "<group>"; };
                C507E8A614C6545B005D6B3B /* InspectorBar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorBar.mm; sourceTree = "<group>"; };
+               C51AFB98169F49FF009CCF66 /* FindMatches.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FindMatches.mm; sourceTree = "<group>"; };
                C540F775152E4DA000A40C8C /* SimplifyMarkup.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SimplifyMarkup.mm; sourceTree = "<group>"; };
                C540F783152E5A7800A40C8C /* verboseMarkup.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = verboseMarkup.html; sourceTree = "<group>"; };
                E1220D9F155B25480013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCacheDisableWithinResourceLoadDelegate.mm; sourceTree = "<group>"; };
                                1A5FEFDC1270E2A3000E2921 /* EvaluateJavaScript.cpp */,
                                BCC8B95A12611F4700DE46A4 /* FailedLoad.cpp */,
                                1A02C84E125D4A8400E3F4BD /* Find.cpp */,
+                               C51AFB98169F49FF009CCF66 /* FindMatches.mm */,
                                1ADBEFAD130C689C00D61D19 /* ForceRepaint.cpp */,
                                BCBD370F125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp */,
                                BCBD3760125ABCFE00D2C29F /* FrameMIMETypePNG.cpp */,
                                A5E2027315B2181900C13E14 /* WindowlessWebViewWithMedia.mm in Sources */,
                                26B2DFF915BDE599004F691D /* HashSet.cpp in Sources */,
                                00CD9F6315BE312C002DA2CE /* BackForwardList.mm in Sources */,
+                               BC7B61AA129A038700D174A4 /* WKPreferences.cpp in Sources */,
+                               BC90995E12567BC100083756 /* WKString.cpp in Sources */,
+                               BC9099941256ACF100083756 /* WKStringJSString.cpp in Sources */,
+                               265AF55015D1E48A00B0CB4A /* WTFString.cpp in Sources */,
+                               C51AFB99169F49FF009CCF66 /* FindMatches.mm in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FindMatches.mm b/Tools/TestWebKitAPI/Tests/WebKit2/FindMatches.mm
new file mode 100644 (file)
index 0000000..4b08972
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 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"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#import <WebKit/WebDocumentPrivate.h>
+#import <WebKit/DOMPrivate.h>
+#include <WebKit2/WKImage.h>
+#import <wtf/RetainPtr.h>
+
+@interface FindMatchesWK1FrameLoadDelegate : NSObject {
+}
+@end
+
+static bool didFinishLoadWK1;
+
+@implementation FindMatchesWK1FrameLoadDelegate
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+    didFinishLoadWK1 = true;
+}
+
+@end
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad = false;
+static bool didCallFindStringMatches = false;
+static bool didCallGetImage = false;
+
+RetainPtr<WebView> webkit1View;
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+    didFinishLoad = true;
+}
+
+static void didFindStringMatches(WKPageRef page, WKStringRef string, WKArrayRef matches, int firstIndex, const void* clientInfo)
+{
+    EXPECT_WK_STREQ("Hello", string);
+    size_t numMatches = WKArrayGetSize(matches);
+    EXPECT_EQ(3u, numMatches);
+
+    for (size_t i = 0; i < numMatches; ++i) {
+        WKTypeRef items = WKArrayGetItemAtIndex(matches, i);
+        WKTypeID type = WKGetTypeID(items);
+        EXPECT_EQ(type, WKArrayGetTypeID());
+        WKArrayRef rects = reinterpret_cast<WKArrayRef>(items);
+        size_t numRects = WKArrayGetSize(rects);
+        EXPECT_EQ(1u, numRects);
+        items = WKArrayGetItemAtIndex(rects, 0);
+        type = WKGetTypeID(items);
+        EXPECT_EQ(type, WKRectGetTypeID());
+        WKRect rect = WKRectGetValue(reinterpret_cast<WKRectRef>(items));
+        rect = rect;
+    }
+    didCallFindStringMatches = true;
+}
+
+static void didGetImageForMatchResult(WKPageRef page, WKImageRef image, uint32_t index, const void* clientInfo)
+{
+    WKSize size = WKImageGetSize(image);
+
+    DOMDocument *document = webkit1View.get().mainFrameDocument;
+    DOMRange *range = [document createRange];
+    DOMNode *target = [document getElementById:@"target"];
+    [range selectNode:target];
+    NSImage *expectedImage = [range renderedImageForcingBlackText:YES];
+    NSSize expectedSize = [expectedImage size];
+    EXPECT_EQ(size.width, expectedSize.width);
+    EXPECT_EQ(size.height, expectedSize.height);
+    didCallGetImage = true;
+}
+
+TEST(WebKit2, FindMatches)
+{
+    WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+    PlatformWebView webView(context.get());
+    
+    WKPageLoaderClient loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+    
+    loaderClient.version = 0;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+    WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+    WKPageFindMatchesClient findMatchesClient;
+    memset(&findMatchesClient, 0, sizeof(findMatchesClient));
+
+    findMatchesClient.version = 0;
+    findMatchesClient.didFindStringMatches = didFindStringMatches;
+    findMatchesClient.didGetImageForMatchResult = didGetImageForMatchResult;
+
+    WKPageSetPageFindMatchesClient(webView.page(), &findMatchesClient);
+
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("find", "html"));
+    WKPageLoadURL(webView.page(), url.get());
+
+    Util::run(&didFinishLoad);
+
+    WKRetainPtr<WKStringRef> findString(AdoptWK, WKStringCreateWithUTF8CString("Hello"));
+    WKPageFindStringMatches(webView.page(), findString.get(), true, 100);
+    Util::run(&didCallFindStringMatches);
+
+    webkit1View.adoptNS([[WebView alloc] initWithFrame:NSMakeRect(0, 0, 120, 200) frameName:nil groupName:nil]);
+    RetainPtr<FindMatchesWK1FrameLoadDelegate> frameLoadDelegate(AdoptNS, [FindMatchesWK1FrameLoadDelegate new]);
+
+    webkit1View.get().frameLoadDelegate = frameLoadDelegate.get();
+    [webkit1View.get().mainFrame loadHTMLString:@"Test search. Hello <span id=\"target\">Hello</span> Hello!" baseURL:[NSURL URLWithString:@"about:blank"]];
+
+    Util::run(&didFinishLoadWK1);
+
+    WKPageGetImageForFindMatch(webView.page(), 0);
+    Util::run(&didCallGetImage);
+
+    WKPageHideFindUI(webView.page());
+}
+
+} // namespace TestWebKitAPI