summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_webview/android_webview.gyp3
-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
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java29
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsClient.java8
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AndroidWebViewTestBase.java11
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java5
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java141
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/WebViewFindApisTestBase.java184
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/WebViewMixedFindApisTest.java42
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/WebViewSynchronousFindApisTest.java141
-rw-r--r--android_webview/lib/main/webview_entry_point.cc7
-rw-r--r--android_webview/native/aw_contents.cc86
-rw-r--r--android_webview/native/aw_contents.h18
-rw-r--r--android_webview/native/aw_web_contents_delegate.cc21
-rw-r--r--android_webview/native/aw_web_contents_delegate.h6
-rw-r--r--android_webview/native/cookie_manager.cc11
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc20
-rw-r--r--content/browser/renderer_host/render_process_host_impl.h10
-rw-r--r--content/browser/renderer_host/render_view_host_impl.cc15
-rw-r--r--content/browser/renderer_host/render_view_host_impl.h5
-rw-r--r--content/common/view_messages.h145
-rw-r--r--content/public/browser/render_view_host.h8
-rw-r--r--content/public/common/content_switches.cc4
-rw-r--r--content/public/common/content_switches.h1
-rw-r--r--content/renderer/render_view_impl.cc176
-rw-r--r--content/renderer/render_view_impl.h73
29 files changed, 1251 insertions, 192 deletions
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index cb303f9..dd0b31a 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -32,12 +32,15 @@
'browser/aw_http_auth_handler_base.h',
'browser/aw_login_delegate.cc',
'browser/aw_login_delegate.h',
+ 'browser/find_helper.cc',
+ 'browser/find_helper.h',
'browser/net/aw_network_delegate.cc',
'browser/net/aw_network_delegate.h',
'browser/renderer_host/aw_render_view_host_ext.cc',
'browser/renderer_host/aw_render_view_host_ext.h',
'browser/renderer_host/aw_resource_dispatcher_host_delegate.cc',
'browser/renderer_host/aw_resource_dispatcher_host_delegate.h',
+ 'browser/scoped_allow_wait_for_legacy_web_view_api.h',
'lib/aw_browser_dependency_factory_impl.cc',
'lib/aw_browser_dependency_factory_impl.h',
'lib/aw_content_browser_client.cc',
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
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 3f826a9..c0a1a6f 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -102,8 +102,24 @@ public class AwContents {
mCleanupReference.cleanupNow();
}
+ public int findAllSync(String searchString) {
+ return nativeFindAllSync(mNativeAwContents, searchString);
+ }
+
+ public void findAllAsync(String searchString) {
+ nativeFindAllAsync(mNativeAwContents, searchString);
+ }
+
+ public void findNext(boolean forward) {
+ nativeFindNext(mNativeAwContents, forward);
+ }
+
+ public void clearMatches() {
+ nativeClearMatches(mNativeAwContents);
+ }
+
/**
- * @return load progress of the WebContents
+ * @return load progress of the WebContents.
*/
public int getMostRecentProgress() {
// WebContentsDelegateAndroid conveniently caches the most recent notified value for us.
@@ -182,6 +198,12 @@ public class AwContents {
mContentsClient.onReceivedHttpAuthRequest(handler, host, realm);
}
+ @CalledByNative
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting) {
+ mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
+ }
+
// -------------------------------------------------------------------------------------------
// Helper methods
// -------------------------------------------------------------------------------------------
@@ -270,4 +292,9 @@ public class AwContents {
private native void nativeSetIoThreadClient(int nativeAwContents,
AwContentsIoThreadClient ioThreadClient);
+
+ private native int nativeFindAllSync(int nativeAwContents, String searchString);
+ private native void nativeFindAllAsync(int nativeAwContents, String searchString);
+ private native void nativeFindNext(int nativeAwContents, boolean forward);
+ private native void nativeClearMatches(int nativeAwContents);
}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
index 4a4233d..b933a6e 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
@@ -133,6 +133,14 @@ public abstract class AwContentsClient extends ContentViewClient {
JsPromptResultReceiver receiver);
//--------------------------------------------------------------------------------------------
+ // Other WebView-specific methods
+ //--------------------------------------------------------------------------------------------
+ //
+
+ public abstract void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting);
+
+ //--------------------------------------------------------------------------------------------
// Stuff that we ignore since it only makes sense for Chrome browser
//--------------------------------------------------------------------------------------------
//
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidWebViewTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidWebViewTestBase.java
index 3b246fc..85a64f7 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidWebViewTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidWebViewTestBase.java
@@ -8,7 +8,6 @@ import android.app.Instrumentation;
import android.content.Context;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
-import android.view.ViewGroup;
import junit.framework.Assert;
@@ -181,6 +180,16 @@ public class AndroidWebViewTestBase
return testContainerView.get();
}
+ protected void destroyAwContentsOnMainSync(final AwContents contents) {
+ if (contents == null) return;
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ contents.destroy();
+ }
+ });
+ }
+
protected String getTitleOnUiThread(final ContentViewCore contentViewCore) throws Throwable {
return runTestOnUiThreadAndGetResult(new Callable<String>() {
@Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java
index bd1809c..f50b6a8 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/NullContentsClient.java
@@ -57,4 +57,9 @@ class NullContentsClient extends AwContentsClient {
public void handleJsPrompt(
String url, String message, String defaultValue, JsPromptResultReceiver receiver) {
}
+
+ @Override
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting) {
+ }
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java
new file mode 100644
index 0000000..218c0a7
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewAsynchronousFindApisTest.java
@@ -0,0 +1,141 @@
+// 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.
+
+package org.chromium.android_webview.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.Feature;
+
+/**
+ * Tests the asynchronous find-in-page APIs in WebView.
+ */
+public class WebViewAsynchronousFindApisTest extends WebViewFindApisTestBase {
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllFinds() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDouble() throws Throwable {
+ findAllAsyncOnUiThread("wood");
+ assertEquals(4, findAllAsyncOnUiThread("chuck"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDoubleNext() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(2, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDoesNotFind() throws Throwable {
+ assertEquals(0, findAllAsyncOnUiThread("foo"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyPage() throws Throwable {
+ assertEquals(0, findAllAsyncOnUiThread("foo"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyString() throws Throwable {
+ assertEquals(0, findAllAsyncOnUiThread(""));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextForward() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+
+ for (int i = 2; i <= 4; i++) {
+ assertEquals(i - 1, findNextOnUiThread(true));
+ }
+ assertEquals(0, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextBackward() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+
+ for (int i = 4; i >= 1; i--) {
+ assertEquals(i - 1, findNextOnUiThread(false));
+ }
+ assertEquals(3, findNextOnUiThread(false));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextBig() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findNextOnUiThread(false));
+ assertEquals(3, findNextOnUiThread(false));
+ for (int i = 1; i <= 4; i++) {
+ assertEquals(i - 1, findNextOnUiThread(true));
+ }
+ assertEquals(0, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyNext() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findAllAsyncOnUiThread(""));
+ assertEquals(0, findNextOnUiThread(true));
+ assertEquals(0, findAllAsyncOnUiThread(""));
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testClearMatches() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ clearMatchesOnUiThread();
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testClearFindNext() throws Throwable {
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ clearMatchesOnUiThread();
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(2, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindEmptyNext() throws Throwable {
+ assertEquals(0, findAllAsyncOnUiThread(""));
+ assertEquals(0, findNextOnUiThread(true));
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextFirst() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ contents().findNext(true);
+ }
+ });
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findNextOnUiThread(false));
+ assertEquals(3, findNextOnUiThread(false));
+ }
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewFindApisTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewFindApisTestBase.java
new file mode 100644
index 0000000..bdefbfb
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewFindApisTestBase.java
@@ -0,0 +1,184 @@
+// 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.
+
+package org.chromium.android_webview.test;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.chromium.android_webview.AwContents;
+
+/**
+ * Base class for WebView find-in-page API tests.
+ */
+public class WebViewFindApisTestBase extends AndroidWebViewTestBase {
+
+ private static final String WOODCHUCK =
+ "How much WOOD would a woodchuck chuck if a woodchuck could chuck wOoD?";
+
+ private FindResultListener mFindResultListener;
+ private AwContents mContents;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ try {
+ mContents = loadContentsFromStringSync(WOODCHUCK);
+ } catch (Throwable t) {
+ throw new Exception(t);
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ destroyAwContentsOnMainSync(mContents);
+ super.tearDown();
+ }
+
+ protected AwContents contents() {
+ return mContents;
+ }
+
+ // Internal interface to intercept find results from AwContentsClient.
+ private interface FindResultListener {
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting);
+ };
+
+ private AwContents loadContentsFromStringSync(final String html) throws Throwable {
+ final TestAwContentsClient contentsClient = new TestAwContentsClient() {
+ @Override
+ public void onFindResultReceived(int activeMatchOrdinal,
+ int numberOfMatches, boolean isDoneCounting) {
+ if (mFindResultListener == null) return;
+ mFindResultListener.onFindResultReceived(activeMatchOrdinal, numberOfMatches,
+ isDoneCounting);
+ }
+ };
+
+ final AwContents contents =
+ createAwTestContainerViewOnMainSync(contentsClient).getAwContents();
+ final String data = "<html><head></head><body>" + html + "</body></html>";
+ loadDataSync(contents.getContentViewCore(), contentsClient.getOnPageFinishedHelper(),
+ data, "text/html", false);
+ return contents;
+ }
+
+ /**
+ * Invokes findAllSync on the UI thread and returns the number of matches.
+ *
+ * @param searchString A string to search for.
+ * @return The number of instances of the string that were found.
+ * @throws Throwable
+ */
+ protected int findAllSyncOnUiThread(final String searchString)
+ throws Throwable {
+ return runTestOnUiThreadAndGetResult(new Callable<Integer>() {
+ @Override
+ public Integer call() {
+ return mContents.findAllSync(searchString);
+ }
+ });
+ }
+
+ /**
+ * Invokes findAllAsync on the UI thread, blocks until find results are
+ * received, and returns the number of matches.
+ *
+ * @param searchString A string to search for.
+ * @return The number of instances of the string that were found.
+ * @throws Throwable
+ */
+ protected int findAllAsyncOnUiThread(final String searchString)
+ throws Throwable {
+ final IntegerFuture future = new IntegerFuture() {
+ @Override
+ public void run() {
+ mFindResultListener = new FindResultListener() {
+ @Override
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting) {
+ if (isDoneCounting) set(numberOfMatches);
+ }
+ };
+ mContents.findAllAsync(searchString);
+ }
+ };
+ runTestOnUiThread(future);
+ return future.get(10, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Invokes findNext on the UI thread, blocks until find results are
+ * received, and returns the ordinal of the highlighted match.
+ *
+ * @param forwards The direction to search as a boolean, with forwards
+ * represented as true and backwards as false.
+ * @return The ordinal of the highlighted match.
+ * @throws Throwable
+ */
+ protected int findNextOnUiThread(final boolean forwards)
+ throws Throwable {
+ final IntegerFuture future = new IntegerFuture() {
+ @Override
+ public void run() {
+ mFindResultListener = new FindResultListener() {
+ @Override
+ public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
+ boolean isDoneCounting) {
+ if (isDoneCounting) set(activeMatchOrdinal);
+ }
+ };
+ mContents.findNext(forwards);
+ }
+ };
+ runTestOnUiThread(future);
+ return future.get(10, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Invokes clearMatches on the UI thread.
+ *
+ * @throws Throwable
+ */
+ protected void clearMatchesOnUiThread() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mContents.clearMatches();
+ }
+ });
+ }
+
+ // Similar to java.util.concurrent.Future, but without the ability to cancel.
+ private static abstract class IntegerFuture implements Runnable {
+ private CountDownLatch mLatch = new CountDownLatch(1);
+ private int mValue;
+
+ @Override
+ public abstract void run();
+
+ /**
+ * Gets the value of this Future, blocking for up to the specified
+ * timeout for it become available. Throws a TimeoutException if the
+ * timeout expires.
+ */
+ public int get(long timeout, TimeUnit unit) throws Throwable {
+ if (!mLatch.await(timeout, unit)) {
+ throw new TimeoutException();
+ }
+ return mValue;
+ }
+
+ /**
+ * Sets the value of this Future.
+ */
+ protected void set(int value) {
+ mValue = value;
+ mLatch.countDown();
+ }
+ }
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewMixedFindApisTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewMixedFindApisTest.java
new file mode 100644
index 0000000..b91523f
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewMixedFindApisTest.java
@@ -0,0 +1,42 @@
+// 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.
+
+package org.chromium.android_webview.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.Feature;
+
+/**
+ * Tests the mixed use of synchronous and asynchronous find-in-page APIs in WebView.
+ * Helps to spot race conditions or potential deadlocks caused by the renderer receiving
+ * asynchronous messages while synchronous requests are being processed.
+ */
+public class WebViewMixedFindApisTest extends WebViewFindApisTestBase {
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testAsyncFindOperationsMixedWithSyncFind() throws Throwable {
+ clearMatchesOnUiThread();
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ clearMatchesOnUiThread();
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(3, findNextOnUiThread(true));
+ clearMatchesOnUiThread();
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testInterleavedFinds() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(3, findNextOnUiThread(true));
+ assertEquals(4, findAllAsyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ }
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/WebViewSynchronousFindApisTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewSynchronousFindApisTest.java
new file mode 100644
index 0000000..272e330
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/WebViewSynchronousFindApisTest.java
@@ -0,0 +1,141 @@
+// 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.
+
+package org.chromium.android_webview.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.Feature;
+
+/**
+ * Tests the synchronous find-in-page APIs in WebView.
+ */
+public class WebViewSynchronousFindApisTest extends WebViewFindApisTestBase {
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllFinds() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDouble() throws Throwable {
+ findAllSyncOnUiThread("wood");
+ assertEquals(4, findAllSyncOnUiThread("chuck"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDoubleNext() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(2, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllDoesNotFind() throws Throwable {
+ assertEquals(0, findAllSyncOnUiThread("foo"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyPage() throws Throwable {
+ assertEquals(0, findAllSyncOnUiThread("foo"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyString() throws Throwable {
+ assertEquals(0, findAllSyncOnUiThread(""));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextForward() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+
+ for (int i = 2; i <= 4; i++) {
+ assertEquals(i - 1, findNextOnUiThread(true));
+ }
+ assertEquals(0, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextBackward() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+
+ for (int i = 4; i >= 1; i--) {
+ assertEquals(i - 1, findNextOnUiThread(false));
+ }
+ assertEquals(3, findNextOnUiThread(false));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextBig() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findNextOnUiThread(false));
+ assertEquals(3, findNextOnUiThread(false));
+ for (int i = 1; i <= 4; i++) {
+ assertEquals(i - 1, findNextOnUiThread(true));
+ }
+ assertEquals(0, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindAllEmptyNext() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findAllSyncOnUiThread(""));
+ assertEquals(0, findNextOnUiThread(true));
+ assertEquals(0, findAllSyncOnUiThread(""));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testClearMatches() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ clearMatchesOnUiThread();
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testClearFindNext() throws Throwable {
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ clearMatchesOnUiThread();
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(2, findNextOnUiThread(true));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindEmptyNext() throws Throwable {
+ assertEquals(0, findAllSyncOnUiThread(""));
+ assertEquals(0, findNextOnUiThread(true));
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ }
+
+ @SmallTest
+ @Feature({"Android-WebView", "FindInPage"})
+ public void testFindNextFirst() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ contents().findNext(true);
+ }
+ });
+ assertEquals(4, findAllSyncOnUiThread("wood"));
+ assertEquals(1, findNextOnUiThread(true));
+ assertEquals(0, findNextOnUiThread(false));
+ assertEquals(3, findNextOnUiThread(false));
+ }
+}
diff --git a/android_webview/lib/main/webview_entry_point.cc b/android_webview/lib/main/webview_entry_point.cc
index 567161e..8a4996f 100644
--- a/android_webview/lib/main/webview_entry_point.cc
+++ b/android_webview/lib/main/webview_entry_point.cc
@@ -5,8 +5,10 @@
#include "android_webview/lib/main/aw_main_delegate.h"
#include "android_webview/native/android_webview_jni_registrar.h"
#include "base/android/jni_android.h"
+#include "base/command_line.h"
#include "content/public/app/android_library_loader_hooks.h"
#include "content/public/app/content_main.h"
+#include "content/public/common/content_switches.h"
// This is called by the VM when the shared library is first loaded.
// Most of the initialization is done in LibraryLoadedOnMainThread(), not here.
@@ -19,6 +21,11 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
if (!android_webview::RegisterJni(env))
return -1;
+ // Set the command line to enable synchronous API compatibility.
+ CommandLine::Init(0, NULL);
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableWebViewSynchronousAPIs);
+
content::SetContentMainDelegate(new android_webview::AwMainDelegate());
return JNI_VERSION_1_4;
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index fab4809..024da78 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -20,8 +20,11 @@
#include "jni/AwContents_jni.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
@@ -37,7 +40,14 @@ const void* kAwContentsUserDataKey = &kAwContentsUserDataKey;
class AwContentsUserData : public base::SupportsUserData::Data {
public:
AwContentsUserData(AwContents* ptr) : contents_(ptr) {}
- AwContents* get() { return contents_; }
+
+ static AwContents* GetContents(WebContents* web_contents) {
+ if (!web_contents)
+ return NULL;
+ AwContentsUserData* data = reinterpret_cast<AwContentsUserData*>(
+ web_contents->GetUserData(kAwContentsUserDataKey));
+ return data ? data->contents_ : NULL;
+ }
private:
AwContents* contents_;
@@ -46,13 +56,8 @@ class AwContentsUserData : public base::SupportsUserData::Data {
} // namespace
// static
-AwContents* AwContents::FromWebContents(content::WebContents* web_contents) {
- if (web_contents) {
- AwContentsUserData* data = reinterpret_cast<AwContentsUserData*>(
- web_contents->GetUserData(kAwContentsUserDataKey));
- if (data) return data->get();
- }
- return NULL;
+AwContents* AwContents::FromWebContents(WebContents* web_contents) {
+ return AwContentsUserData::GetContents(web_contents);
}
AwContents::AwContents(JNIEnv* env,
@@ -64,20 +69,26 @@ AwContents::AwContents(JNIEnv* env,
new AwWebContentsDelegate(env, web_contents_delegate)) {
android_webview::AwBrowserDependencyFactory* dependency_factory =
android_webview::AwBrowserDependencyFactory::GetInstance();
- content::WebContents* web_contents =
+
+ WebContents* web_contents =
dependency_factory->CreateWebContents(private_browsing);
+
+ DCHECK(!AwContents::FromWebContents(web_contents));
+ web_contents->SetUserData(kAwContentsUserDataKey,
+ new AwContentsUserData(this));
+
contents_container_.reset(dependency_factory->CreateContentsContainer(
web_contents));
web_contents->SetDelegate(web_contents_delegate_.get());
- web_contents->SetUserData(kAwContentsUserDataKey,
- new AwContentsUserData(this));
render_view_host_ext_.reset(new AwRenderViewHostExt(web_contents));
}
AwContents::~AwContents() {
- content::WebContents* web_contents = contents_container_->GetWebContents();
+ WebContents* web_contents = contents_container_->GetWebContents();
DCHECK(AwContents::FromWebContents(web_contents) == this);
web_contents->RemoveUserData(kAwContentsUserDataKey);
+ if (find_helper_.get())
+ find_helper_->SetListener(NULL);
}
jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
@@ -113,7 +124,7 @@ void GenerateMHTMLCallback(ScopedJavaGlobalRef<jobject>* callback,
// Android files are UTF8, so the path conversion below is safe.
Java_AwContents_generateMHTMLCallback(
env,
- base::android::ConvertUTF8ToJavaString(env, path.AsUTF8Unsafe()).obj(),
+ ConvertUTF8ToJavaString(env, path.AsUTF8Unsafe()).obj(),
size, callback->obj());
}
} // namespace
@@ -123,7 +134,7 @@ void AwContents::GenerateMHTML(JNIEnv* env, jobject obj,
ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
j_callback->Reset(env, callback);
contents_container_->GetWebContents()->GenerateMHTML(
- FilePath(base::android::ConvertJavaStringToUTF8(env, jpath)),
+ FilePath(ConvertJavaStringToUTF8(env, jpath)),
base::Bind(&GenerateMHTMLCallback, base::Owned(j_callback)));
}
@@ -132,8 +143,8 @@ void AwContents::RunJavaScriptDialog(
const GURL& origin_url,
const string16& message_text,
const string16& default_prompt_text,
- const base::android::ScopedJavaLocalRef<jobject>& js_result) {
- JNIEnv* env = base::android::AttachCurrentThread();
+ const ScopedJavaLocalRef<jobject>& js_result) {
+ JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
@@ -168,8 +179,8 @@ void AwContents::RunJavaScriptDialog(
void AwContents::RunBeforeUnloadDialog(
const GURL& origin_url,
const string16& message_text,
- const base::android::ScopedJavaLocalRef<jobject>& js_result) {
- JNIEnv* env = base::android::AttachCurrentThread();
+ const ScopedJavaLocalRef<jobject>& js_result) {
+ JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
@@ -184,7 +195,7 @@ void AwContents::RunBeforeUnloadDialog(
}
void AwContents::onReceivedHttpAuthRequest(
- const base::android::JavaRef<jobject>& handler,
+ const JavaRef<jobject>& handler,
const std::string& host,
const std::string& realm) {
JNIEnv* env = AttachCurrentThread();
@@ -215,5 +226,42 @@ bool RegisterAwContents(JNIEnv* env) {
return RegisterNativesImpl(env) >= 0;
}
+jint AwContents::FindAllSync(JNIEnv* env, jobject obj, jstring search_string) {
+ return GetFindHelper()->FindAllSync(
+ ConvertJavaStringToUTF16(env, search_string));
+}
+
+void AwContents::FindAllAsync(JNIEnv* env, jobject obj, jstring search_string) {
+ GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string));
+}
+
+void AwContents::FindNext(JNIEnv* env, jobject obj, jboolean forward) {
+ GetFindHelper()->FindNext(forward);
+}
+
+void AwContents::ClearMatches(JNIEnv* env, jobject obj) {
+ GetFindHelper()->ClearMatches();
+}
+
+FindHelper* AwContents::GetFindHelper() {
+ if (!find_helper_.get()) {
+ WebContents* web_contents = contents_container_->GetWebContents();
+ find_helper_.reset(new FindHelper(web_contents));
+ find_helper_->SetListener(this);
+ }
+ return find_helper_.get();
+}
+
+void AwContents::OnFindResultReceived(int active_ordinal,
+ int match_count,
+ bool finished) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AwContents_onFindResultReceived(
+ env, obj.obj(), active_ordinal, match_count, finished);
+}
} // namespace android_webview
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 472075e..556f5054 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -8,6 +8,7 @@
#include <jni.h>
#include <string>
+#include "android_webview/browser/find_helper.h"
#include "base/android/scoped_java_ref.h"
#include "base/android/jni_helper.h"
#include "base/memory/scoped_ptr.h"
@@ -29,7 +30,7 @@ class AwWebContentsDelegate;
// Provides the ownership of and access to browser components required for
// WebView functionality; analogous to chrome's TabContents, but with a
// level of indirection provided by the AwContentsContainer abstraction.
-class AwContents {
+class AwContents : public FindHelper::Listener {
public:
// Returns the AwContents instance associated with |web_contents|, or NULL.
static AwContents* FromWebContents(content::WebContents* web_contents);
@@ -38,7 +39,7 @@ class AwContents {
jobject obj,
jobject web_contents_delegate,
bool private_browsing);
- ~AwContents();
+ virtual ~AwContents();
void RunJavaScriptDialog(
content::JavaScriptMessageType message_type,
@@ -65,11 +66,24 @@ class AwContents {
void GenerateMHTML(JNIEnv* env, jobject obj, jstring jpath, jobject callback);
void SetIoThreadClient(JNIEnv* env, jobject obj, jobject client);
+ // Find-in-page API and related methods.
+ jint FindAllSync(JNIEnv* env, jobject obj, jstring search_string);
+ void FindAllAsync(JNIEnv* env, jobject obj, jstring search_string);
+ void FindNext(JNIEnv* env, jobject obj, jboolean forward);
+ void ClearMatches(JNIEnv* env, jobject obj);
+
+ FindHelper* GetFindHelper();
+
+ // FindHelper::Listener implementation.
+ virtual void OnFindResultReceived(int active_ordinal,
+ int match_count,
+ bool finished) OVERRIDE;
private:
JavaObjectWeakGlobalRef java_ref_;
scoped_ptr<AwContentsContainer> contents_container_;
scoped_ptr<AwWebContentsDelegate> web_contents_delegate_;
scoped_ptr<AwRenderViewHostExt> render_view_host_ext_;
+ scoped_ptr<FindHelper> find_helper_;
DISALLOW_COPY_AND_ASSIGN(AwContents);
};
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index 249ee0f..2a04d2d 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -5,7 +5,12 @@
#include "android_webview/native/aw_web_contents_delegate.h"
#include "base/lazy_instance.h"
+#include "android_webview/browser/find_helper.h"
+#include "android_webview/native/aw_contents.h"
#include "android_webview/native/aw_javascript_dialog_creator.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
namespace android_webview {
@@ -26,4 +31,20 @@ AwWebContentsDelegate::GetJavaScriptDialogCreator() {
return g_javascript_dialog_creator.Pointer();
}
+void AwWebContentsDelegate::FindReply(WebContents* web_contents,
+ int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) {
+ AwContents* aw_contents = AwContents::FromWebContents(web_contents);
+ if (!aw_contents)
+ return;
+
+ aw_contents->GetFindHelper()->HandleFindReply(request_id,
+ number_of_matches,
+ active_match_ordinal,
+ final_update);
+}
+
} // namespace android_webview
diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h
index 011451e..1ce3f31 100644
--- a/android_webview/native/aw_web_contents_delegate.h
+++ b/android_webview/native/aw_web_contents_delegate.h
@@ -21,6 +21,12 @@ class AwWebContentsDelegate
virtual ~AwWebContentsDelegate();
virtual content::JavaScriptDialogCreator* GetJavaScriptDialogCreator()
OVERRIDE;
+ virtual void FindReply(content::WebContents* web_contents,
+ int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) OVERRIDE;
};
} // namespace android_webview
diff --git a/android_webview/native/cookie_manager.cc b/android_webview/native/cookie_manager.cc
index fbbfc06..d4b6619 100644
--- a/android_webview/native/cookie_manager.cc
+++ b/android_webview/native/cookie_manager.cc
@@ -5,6 +5,7 @@
#include "android_webview/native/cookie_manager.h"
#include "android_webview/browser/aw_cookie_access_policy.h"
+#include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h"
#include "android_webview/native/aw_browser_dependency_factory.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
@@ -26,16 +27,6 @@ using net::CookieList;
using net::CookieMonster;
using net::URLRequestContextGetter;
-// This class is only available when building the chromium back-end for andriod
-// 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;
-};
-
// CookieManager should be refactored to not require all tasks accessing the
// CookieStore to be piped through the IO thread. It is currently required as
// the URLRequestContext provides the easiest mechanism for accessing the
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index bc5c4bf..49ef084 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -111,6 +111,7 @@
#include "ipc/ipc_logging.h"
#include "ipc/ipc_platform_file.h"
#include "ipc/ipc_switches.h"
+#include "ipc/ipc_sync_channel.h"
#include "media/base/media_switches.h"
#include "net/url_request/url_request_context_getter.h"
#include "ui/base/ui_base_switches.h"
@@ -343,6 +344,9 @@ RenderProcessHostImpl::RenderProcessHostImpl(
storage_partition_impl_(storage_partition_impl),
sudden_termination_allowed_(true),
ignore_input_events_(false),
+#if defined(OS_ANDROID)
+ dummy_shutdown_event_(false, false),
+#endif
is_guest_(is_guest) {
widget_helper_ = new RenderWidgetHelper();
@@ -450,9 +454,19 @@ bool RenderProcessHostImpl::Init() {
// Setup the IPC channel.
const std::string channel_id =
IPC::Channel::GenerateVerifiedChannelID(std::string());
- channel_.reset(new IPC::ChannelProxy(
- channel_id, IPC::Channel::MODE_SERVER, this,
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
+ channel_.reset(
+#if defined(OS_ANDROID)
+ // Android WebView needs to be able to wait from the UI thread to support
+ // the synchronous legacy APIs.
+ browser_command_line.HasSwitch(switches::kEnableWebViewSynchronousAPIs) ?
+ new IPC::SyncChannel(
+ channel_id, IPC::Channel::MODE_SERVER, this,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
+ true, &dummy_shutdown_event_) :
+#endif
+ new IPC::ChannelProxy(
+ channel_id, IPC::Channel::MODE_SERVER, this,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
// Call the embedder first so that their IPC filters have priority.
GetContentClient()->browser()->RenderProcessHostCreated(this);
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 919115a..d28a69c 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/process.h"
+#include "base/synchronization/waitable_event.h"
#include "base/timer.h"
#include "content/browser/child_process_launcher.h"
#include "content/common/content_export.h"
@@ -293,6 +294,15 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Records the last time we regarded the child process active.
base::TimeTicks child_process_activity_time_;
+#if defined(OS_ANDROID)
+ // Android WebView needs to use a SyncChannel to block the browser process
+ // for synchronous find-in-page API support. In that case the shutdown event
+ // makes no sense as the Android port doesn't shutdown, but gets killed.
+ // SyncChannel still expects a shutdown event, so create a dummy one that
+ // will never will be signaled.
+ base::WaitableEvent dummy_shutdown_event_;
+#endif
+
// Indicates whether this is a RenderProcessHost of a Browser Plugin guest
// renderer.
bool is_guest_;
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 7b99267..246d121 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -12,6 +12,7 @@
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "base/string_util.h"
@@ -510,6 +511,20 @@ void RenderViewHostImpl::ActivateNearestFindResult(int request_id,
void RenderViewHostImpl::RequestFindMatchRects(int current_version) {
Send(new ViewMsg_FindMatchRects(GetRoutingID(), current_version));
}
+
+void RenderViewHostImpl::SynchronousFind(int request_id,
+ const string16& search_text,
+ const WebKit::WebFindOptions& options,
+ int* match_count,
+ int* active_ordinal) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableWebViewSynchronousAPIs)) {
+ return;
+ }
+
+ Send(new ViewMsg_SynchronousFind(GetRoutingID(), request_id, search_text,
+ options, match_count, active_ordinal));
+}
#endif
void RenderViewHostImpl::DragTargetDragEnter(
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 0e3f1dd..ef5e789 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -228,6 +228,11 @@ class CONTENT_EXPORT RenderViewHostImpl
float x,
float y) OVERRIDE;
virtual void RequestFindMatchRects(int current_version) OVERRIDE;
+ virtual void SynchronousFind(int request_id,
+ const string16& search_text,
+ const WebKit::WebFindOptions& options,
+ int* match_count,
+ int* active_ordinal) OVERRIDE;
#endif
void set_delegate(RenderViewHostDelegate* d) {
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 6751e30..f4e12ad 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -867,28 +867,6 @@ IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetMonitorColorProfile,
IPC_MESSAGE_CONTROL1(ViewMsg_New,
ViewMsg_New_Params)
-#if defined(OS_ANDROID)
-// Sent when the user clicks on the find result bar to activate a find result.
-// The point (x,y) is in fractions of the content document's width and height.
-IPC_MESSAGE_ROUTED3(ViewMsg_ActivateNearestFindResult,
- int /* request_id */,
- float /* x */,
- float /* y */)
-
-// Sent when the browser wants the bounding boxes of the current find matches.
-//
-// If match rects are already cached on the browser side, |current_version|
-// should be the version number from the ViewHostMsg_FindMatchRects_Reply
-// they came in, so the renderer can tell if it needs to send updated rects.
-// Otherwise just pass -1 to always receive the list of rects.
-//
-// There must be an active search string (it is probably most useful to call
-// this immediately after a ViewHostMsg_Find_Reply message arrives with
-// final_update set to true).
-IPC_MESSAGE_ROUTED1(ViewMsg_FindMatchRects,
- int /* current_version */)
-#endif
-
// Reply in response to ViewHostMsg_ShowView or ViewHostMsg_ShowWidget.
// similar to the new command, but used when the renderer created a view
// first, and we need to update it.
@@ -1134,16 +1112,6 @@ IPC_MESSAGE_ROUTED2(ViewMsg_CSSInsertRequest,
string16, /* frame_xpath */
std::string /* css string */)
-// External popup menus.
-#if defined(OS_MACOSX)
-IPC_MESSAGE_ROUTED1(ViewMsg_SelectPopupMenuItem,
- int /* selected index, -1 means no selection */)
-#elif defined(OS_ANDROID)
-IPC_MESSAGE_ROUTED2(ViewMsg_SelectPopupMenuItems,
- bool /* user canceled the popup */,
- std::vector<int> /* selected indices */)
-#endif
-
// Change the zoom level for the current main frame. If the level actually
// changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
// telling it what url got zoomed and what its current zoom level is.
@@ -1351,27 +1319,6 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SetActive,
IPC_MESSAGE_ROUTED1(ViewMsg_SetNavigationStartTime,
base::TimeTicks /* browser_navigation_start */)
-#if defined(OS_MACOSX)
-// Let the RenderView know its window has changed visibility.
-IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility,
- bool /* visibile */)
-
-// Let the RenderView know its window's frame has changed.
-IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged,
- gfx::Rect /* window frame */,
- gfx::Rect /* content view frame */)
-
-// Message sent from the browser to the renderer when the user starts or stops
-// resizing the view.
-IPC_MESSAGE_ROUTED1(ViewMsg_SetInLiveResize,
- bool /* enable */)
-
-// Tell the renderer that plugin IME has completed.
-IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionCompleted,
- string16 /* text */,
- int /* plugin_id */)
-#endif
-
// Response message to ViewHostMsg_CreateShared/DedicatedWorker.
// Sent when the worker has started.
IPC_MESSAGE_ROUTED0(ViewMsg_WorkerCreated)
@@ -1426,6 +1373,72 @@ IPC_MESSAGE_CONTROL1(ViewMsg_TempCrashWithData,
IPC_MESSAGE_ROUTED1(ViewMsg_SetAccessibilityMode,
AccessibilityMode)
+#if defined(OS_ANDROID)
+// Sent when the user clicks on the find result bar to activate a find result.
+// The point (x,y) is in fractions of the content document's width and height.
+IPC_MESSAGE_ROUTED3(ViewMsg_ActivateNearestFindResult,
+ int /* request_id */,
+ float /* x */,
+ float /* y */)
+
+// Sent when the browser wants the bounding boxes of the current find matches.
+//
+// If match rects are already cached on the browser side, |current_version|
+// should be the version number from the ViewHostMsg_FindMatchRects_Reply
+// they came in, so the renderer can tell if it needs to send updated rects.
+// Otherwise just pass -1 to always receive the list of rects.
+//
+// There must be an active search string (it is probably most useful to call
+// this immediately after a ViewHostMsg_Find_Reply message arrives with
+// final_update set to true).
+IPC_MESSAGE_ROUTED1(ViewMsg_FindMatchRects,
+ int /* current_version */)
+
+// Sent when the user wants to search for all occurrences of a word or find
+// the next result in a synchronous way. This method forces the UI thread in
+// the browser to wait for the renderer to reply, therefore blocking the UI.
+//
+// This functionality is required for compatibility with the legacy Android
+// WebView API. As this goes strongly against the Chromium design guidelines,
+// don't use this as inspiration.
+//
+IPC_SYNC_MESSAGE_ROUTED3_2(ViewMsg_SynchronousFind,
+ int /* request_id */,
+ string16 /* search_string */,
+ WebKit::WebFindOptions /* options */,
+ int /* match_count */,
+ int /* active_ordinal */)
+
+// External popup menus.
+IPC_MESSAGE_ROUTED2(ViewMsg_SelectPopupMenuItems,
+ bool /* user canceled the popup */,
+ std::vector<int> /* selected indices */)
+
+#elif defined(OS_MACOSX)
+// Let the RenderView know its window has changed visibility.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility,
+ bool /* visibile */)
+
+// Let the RenderView know its window's frame has changed.
+IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged,
+ gfx::Rect /* window frame */,
+ gfx::Rect /* content view frame */)
+
+// Message sent from the browser to the renderer when the user starts or stops
+// resizing the view.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetInLiveResize,
+ bool /* enable */)
+
+// Tell the renderer that plugin IME has completed.
+IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionCompleted,
+ string16 /* text */,
+ int /* plugin_id */)
+
+// External popup menus.
+IPC_MESSAGE_ROUTED1(ViewMsg_SelectPopupMenuItem,
+ int /* selected index, -1 means no selection */)
+#endif
+
// -----------------------------------------------------------------------------
// Messages sent from the renderer to the browser.
@@ -1984,15 +1997,6 @@ IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_DestroyPluginContainer,
gfx::PluginWindowHandle /* id */)
#endif
-#if defined(OS_MACOSX)
-// Request that the browser load a font into shared memory for us.
-IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LoadFont,
- FontDescriptor /* font to load */,
- uint32 /* buffer size */,
- base::SharedMemoryHandle /* font data */,
- uint32 /* font id */)
-#endif
-
// Send the tooltip text for the current mouse position to the browser.
IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText,
string16 /* tooltip text string */,
@@ -2124,6 +2128,13 @@ IPC_MESSAGE_CONTROL1(ViewHostMsg_SuddenTerminationChanged,
bool /* enabled */)
#if defined(OS_MACOSX)
+// Request that the browser load a font into shared memory for us.
+IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LoadFont,
+ FontDescriptor /* font to load */,
+ uint32 /* buffer size */,
+ base::SharedMemoryHandle /* font data */,
+ uint32 /* font id */)
+
// On OSX, we cannot allocated shared memory from within the sandbox, so
// this call exists for the renderer to ask the browser to allocate memory
// on its behalf. We return a file descriptor to the POSIX shared memory.
@@ -2292,12 +2303,6 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_SendSerializedHtmlData,
std::string /* data buffer */,
int32 /* complete status */)
-#if defined(OS_ANDROID)
-// Start an android intent with the given URI.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_StartContentIntent,
- GURL /* content_url */)
-#endif
-
// Notifies the browser of an event occurring in the media pipeline.
IPC_MESSAGE_CONTROL1(ViewHostMsg_MediaLogEvent,
media::MediaLogEvent /* event */)
@@ -2391,6 +2396,10 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_FindMatchRects_Reply,
std::vector<gfx::RectF> /* rects */,
gfx::RectF /* active_rect */)
+// Start an android intent with the given URI.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_StartContentIntent,
+ GURL /* content_url */)
+
// Messages for notifying the render process of media playback status -------
// Media buffering has updated.
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
index 5f0e686..0e95386 100644
--- a/content/public/browser/render_view_host.h
+++ b/content/public/browser/render_view_host.h
@@ -273,6 +273,14 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
// Asks the renderer to send the rects of the current find matches.
virtual void RequestFindMatchRects(int current_version) = 0;
+
+ // Synchronous find request. Returns the number of matches found and the
+ // ordinal of the active match. Required by the legacy Android WebView API.
+ virtual void SynchronousFind(int request_id,
+ const string16& search_text,
+ const WebKit::WebFindOptions& options,
+ int* match_count,
+ int* active_ordinal) = 0;
#endif
};
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 1126f02..7039ed8 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -651,6 +651,7 @@ const char kMediaPlayerInRenderProcess[] = "media-player-in-render-process";
// Set when Chromium should use a mobile user agent.
const char kUseMobileUserAgent[] = "use-mobile-user-agent";
+
// Omnibus flag setting an Android graphics mode. May be:
// "basic" (untiled software path)
// "compositor" (hardware-accelerated compositing),
@@ -660,6 +661,9 @@ const char kGraphicsModeValueCompositor[] = "compositor";
// The telephony region (ISO country code) to use in phone number detection.
const char kNetworkCountryIso[] = "network-country-iso";
+
+// Set to enable compatibility with legacy WebView synchronous APIs.
+const char kEnableWebViewSynchronousAPIs[] = "enable-webview-synchronous-apis";
#endif
#if defined(OS_POSIX)
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index da345c7..d976a83 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -212,6 +212,7 @@ extern const char kGraphicsMode[];
// Not actual flags, just values: for example, --graphics-mode=compositor
extern const char kGraphicsModeValueBasic[];
extern const char kGraphicsModeValueCompositor[];
+extern const char kEnableWebViewSynchronousAPIs[];
#endif
#if defined(OS_POSIX)
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 33c5b12..181b273 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -618,6 +618,7 @@ RenderViewImpl::RenderViewImpl(
#if defined(OS_ANDROID)
expected_content_intent_id_(0),
media_player_proxy_(NULL),
+ synchronous_find_active_match_ordinal_(-1),
#endif
session_storage_namespace_id_(session_storage_namespace_id),
handling_select_range_(false),
@@ -945,9 +946,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewMsg_CopyToFindPboard, OnCopyToFindPboard)
-#endif
IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
IPC_MESSAGE_HANDLER(ViewMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
@@ -966,12 +964,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_ExecuteEditCommand, OnExecuteEditCommand)
IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
-#if defined(OS_ANDROID)
- IPC_MESSAGE_HANDLER(ViewMsg_ActivateNearestFindResult,
- OnActivateNearestFindResult)
- IPC_MESSAGE_HANDLER(ViewMsg_FindMatchRects,
- OnFindMatchRects)
-#endif
IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)
IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevel, OnSetZoomLevel)
IPC_MESSAGE_HANDLER(ViewMsg_ZoomFactor, OnZoomFactor)
@@ -1024,12 +1016,6 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_SetActive, OnSetActive)
IPC_MESSAGE_HANDLER(ViewMsg_SetNavigationStartTime,
OnSetNavigationStartTime)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
- IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
- IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted,
- OnPluginImeCompositionCompleted)
-#endif
IPC_MESSAGE_HANDLER(ViewMsg_SetEditCommandsForNextKeyEvent,
OnSetEditCommandsForNextKeyEvent)
IPC_MESSAGE_HANDLER(ViewMsg_CustomContextMenuAction,
@@ -1044,22 +1030,29 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(
ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItem, OnSelectPopupMenuItem)
-#elif defined(OS_ANDROID)
- IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItems, OnSelectPopupMenuItems)
-#endif
IPC_MESSAGE_HANDLER(ViewMsg_ContextMenuClosed, OnContextMenuClosed)
// TODO(viettrungluu): Move to a separate message filter.
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewMsg_SetInLiveResize, OnSetInLiveResize)
-#endif
IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune,
OnSetHistoryLengthAndPrune)
IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
IPC_MESSAGE_HANDLER(JavaBridgeMsg_Init, OnJavaBridgeInit)
IPC_MESSAGE_HANDLER(ViewMsg_SetAccessibilityMode, OnSetAccessibilityMode)
IPC_MESSAGE_HANDLER(ViewMsg_UpdateFrameTree, OnUpdatedFrameTree)
+#if defined(OS_ANDROID)
+ IPC_MESSAGE_HANDLER(ViewMsg_ActivateNearestFindResult,
+ OnActivateNearestFindResult)
+ IPC_MESSAGE_HANDLER(ViewMsg_FindMatchRects, OnFindMatchRects)
+ IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItems, OnSelectPopupMenuItems)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewMsg_SynchronousFind, OnSynchronousFind)
+#elif defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ViewMsg_CopyToFindPboard, OnCopyToFindPboard)
+ IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted,
+ OnPluginImeCompositionCompleted)
+ IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItem, OnSelectPopupMenuItem)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetInLiveResize, OnSetInLiveResize)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
+ IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
+#endif
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
@@ -3926,30 +3919,64 @@ void RenderViewImpl::hasTouchEventHandlers(bool has_handlers) {
Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
}
-void RenderViewImpl::reportFindInPageMatchCount(int request_id, int count,
+void RenderViewImpl::SendFindReply(int request_id,
+ int match_count,
+ int ordinal,
+ const WebRect& selection_rect,
+ bool final_status_update) {
+#if defined(OS_ANDROID)
+ if (synchronous_find_reply_message_.get()) {
+ if (final_status_update) {
+ ViewMsg_SynchronousFind::WriteReplyParams(
+ synchronous_find_reply_message_.get(),
+ match_count,
+ match_count ? synchronous_find_active_match_ordinal_ : 0);
+ Send(synchronous_find_reply_message_.release());
+ }
+ return;
+ }
+#endif
+
+ Send(new ViewHostMsg_Find_Reply(routing_id_,
+ request_id,
+ match_count,
+ selection_rect,
+ ordinal,
+ final_status_update));
+}
+
+void RenderViewImpl::reportFindInPageMatchCount(int request_id,
+ int count,
bool final_update) {
int active_match_ordinal = -1; // -1 = don't update active match ordinal
if (!count)
active_match_ordinal = 0;
- Send(new ViewHostMsg_Find_Reply(routing_id_,
- request_id,
- count,
- gfx::Rect(),
- active_match_ordinal,
- final_update));
+ // Send the search result over to the browser process.
+ SendFindReply(request_id,
+ count,
+ active_match_ordinal,
+ gfx::Rect(),
+ final_update);
}
void RenderViewImpl::reportFindInPageSelection(int request_id,
int active_match_ordinal,
const WebRect& selection_rect) {
- // Send the search result over to the browser process.
- Send(new ViewHostMsg_Find_Reply(routing_id_,
- request_id,
- -1,
- selection_rect,
- active_match_ordinal,
- false));
+#if defined(OS_ANDROID)
+ // If this was a SynchronousFind request, we need to remember the ordinal
+ // value here for replying when reportFindInPageMatchCount is called.
+ if (synchronous_find_reply_message_.get()) {
+ synchronous_find_active_match_ordinal_ = active_match_ordinal;
+ return;
+ }
+#endif
+
+ SendFindReply(request_id,
+ -1,
+ active_match_ordinal,
+ selection_rect,
+ false);
}
void RenderViewImpl::openFileSystem(
@@ -4557,8 +4584,22 @@ WebKit::WebPlugin* RenderViewImpl::GetWebPluginFromPluginDocument() {
return webview()->mainFrame()->document().to<WebPluginDocument>().plugin();
}
-void RenderViewImpl::OnFind(int request_id, const string16& search_text,
+void RenderViewImpl::OnFind(int request_id,
+ const string16& search_text,
const WebFindOptions& options) {
+#if defined(OS_ANDROID)
+ // Make sure any asynchronous messages do not disrupt an ongoing synchronous
+ // find request as it might lead to deadlocks. Also, these should be safe to
+ // ignore since they would belong to a previous find request.
+ if (synchronous_find_reply_message_.get())
+ return;
+#endif
+ Find(request_id, search_text, options);
+}
+
+void RenderViewImpl::Find(int request_id,
+ const string16& search_text,
+ const WebFindOptions& options) {
WebFrame* main_frame = webview()->mainFrame();
// Check if the plugin still exists in the document.
@@ -4568,16 +4609,10 @@ void RenderViewImpl::OnFind(int request_id, const string16& search_text,
// Just navigate back/forward.
GetWebPluginFromPluginDocument()->selectFindResult(options.forward);
} else {
- if (GetWebPluginFromPluginDocument()->startFind(
+ if (!GetWebPluginFromPluginDocument()->startFind(
search_text, options.matchCase, request_id)) {
- } else {
// Send "no results".
- Send(new ViewHostMsg_Find_Reply(routing_id_,
- request_id,
- 0,
- gfx::Rect(),
- 0,
- true));
+ SendFindReply(request_id, 0, 0, gfx::Rect(), true);
}
}
return;
@@ -4650,13 +4685,8 @@ void RenderViewImpl::OnFind(int request_id, const string16& search_text,
// Otherwise the scoping effort will send more results.
bool final_status_update = !result;
- // Send the search result over to the browser process.
- Send(new ViewHostMsg_Find_Reply(routing_id_,
- request_id,
- match_count,
- selection_rect,
- ordinal,
- final_status_update));
+ SendFindReply(request_id, match_count, ordinal, selection_rect,
+ final_status_update);
// Scoping effort begins, starting with the mainframe.
search_frame = main_frame;
@@ -4686,6 +4716,18 @@ void RenderViewImpl::OnFind(int request_id, const string16& search_text,
}
void RenderViewImpl::OnStopFinding(content::StopFindAction action) {
+#if defined(OS_ANDROID)
+ // Make sure any asynchronous messages do not disrupt an ongoing synchronous
+ // find request as it might lead to deadlocks. Also, these should be safe to
+ // ignore since they would belong to a previous find request.
+ if (synchronous_find_reply_message_.get())
+ return;
+#endif
+
+ StopFinding(action);
+}
+
+void RenderViewImpl::StopFinding(content::StopFindAction action) {
WebView* view = webview();
if (!view)
return;
@@ -4720,6 +4762,23 @@ void RenderViewImpl::OnStopFinding(content::StopFindAction action) {
}
#if defined(OS_ANDROID)
+void RenderViewImpl::OnSynchronousFind(int request_id,
+ const string16& search_string,
+ const WebFindOptions& options,
+ IPC::Message* reply_msg) {
+ // It is impossible for simultaneous blocking finds to occur.
+ CHECK(!synchronous_find_reply_message_.get());
+ synchronous_find_reply_message_.reset(reply_msg);
+
+ // Find next should be asynchronous in order to minimize blocking
+ // the UI thread as much as possible.
+ DCHECK(!options.findNext);
+ StopFinding(content::STOP_FIND_ACTION_KEEP_SELECTION);
+ synchronous_find_active_match_ordinal_ = -1;
+
+ Find(request_id, search_string, options);
+}
+
void RenderViewImpl::OnActivateNearestFindResult(int request_id,
float x, float y) {
if (!webview())
@@ -4737,12 +4796,11 @@ void RenderViewImpl::OnActivateNearestFindResult(int request_id,
return;
}
- Send(new ViewHostMsg_Find_Reply(routing_id_,
- request_id,
- -1 /* number_of_matches */,
- selection_rect,
- ordinal,
- true /* final_update */));
+ SendFindReply(request_id,
+ -1 /* number_of_matches */,
+ ordinal,
+ selection_rect,
+ true /* final_update */);
}
void RenderViewImpl::OnFindMatchRects(int current_version) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 3cabb8f..c9df7b7 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -904,9 +904,6 @@ class RenderViewImpl : public RenderWidget,
// The documentation for these functions should be in
// render_messages_internal.h for the message that the function is handling.
-#if defined(OS_ANDROID)
- void OnActivateNearestFindResult(int request_id, float x, float y);
-#endif
CONTENT_EXPORT void OnAllowBindings(int enabled_bindings_flags);
void OnAllowScriptToClose(bool script_can_close);
void OnAsyncFileOpened(base::PlatformFileError error_code,
@@ -922,9 +919,6 @@ class RenderViewImpl : public RenderWidget,
const content::CustomContextMenuContext& custom_context);
void OnCopy();
void OnCopyImageAt(int x, int y);
-#if defined(OS_MACOSX)
- void OnCopyToFindPboard();
-#endif
void OnCut();
void OnCSSInsertRequest(const string16& frame_xpath,
const std::string& css);
@@ -964,9 +958,6 @@ class RenderViewImpl : public RenderWidget,
const std::vector<ui::SelectedFileInfo>& files);
void OnFind(int request_id, const string16&, const WebKit::WebFindOptions&);
void OnGetAllSavableResourceLinksForCurrentPage(const GURL& page_url);
-#if defined(OS_ANDROID)
- void OnFindMatchRects(int current_version);
-#endif
void OnGetSerializedHtmlDataForCurrentPageWithLocalLinks(
const std::vector<GURL>& links,
const std::vector<FilePath>& local_paths,
@@ -983,9 +974,6 @@ class RenderViewImpl : public RenderWidget,
CONTENT_EXPORT void OnNavigate(const ViewMsg_Navigate_Params& params);
void OnPaste();
void OnPasteAndMatchStyle();
-#if defined(OS_MACOSX)
- void OnPluginImeCompositionCompleted(const string16& text, int plugin_id);
-#endif
void OnPostMessageEvent(const ViewMsg_PostMessage_Params& params);
void OnRedo();
void OnReloadFrame();
@@ -1014,15 +1002,9 @@ class RenderViewImpl : public RenderWidget,
CONTENT_EXPORT void OnSetHistoryLengthAndPrune(int history_length,
int32 minimum_page_id);
void OnSetInitialFocus(bool reverse);
-#if defined(OS_MACOSX)
- void OnSetInLiveResize(bool in_live_resize);
-#endif
void OnScrollFocusedEditableNodeIntoRect(const gfx::Rect& rect);
void OnSetPageEncoding(const std::string& encoding_name);
void OnSetRendererPrefs(const content::RendererPreferences& renderer_prefs);
-#if defined(OS_MACOSX)
- void OnSetWindowVisibility(bool visible);
-#endif
void OnSetZoomLevel(double zoom_level);
CONTENT_EXPORT void OnSetZoomLevelForLoadingURL(const GURL& url,
double zoom_level);
@@ -1038,17 +1020,6 @@ class RenderViewImpl : public RenderWidget,
const webkit_glue::WebPreferences& prefs);
CONTENT_EXPORT void OnUnselect();
-#if defined(OS_MACOSX)
- void OnWindowFrameChanged(const gfx::Rect& window_frame,
- const gfx::Rect& view_frame);
- CONTENT_EXPORT void OnSelectPopupMenuItem(int selected_index);
-#endif
-
-#if defined(OS_ANDROID)
- void OnSelectPopupMenuItems(bool canceled,
- const std::vector<int>& selected_indices);
-#endif
-
void OnZoom(content::PageZoom zoom);
void OnZoomFactor(content::PageZoom zoom, int zoom_center_x,
int zoom_center_y);
@@ -1061,6 +1032,26 @@ class RenderViewImpl : public RenderWidget,
int route_id,
const std::string& frame_tree);
+#if defined(OS_ANDROID)
+ void OnActivateNearestFindResult(int request_id, float x, float y);
+ void OnFindMatchRects(int current_version);
+ void OnSelectPopupMenuItems(bool canceled,
+ const std::vector<int>& selected_indices);
+ void OnSynchronousFind(int request_id,
+ const string16& search_string,
+ const WebKit::WebFindOptions& options,
+ IPC::Message* reply_msg);
+#elif defined(OS_MACOSX)
+ void OnCopyToFindPboard();
+ void OnPluginImeCompositionCompleted(const string16& text, int plugin_id);
+ CONTENT_EXPORT void OnSelectPopupMenuItem(int selected_index);
+ void OnSetInLiveResize(bool in_live_resize);
+ void OnSetWindowVisibility(bool visible);
+ void OnWindowFrameChanged(const gfx::Rect& window_frame,
+ const gfx::Rect& view_frame);
+#endif
+
+
// Adding a new message handler? Please add it in alphabetical order above
// and put it in the same position in the .cc file.
@@ -1115,6 +1106,11 @@ class RenderViewImpl : public RenderWidget,
// doesn't have a frame at the specified size, the first is returned.
bool DownloadFavicon(int id, const GURL& image_url, int image_size);
+ // Starts a new find-in-page search or looks for the next match.
+ void Find(int request_id,
+ const string16& search_text,
+ const WebKit::WebFindOptions& options);
+
GURL GetAlternateErrorPageURL(const GURL& failed_url,
ErrorPageType error_type);
@@ -1161,9 +1157,20 @@ class RenderViewImpl : public RenderWidget,
// --enable-fixed-layout[=w,h].
void ProcessViewLayoutFlags(const CommandLine& command_line);
+ // Sends a reply to the current find operation handling if it was a
+ // synchronous find request.
+ void SendFindReply(int request_id,
+ int match_count,
+ int ordinal,
+ const WebKit::WebRect& selection_rect,
+ bool final_status_update);
+
// Starts nav_state_sync_timer_ if it isn't already running.
void StartNavStateSyncTimerIfNecessary();
+ // Stops the current find-in-page search.
+ void StopFinding(content::StopFindAction action);
+
// Dispatches the current navigation state to the browser. Called on a
// periodic timer so we don't send too many messages.
void SyncNavigationState();
@@ -1422,6 +1429,14 @@ class RenderViewImpl : public RenderWidget,
// Resource manager for all the android media player objects if they are
// created in the renderer process.
scoped_ptr<webkit_media::MediaPlayerBridgeManagerImpl> media_bridge_manager_;
+
+ // Holds the message used to return find results to the browser during
+ // synchronous find-in-page requests. Only non-null during these requests.
+ scoped_ptr<IPC::Message> synchronous_find_reply_message_;
+
+ // The active find-in-page match ordinal during synchronous requests.
+ // Needed to be remembered across WebKit callbacks.
+ int synchronous_find_active_match_ordinal_;
#endif
// Misc ----------------------------------------------------------------------