Index: content/browser/android/content_view_core_impl.cc |
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc |
index b18831bde52ca5a2b832f5a3f73e3e844fbef09e..68851d943299918b6e3cb03a811c1740aeda14f7 100644 |
--- a/content/browser/android/content_view_core_impl.cc |
+++ b/content/browser/android/content_view_core_impl.cc |
@@ -65,24 +65,66 @@ enum PopupItemType { |
POPUP_ITEM_TYPE_ENABLED |
}; |
+namespace content { |
+ |
namespace { |
jfieldID g_native_content_view; |
+ |
+const void* kContentViewUserDataKey = &kContentViewUserDataKey; |
} // namespace |
-namespace content { |
+// Enables a callback when the underlying WebContents is destroyed, to enable |
+// nulling the back-pointer. |
+class ContentViewCoreImpl::ContentViewUserData |
+ : public base::SupportsUserData::Data { |
+ public: |
+ explicit ContentViewUserData(ContentViewCoreImpl* content_view_core) |
+ : content_view_core_(content_view_core) { |
+ } |
+ |
+ virtual ~ContentViewUserData() { |
+ // TODO(joth): When chrome has finished removing the TabContents class (see |
+ // crbug.com/107201) consider inverting relationship, so ContentViewCore |
+ // would own WebContents. That effectively implies making the WebContents |
+ // destructor private on Android. |
+ delete content_view_core_; |
+ } |
+ |
+ ContentViewCoreImpl* get() const { return content_view_core_; } |
+ |
+ private: |
+ // Not using scoped_ptr as ContentViewCoreImpl destructor is private. |
+ ContentViewCoreImpl* content_view_core_; |
+ |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData); |
+}; |
struct ContentViewCoreImpl::JavaObject { |
ScopedJavaGlobalRef<jclass> rect_clazz; |
jmethodID rect_constructor; |
}; |
+// static |
+ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents( |
+ content::WebContents* web_contents) { |
+ ContentViewCoreImpl::ContentViewUserData* data = |
+ reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>( |
+ web_contents->GetUserData(kContentViewUserDataKey)); |
+ return data ? data->get() : NULL; |
+} |
+ |
+// static |
+ContentViewCore* ContentViewCore::FromWebContents( |
+ content::WebContents* web_contents) { |
+ return ContentViewCoreImpl::FromWebContents(web_contents); |
+} |
+ |
ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env, |
jobject obj) { |
return reinterpret_cast<ContentViewCore*>( |
env->GetIntField(obj, g_native_content_view)); |
} |
- |
ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, jobject obj, |
bool hardware_accelerated, |
WebContents* web_contents, |
@@ -119,31 +161,42 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, jobject obj, |
webkit_glue::BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product); |
web_contents->SetUserAgentOverride(spoofed_ua); |
- InitWebContents(web_contents); |
+ InitWebContents(); |
} |
ContentViewCoreImpl::~ContentViewCoreImpl() { |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
+ java_ref_.reset(); |
+ if (!j_obj.is_null()) { |
+ Java_ContentViewCore_onNativeContentViewCoreDestroyed( |
+ env, j_obj.obj(), reinterpret_cast<jint>(this)); |
+ } |
// Make sure nobody calls back into this object while we are tearing things |
// down. |
notification_registrar_.RemoveAll(); |
delete java_object_; |
java_object_ = NULL; |
- java_ref_.reset(); |
} |
-void ContentViewCoreImpl::Destroy(JNIEnv* env, jobject obj) { |
- delete this; |
+void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env, |
+ jobject obj) { |
+ DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj)); |
+ java_ref_.reset(); |
} |
-void ContentViewCoreImpl::InitWebContents(WebContents* web_contents) { |
- web_contents_ = static_cast<WebContentsImpl*>(web_contents); |
+void ContentViewCoreImpl::InitWebContents() { |
+ DCHECK(web_contents_); |
notification_registrar_.Add(this, |
NOTIFICATION_RENDER_VIEW_HOST_CHANGED, |
Source<NavigationController>(&web_contents_->GetController())); |
static_cast<WebContentsViewAndroid*>(web_contents_->GetView())-> |
SetContentViewCore(this); |
+ DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey)); |
+ web_contents_->SetUserData(kContentViewUserDataKey, |
+ new ContentViewUserData(this)); |
} |
void ContentViewCoreImpl::Observe(int type, |