2007-12-19 Christian Dywan <christian@twotoasts.de>
authoralp@webkit.org <alp@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Dec 2007 00:23:03 +0000 (00:23 +0000)
committeralp@webkit.org <alp@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Dec 2007 00:23:03 +0000 (00:23 +0000)
        Reviewed by Alp Toker.

        http://bugs.webkit.org/show_bug.cgi?id=16222
        [GTK] Implement inline search and highlighting of matching strings.

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

WebCore/ChangeLog
WebCore/page/Page.cpp
WebCore/page/Page.h
WebKit/gtk/ChangeLog
WebKit/gtk/WebView/webkitwebview.cpp
WebKit/gtk/WebView/webkitwebview.h

index 85c7f792118a4444847c7fdcb35ac814b18909a0..afad6ee3b6d1524970600f57547e9edaf757d884 100644 (file)
@@ -1,3 +1,19 @@
+2007-12-19  Christian Dywan  <christian@twotoasts.de> 
+
+        Reviewed by Alp Toker.
+
+        http://bugs.webkit.org/show_bug.cgi?id=16222
+        [GTK] Implement inline search and highlighting of matching strings.
+
+        Implement search and highlighting logic directly in WebCore.
+
+        * page/Page.cpp:
+        (WebCore::incrementFrame):
+        (WebCore::Page::findString):
+        (WebCore::Page::markAllMatchesForText):
+        (WebCore::Page::unmarkAllTextMatches):
+        * page/Page.h:
+
 2007-12-19  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Sam Weinig, Dan Bernstein.
index de74ab5281ba459363e1472061a38df1140683de..fac9780ae06b5fb5f007a6422d0893dafe6c0d95 100644 (file)
@@ -204,6 +204,71 @@ void Page::setNeedsReapplyStyles()
             frame->setNeedsReapplyStyles();
 }
 
+static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
+{
+    return forward
+        ? curr->tree()->traverseNextWithWrap(wrapFlag)
+        : curr->tree()->traversePreviousWithWrap(wrapFlag);
+}
+
+bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
+{
+    if (target.isEmpty() || !mainFrame())
+        return false;
+
+    Frame* frame = focusController()->focusedOrMainFrame();
+    Frame* startFrame = frame;
+    do {
+        if (frame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) {
+            if (frame != startFrame)
+                startFrame->selectionController()->clear();
+            focusController()->setFocusedFrame(frame);
+            return true;
+        }
+        frame = incrementFrame(frame, direction == FindDirectionForward, shouldWrap);
+    } while (frame && frame != startFrame);
+
+    // Search contents of startFrame, on the other side of the selection that we did earlier.
+    // We cheat a bit and just research with wrap on
+    if (shouldWrap && !startFrame->selectionController()->isNone()) {
+        bool found = startFrame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true);
+        focusController()->setFocusedFrame(frame);
+        return found;
+    }
+
+    return false;
+}
+
+uint Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
+{
+    if (target.isEmpty() || !mainFrame())
+        return 0;
+
+    unsigned matches = 0;
+
+    Frame* frame = mainFrame();
+    do {
+        frame->setMarkedTextMatchesAreHighlighted(shouldHighlight);
+        matches += frame->markAllMatchesForText(target, caseSensitivity == TextCaseSensitive, (limit == 0) ? 0 : (limit - matches));
+        frame = incrementFrame(frame, true, false);
+    } while (frame);
+
+    return matches;
+}
+
+void Page::unmarkAllTextMatches()
+{
+    if (!mainFrame())
+        return;
+
+    Frame* frame = mainFrame();
+    do {
+        if (Document* document = frame->document())
+            document->removeMarkers(DocumentMarker::TextMatch);
+        frame = incrementFrame(frame, true, false);
+    } while (frame);
+}
+
 const Selection& Page::selection() const
 {
     return focusController()->focusedOrMainFrame()->selectionController()->selection();
index 27b8f2de639b82019a24200573d70967bca85e2a..b8bfa12342e2cccfcf75336345356d320d7d1441 100644 (file)
 typedef struct HINSTANCE__* HINSTANCE;
 #endif
 
+typedef enum TextCaseSensitivity {
+    TextCaseSensitive,
+    TextCaseInsensitive
+};
+
+typedef enum FindDirection {
+    FindDirectionForward,
+    FindDirectionBackward
+};
+
 namespace WebCore {
 
     class Chrome;
@@ -98,7 +108,11 @@ namespace WebCore {
         
         void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; }
         bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; }
-        
+
+        bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap);
+        uint markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);
+        void unmarkAllTextMatches();
+
         const Selection& selection() const;
 
         void setDefersLoading(bool);
index dbfc390f3da4de0b4f4c28c3e412bc83e78486fe..3213cfb243f8b3129419bb6600b5bf32d45c029c 100644 (file)
@@ -1,3 +1,13 @@
+2007-12-19  Christian Dywan  <christian@twotoasts.de> 
+
+        Reviewed by Alp Toker.
+
+        http://bugs.webkit.org/show_bug.cgi?id=16222
+        [GTK] Implement inline search and highlighting of matching strings.
+
+        * WebView/webkitwebview.cpp:
+        * WebView/webkitwebview.h:
+
 2007-12-19  Alp Toker  <alp@atoker.com>
 
         Reviewed by Holger Freyther.
index 868c6427559b9217ad6d9f866224087143305d4c..00ca4bb0f1812c33dbc97d1908fdf8ed7b0fe476 100644 (file)
@@ -946,6 +946,82 @@ void webkit_web_view_stop_loading(WebKitWebView* webView)
         loader->stopAllLoaders();
 }
 
+/**
+ * webkit_web_view_search_text:
+ * @web_view: a #WebKitWebView
+ * @text: a string to look for
+ * @forward: wether to find forward or not
+ * @case_sensitive: wether to respect the case of text
+ * @wrap: wether to continue looking at the beginning after reaching the end
+ *
+ * Looks for a specified string inside #web_view.
+ *
+ * Return value: %TRUE on success or %FALSE on failure
+ */
+gboolean webkit_web_view_search_text(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, gboolean forward, gboolean shouldWrap)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
+    g_return_val_if_fail(string, FALSE);
+
+    TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
+    FindDirection direction = forward ? FindDirectionForward : FindDirectionBackward;
+
+    WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
+    return webViewData->corePage->findString(String::fromUTF8(string), caseSensitivity, direction, shouldWrap);
+}
+
+/**
+ * webkit_web_view_mark_text_matches:
+ * @web_view: a #WebKitWebView
+ * @string: a string to look for
+ * @case_sensitive: wether to respect the case of text
+ * @limit: the maximum number of strings to look for or %0 for all
+ *
+ * Attempts to highlight all occurances of #string inside #web_view.
+ *
+ * Return value: the number of strings highlighted
+ */
+guint webkit_web_view_mark_text_matches(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, guint limit)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
+    g_return_val_if_fail(string, 0);
+
+    TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
+
+    WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
+    return webViewData->corePage->markAllMatchesForText(String::fromUTF8(string), caseSensitivity, false, limit);
+}
+
+/**
+ * webkit_web_view_set_highlight_text_matches:
+ * @web_view: a #WebKitWebView
+ * @highlight: Wether to highlight text matches
+ *
+ * Highlights text matches previously marked by webkit_web_view_mark_text_matches.
+ */
+void webkit_web_view_set_highlight_text_matches(WebKitWebView* webView, gboolean shouldHighlight)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
+
+    WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
+    WebKitWebFramePrivate* frameData = WEBKIT_WEB_FRAME_GET_PRIVATE(webViewData->mainFrame);
+    frameData->frame->setMarkedTextMatchesAreHighlighted(shouldHighlight);
+}
+
+/**
+ * webkit_web_view_unmark_text_matches:
+ * @web_view: a #WebKitWebView
+ *
+ * Removes highlighting previously set by webkit_web_view_mark_text_matches.
+ */
+void webkit_web_view_unmark_text_matches(WebKitWebView* webView)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
+
+    WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
+    return webViewData->corePage->unmarkAllTextMatches();
+}
+
 WebKitWebFrame* webkit_web_view_get_main_frame(WebKitWebView* webView)
 {
     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
index e2d96466ad2954719b53a5cc4034c9b7808899c0..2d6d848f3e7237cdb0d5804302924216a6dd082e 100644 (file)
@@ -113,6 +113,18 @@ webkit_web_view_load_string (WebKitWebView* web_view, const gchar* content, cons
 WEBKIT_API void
 webkit_web_view_load_html_string (WebKitWebView* web_view, const gchar* content, const gchar* base_uri);
 
+WEBKIT_API gboolean
+webkit_web_view_search_text (WebKitWebView* web_view, const gchar* string, gboolean case_sensitive, gboolean forward, gboolean wrap);
+
+WEBKIT_API guint
+webkit_web_view_mark_text_matches (WebKitWebView* web_view, const gchar* string, gboolean case_sensitive, guint limit);
+
+WEBKIT_API void
+webkit_web_view_set_highlight_text_matches (WebKitWebView* web_view, gboolean highlight);
+
+WEBKIT_API void
+webkit_web_view_unmark_text_matches (WebKitWebView* web_view);
+
 WEBKIT_API WebKitWebFrame*
 webkit_web_view_get_main_frame (WebKitWebView* web_view);