summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 23:40:32 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-14 23:40:32 +0000
commit14a2df0d0dee8e5b861e6f9a13df932a39a05f61 (patch)
treedac870b1c6aa5827e177252f9e5b663bbdb2d436
parentf1b149409ab54866b1a1e619ab9d59dc1d8f808d (diff)
downloadchromium_src-14a2df0d0dee8e5b861e6f9a13df932a39a05f61.zip
chromium_src-14a2df0d0dee8e5b861e6f9a13df932a39a05f61.tar.gz
chromium_src-14a2df0d0dee8e5b861e6f9a13df932a39a05f61.tar.bz2
Fix Popup window flow to work with synchronous compositor gfx mode
This switches around the object lifetimes, so WebContents and AwContents (native) have identical lifetimes, but now the native AwContents may exist before its java counterpart, and in the popup flow the java object may switch from its default peer instance to acquire the pop-up AwContents/WebContents instead. Additionally, makes some simplifications to the way AwSettings is created and also fixes a potential leak (the native instance was never deleted if destroy() was not called). NOTRY=true BUG=245801 Review URL: https://chromiumcodereview.appspot.com/16843008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@206516 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--android_webview/browser/aw_browser_context.cc13
-rw-r--r--android_webview/browser/aw_browser_context.h3
-rw-r--r--android_webview/browser/aw_content_browser_client.cc6
-rw-r--r--android_webview/browser/aw_content_browser_client.h2
-rw-r--r--android_webview/browser/browser_view_renderer.h3
-rw-r--r--android_webview/browser/in_process_view_renderer.cc36
-rw-r--r--android_webview/browser/in_process_view_renderer.h5
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java9
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java278
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwSettings.java97
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java9
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java4
-rw-r--r--android_webview/native/aw_contents.cc133
-rw-r--r--android_webview/native/aw_contents.h32
-rw-r--r--android_webview/native/aw_settings.cc29
-rw-r--r--android_webview/native/aw_settings.h5
-rw-r--r--android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java10
-rw-r--r--content/browser/android/in_process/synchronous_input_event_filter.cc8
18 files changed, 350 insertions, 332 deletions
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index ea98457..958c66f 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -41,6 +41,8 @@ class AwResourceContext : public content::ResourceContext {
DISALLOW_COPY_AND_ASSIGN(AwResourceContext);
};
+AwBrowserContext* g_browser_context = NULL;
+
} // namespace
AwBrowserContext::AwBrowserContext(
@@ -48,9 +50,20 @@ AwBrowserContext::AwBrowserContext(
JniDependencyFactory* native_factory)
: context_storage_path_(path),
native_factory_(native_factory) {
+ DCHECK(g_browser_context == NULL);
+ g_browser_context = this;
}
AwBrowserContext::~AwBrowserContext() {
+ DCHECK(g_browser_context == this);
+ g_browser_context = NULL;
+}
+
+// static
+AwBrowserContext* AwBrowserContext::GetDefault() {
+ // TODO(joth): rather than store in a global here, lookup this instance
+ // from the Java-side peer.
+ return g_browser_context;
}
// static
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index b2f9178..b6a1134 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -46,6 +46,9 @@ class AwBrowserContext : public content::BrowserContext,
JniDependencyFactory* native_factory);
virtual ~AwBrowserContext();
+ // Currently only one instance per process is supported.
+ static AwBrowserContext* GetDefault();
+
// Convenience method to returns the AwBrowserContext corresponding to the
// given WebContents.
static AwBrowserContext* FromWebContents(
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index d41eccc..d58b8d7 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -29,8 +29,6 @@
namespace android_webview {
namespace {
-AwBrowserContext* g_browser_context;
-
class AwAccessTokenStore : public content::AccessTokenStore {
public:
AwAccessTokenStore() { }
@@ -67,7 +65,7 @@ std::string AwContentBrowserClient::GetAcceptLangsImpl() {
}
AwBrowserContext* AwContentBrowserClient::GetAwBrowserContext() {
- return g_browser_context;
+ return AwBrowserContext::GetDefault();
}
AwContentBrowserClient::AwContentBrowserClient(
@@ -79,11 +77,9 @@ AwContentBrowserClient::AwContentBrowserClient(
}
browser_context_.reset(
new AwBrowserContext(user_data_dir, native_factory_));
- g_browser_context = browser_context_.get();
}
AwContentBrowserClient::~AwContentBrowserClient() {
- g_browser_context = NULL;
}
void AwContentBrowserClient::AddCertificate(net::URLRequest* request,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 5724efa..1ecd2f5 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -21,7 +21,7 @@ class AwContentBrowserClient : public content::ContentBrowserClient {
// This is what AwContentBrowserClient::GetAcceptLangs uses.
static std::string GetAcceptLangsImpl();
- // Returns the one AwBrowserContext for this process.
+ // Deprecated: use AwBrowserContext::GetDefault() instead.
static AwBrowserContext* GetAwBrowserContext();
AwContentBrowserClient(JniDependencyFactory* native_factory);
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index e24b25c..7d05aee 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -78,9 +78,6 @@ class BrowserViewRenderer {
static AwDrawSWFunctionTable* GetAwDrawSWFunctionTable();
static bool IsSkiaVersionCompatible();
- // Content control methods.
- virtual void SetContents(content::ContentViewCore* content_view_core) = 0;
-
// Rendering methods.
// Main handler for view drawing: performs a SW draw immediately, or sets up
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index 0ad4a41..e79591c 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -299,10 +299,11 @@ bool BrowserViewRenderer::IsSkiaVersionCompatible() {
InProcessViewRenderer::InProcessViewRenderer(
BrowserViewRenderer::Client* client,
- JavaHelper* java_helper)
+ JavaHelper* java_helper,
+ content::WebContents* web_contents)
: client_(client),
java_helper_(java_helper),
- web_contents_(NULL),
+ web_contents_(web_contents),
compositor_(NULL),
view_visible_(false),
continuous_invalidate_(false),
@@ -314,11 +315,18 @@ InProcessViewRenderer::InProcessViewRenderer(
hardware_failed_(false),
egl_context_at_init_(NULL),
weak_factory_(this) {
+ CHECK(web_contents_);
+ web_contents_->SetUserData(kUserDataKey, new UserData(this));
+ content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
+ // Currently the logic in this class relies on |compositor_| remaining NULL
+ // until the DidInitializeCompositor() call, hence it is not set here.
}
InProcessViewRenderer::~InProcessViewRenderer() {
- SetContents(NULL);
- DCHECK(compositor_ == NULL);
+ CHECK(web_contents_);
+ content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
+ web_contents_->SetUserData(kUserDataKey, NULL);
+ DCHECK(web_contents_ == NULL); // WebContentsGone should have been called.
}
// static
@@ -327,26 +335,6 @@ InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
return UserData::GetInstance(contents);
}
-void InProcessViewRenderer::SetContents(
- content::ContentViewCore* content_view_core) {
- // First remove association from the prior ContentViewCore / WebContents.
- if (web_contents_) {
- content::SynchronousCompositor::SetClientForWebContents(web_contents_,
- NULL);
- web_contents_->SetUserData(kUserDataKey, NULL);
- DCHECK(!web_contents_); // WebContentsGone should have been called.
- }
-
- if (!content_view_core)
- return;
-
- web_contents_ = content_view_core->GetWebContents();
- web_contents_->SetUserData(kUserDataKey, new UserData(this));
- content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
- // Currently the logic in this class relies on |compositor_| remaining NULL
- // until the DidInitializeCompositor() call, hence it is not set here.
-}
-
void InProcessViewRenderer::WebContentsGone() {
web_contents_ = NULL;
compositor_ = NULL;
diff --git a/android_webview/browser/in_process_view_renderer.h b/android_webview/browser/in_process_view_renderer.h
index 55d5415b..d3e4166 100644
--- a/android_webview/browser/in_process_view_renderer.h
+++ b/android_webview/browser/in_process_view_renderer.h
@@ -26,15 +26,14 @@ class InProcessViewRenderer : public BrowserViewRenderer,
public content::SynchronousCompositorClient {
public:
InProcessViewRenderer(BrowserViewRenderer::Client* client,
- JavaHelper* java_helper);
+ JavaHelper* java_helper,
+ content::WebContents* web_contents);
virtual ~InProcessViewRenderer();
static InProcessViewRenderer* FromWebContents(
content::WebContents* contents);
// BrowserViewRenderer overrides
- virtual void SetContents(
- content::ContentViewCore* content_view_core) OVERRIDE;
virtual bool OnDraw(jobject java_canvas,
bool is_hardware_canvas,
const gfx::Point& scroll,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
index 2536d7b..9b0c987 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
@@ -24,7 +24,14 @@ public class AwBrowserContext {
private AwGeolocationPermissions mGeolocationPermissions;
private AwCookieManager mCookieManager;
private AwFormDatabase mFormDatabase;
+ boolean mIsFileAccessGrantedByDefault;
+ public AwBrowserContext(SharedPreferences sharedPreferences,
+ boolean isFileAccessGrantedByDefault) {
+ mIsFileAccessGrantedByDefault = isFileAccessGrantedByDefault;
+ }
+
+ @Deprecated
public AwBrowserContext(SharedPreferences sharedPreferences) {
mSharedPreferences = sharedPreferences;
}
@@ -63,4 +70,4 @@ public class AwBrowserContext {
public void resumeTimers() {
ContentViewStatics.setWebKitSharedTimersSuspended(false);
}
-} \ No newline at end of file
+}
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 4730d24..9793b06 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -4,6 +4,7 @@
package org.chromium.android_webview;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -15,6 +16,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
+import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -107,19 +109,20 @@ public class AwContents {
}
private int mNativeAwContents;
- private AwBrowserContext mBrowserContext;
- private ViewGroup mContainerView;
+ private final AwBrowserContext mBrowserContext;
+ private final ViewGroup mContainerView;
private ContentViewCore mContentViewCore;
- private AwContentsClient mContentsClient;
- private AwContentsClientBridge mContentsClientBridge;
- private AwWebContentsDelegate mWebContentsDelegate;
- private AwContentsIoThreadClient mIoThreadClient;
- private InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
- private InternalAccessDelegate mInternalAccessAdapter;
+ private final AwContentsClient mContentsClient;
+ private final AwContentsClientBridge mContentsClientBridge;
+ private final AwWebContentsDelegate mWebContentsDelegate;
+ private final AwContentsIoThreadClient mIoThreadClient;
+ private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
+ private final InternalAccessDelegate mInternalAccessAdapter;
private final AwLayoutSizer mLayoutSizer;
- private AwZoomControls mZoomControls;
+ private final AwZoomControls mZoomControls;
// This can be accessed on any thread after construction. See AwContentsIoThreadClient.
private final AwSettings mSettings;
+
private boolean mIsPaused;
private Bitmap mFavicon;
private boolean mHasRequestedVisitedHistoryFromClient;
@@ -127,7 +130,7 @@ public class AwContents {
private final double mDIPScale;
// Must call nativeUpdateLastHitTestData first to update this before use.
- private final HitTestData mPossiblyStaleHitTestData;
+ private final HitTestData mPossiblyStaleHitTestData = new HitTestData();
private DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
@@ -313,15 +316,24 @@ public class AwContents {
* @param containerView the view-hierarchy item this object will be bound to.
* @param internalAccessAdapter to access private methods on containerView.
* @param contentsClient will receive API callbacks from this WebView Contents
- * @param isAccessFromFileURLsGrantedByDefault passed to AwSettings.
*
* This constructor uses the default view sizing policy.
*/
public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
+ InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient) {
+ this(browserContext, containerView, internalAccessAdapter, contentsClient,
+ new AwLayoutSizer());
+ }
+
+ // TODO(joth): Remove this overload when downstream no-longer passing
+ // isAccessFromFileURLsGrantedByDefault.
+ @Deprecated
+ public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
boolean isAccessFromFileURLsGrantedByDefault) {
this(browserContext, containerView, internalAccessAdapter, contentsClient,
- isAccessFromFileURLsGrantedByDefault, new AwLayoutSizer());
+ new AwLayoutSizer());
+ browserContext.mIsFileAccessGrantedByDefault = isAccessFromFileURLsGrantedByDefault;
}
private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
@@ -348,96 +360,130 @@ public class AwContents {
*/
public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
- boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer) {
+ AwLayoutSizer layoutSizer) {
mBrowserContext = browserContext;
mContainerView = containerView;
mInternalAccessAdapter = internalAccessAdapter;
- mDIPScale = DeviceDisplayInfo.create(containerView.getContext()).getDIPScale();
- // Note that ContentViewCore must be set up before AwContents, as ContentViewCore
- // setup performs process initialisation work needed by AwContents.
- mContentsClientBridge = new AwContentsClientBridge(contentsClient);
+ mContentsClient = contentsClient;
mLayoutSizer = layoutSizer;
+ mDIPScale = DeviceDisplayInfo.create(containerView.getContext()).getDIPScale();
mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
mLayoutSizer.setDIPScale(mDIPScale);
mWebContentsDelegate = new AwWebContentsDelegateAdapter(contentsClient,
mLayoutSizer.getPreferredSizeChangedListener());
- mNativeAwContents = nativeInit(mWebContentsDelegate, mContentsClientBridge);
- mContentsClient = contentsClient;
+ mContentsClientBridge = new AwContentsClientBridge(contentsClient);
+ mZoomControls = new AwZoomControls(this);
+ mIoThreadClient = new IoThreadClientImpl();
+ mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
+
+ boolean hasInternetPermission = containerView.getContext().checkPermission(
+ android.Manifest.permission.INTERNET,
+ Process.myPid(),
+ Process.myUid()) == PackageManager.PERMISSION_GRANTED;
+ AwSettings.ZoomSupportChangeListener zoomListener =
+ new AwSettings.ZoomSupportChangeListener() {
+ @Override
+ public void onMultiTouchZoomSupportChanged(boolean supportsMultiTouchZoom) {
+ mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
+ }
+ };
+ mSettings = new AwSettings(hasInternetPermission, zoomListener,
+ mBrowserContext.mIsFileAccessGrantedByDefault, mDIPScale);
+ mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
+ mSettings.setDefaultVideoPosterURL(
+ mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
+ mContentsClient.setDIPScale(mDIPScale);
+
+ setNewAwContents(nativeInit(browserContext));
+ }
+
+ /**
+ * Common initialization routine for adopting a native AwContents instance into this
+ * java instance.
+ *
+ * TAKE CARE! This method can get called multiple times per java instance. Code accordingly.
+ * ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes.
+ */
+ private void setNewAwContents(int newAwContentsPtr) {
+ if (mNativeAwContents != 0) {
+ destroy();
+ mContentViewCore = null;
+ }
+
+ assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null;
+
+ mNativeAwContents = newAwContentsPtr;
+ // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to
+ // each other, we should update |mBrowserContext| according to the newly received native
+ // WebContent's browser context.
+
+ // The native side object has been bound to this java instance, so now is the time to
+ // bind all the native->java relationships.
mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
int nativeWebContents = nativeGetWebContents(mNativeAwContents);
- mZoomControls = new AwZoomControls(this);
mContentViewCore = createAndInitializeContentViewCore(
- containerView, internalAccessAdapter, nativeWebContents,
+ mContainerView, mInternalAccessAdapter, nativeWebContents,
new AwPinchGestureStateListener(), mContentsClient.getContentViewClient(),
mZoomControls);
+ nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
+ mIoThreadClient, mInterceptNavigationDelegate);
mContentsClient.installWebContentsObserver(mContentViewCore);
+ mSettings.setWebContents(nativeWebContents);
+ }
- mSettings = new AwSettings(mContentViewCore.getContext(), nativeWebContents,
- mContentViewCore, isAccessFromFileURLsGrantedByDefault);
- setIoThreadClient(new IoThreadClientImpl());
- setInterceptNavigationDelegate(new InterceptNavigationDelegateImpl());
-
- mPossiblyStaleHitTestData = new HitTestData();
- nativeDidInitializeContentViewCore(mNativeAwContents,
- mContentViewCore.getNativeContentViewCore());
-
- mContentsClient.setDIPScale(mDIPScale);
- mSettings.setDIPScale(mDIPScale);
- mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
- mSettings.setDefaultVideoPosterURL(
- mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
- }
-
- // Only valid within updatePhysicalBackingSizeIfNeeded().
- private final Rect mGlobalVisibleBoundsTemporary = new Rect();
-
- private void updatePhysicalBackingSizeIfNeeded() {
- // We musn't let the physical backing size get too big, otherwise we
- // will try to allocate a SurfaceTexture beyond what the GL driver can
- // cope with. In most cases, limiting the SurfaceTexture size to that
- // of the visible bounds of the WebView will be good enough i.e. the maximum
- // SurfaceTexture dimensions will match the screen dimensions).
- mContainerView.getGlobalVisibleRect(mGlobalVisibleBoundsTemporary);
- int width = mGlobalVisibleBoundsTemporary.width();
- int height = mGlobalVisibleBoundsTemporary.height();
- if (width != mLastGlobalVisibleWidth || height != mLastGlobalVisibleHeight) {
- mLastGlobalVisibleWidth = width;
- mLastGlobalVisibleHeight = height;
- mContentViewCore.onPhysicalBackingSizeChanged(width, height);
+ /**
+ * Called on the "source" AwContents that is opening the popup window to
+ * provide the AwContents to host the pop up content.
+ */
+ public void supplyContentsForPopup(AwContents newContents) {
+ int popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
+ if (popupNativeAwContents == 0) {
+ Log.w(TAG, "Popup WebView bind failed: no pending content.");
+ if (newContents != null) newContents.destroy();
+ return;
+ }
+ if (newContents == null) {
+ nativeDestroy(popupNativeAwContents);
+ return;
}
- }
-
- @VisibleForTesting
- public ContentViewCore getContentViewCore() {
- return mContentViewCore;
- }
- // Can be called from any thread.
- public AwSettings getSettings() {
- return mSettings;
+ newContents.receivePopupContents(popupNativeAwContents);
}
- public void setIoThreadClient(AwContentsIoThreadClient ioThreadClient) {
- mIoThreadClient = ioThreadClient;
- nativeSetIoThreadClient(mNativeAwContents, mIoThreadClient);
- }
+ // Recap: supplyContentsForPopup() is called on the parent window's content, this method is
+ // called on the popup window's content.
+ private void receivePopupContents(int popupNativeAwContents) {
+ setNewAwContents(popupNativeAwContents);
- private void setInterceptNavigationDelegate(InterceptNavigationDelegateImpl delegate) {
- mInterceptNavigationDelegate = delegate;
- nativeSetInterceptNavigationDelegate(mNativeAwContents, delegate);
+ // Finally refresh view size and visibility, to poke new values into ContentViewCore.
+ mLastGlobalVisibleWidth = 0;
+ mLastGlobalVisibleHeight = 0;
+ onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
+ updateVisiblityState();
+ onWindowFocusChanged(mWindowFocused);
}
public void destroy() {
mContentViewCore.destroy();
- // The native part of AwSettings isn't needed for the IoThreadClient instance.
- mSettings.destroy();
// We explicitly do not null out the mContentViewCore reference here
// because ContentViewCore already has code to deal with the case
// methods are called on it after it's been destroyed, and other
// code relies on AwContents.mContentViewCore to be non-null.
+
mCleanupReference.cleanupNow();
mNativeAwContents = 0;
+ mCleanupReference = null;
+ }
+
+ @VisibleForTesting
+ public ContentViewCore getContentViewCore() {
+ return mContentViewCore;
+ }
+
+ // Can be called from any thread.
+ public AwSettings getSettings() {
+ return mSettings;
}
public static void setAwDrawSWFunctionTable(int functionTablePointer) {
@@ -458,6 +504,29 @@ public class AwContents {
return nativeGetAwDrawGLViewContext(mNativeAwContents);
}
+ // Only valid within updatePhysicalBackingSizeIfNeeded().
+ private final Rect mGlobalVisibleBoundsTemporary = new Rect();
+
+ private void updatePhysicalBackingSizeIfNeeded() {
+ // We musn't let the physical backing size get too big, otherwise we
+ // will try to allocate a SurfaceTexture beyond what the GL driver can
+ // cope with. In most cases, limiting the SurfaceTexture size to that
+ // of the visible bounds of the WebView will be good enough i.e. the maximum
+ // SurfaceTexture dimensions will match the screen dimensions).
+ mContainerView.getGlobalVisibleRect(mGlobalVisibleBoundsTemporary);
+ int width = mGlobalVisibleBoundsTemporary.width();
+ int height = mGlobalVisibleBoundsTemporary.height();
+ if (width != mLastGlobalVisibleWidth || height != mLastGlobalVisibleHeight) {
+ mLastGlobalVisibleWidth = width;
+ mLastGlobalVisibleHeight = height;
+ mContentViewCore.onPhysicalBackingSizeChanged(width, height);
+ }
+ }
+
+ //--------------------------------------------------------------------------------------------
+ // WebView[Provider] method implementations (where not provided by ContentViewCore)
+ //--------------------------------------------------------------------------------------------
+
// Only valid within onDraw().
private final Rect mClipBoundsTemporary = new Rect();
@@ -602,50 +671,6 @@ public class AwContents {
if (url == null || url.trim().isEmpty()) return null;
return url;
}
- /**
- * Called on the "source" AwContents that is opening the popup window to
- * provide the AwContents to host the pop up content.
- */
- public void supplyContentsForPopup(AwContents newContents) {
- int popupWebContents = nativeReleasePopupWebContents(mNativeAwContents);
- assert popupWebContents != 0;
- newContents.setNewWebContents(popupWebContents);
- }
-
- private void setNewWebContents(int newWebContentsPtr) {
- // When setting a new WebContents, we new up a ContentViewCore that will
- // wrap it and then swap it.
- ContentViewCore newCore = createAndInitializeContentViewCore(
- mContainerView, mInternalAccessAdapter, newWebContentsPtr,
- new AwPinchGestureStateListener(), mContentsClient.getContentViewClient(),
- mZoomControls);
- mContentsClient.installWebContentsObserver(newCore);
-
- // Now swap the Java side reference.
- mContentViewCore.destroy();
- mContentViewCore = newCore;
-
- // Now rewire native side to use the new WebContents.
- nativeSetWebContents(mNativeAwContents, newWebContentsPtr);
- nativeSetIoThreadClient(mNativeAwContents, mIoThreadClient);
- nativeSetInterceptNavigationDelegate(mNativeAwContents, mInterceptNavigationDelegate);
-
- // This will also apply settings to the new WebContents.
- mSettings.setWebContents(newWebContentsPtr);
-
- // Finally poke the new ContentViewCore with the size of the container view and show it.
- if (mContainerView.getWidth() != 0 || mContainerView.getHeight() != 0) {
- mContentViewCore.onSizeChanged(
- mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
- }
- nativeDidInitializeContentViewCore(mNativeAwContents,
- mContentViewCore.getNativeContentViewCore());
- if (mContainerView.getVisibility() == View.VISIBLE) {
- // The popup window was hidden when we prompted the embedder to display
- // it, so show it again now we have a container.
- mContentViewCore.onShow();
- }
- }
public void requestFocus() {
if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
@@ -661,10 +686,6 @@ public class AwContents {
return mZoomControls.getZoomControlsViewForTest();
}
- //--------------------------------------------------------------------------------------------
- // WebView[Provider] method implementations (where not provided by ContentViewCore)
- //--------------------------------------------------------------------------------------------
-
/**
* @see ContentViewCore#getContentSettings()
*/
@@ -1425,26 +1446,22 @@ public class AwContents {
// Native methods
//--------------------------------------------------------------------------------------------
- private native int nativeInit(AwWebContentsDelegate webViewWebContentsDelegate,
- AwContentsClientBridge contentsClientBridge);
+ private static native int nativeInit(AwBrowserContext browserContext);
private static native void nativeDestroy(int nativeAwContents);
private static native void nativeSetAwDrawSWFunctionTable(int functionTablePointer);
private static native void nativeSetAwDrawGLFunctionTable(int functionTablePointer);
private static native int nativeGetAwDrawGLFunction();
-
+ private native void nativeSetJavaPeers(int nativeAwContents, AwContents awContents,
+ AwWebContentsDelegate webViewWebContentsDelegate,
+ AwContentsClientBridge contentsClientBridge,
+ AwContentsIoThreadClient ioThreadClient,
+ InterceptNavigationDelegate navigationInterceptionDelegate);
private native int nativeGetWebContents(int nativeAwContents);
- private native void nativeDidInitializeContentViewCore(int nativeAwContents,
- int nativeContentViewCore);
private native void nativeDocumentHasImages(int nativeAwContents, Message message);
private native void nativeGenerateMHTML(
int nativeAwContents, String path, ValueCallback<String> callback);
- private native void nativeSetIoThreadClient(int nativeAwContents,
- AwContentsIoThreadClient ioThreadClient);
- private native void nativeSetInterceptNavigationDelegate(int nativeAwContents,
- InterceptNavigationDelegate navigationInterceptionDelegate);
-
private native void nativeAddVisitedLinks(int nativeAwContents, String[] visitedLinks);
private native boolean nativeOnDraw(int nativeAwContents, Canvas canvas,
boolean isHardwareAccelerated, int scrollX, int ScrollY,
@@ -1471,8 +1488,7 @@ public class AwContents {
// Returns false if restore state fails.
private native boolean nativeRestoreFromOpaqueState(int nativeAwContents, byte[] state);
- private native int nativeReleasePopupWebContents(int nativeAwContents);
- private native void nativeSetWebContents(int nativeAwContents, int nativeNewWebContents);
+ private native int nativeReleasePopupAwContents(int nativeAwContents);
private native void nativeFocusFirstNode(int nativeAwContents);
private native int nativeGetAwDrawGLViewContext(int nativeAwContents);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index 2be4d46..0f3ddc2 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -4,12 +4,9 @@
package org.chromium.android_webview;
-import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebSettings;
import android.webkit.WebView;
@@ -43,12 +40,14 @@ public class AwSettings {
// used from any thread. Internally, the class uses a message queue
// to call native code on the UI thread only.
+ // Values passed in on construction.
+ private final boolean mHasInternetPermission;
+ private final ZoomSupportChangeListener mZoomChangeListener;
+ private final double mDIPScale;
+
// Lock to protect all settings.
private final Object mAwSettingsLock = new Object();
- private final Context mContext;
- private double mDIPScale;
-
private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
private int mTextSizePercent = 100;
private String mStandardFontFamily = "sans-serif";
@@ -94,6 +93,7 @@ public class AwSettings {
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
private boolean mDisplayZoomControls = true;
+
static class LazyDefaultUserAgent{
// Lazy Holder pattern
private static final String sInstance = nativeGetDefaultUserAgent();
@@ -106,11 +106,9 @@ public class AwSettings {
// client.
private static boolean sAppCachePathIsSet = false;
- // The native side of this object.
+ // The native side of this object. It's lifetime is bounded by the WebContent it is attached to.
private int mNativeAwSettings = 0;
- private ContentViewCore mContentViewCore;
-
// A flag to avoid sending superfluous synchronization messages.
private boolean mIsUpdateWebkitPrefsMessagePending = false;
// Custom handler that queues messages to call native code on the UI thread.
@@ -166,44 +164,39 @@ public class AwSettings {
}
}
- public AwSettings(Context context,
- int nativeWebContents,
- ContentViewCore contentViewCore,
- boolean isAccessFromFileURLsGrantedByDefault) {
- ThreadUtils.assertOnUiThread();
- mContext = context;
- mBlockNetworkLoads = mContext.checkPermission(
- android.Manifest.permission.INTERNET,
- Process.myPid(),
- Process.myUid()) != PackageManager.PERMISSION_GRANTED;
- mContentViewCore = contentViewCore;
- mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoomLocked());
+ interface ZoomSupportChangeListener {
+ public void onMultiTouchZoomSupportChanged(boolean supportsMultiTouchZoom);
+ }
- if (isAccessFromFileURLsGrantedByDefault) {
- mAllowUniversalAccessFromFileURLs = true;
- mAllowFileAccessFromFileURLs = true;
- }
+ public AwSettings(boolean hasInternetPermission,
+ ZoomSupportChangeListener zoomChangeListener,
+ boolean isAccessFromFileURLsGrantedByDefault,
+ double dipScale) {
+ ThreadUtils.assertOnUiThread();
+ synchronized (mAwSettingsLock) {
+ mHasInternetPermission = hasInternetPermission;
+ mZoomChangeListener = zoomChangeListener;
+ mDIPScale = dipScale;
+ mEventHandler = new EventHandler();
+ mBlockNetworkLoads = !hasInternetPermission;
- mEventHandler = new EventHandler();
- mUserAgent = LazyDefaultUserAgent.sInstance;
+ if (isAccessFromFileURLsGrantedByDefault) {
+ mAllowUniversalAccessFromFileURLs = true;
+ mAllowFileAccessFromFileURLs = true;
+ }
- synchronized (mAwSettingsLock) {
- mNativeAwSettings = nativeInit(nativeWebContents);
+ mUserAgent = LazyDefaultUserAgent.sInstance;
+ onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
}
- assert mNativeAwSettings != 0;
+ // Defer initializing the native side until a native WebContents instance is set.
}
- public void destroy() {
- nativeDestroy(mNativeAwSettings);
+ @CalledByNative
+ private void nativeAwSettingsGone(int nativeAwSettings) {
+ assert mNativeAwSettings != 0 && mNativeAwSettings == nativeAwSettings;
mNativeAwSettings = 0;
}
- public void setDIPScale(double dipScale) {
- synchronized (mAwSettingsLock) {
- mDIPScale = dipScale;
- }
- }
-
@CalledByNative
private double getDIPScaleLocked() {
return mDIPScale;
@@ -211,7 +204,14 @@ public class AwSettings {
public void setWebContents(int nativeWebContents) {
synchronized (mAwSettingsLock) {
- nativeSetWebContentsLocked(mNativeAwSettings, nativeWebContents);
+ if (mNativeAwSettings != 0) {
+ nativeDestroy(mNativeAwSettings);
+ assert mNativeAwSettings == 0; // nativeAwSettingsGone should have been called.
+ }
+ if (nativeWebContents != 0) {
+ mNativeAwSettings = nativeInit(nativeWebContents);
+ nativeUpdateEverythingLocked(mNativeAwSettings);
+ }
}
}
@@ -220,10 +220,7 @@ public class AwSettings {
*/
public void setBlockNetworkLoads(boolean flag) {
synchronized (mAwSettingsLock) {
- if (!flag && mContext.checkPermission(
- android.Manifest.permission.INTERNET,
- Process.myPid(),
- Process.myUid()) != PackageManager.PERMISSION_GRANTED) {
+ if (!flag && !mHasInternetPermission) {
throw new SecurityException("Permission denied - " +
"application missing INTERNET permission");
}
@@ -1239,11 +1236,12 @@ public class AwSettings {
return mDefaultVideoPosterURL;
}
- private void updateMultiTouchZoomSupport(final boolean supportsMultiTouchZoom) {
- ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+ private void onMultiTouchZoomSupportChanged(final boolean supportsMultiTouchZoom) {
+ // Always post asynchronously here, to avoid doubling back onto the caller.
+ ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
- mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
+ mZoomChangeListener.onMultiTouchZoomSupportChanged(supportsMultiTouchZoom);
}
});
}
@@ -1255,7 +1253,7 @@ public class AwSettings {
synchronized (mAwSettingsLock) {
if (mSupportZoom != support) {
mSupportZoom = support;
- updateMultiTouchZoomSupport(supportsMultiTouchZoomLocked());
+ onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
}
}
}
@@ -1276,7 +1274,7 @@ public class AwSettings {
synchronized (mAwSettingsLock) {
if (mBuiltInZoomControls != enabled) {
mBuiltInZoomControls = enabled;
- updateMultiTouchZoomSupport(supportsMultiTouchZoomLocked());
+ onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
}
}
}
@@ -1309,6 +1307,7 @@ public class AwSettings {
}
private boolean supportsMultiTouchZoomLocked() {
+ assert Thread.holdsLock(mAwSettingsLock);
return mSupportZoom && mBuiltInZoomControls;
}
@@ -1353,8 +1352,6 @@ public class AwSettings {
private native void nativeResetScrollAndScaleState(int nativeAwSettings);
- private native void nativeSetWebContentsLocked(int nativeAwSettings, int nativeWebContents);
-
private native void nativeUpdateEverythingLocked(int nativeAwSettings);
private native void nativeUpdateInitialPageScaleLocked(int nativeAwSettings);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
index 69a2c50a..3bdeb31 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -217,14 +217,17 @@ public class AwTestBase
return testContainerView;
}
+ // The browser context needs to be a process-wide singleton.
+ private AwBrowserContext mBrowserContext =
+ new AwBrowserContext(new InMemorySharedPreferences(), false);
+
protected AwTestContainerView createDetachedAwTestContainerView(
final AwContentsClient awContentsClient,
final TestDependencyFactory testDependencyFactory) {
final AwTestContainerView testContainerView = new AwTestContainerView(getActivity());
testContainerView.initialize(new AwContents(
- new AwBrowserContext(new InMemorySharedPreferences()),
- testContainerView, testContainerView.getInternalAccessDelegate(),
- awContentsClient, false, testDependencyFactory.createLayoutSizer()));
+ mBrowserContext, testContainerView, testContainerView.getInternalAccessDelegate(),
+ awContentsClient, testDependencyFactory.createLayoutSizer()));
return testContainerView;
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
index 1f36e68..76d2265 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
@@ -58,9 +58,9 @@ public class LoadUrlTest extends AwTestBase {
@SmallTest
@Feature({"AndroidWebView"})
public void testDataUrlCharset() throws Throwable {
- // Note that the '£' is the important character in the following
+ // Note that the \u00a3 (pound sterling) is the important character in the following
// string as it's not in the US_ASCII character set.
- final String expectedTitle = "You win £100!";
+ final String expectedTitle = "You win \u00a3100!";
final String data =
"<html><head><title>" + expectedTitle + "</title></head><body>foo</body></html>";
final TestAwContentsClient contentsClient = new TestAwContentsClient();
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 8d726da..142f413 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -79,7 +79,11 @@ namespace android_webview {
namespace {
-static JavaBrowserViewRendererHelper java_renderer_helper;
+JavaBrowserViewRendererHelper* java_renderer_helper() {
+ static JavaBrowserViewRendererHelper* g_instance
+ = new JavaBrowserViewRendererHelper;
+ return g_instance;
+}
const void* kAwContentsUserDataKey = &kAwContentsUserDataKey;
@@ -118,38 +122,15 @@ AwContents* AwContents::FromID(int render_process_id, int render_view_id) {
return FromWebContents(web_contents);
}
-AwContents::AwContents(JNIEnv* env,
- jobject obj,
- jobject web_contents_delegate,
- jobject contents_client_bridge)
- : java_ref_(env, obj),
- web_contents_delegate_(
- new AwWebContentsDelegate(env, web_contents_delegate)),
- contents_client_bridge_(
- new AwContentsClientBridge(env, contents_client_bridge)),
+AwContents::AwContents(scoped_ptr<WebContents> web_contents)
+ : web_contents_(web_contents.Pass()),
browser_view_renderer_(
- new InProcessViewRenderer(this, &java_renderer_helper)) {
- android_webview::AwBrowserDependencyFactory* dependency_factory =
- android_webview::AwBrowserDependencyFactory::GetInstance();
-
- // TODO(joth): rather than create and set the WebContents here, expose the
- // factory method to java side and have that orchestrate the construction
- // order.
- SetWebContents(dependency_factory->CreateWebContents());
-}
-
-void AwContents::SetWebContents(content::WebContents* web_contents) {
- web_contents_.reset(web_contents);
- if (find_helper_.get()) {
- find_helper_->SetListener(NULL);
- }
+ new InProcessViewRenderer(this, java_renderer_helper(),
+ web_contents_.get())) {
icon_helper_.reset(new IconHelper(web_contents_.get()));
icon_helper_->SetListener(this);
web_contents_->SetUserData(kAwContentsUserDataKey,
new AwContentsUserData(this));
- AwContentsClientBridgeBase::Associate(web_contents_.get(),
- contents_client_bridge_.get());
- web_contents_->SetDelegate(web_contents_delegate_.get());
render_view_host_ext_.reset(
new AwRenderViewHostExt(this, web_contents_.get()));
@@ -160,6 +141,40 @@ void AwContents::SetWebContents(content::WebContents* web_contents) {
InitAutofillIfNecessary(autofill_manager_delegate->GetSaveFormData());
}
+void AwContents::SetJavaPeers(JNIEnv* env,
+ jobject obj,
+ jobject aw_contents,
+ jobject web_contents_delegate,
+ jobject contents_client_bridge,
+ jobject io_thread_client,
+ jobject intercept_navigation_delegate) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // The |aw_content| param is technically spurious as it duplicates |obj| but
+ // is passed over anyway to make the binding more explicit.
+ java_ref_ = JavaObjectWeakGlobalRef(env, aw_contents);
+
+ web_contents_delegate_.reset(
+ new AwWebContentsDelegate(env, web_contents_delegate));
+ web_contents_->SetDelegate(web_contents_delegate_.get());
+
+ contents_client_bridge_.reset(
+ new AwContentsClientBridge(env, contents_client_bridge));
+ AwContentsClientBridgeBase::Associate(web_contents_.get(),
+ contents_client_bridge_.get());
+
+ AwContentsIoThreadClientImpl::Associate(
+ web_contents_.get(), ScopedJavaLocalRef<jobject>(env, io_thread_client));
+ int child_id = web_contents_->GetRenderProcessHost()->GetID();
+ int route_id = web_contents_->GetRoutingID();
+ AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id);
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ InterceptNavigationDelegate::Associate(
+ web_contents_.get(),
+ make_scoped_ptr(new InterceptNavigationDelegate(
+ env, intercept_navigation_delegate)));
+}
+
void AwContents::SetSaveFormData(bool enabled) {
InitAutofillIfNecessary(enabled);
// We need to check for the existence, since autofill_manager_delegate
@@ -196,10 +211,6 @@ void AwContents::InitAutofillIfNecessary(bool enabled) {
AutofillExternalDelegate::FromWebContents(web_contents));
}
-void AwContents::SetWebContents(JNIEnv* env, jobject obj, jint new_wc) {
- SetWebContents(reinterpret_cast<content::WebContents*>(new_wc));
-}
-
AwContents::~AwContents() {
DCHECK(AwContents::FromWebContents(web_contents_.get()) == this);
web_contents_->RemoveUserData(kAwContentsUserDataKey);
@@ -210,34 +221,35 @@ AwContents::~AwContents() {
}
jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
+ DCHECK(web_contents_);
return reinterpret_cast<jint>(web_contents_.get());
}
-void AwContents::DidInitializeContentViewCore(JNIEnv* env, jobject obj,
- jint content_view_core) {
- ContentViewCore* core = reinterpret_cast<ContentViewCore*>(content_view_core);
- DCHECK(core == ContentViewCore::FromWebContents(web_contents_.get()));
- browser_view_renderer_->SetContents(core);
-}
-
void AwContents::Destroy(JNIEnv* env, jobject obj) {
delete this;
}
-// static
-void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) {
+static jint Init(JNIEnv* env, jclass, jobject browser_context) {
+ // TODO(joth): Use |browser_context| to get the native BrowserContext, rather
+ // than hard-code the default instance lookup here.
+ scoped_ptr<WebContents> web_contents(content::WebContents::Create(
+ content::WebContents::CreateParams(AwBrowserContext::GetDefault())));
+ // Return an 'uninitialized' instance; most work is deferred until the
+ // subsequent SetJavaPeers() call.
+ return reinterpret_cast<jint>(new AwContents(web_contents.Pass()));
+}
+
+static void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) {
BrowserViewRenderer::SetAwDrawSWFunctionTable(
reinterpret_cast<AwDrawSWFunctionTable*>(function_table));
}
-// static
-void SetAwDrawGLFunctionTable(JNIEnv* env, jclass, jint function_table) {
+static void SetAwDrawGLFunctionTable(JNIEnv* env, jclass, jint function_table) {
GpuMemoryBufferImpl::SetAwDrawGLFunctionTable(
reinterpret_cast<AwDrawGLFunctionTable*>(function_table));
}
-// static
-jint GetAwDrawGLFunction(JNIEnv* env, jclass) {
+static jint GetAwDrawGLFunction(JNIEnv* env, jclass) {
return reinterpret_cast<jint>(&DrawGLFunction);
}
@@ -306,24 +318,6 @@ bool AwContents::OnReceivedHttpAuthRequest(const JavaRef<jobject>& handler,
return true;
}
-void AwContents::SetIoThreadClient(JNIEnv* env, jobject obj, jobject client) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- AwContentsIoThreadClientImpl::Associate(
- web_contents_.get(), ScopedJavaLocalRef<jobject>(env, client));
- int child_id = web_contents_->GetRenderProcessHost()->GetID();
- int route_id = web_contents_->GetRoutingID();
- AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id);
-}
-
-void AwContents::SetInterceptNavigationDelegate(JNIEnv* env,
- jobject obj,
- jobject delegate) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- InterceptNavigationDelegate::Associate(
- web_contents_.get(),
- make_scoped_ptr(new InterceptNavigationDelegate(env, delegate)));
-}
-
void AwContents::AddVisitedLinks(JNIEnv* env,
jobject obj,
jobjectArray jvisited_links) {
@@ -343,15 +337,6 @@ void AwContents::AddVisitedLinks(JNIEnv* env,
->AddVisitedURLs(visited_link_gurls);
}
-static jint Init(JNIEnv* env,
- jobject obj,
- jobject web_contents_delegate,
- jobject contents_client_bridge) {
- AwContents* tab = new AwContents(env, obj, web_contents_delegate,
- contents_client_bridge);
- return reinterpret_cast<jint>(tab);
-}
-
bool RegisterAwContents(JNIEnv* env) {
return RegisterNativesImpl(env) >= 0;
}
@@ -673,14 +658,14 @@ void AwContents::SetPendingWebContentsForPopup(
base::MessageLoop::current()->DeleteSoon(FROM_HERE, pending.release());
return;
}
- pending_contents_ = pending.Pass();
+ pending_contents_.reset(new AwContents(pending.Pass()));
}
void AwContents::FocusFirstNode(JNIEnv* env, jobject obj) {
web_contents_->FocusThroughTabTraversal(false);
}
-jint AwContents::ReleasePopupWebContents(JNIEnv* env, jobject obj) {
+jint AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
return reinterpret_cast<jint>(pending_contents_.release());
}
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 170e9b7..1189e9f 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -36,6 +36,15 @@ 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.
+//
+// Object lifetime:
+// For most purposes the java and native objects can be considered to have
+// 1:1 lifetime and relationship. The exception is the java instance that
+// hosts a popup will be rebound to a second native instance (carrying the
+// popup content) and discard the 'default' native instance it made on
+// construction. A native instance is only bound to at most one Java peer over
+// its entire lifetime - see Init() and SetPendingWebContentsForPopup() for the
+// construction points, and SetJavaPeers() where these paths join.
class AwContents : public FindHelper::Listener,
public IconHelper::Listener,
public AwRenderViewHostExtClient,
@@ -48,10 +57,7 @@ class AwContents : public FindHelper::Listener,
// render_process_id and render_view_id, or NULL.
static AwContents* FromID(int render_process_id, int render_view_id);
- AwContents(JNIEnv* env,
- jobject obj,
- jobject web_contents_delegate,
- jobject contents_client_bridge);
+ AwContents(scoped_ptr<content::WebContents> web_contents);
virtual ~AwContents();
AwRenderViewHostExt* render_view_host_ext() {
@@ -67,18 +73,19 @@ class AwContents : public FindHelper::Listener,
const std::string& realm);
// Methods called from Java.
+ void SetJavaPeers(JNIEnv* env,
+ jobject obj,
+ jobject aw_contents,
+ jobject web_contents_delegate,
+ jobject contents_client_bridge,
+ jobject io_thread_client,
+ jobject intercept_navigation_delegate);
jint GetWebContents(JNIEnv* env, jobject obj);
- void SetWebContents(JNIEnv* env, jobject obj, jint web_contents);
jint GetAwContentsClientBridge(JNIEnv* env, jobject obj);
- void DidInitializeContentViewCore(JNIEnv* env, jobject obj,
- jint content_view_core);
void Destroy(JNIEnv* env, jobject obj);
void DocumentHasImages(JNIEnv* env, jobject obj, jobject message);
void GenerateMHTML(JNIEnv* env, jobject obj, jstring jpath, jobject callback);
- void SetIoThreadClient(JNIEnv* env, jobject obj, jobject client);
- void SetInterceptNavigationDelegate(JNIEnv* env, jobject obj,
- jobject delegate);
void AddVisitedLinks(JNIEnv* env, jobject obj, jobjectArray jvisited_links);
base::android::ScopedJavaLocalRef<jbyteArray> GetCertificate(
JNIEnv* env, jobject obj);
@@ -145,12 +152,11 @@ class AwContents : public FindHelper::Listener,
void ClearCache(JNIEnv* env, jobject obj, jboolean include_disk_files);
void SetPendingWebContentsForPopup(scoped_ptr<content::WebContents> pending);
- jint ReleasePopupWebContents(JNIEnv* env, jobject obj);
+ jint ReleasePopupAwContents(JNIEnv* env, jobject obj);
void SetSaveFormData(bool enabled);
private:
- void SetWebContents(content::WebContents* web_contents);
void InitAutofillIfNecessary(bool enabled);
JavaObjectWeakGlobalRef java_ref_;
@@ -160,7 +166,7 @@ class AwContents : public FindHelper::Listener,
scoped_ptr<AwRenderViewHostExt> render_view_host_ext_;
scoped_ptr<FindHelper> find_helper_;
scoped_ptr<IconHelper> icon_helper_;
- scoped_ptr<content::WebContents> pending_contents_;
+ scoped_ptr<AwContents> pending_contents_;
scoped_ptr<BrowserViewRenderer> browser_view_renderer_;
// GURL is supplied by the content layer as requesting frame.
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index 8d44487..15c60aa 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -24,11 +24,19 @@ using base::android::ScopedJavaLocalRef;
namespace android_webview {
-AwSettings::AwSettings(JNIEnv* env, jobject obj)
- : aw_settings_(env, obj) {
+AwSettings::AwSettings(JNIEnv* env, jobject obj, jint web_contents)
+ : WebContentsObserver(
+ reinterpret_cast<content::WebContents*>(web_contents)),
+ aw_settings_(env, obj) {
}
AwSettings::~AwSettings() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> scoped_obj = aw_settings_.get(env);
+ jobject obj = scoped_obj.obj();
+ if (!obj) return;
+ Java_AwSettings_nativeAwSettingsGone(env, obj,
+ reinterpret_cast<jint>(this));
}
void AwSettings::Destroy(JNIEnv* env, jobject obj) {
@@ -48,15 +56,6 @@ void AwSettings::ResetScrollAndScaleState(JNIEnv* env, jobject obj) {
rvhe->ResetScrollAndScaleState();
}
-void AwSettings::SetWebContentsLocked(
- JNIEnv* env, jobject obj, jint jweb_contents) {
- content::WebContents* web_contents =
- reinterpret_cast<content::WebContents*>(jweb_contents);
- Observe(web_contents);
-
- UpdateEverythingLocked(env, obj);
-}
-
void AwSettings::UpdateEverything() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
@@ -250,12 +249,14 @@ void AwSettings::RenderViewCreated(content::RenderViewHost* render_view_host) {
UpdateEverything();
}
-// Assumed to be called from the Java object's constructor, thus is "Locked".
+void AwSettings::WebContentsDestroyed(content::WebContents* web_contents) {
+ delete this;
+}
+
static jint Init(JNIEnv* env,
jobject obj,
jint web_contents) {
- AwSettings* settings = new AwSettings(env, obj);
- settings->SetWebContentsLocked(env, obj, web_contents);
+ AwSettings* settings = new AwSettings(env, obj, web_contents);
return reinterpret_cast<jint>(settings);
}
diff --git a/android_webview/native/aw_settings.h b/android_webview/native/aw_settings.h
index 4d0d5a0..d547f34 100644
--- a/android_webview/native/aw_settings.h
+++ b/android_webview/native/aw_settings.h
@@ -18,14 +18,13 @@ class AwRenderViewHostExt;
class AwSettings : public content::WebContentsObserver {
public:
- AwSettings(JNIEnv* env, jobject obj);
+ AwSettings(JNIEnv* env, jobject obj, jint web_contents);
virtual ~AwSettings();
// Called from Java. Methods with "Locked" suffix require that the settings
// access lock is held during their execution.
void Destroy(JNIEnv* env, jobject obj);
void ResetScrollAndScaleState(JNIEnv* env, jobject obj);
- void SetWebContentsLocked(JNIEnv* env, jobject obj, jint web_contents);
void UpdateEverythingLocked(JNIEnv* env, jobject obj);
void UpdateInitialPageScaleLocked(JNIEnv* env, jobject obj);
void UpdateUserAgentLocked(JNIEnv* env, jobject obj);
@@ -40,6 +39,8 @@ class AwSettings : public content::WebContentsObserver {
// WebContentsObserver overrides:
virtual void RenderViewCreated(
content::RenderViewHost* render_view_host) OVERRIDE;
+ virtual void WebContentsDestroyed(
+ content::WebContents* web_contents) OVERRIDE;
JavaObjectWeakGlobalRef aw_settings_;
};
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
index e2d6dcf..5646bc1 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
@@ -39,6 +39,7 @@ import org.chromium.content.browser.LoadUrlParams;
public class AwShellActivity extends Activity {
private final static String PREFERENCES_NAME = "AwShellPrefs";
private final static String INITIAL_URL = "about:blank";
+ private AwBrowserContext mBrowserContext;
private AwTestContainerView mAwTestContainerView;
private EditText mUrlTextView;
private ImageButton mPrevButton;
@@ -83,11 +84,12 @@ public class AwShellActivity extends Activity {
SharedPreferences sharedPreferences =
getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
- AwBrowserContext browserContext = new AwBrowserContext(sharedPreferences);
-
- testContainerView.initialize(new AwContents(browserContext, testContainerView,
+ if (mBrowserContext == null) {
+ mBrowserContext = new AwBrowserContext(sharedPreferences, false);
+ }
+ testContainerView.initialize(new AwContents(mBrowserContext, testContainerView,
testContainerView.getInternalAccessDelegate(),
- awContentsClient, false));
+ awContentsClient));
testContainerView.getAwContents().getSettings().setJavaScriptEnabled(true);
return testContainerView;
}
diff --git a/content/browser/android/in_process/synchronous_input_event_filter.cc b/content/browser/android/in_process/synchronous_input_event_filter.cc
index 30f96a2..57ee7d9 100644
--- a/content/browser/android/in_process/synchronous_input_event_filter.cc
+++ b/content/browser/android/in_process/synchronous_input_event_filter.cc
@@ -47,8 +47,12 @@ void SynchronousInputEventFilter::SetBoundHandlerOnUIThread(
void SynchronousInputEventFilter::DidAddInputHandler(
int routing_id,
cc::InputHandler* input_handler) {
- SynchronousCompositorImpl::FromRoutingID(routing_id)
- ->SetInputHandler(input_handler);
+ // The SynchronusCompositorImpl can be NULL if the WebContents that it's
+ // bound to has already been deleted.
+ SynchronousCompositorImpl* compositor =
+ SynchronousCompositorImpl::FromRoutingID(routing_id);
+ if (compositor)
+ compositor->SetInputHandler(input_handler);
}
void SynchronousInputEventFilter::DidRemoveInputHandler(int routing_id) {