Title: [110492] trunk/Source/WebKit/blackberry
Revision
110492
Author
[email protected]
Date
2012-03-12 15:38:05 -0700 (Mon, 12 Mar 2012)

Log Message

[Blackberry] Make the process of marking all matches interruptible and asynchronous for find-in-page
https://bugs.webkit.org/show_bug.cgi?id=80831

Patch by Andy Chen <[email protected]> on 2012-03-12
Reviewed by Antonio Gomes.

* WebKitSupport/InPageSearchManager.cpp:
(BlackBerry::WebKit::InPageSearchManager::DeferredScopeStringMatches::DeferredScopeStringMatches):
(BlackBerry::WebKit::InPageSearchManager::DeferredScopeStringMatches::doTimeout):
(BlackBerry::WebKit::InPageSearchManager::InPageSearchManager):
(BlackBerry::WebKit::InPageSearchManager::~InPageSearchManager):
(BlackBerry::WebKit::InPageSearchManager::findNextString):
(BlackBerry::WebKit::InPageSearchManager::shouldSearchForText):
(BlackBerry::WebKit::InPageSearchManager::findAndMarkText):
(BlackBerry::WebKit::InPageSearchManager::clearTextMatches):
(BlackBerry::WebKit::InPageSearchManager::frameUnloaded):
(BlackBerry::WebKit::InPageSearchManager::scopeStringMatches):
(BlackBerry::WebKit::InPageSearchManager::scopeStringMatchesSoon):
(BlackBerry::WebKit::InPageSearchManager::callScopeStringMatches):
(BlackBerry::WebKit::InPageSearchManager::cancelPendingScopingEffort):
* WebKitSupport/InPageSearchManager.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit/blackberry/ChangeLog (110491 => 110492)


--- trunk/Source/WebKit/blackberry/ChangeLog	2012-03-12 22:37:02 UTC (rev 110491)
+++ trunk/Source/WebKit/blackberry/ChangeLog	2012-03-12 22:38:05 UTC (rev 110492)
@@ -1,3 +1,26 @@
+2012-03-12  Andy Chen  <[email protected]>
+
+        [Blackberry] Make the process of marking all matches interruptible and asynchronous for find-in-page
+        https://bugs.webkit.org/show_bug.cgi?id=80831
+
+        Reviewed by Antonio Gomes.
+
+        * WebKitSupport/InPageSearchManager.cpp:
+        (BlackBerry::WebKit::InPageSearchManager::DeferredScopeStringMatches::DeferredScopeStringMatches):
+        (BlackBerry::WebKit::InPageSearchManager::DeferredScopeStringMatches::doTimeout):
+        (BlackBerry::WebKit::InPageSearchManager::InPageSearchManager):
+        (BlackBerry::WebKit::InPageSearchManager::~InPageSearchManager):
+        (BlackBerry::WebKit::InPageSearchManager::findNextString):
+        (BlackBerry::WebKit::InPageSearchManager::shouldSearchForText):
+        (BlackBerry::WebKit::InPageSearchManager::findAndMarkText):
+        (BlackBerry::WebKit::InPageSearchManager::clearTextMatches):
+        (BlackBerry::WebKit::InPageSearchManager::frameUnloaded):
+        (BlackBerry::WebKit::InPageSearchManager::scopeStringMatches):
+        (BlackBerry::WebKit::InPageSearchManager::scopeStringMatchesSoon):
+        (BlackBerry::WebKit::InPageSearchManager::callScopeStringMatches):
+        (BlackBerry::WebKit::InPageSearchManager::cancelPendingScopingEffort):
+        * WebKitSupport/InPageSearchManager.h:
+
 2012-03-09  Jon Lee  <[email protected]>
 
         Rename NotificationPresenter to NotificationClient

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;
 };
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to