summaryrefslogtreecommitdiffstats
path: root/android_webview/browser
diff options
context:
space:
mode:
Diffstat (limited to 'android_webview/browser')
-rw-r--r--android_webview/browser/DEPS3
-rw-r--r--android_webview/browser/find_helper.cc173
-rw-r--r--android_webview/browser/find_helper.h77
-rw-r--r--android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h20
4 files changed, 273 insertions, 0 deletions
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 923f45e..2a21cd21 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -2,4 +2,7 @@ include_rules = [
"-android_webview",
"+android_webview/browser",
"+android_webview/common",
+
+ # POD structure required by the find-in-page IPC messages.
+ "+third_party/WebKit/Source/WebKit/chromium/public/WebFindOptions.h",
]
diff --git a/android_webview/browser/find_helper.cc b/android_webview/browser/find_helper.cc
new file mode 100644
index 0000000..b4c7669
--- /dev/null
+++ b/android_webview/browser/find_helper.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/browser/find_helper.h"
+
+#include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
+#include "base/message_loop.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/stop_find_action.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFindOptions.h"
+
+using content::WebContents;
+using WebKit::WebFindOptions;
+
+namespace android_webview {
+
+FindHelper::FindHelper(WebContents* web_contents)
+ : WebContentsObserver(web_contents),
+ listener_(NULL),
+ async_find_started_(false),
+ sync_find_started_(false),
+ find_request_id_counter_(0),
+ current_request_id_(0),
+ last_match_count_(-1),
+ last_active_ordinal_(-1),
+ weak_factory_(this) {
+}
+
+FindHelper::~FindHelper() {
+}
+
+void FindHelper::SetListener(Listener* listener) {
+ listener_ = listener;
+}
+
+int FindHelper::FindAllSync(const string16& search_string) {
+ sync_find_started_ = true;
+ async_find_started_ = false;
+
+ WebFindOptions options;
+ options.forward = true;
+ options.matchCase = false;
+ options.findNext = false;
+
+ int match_count = 0;
+ int active_ordinal = 0;
+
+ StartNewRequest(search_string);
+
+ // Any ongoing asynchronous requests will be stopped in the renderer when
+ // calling SynchronousFind. Using the asynchronous StopFinding message could
+ // lead to deadblocks as the message could arrive in the middle of the
+ // synchronous operation and cancel the reply back.
+ ScopedAllowWaitForLegacyWebViewApi wait;
+ web_contents()->GetRenderViewHost()->SynchronousFind(current_request_id_,
+ search_string,
+ options,
+ &match_count,
+ &active_ordinal);
+
+ // Post the task to ourselves to prevent trigerring the notification before
+ // we actually return from the request.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&FindHelper::NotifyResults, weak_factory_.GetWeakPtr(),
+ active_ordinal, match_count, true));
+
+ return match_count;
+}
+
+void FindHelper::FindAllAsync(const string16& search_string) {
+ // Stop any ongoing asynchronous request.
+ web_contents()->GetRenderViewHost()->StopFinding(
+ content::STOP_FIND_ACTION_KEEP_SELECTION);
+
+ sync_find_started_ = false;
+ async_find_started_ = true;
+
+ WebFindOptions options;
+ options.forward = true;
+ options.matchCase = false;
+ options.findNext = false;
+
+ StartNewRequest(search_string);
+ web_contents()->GetRenderViewHost()->Find(current_request_id_,
+ search_string, options);
+}
+
+void FindHelper::HandleFindReply(int request_id,
+ int match_count,
+ int active_ordinal,
+ bool finished) {
+ if ((!async_find_started_ && !sync_find_started_) ||
+ request_id != current_request_id_) {
+ return;
+ }
+
+ NotifyResults(active_ordinal, match_count, finished);
+}
+
+void FindHelper::FindNext(bool forward) {
+ if (!sync_find_started_ && !async_find_started_)
+ return;
+
+ WebFindOptions options;
+ options.forward = forward;
+ options.matchCase = false;
+ options.findNext = true;
+
+ web_contents()->GetRenderViewHost()->Find(current_request_id_,
+ last_search_string_,
+ options);
+}
+
+void FindHelper::ClearMatches() {
+ web_contents()->GetRenderViewHost()->StopFinding(
+ content::STOP_FIND_ACTION_CLEAR_SELECTION);
+
+ sync_find_started_ = false;
+ async_find_started_ = false;
+ last_search_string_.clear();
+ last_match_count_ = -1;
+ last_active_ordinal_ = -1;
+}
+
+void FindHelper::StartNewRequest(const string16& search_string) {
+ current_request_id_ = find_request_id_counter_++;
+ last_search_string_ = search_string;
+ last_match_count_ = -1;
+ last_active_ordinal_ = -1;
+}
+
+void FindHelper::NotifyResults(int active_ordinal,
+ int match_count,
+ bool finished) {
+ // Match count or ordinal values set to -1 refer to the received replies.
+ if (match_count == -1)
+ match_count = last_match_count_;
+ else
+ last_match_count_ = match_count;
+
+ if (active_ordinal == -1)
+ active_ordinal = last_active_ordinal_;
+ else
+ last_active_ordinal_ = active_ordinal;
+
+ // Skip the update if we don't still have a valid ordinal.
+ // The next update, final or not, should have this information.
+ if (!finished && active_ordinal == -1)
+ return;
+
+ // Safeguard in case of errors to prevent reporting -1 to the API listeners.
+ if (match_count == -1) {
+ NOTREACHED();
+ match_count = 0;
+ }
+
+ if (active_ordinal == -1) {
+ NOTREACHED();
+ active_ordinal = 0;
+ }
+
+ // WebView.FindListener active match ordinals are 0-based while WebKit sends
+ // 1-based ordinals. Still we can receive 0 ordinal in case of no results.
+ active_ordinal = std::max(active_ordinal - 1, 0);
+
+ if (listener_)
+ listener_->OnFindResultReceived(active_ordinal, match_count, finished);
+}
+
+} // namespace android_webview
diff --git a/android_webview/browser/find_helper.h b/android_webview/browser/find_helper.h
new file mode 100644
index 0000000..a9d7aed
--- /dev/null
+++ b/android_webview/browser/find_helper.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_FIND_HELPER_H_
+#define ANDROID_WEBVIEW_BROWSER_FIND_HELPER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace android_webview {
+
+// Handles the WebView find-in-page API requests.
+class FindHelper : public content::WebContentsObserver {
+ public:
+ class Listener {
+ public:
+ // Called when receiving a new find-in-page update.
+ // This will be triggered when the results of FindAllSync, FindAllAsync and
+ // FindNext are available. The value provided in active_ordinal is 0-based.
+ virtual void OnFindResultReceived(int active_ordinal,
+ int match_count,
+ bool finished) = 0;
+ virtual ~Listener() {}
+ };
+
+ explicit FindHelper(content::WebContents* web_contents);
+ virtual ~FindHelper();
+
+ // Sets the listener to receive find result updates.
+ // Does not own the listener and must set to NULL when invalid.
+ void SetListener(Listener* listener);
+
+ // Synchronous API.
+ int FindAllSync(const string16& search_string);
+
+ // Asynchronous API.
+ void FindAllAsync(const string16& search_string);
+ void HandleFindReply(int request_id,
+ int match_count,
+ int active_ordinal,
+ bool finished);
+
+ // Methods valid in both synchronous and asynchronous modes.
+ void FindNext(bool forward);
+ void ClearMatches();
+
+ private:
+ void StartNewRequest(const string16& search_string);
+ void NotifyResults(int active_ordinal, int match_count, bool finished);
+
+ // Listener results are reported to.
+ Listener* listener_;
+
+ // Used to check the validity of FindNext operations.
+ bool async_find_started_;
+ bool sync_find_started_;
+
+ // Used to provide different ids to each request and for result
+ // verification in asynchronous calls.
+ int find_request_id_counter_;
+ int current_request_id_;
+
+ // Required by FindNext and the incremental find replies.
+ string16 last_search_string_;
+ int last_match_count_;
+ int last_active_ordinal_;
+
+ // Used to post synchronous result notifications to ourselves.
+ base::WeakPtrFactory<FindHelper> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FindHelper);
+};
+
+} // namespace android_webview
+
+#endif // ANDROID_WEBVIEW_BROWSER_FIND_HELPER_H_
diff --git a/android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h b/android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h
new file mode 100644
index 0000000..af2154b
--- /dev/null
+++ b/android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_SCOPED_ALLOW_WAIT_FOR_LEGACY_WEB_VIEW_API_H
+#define ANDROID_WEBVIEW_BROWSER_SCOPED_ALLOW_WAIT_FOR_LEGACY_WEB_VIEW_API_H
+
+#include "base/threading/thread_restrictions.h"
+
+// This class is only available when building the chromium back-end for android
+// webview: it is required where API backward compatibility demands that the UI
+// thread must block waiting on other threads e.g. to obtain a synchronous
+// return value. Long term, asynchronous overloads of all such methods will be
+// added in the public API, and and no new uses of this will be allowed.
+class ScopedAllowWaitForLegacyWebViewApi {
+ private:
+ base::ThreadRestrictions::ScopedAllowWait wait;
+};
+
+#endif // ANDROID_WEBVIEW_BROWSER_SCOPED_ALLOW_WAIT_FOR_LEGACY_WEB_VIEW_API_H