| Index: chrome/renderer/extensions/event_bindings.cc
|
| diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
|
| index bb8df28c6b8976220084bd879cd3493fad15b1f0..9d7104cc40d532a18404fae54e1f56f1ddd358ce 100644
|
| --- a/chrome/renderer/extensions/event_bindings.cc
|
| +++ b/chrome/renderer/extensions/event_bindings.cc
|
| @@ -14,6 +14,8 @@
|
| #include "chrome/renderer/render_thread.h"
|
| #include "chrome/renderer/render_view.h"
|
| #include "grit/renderer_resources.h"
|
| +#include "webkit/api/public/WebDataSource.h"
|
| +#include "webkit/api/public/WebURLRequest.h"
|
| #include "webkit/glue/webframe.h"
|
|
|
| using bindings_utils::CallFunctionInContext;
|
| @@ -29,6 +31,7 @@ namespace {
|
|
|
| // Keep a local cache of RenderThread so that we can mock it out for unit tests.
|
| static RenderThreadBase* render_thread = NULL;
|
| +static bool in_unit_tests = false;
|
|
|
| // Set to true if these bindings are registered. Will be false when extensions
|
| // are disabled.
|
| @@ -111,6 +114,7 @@ v8::Extension* EventBindings::Get() {
|
| // static
|
| void EventBindings::SetRenderThread(RenderThreadBase* thread) {
|
| render_thread = thread;
|
| + in_unit_tests = true;
|
| }
|
|
|
| // static
|
| @@ -150,12 +154,17 @@ static void HandleContextDestroyed(ContextList::iterator context_iter,
|
| (*context_iter)->context.ClearWeak();
|
| (*context_iter)->context.Dispose();
|
| (*context_iter)->context.Clear();
|
| +
|
| + if (!(*context_iter)->parent_context.IsEmpty()) {
|
| + (*context_iter)->parent_context.Dispose();
|
| + (*context_iter)->parent_context.Clear();
|
| + }
|
| +
|
| GetContexts().erase(context_iter);
|
| }
|
|
|
| static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context,
|
| - void*)
|
| -{
|
| + void*) {
|
| for (ContextList::iterator it = GetContexts().begin();
|
| it != GetContexts().end(); ++it) {
|
| if ((*it)->context == context) {
|
| @@ -167,7 +176,7 @@ static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context,
|
| NOTREACHED();
|
| }
|
|
|
| -void EventBindings::HandleContextCreated(WebFrame* frame) {
|
| +void EventBindings::HandleContextCreated(WebFrame* frame, bool content_script) {
|
| if (!bindings_registered)
|
| return;
|
|
|
| @@ -178,26 +187,46 @@ void EventBindings::HandleContextCreated(WebFrame* frame) {
|
| DCHECK(!context.IsEmpty());
|
| DCHECK(bindings_utils::FindContext(context) == contexts.end());
|
|
|
| - GURL url = frame->GetView()->GetMainFrame()->GetURL();
|
| + // Figure out the URL for the toplevel frame. If the top frame is loading,
|
| + // use its provisional URL, since we get this notification before commit.
|
| + WebFrame* main_frame = frame->GetView()->GetMainFrame();
|
| + WebKit::WebDataSource* ds = main_frame->GetProvisionalDataSource();
|
| + if (!ds)
|
| + ds = main_frame->GetDataSource();
|
| + GURL url = ds->request().url();
|
| std::string extension_id;
|
| - if (url.SchemeIs(chrome::kExtensionScheme))
|
| + if (url.SchemeIs(chrome::kExtensionScheme)) {
|
| extension_id = url.host();
|
| + } else if (!content_script) {
|
| + // This context is a regular non-extension web page. Ignore it. We only
|
| + // care about content scripts and extension frames.
|
| + // (Unless we're in unit tests, in which case we don't care what the URL
|
| + // is).
|
| + DCHECK(frame_context == context);
|
| + if (!in_unit_tests)
|
| + return;
|
| + }
|
|
|
| v8::Persistent<v8::Context> persistent_context =
|
| v8::Persistent<v8::Context>::New(context);
|
| 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());
|
| + if (content_script) {
|
| + DCHECK(frame_context != context);
|
| +
|
| 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);
|
| }
|
|
|
| + RenderView* render_view = NULL;
|
| + if (frame->GetView() && frame->GetView()->GetDelegate())
|
| + render_view = static_cast<RenderView*>(frame->GetView()->GetDelegate());
|
| +
|
| contexts.push_back(linked_ptr<ContextInfo>(
|
| - new ContextInfo(persistent_context, extension_id, parent_context)));
|
| + new ContextInfo(persistent_context, extension_id, parent_context,
|
| + render_view)));
|
|
|
| v8::Handle<v8::Value> argv[1];
|
| argv[0] = v8::String::New(extension_id.c_str());
|
| @@ -214,15 +243,18 @@ void EventBindings::HandleContextDestroyed(WebFrame* frame) {
|
| DCHECK(!context.IsEmpty());
|
|
|
| ContextList::iterator context_iter = bindings_utils::FindContext(context);
|
| - DCHECK(context_iter != GetContexts().end());
|
| - ::HandleContextDestroyed(context_iter, true);
|
| + if (context_iter != GetContexts().end())
|
| + ::HandleContextDestroyed(context_iter, true);
|
| }
|
|
|
| // static
|
| void EventBindings::CallFunction(const std::string& function_name,
|
| - int argc, v8::Handle<v8::Value>* argv) {
|
| + int argc, v8::Handle<v8::Value>* argv,
|
| + RenderView* render_view) {
|
| for (ContextList::iterator it = GetContexts().begin();
|
| it != GetContexts().end(); ++it) {
|
| + if (render_view && render_view != (*it)->render_view)
|
| + continue;
|
| CallFunctionInContext((*it)->context, function_name, argc, argv);
|
| }
|
| }
|
|
|