[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
__ZN7WebCore4Page21markAllMatchesForTextERKN3WTF6StringEjbj
__ZN7WebCore4Page22allVisitedStateChangedEPNS_9PageGroupE
__ZN7WebCore4Page23clearUndoRedoOperationsEv
+__ZN7WebCore4Page24findStringMatchingRangesERKN3WTF6StringEjiPNS1_6VectorINS1_6RefPtrINS_5RangeEEELm0EEERi
__ZN7WebCore4Page24resumeScriptedAnimationsEv
__ZN7WebCore4Page25suspendScriptedAnimationsEv
__ZN7WebCore4Page27setJavaScriptURLsAreAllowedEb
__ZN7WebCore6Editor18confirmCompositionERKN3WTF6StringE
__ZN7WebCore6Editor18confirmCompositionEv
__ZN7WebCore6Editor18insertDictatedTextERKN3WTF6StringERKNS1_6VectorINS_20DictationAlternativeELm0EEEPNS_5EventE
-__ZN7WebCore6Editor19countMatchesForTextERKN3WTF6StringEPNS_5RangeEjjb
__ZN7WebCore6Editor19deleteWithDirectionENS_18SelectionDirectionENS_15TextGranularityEbb
__ZN7WebCore6Editor19insertUnorderedListEv
__ZN7WebCore6Editor21applyStyleToSelectionEPNS_16StylePropertySetENS_10EditActionE
__ZN7WebCore6Editor7CommandC1Ev
__ZN7WebCore6Editor7commandERKN3WTF6StringE
__ZN7WebCore6Editor7outdentEv
+__ZN7WebCore6Editor19countMatchesForTextERKN3WTF6StringEPNS_5RangeEjjbPNS1_6VectorINS1_6RefPtrIS5_EELm0EEE
__ZN7WebCore6JSNode6s_infoE
__ZN7WebCore6Region5uniteERKS0_
__ZN7WebCore6Region8subtractERKS0_
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;
}
++matchCount;
+ if (matches)
+ matches->append(resultRange);
+
if (markMatches)
m_frame->document()->markers()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
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.
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);
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())
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);
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>);
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
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);
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);
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);
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);
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
namespace WebKit {
+class ImmutableArray;
class WebPageProxy;
+class WebImage;
class WebFindClient : public APIClient<WKPageFindClient, kWKPageFindClientCurrentVersion> {
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
#include "DrawingAreaProxy.h"
#include "EventDispatcherMessages.h"
#include "FindIndicator.h"
+#include "ImmutableArray.h"
#include "Logging.h"
#include "MessageID.h"
#include "NativeWebKeyboardEvent.h"
m_findClient.initialize(client);
}
+void WebPageProxy::initializeFindMatchesClient(const WKPageFindMatchesClient* client)
+{
+ m_findMatchesClient.initialize(client);
+}
+
#if ENABLE(CONTEXT_MENUS)
void WebPageProxy::initializeContextMenuClient(const WKPageContextMenuClient* client)
{
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)
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);
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);
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);
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*);
// 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
WebResourceLoadClient m_resourceLoadClient;
WebUIClient m_uiClient;
WebFindClient m_findClient;
+ WebFindMatchesClient m_findMatchesClient;
#if ENABLE(CONTEXT_MENUS)
WebPageContextMenuClient m_contextMenuClient;
#endif
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
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());
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;
#define FindController_h
#include "PageOverlay.h"
+#include "ShareableBitmap.h"
#include "WebFindOptions.h"
#include <WebCore/IntRect.h>
#include <wtf/Forward.h>
namespace WebCore {
class Frame;
+ class Range;
}
namespace WebKit {
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);
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);
// 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
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();
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);
# 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)
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;
};
--- /dev/null
+/*
+ * 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