Modified: trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.cpp (110491 => 110492)
--- trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.cpp 2012-03-12 22:37:02 UTC (rev 110491)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.cpp 2012-03-12 22:38:05 UTC (rev 110492)
@@ -24,30 +24,62 @@
#include "DocumentMarkerController.h"
#include "Editor.h"
#include "Frame.h"
+#include "Node.h"
#include "Page.h"
+#include "TextIterator.h"
+#include "Timer.h"
#include "WebPage_p.h"
-static const int TextMatchMarkerLimit = 100;
+static const double MaxScopingDuration = 0.1;
using namespace WebCore;
namespace BlackBerry {
namespace WebKit {
+class InPageSearchManager::DeferredScopeStringMatches {
+public:
+ DeferredScopeStringMatches(InPageSearchManager* ipsm, Frame* scopingFrame, const String& text, bool reset)
+ : m_searchManager(ipsm)
+ , m_scopingFrame(scopingFrame)
+ , m_timer(this, &DeferredScopeStringMatches::doTimeout)
+ , m_searchText(text)
+ , m_reset(reset)
+ {
+ m_timer.startOneShot(0.0);
+ }
+
+private:
+ void doTimeout(Timer<DeferredScopeStringMatches>*)
+ {
+ m_searchManager->callScopeStringMatches(this, m_scopingFrame, m_searchText, m_reset);
+ }
+ InPageSearchManager* m_searchManager;
+ Frame* m_scopingFrame;
+ Timer<DeferredScopeStringMatches> m_timer;
+ String m_searchText;
+ bool m_reset;
+};
+
InPageSearchManager::InPageSearchManager(WebPagePrivate* page)
: m_webPage(page)
, m_activeMatch(0)
+ , m_resumeScopingFromRange(0)
+ , m_scopingComplete(false)
+ , m_locatingActiveMatch(false)
{
}
InPageSearchManager::~InPageSearchManager()
{
+ cancelPendingScopingEffort();
}
bool InPageSearchManager::findNextString(const String& text, bool forward)
{
if (!text.length()) {
clearTextMatches();
+ cancelPendingScopingEffort();
m_activeSearchString = String();
return false;
}
@@ -62,14 +94,11 @@
m_activeMatch = 0;
RefPtr<Range> searchStartingPoint(m_activeMatch);
- if (m_activeSearchString != text) { // Start a new search.
+ bool newSearch = m_activeSearchString != text;
+ if (newSearch) { // Start a new search.
m_activeSearchString = text;
+ cancelPendingScopingEffort();
m_webPage->m_page->unmarkAllTextMatches();
- m_activeMatchCount = m_webPage->m_page->markAllMatchesForText(text, CaseInsensitive, true /* shouldHighlight */, TextMatchMarkerLimit);
- if (!m_activeMatchCount) {
- clearTextMatches();
- return false;
- }
} else { // Search same string for next occurrence.
setMarkerActive(m_activeMatch.get(), false /* active */);
// Searching for same string should start from the end of last match.
@@ -94,19 +123,19 @@
| CaseInsensitive
| StartInSelection;
- if (findAndMarkText(text, searchStartingPoint.get(), currentActiveMatchFrame, findOptions))
+ if (findAndMarkText(text, searchStartingPoint.get(), currentActiveMatchFrame, findOptions, newSearch))
return true;
Frame* startFrame = currentActiveMatchFrame;
do {
currentActiveMatchFrame = DOMSupport::incrementFrame(currentActiveMatchFrame, forward, true /* wrapFlag */);
- if (findAndMarkText(text, 0, currentActiveMatchFrame, findOptions))
+ if (findAndMarkText(text, 0, currentActiveMatchFrame, findOptions, newSearch))
return true;
} while (currentActiveMatchFrame && startFrame != currentActiveMatchFrame);
clearTextMatches();
- ASSERT_NOT_REACHED();
+ // FIXME: We need to notify client here.
return false;
}
@@ -117,7 +146,8 @@
// If the previous search string is prefix of new search string,
// don't search if the previous one has zero result.
- if (!m_activeMatchCount
+ if (m_scopingComplete
+ && !m_activeMatchCount
&& m_activeSearchString.length()
&& text.length() > m_activeSearchString.length()
&& m_activeSearchString == text.substring(0, m_activeSearchString.length()))
@@ -125,11 +155,15 @@
return true;
}
-bool InPageSearchManager::findAndMarkText(const String& text, Range* range, Frame* frame, const FindOptions& options)
+bool InPageSearchManager::findAndMarkText(const String& text, Range* range, Frame* frame, const FindOptions& options, bool isNewSearch)
{
m_activeMatch = frame->editor()->findStringAndScrollToVisible(text, range, options);
if (m_activeMatch) {
setMarkerActive(m_activeMatch.get(), true /* active */);
+ if (isNewSearch) {
+ scopeStringMatches(text, true /* reset */);
+ // FIXME: If it is a not new search, we need to calculate activeMatchIndex and notify client.
+ }
return true;
}
return false;
@@ -139,6 +173,8 @@
{
m_webPage->m_page->unmarkAllTextMatches();
m_activeMatch = 0;
+ m_activeMatchCount = 0;
+ m_activeMatchIndex = 0;
}
void InPageSearchManager::setMarkerActive(Range* range, bool active)
@@ -161,6 +197,8 @@
Frame* currentActiveMatchFrame = m_activeMatch->ownerDocument()->frame();
if (currentActiveMatchFrame == frame) {
+ // FIXME: We need to re-scope this frame instead of cancelling all effort?
+ cancelPendingScopingEffort();
m_activeMatch = 0;
m_activeSearchString = String();
m_activeMatchCount = 0;
@@ -171,5 +209,100 @@
}
}
+void InPageSearchManager::scopeStringMatches(const String& text, bool reset, Frame* scopingFrame)
+{
+ if (reset) {
+ m_activeMatchCount = 0;
+ m_resumeScopingFromRange = 0;
+ m_scopingComplete = false;
+ m_locatingActiveMatch = true;
+ // New search should always start from mainFrame.
+ scopeStringMatchesSoon(m_webPage->mainFrame(), text, false /* reset */);
+ return;
+ }
+
+ if (m_resumeScopingFromRange && scopingFrame != m_resumeScopingFromRange->ownerDocument()->frame())
+ m_resumeScopingFromRange = 0;
+
+ RefPtr<Range> searchRange(rangeOfContents(scopingFrame->document()));
+ Node* originalEndContainer = searchRange->endContainer();
+ int originalEndOffset = searchRange->endOffset();
+ ExceptionCode ec = 0, ec2 = 0;
+ if (m_resumeScopingFromRange) {
+ searchRange->setStart(m_resumeScopingFromRange->startContainer(), m_resumeScopingFromRange->startOffset(ec2) + 1, ec);
+ if (ec || ec2) {
+ m_scopingComplete = true; // We should stop scoping because of some stale data.
+ return;
+ }
+ }
+
+ int matchCount = 0;
+ bool timeout = false;
+ double startTime = currentTime();
+ do {
+ RefPtr<Range> resultRange(findPlainText(searchRange.get(), text, CaseInsensitive));
+ if (resultRange->collapsed(ec)) {
+ if (!resultRange->startContainer()->isInShadowTree())
+ break;
+ searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
+ searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
+ continue;
+ }
+
+ if (scopingFrame->editor()->insideVisibleArea(resultRange.get())) {
+ ++matchCount;
+ bool foundActiveMatch = false;
+ if (m_locatingActiveMatch && areRangesEqual(resultRange.get(), m_activeMatch.get())) {
+ foundActiveMatch = true;
+ m_locatingActiveMatch = false;
+ m_activeMatchIndex = m_activeMatchCount + matchCount;
+ // FIXME: We need to notify client with m_activeMatchIndex.
+ }
+ resultRange->ownerDocument()->markers()->addTextMatchMarker(resultRange.get(), foundActiveMatch);
+ }
+ searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
+ Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
+ if (searchRange->collapsed(ec) && shadowTreeRoot)
+ searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
+ m_resumeScopingFromRange = resultRange;
+ timeout = (currentTime() - startTime) >= MaxScopingDuration;
+ } while (!timeout);
+
+ if (matchCount > 0) {
+ scopingFrame->editor()->setMarkedTextMatchesAreHighlighted(true /* highlight */);
+ m_activeMatchCount += matchCount;
+ }
+
+ if (timeout)
+ scopeStringMatchesSoon(scopingFrame, text, false /* reset */);
+ else {
+ // Scoping is done for this frame.
+ Frame* nextFrame = DOMSupport::incrementFrame(scopingFrame, true /* forward */, false /* wrapFlag */);
+ if (!nextFrame) {
+ m_scopingComplete = true;
+ return; // Scoping is done for all frames;
+ }
+ scopeStringMatchesSoon(nextFrame, text, false /* reset */);
+ }
}
+
+void InPageSearchManager::scopeStringMatchesSoon(Frame* scopingFrame, const String& text, bool reset)
+{
+ m_deferredScopingWork.append(new DeferredScopeStringMatches(this, scopingFrame, text, reset));
}
+
+void InPageSearchManager::callScopeStringMatches(DeferredScopeStringMatches* caller, Frame* scopingFrame, const String& text, bool reset)
+{
+ m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
+ scopeStringMatches(text, reset, scopingFrame);
+ delete caller;
+}
+
+void InPageSearchManager::cancelPendingScopingEffort()
+{
+ deleteAllValues(m_deferredScopingWork);
+ m_deferredScopingWork.clear();
+}
+
+}
+}
Modified: trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.h (110491 => 110492)
--- trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.h 2012-03-12 22:37:02 UTC (rev 110491)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InPageSearchManager.h 2012-03-12 22:38:05 UTC (rev 110492)
@@ -43,15 +43,27 @@
void frameUnloaded(const WebCore::Frame*);
private:
+ class DeferredScopeStringMatches;
+ friend class DeferredScopeStringMatches;
+
void clearTextMatches();
void setMarkerActive(WebCore::Range*, bool);
- bool findAndMarkText(const String&, WebCore::Range*, WebCore::Frame*, const WebCore::FindOptions&);
+ bool findAndMarkText(const String&, WebCore::Range*, WebCore::Frame*, const WebCore::FindOptions&, bool);
bool shouldSearchForText(const String&);
+ void scopeStringMatches(const String& text, bool reset, WebCore::Frame* scopingFrame = 0);
+ void scopeStringMatchesSoon(WebCore::Frame* scopingFrame, const String& text, bool reset);
+ void callScopeStringMatches(DeferredScopeStringMatches* caller, WebCore::Frame* scopingFrame, const String& text, bool reset);
+ void cancelPendingScopingEffort();
+ Vector<DeferredScopeStringMatches*> m_deferredScopingWork;
WebPagePrivate* m_webPage;
RefPtr<WebCore::Range> m_activeMatch;
+ RefPtr<WebCore::Range> m_resumeScopingFromRange;
String m_activeSearchString;
int m_activeMatchCount;
+ bool m_scopingComplete;
+ bool m_locatingActiveMatch;
+ int m_activeMatchIndex;
};
}