diff options
-rw-r--r-- | chrome/renderer/extensions/bindings_utils.h | 10 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_bindings.cc | 91 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 8 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 5 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.cc | 15 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.h | 14 | ||||
-rw-r--r-- | webkit/glue/webview_delegate.h | 8 |
7 files changed, 111 insertions, 40 deletions
diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h index 2e8935a5..2c81b0c 100644 --- a/chrome/renderer/extensions/bindings_utils.h +++ b/chrome/renderer/extensions/bindings_utils.h @@ -61,9 +61,15 @@ struct ContextInfo { v8::Persistent<v8::Context> context; std::string extension_id; // empty if the context is not an extension + // If this context is a content script, parent will be the frame that it + // was injected in. This is empty if the context is not a content script. + v8::Persistent<v8::Context> parent_context; + ContextInfo(v8::Persistent<v8::Context> context, - const std::string& extension_id) - : context(context), extension_id(extension_id) {} + const std::string& extension_id, + v8::Persistent<v8::Context> parent_context) + : context(context), extension_id(extension_id), + parent_context(parent_context) {} }; typedef std::list< linked_ptr<ContextInfo> > ContextList; diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 03cccad..eab00fc 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -118,14 +118,61 @@ RenderThreadBase* EventBindings::GetRenderThread() { return render_thread ? render_thread : RenderThread::current(); } +static void HandleContextDestroyed(ContextList::iterator context_iter) { + // Notify the bindings that they're going away. + CallFunctionInContext((*context_iter)->context, "dispatchOnUnload", 0, NULL); + + // Remove all pending requests for this context. + PendingRequestMap& pending_requests = GetPendingRequestMap(); + for (PendingRequestMap::iterator it = pending_requests.begin(); + it != pending_requests.end(); ) { + PendingRequestMap::iterator current = it++; + if (current->second->context == (*context_iter)->context) { + current->second->context.Dispose(); + current->second->context.Clear(); + pending_requests.erase(current); + } + } + + // Unload any content script contexts for this frame. + for (ContextList::iterator it = GetContexts().begin(); + it != GetContexts().end(); ) { + ContextList::iterator current = it++; + if ((*current)->parent_context == (*context_iter)->context) + HandleContextDestroyed(current); + } + + // Remove it from our registered contexts. + (*context_iter)->context.ClearWeak(); + (*context_iter)->context.Dispose(); + (*context_iter)->context.Clear(); + GetContexts().erase(context_iter); +} + +static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context, + void*) +{ + for (ContextList::iterator it = GetContexts().begin(); + it != GetContexts().end(); ++it) { + if ((*it)->context == context) { + HandleContextDestroyed(it); + return; + } + } + + NOTREACHED(); +} + void EventBindings::HandleContextCreated(WebFrame* frame) { if (!bindings_registered) return; v8::HandleScope handle_scope; - v8::Local<v8::Context> context = frame->GetScriptContext(); + ContextList& contexts = GetContexts(); + v8::Local<v8::Context> frame_context = frame->GetScriptContext(); + v8::Local<v8::Context> context = v8::Context::GetCurrent(); DCHECK(!context.IsEmpty()); - DCHECK(bindings_utils::FindContext(context) == GetContexts().end()); + DCHECK(bindings_utils::FindContext(context) == contexts.end()); GURL url = frame->GetView()->GetMainFrame()->GetURL(); std::string extension_id; @@ -134,8 +181,19 @@ void EventBindings::HandleContextCreated(WebFrame* frame) { v8::Persistent<v8::Context> persistent_context = v8::Persistent<v8::Context>::New(context); - GetContexts().push_back(linked_ptr<ContextInfo>( - new ContextInfo(persistent_context, extension_id))); + v8::Persistent<v8::Context> parent_context; + + if (frame_context != context) { + // The new context doesn't belong to the frame: it's a content script. + DCHECK(bindings_utils::FindContext(frame_context) != contexts.end()); + parent_context = v8::Persistent<v8::Context>::New(frame_context); + // Content script contexts can get GCed before their frame goes away, so + // set up a GC callback. + persistent_context.MakeWeak(NULL, &ContextWeakReferenceCallback); + } + + contexts.push_back(linked_ptr<ContextInfo>( + new ContextInfo(persistent_context, extension_id, parent_context))); v8::Handle<v8::Value> argv[1]; argv[0] = v8::String::New(extension_id.c_str()); @@ -151,28 +209,9 @@ void EventBindings::HandleContextDestroyed(WebFrame* frame) { v8::Local<v8::Context> context = frame->GetScriptContext(); DCHECK(!context.IsEmpty()); - ContextList::iterator it = bindings_utils::FindContext(context); - DCHECK(it != GetContexts().end()); - - // Notify the bindings that they're going away. - CallFunctionInContext(context, "dispatchOnUnload", 0, NULL); - - // Remove all pending requests for this context. - PendingRequestMap& pending_requests = GetPendingRequestMap(); - for (PendingRequestMap::iterator it = pending_requests.begin(); - it != pending_requests.end(); ) { - PendingRequestMap::iterator current = it++; - if (current->second->context == context) { - current->second->context.Dispose(); - current->second->context.Clear(); - pending_requests.erase(current); - } - } - - // Remove it from our registered contexts. - (*it)->context.Dispose(); - (*it)->context.Clear(); - GetContexts().erase(it); + ContextList::iterator context_iter = bindings_utils::FindContext(context); + DCHECK(context_iter != GetContexts().end()); + ::HandleContextDestroyed(context_iter); } // static diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 012dc3f..436de6e 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1461,14 +1461,18 @@ void RenderView::DocumentElementAvailable(WebFrame* frame) { frame, UserScript::DOCUMENT_START); } -void RenderView::DidCreateScriptContext(WebFrame* webframe) { +void RenderView::DidCreateScriptContextForFrame(WebFrame* webframe) { EventBindings::HandleContextCreated(webframe); } -void RenderView::DidDestroyScriptContext(WebFrame* webframe) { +void RenderView::DidDestroyScriptContextForFrame(WebFrame* webframe) { EventBindings::HandleContextDestroyed(webframe); } +void RenderView::DidCreateIsolatedScriptContext(WebFrame* webframe) { + EventBindings::HandleContextCreated(webframe); +} + WindowOpenDisposition RenderView::DispositionForNavigationAction( WebView* webview, WebFrame* frame, diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index bf6b6e3..ba6374d 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -218,8 +218,9 @@ class RenderView : public RenderWidget, virtual void WindowObjectCleared(WebFrame* webframe); virtual void DocumentElementAvailable(WebFrame* webframe); - virtual void DidCreateScriptContext(WebFrame* webframe); - virtual void DidDestroyScriptContext(WebFrame* webframe); + virtual void DidCreateScriptContextForFrame(WebFrame* webframe); + virtual void DidDestroyScriptContextForFrame(WebFrame* webframe); + virtual void DidCreateIsolatedScriptContext(WebFrame* webframe); virtual WindowOpenDisposition DispositionForNavigationAction( WebView* webview, diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc index c5d4901..19f1096 100644 --- a/webkit/glue/webframeloaderclient_impl.cc +++ b/webkit/glue/webframeloaderclient_impl.cc @@ -130,18 +130,25 @@ void WebFrameLoaderClient::documentElementAvailable() { d->DocumentElementAvailable(webframe_); } -void WebFrameLoaderClient::didCreateScriptContext() { +void WebFrameLoaderClient::didCreateScriptContextForFrame() { WebViewImpl* webview = webframe_->GetWebViewImpl(); WebViewDelegate* d = webview->delegate(); if (d) - d->DidCreateScriptContext(webframe_); + d->DidCreateScriptContextForFrame(webframe_); } -void WebFrameLoaderClient::didDestroyScriptContext() { +void WebFrameLoaderClient::didDestroyScriptContextForFrame() { WebViewImpl* webview = webframe_->GetWebViewImpl(); WebViewDelegate* d = webview->delegate(); if (d) - d->DidDestroyScriptContext(webframe_); + d->DidDestroyScriptContextForFrame(webframe_); +} + +void WebFrameLoaderClient::didCreateIsolatedScriptContext() { + WebViewImpl* webview = webframe_->GetWebViewImpl(); + WebViewDelegate* d = webview->delegate(); + if (d) + d->DidCreateIsolatedScriptContext(webframe_); } void WebFrameLoaderClient::didPerformFirstNavigation() const { diff --git a/webkit/glue/webframeloaderclient_impl.h b/webkit/glue/webframeloaderclient_impl.h index 98118dd..8532f55 100644 --- a/webkit/glue/webframeloaderclient_impl.h +++ b/webkit/glue/webframeloaderclient_impl.h @@ -49,8 +49,18 @@ class WebFrameLoaderClient : public WebCore::FrameLoaderClient { virtual void windowObjectCleared(); virtual void documentElementAvailable(); - virtual void didCreateScriptContext(); - virtual void didDestroyScriptContext(); + // TODO(mpcomplete): remove these when we pick up webkit r45871 + virtual void didCreateScriptContext() { didCreateScriptContextForFrame(); } + virtual void didDestroyScriptContext() { didDestroyScriptContextForFrame(); } + + // A frame's V8 context was created or destroyed. + virtual void didCreateScriptContextForFrame(); + virtual void didDestroyScriptContextForFrame(); + + // A context untied to a frame was created (through evaluateInNewContext). + // This context is not tied to the lifetime of its frame, and is destroyed + // in garbage collection. + virtual void didCreateIsolatedScriptContext(); virtual bool hasWebView() const; // mainly for assertions virtual bool hasFrameView() const; // ditto diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h index eafd383..1ccc761 100644 --- a/webkit/glue/webview_delegate.h +++ b/webkit/glue/webview_delegate.h @@ -231,11 +231,15 @@ class WebViewDelegate : virtual public WebWidgetDelegate { // Notifies that a new script context has been created for this frame. // This is similar to WindowObjectCleared but only called once per frame // context. - virtual void DidCreateScriptContext(WebFrame* webframe) { + virtual void DidCreateScriptContextForFrame(WebFrame* webframe) { } // Notifies that this frame's script context has been destroyed. - virtual void DidDestroyScriptContext(WebFrame* webframe) { + virtual void DidDestroyScriptContextForFrame(WebFrame* webframe) { + } + + // Notifies that a garbage-collected context was created - content scripts. + virtual void DidCreateIsolatedScriptContext(WebFrame* webframe) { } // PolicyDelegate ---------------------------------------------------------- |