diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-14 22:14:01 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-14 22:14:01 +0000 |
commit | b6ce15971b4139103635132bb9c9d3cd2224973e (patch) | |
tree | 07ac0724aed49c2adb8d8c47aadeb23a34d3e324 /chrome/renderer | |
parent | 95c3c59d275042225cda4589525cb279f66f1f2c (diff) | |
download | chromium_src-b6ce15971b4139103635132bb9c9d3cd2224973e.zip chromium_src-b6ce15971b4139103635132bb9c9d3cd2224973e.tar.gz chromium_src-b6ce15971b4139103635132bb9c9d3cd2224973e.tar.bz2 |
Chrome-side of fixes for content-script messaging.
This change adds registration of content scripts, parented to a frame's
context. When a frame's context goes away, we unregister it and any content
script contexts for it.
There's a corresponding webkit change that lets us know when a content script
context is created. Filed upstream as
https://bugs.webkit.org/show_bug.cgi?id=27104.
BUG=16228
TEST=install an extension with a content script that communicates with a parent
process. Messages should be sendable both ways.
Review URL: http://codereview.chromium.org/155309
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20677 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-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 |
4 files changed, 82 insertions, 32 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, |