Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1935)

Unified Diff: chrome/renderer/extensions/event_bindings.cc

Issue 147033: Refactor extension bindings to share code, avoid exposing hidden variables (Closed)
Patch Set: at head Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/extensions/event_bindings.cc
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index 7c988e2be7a40f10eb036f75ff2a93176e8eb331..240c33068456a07a1740127a11ca6dc20bea0c02 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -7,32 +7,37 @@
#include "base/basictypes.h"
#include "base/singleton.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/url_constants.h"
#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/js_only_v8_extensions.h"
#include "chrome/renderer/render_thread.h"
+#include "chrome/renderer/render_view.h"
#include "grit/renderer_resources.h"
#include "webkit/glue/webframe.h"
+using bindings_utils::CallFunctionInContext;
+using bindings_utils::ContextInfo;
+using bindings_utils::ContextList;
+using bindings_utils::GetContexts;
+using bindings_utils::GetStringResource;
+using bindings_utils::ExtensionBase;
+using bindings_utils::GetPendingRequestMap;
+using bindings_utils::PendingRequest;
+using bindings_utils::PendingRequestMap;
+
namespace {
// Keep a local cache of RenderThread so that we can mock it out for unit tests.
static RenderThreadBase* render_thread = NULL;
-static RenderThreadBase* GetRenderThread() {
- return render_thread ? render_thread : RenderThread::current();
-}
+// Set to true if these bindings are registered. Will be false when extensions
+// are disabled.
+static bool bindings_registered = false;
-// Keep a list of contexts that have registered themselves with us. This lets
-// us know where to dispatch events when we receive them.
-typedef std::list< v8::Persistent<v8::Context> > ContextList;
struct ExtensionData {
- ContextList contexts;
std::map<std::string, int> listener_count;
};
-ContextList& GetRegisteredContexts() {
- return Singleton<ExtensionData>::get()->contexts;
-}
int EventIncrementListenerCount(const std::string& event_name) {
ExtensionData *data = Singleton<ExtensionData>::get();
return ++(data->listener_count[event_name]);
@@ -42,12 +47,10 @@ int EventDecrementListenerCount(const std::string& event_name) {
return --(data->listener_count[event_name]);
}
-const char* kContextAttachCount = "chromium.attachCount";
-
-class ExtensionImpl : public v8::Extension {
+class ExtensionImpl : public ExtensionBase {
public:
ExtensionImpl()
- : v8::Extension(EventBindings::kName,
+ : ExtensionBase(EventBindings::kName,
GetStringResource<IDR_EVENT_BINDINGS_JS>(),
0, NULL) {
}
@@ -59,8 +62,10 @@ class ExtensionImpl : public v8::Extension {
return v8::FunctionTemplate::New(AttachEvent);
} else if (name->Equals(v8::String::New("DetachEvent"))) {
return v8::FunctionTemplate::New(DetachEvent);
+ } else if (name->Equals(v8::String::New("GetNextRequestId"))) {
+ return v8::FunctionTemplate::New(GetNextRequestId);
}
- return v8::Handle<v8::FunctionTemplate>();
+ return ExtensionBase::GetNativeFunction(name);
}
// Attach an event name to an object.
@@ -69,30 +74,10 @@ class ExtensionImpl : public v8::Extension {
// TODO(erikkay) should enforce that event name is a string in the bindings
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
- v8::Persistent<v8::Context> context =
- v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
- v8::Local<v8::Object> global = context->Global();
-
- // Remember how many times this context has been attached, so we can
- // register the context on first attach and unregister on last detach.
- v8::Local<v8::Value> attach_count = global->GetHiddenValue(
- v8::String::New(kContextAttachCount));
- int32_t account_count_value =
- (!attach_count.IsEmpty() && attach_count->IsNumber()) ?
- attach_count->Int32Value() : 0;
- if (account_count_value == 0) {
- // First time attaching.
- GetRegisteredContexts().push_back(context);
- context.MakeWeak(NULL, WeakContextCallback);
- }
- global->SetHiddenValue(
- v8::String::New(kContextAttachCount),
- v8::Integer::New(account_count_value + 1));
-
if (args[0]->IsString()) {
std::string event_name(*v8::String::AsciiValue(args[0]));
if (EventIncrementListenerCount(event_name) == 1) {
- GetRenderThread()->Send(
+ EventBindings::GetRenderThread()->Send(
new ViewHostMsg_ExtensionAddListener(event_name));
}
}
@@ -105,25 +90,10 @@ class ExtensionImpl : public v8::Extension {
// TODO(erikkay) should enforce that event name is a string in the bindings
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
- v8::Local<v8::Context> context = v8::Context::GetCurrent();
- v8::Local<v8::Object> global = context->Global();
- v8::Local<v8::Value> attach_count = global->GetHiddenValue(
- v8::String::New(kContextAttachCount));
- DCHECK(!attach_count.IsEmpty() && attach_count->IsNumber());
- int32_t account_count_value = attach_count->Int32Value();
- DCHECK(account_count_value > 0);
- if (account_count_value == 1) {
- // Clean up after last detach.
- UnregisterContext(context);
- }
- global->SetHiddenValue(
- v8::String::New(kContextAttachCount),
- v8::Integer::New(account_count_value - 1));
-
if (args[0]->IsString()) {
std::string event_name(*v8::String::AsciiValue(args[0]));
if (EventDecrementListenerCount(event_name) == 0) {
- GetRenderThread()->Send(
+ EventBindings::GetRenderThread()->Send(
new ViewHostMsg_ExtensionRemoveListener(event_name));
}
}
@@ -131,24 +101,9 @@ class ExtensionImpl : public v8::Extension {
return v8::Undefined();
}
- // Called when a registered context is garbage collected.
- static void UnregisterContext(v8::Handle<void> context) {
- ContextList& contexts = GetRegisteredContexts();
- ContextList::iterator it = std::find(contexts.begin(), contexts.end(),
- context);
- if (it == contexts.end()) {
- NOTREACHED();
- return;
- }
-
- it->Dispose();
- it->Clear();
- contexts.erase(it);
- }
-
- // Called when a registered context is garbage collected.
- static void WeakContextCallback(v8::Persistent<v8::Value> obj, void*) {
- UnregisterContext(obj);
+ static v8::Handle<v8::Value> GetNextRequestId(const v8::Arguments& args) {
+ static int next_request_id = 0;
+ return v8::Integer::New(next_request_id++);
}
};
@@ -157,6 +112,7 @@ class ExtensionImpl : public v8::Extension {
const char* EventBindings::kName = "chrome/EventBindings";
v8::Extension* EventBindings::Get() {
+ bindings_registered = true;
return new ExtensionImpl();
}
@@ -166,25 +122,90 @@ void EventBindings::SetRenderThread(RenderThreadBase* thread) {
}
// static
+RenderThreadBase* EventBindings::GetRenderThread() {
+ return render_thread ? render_thread : RenderThread::current();
+}
+
void EventBindings::HandleContextCreated(WebFrame* frame) {
+ if (!bindings_registered)
+ return;
+
v8::HandleScope handle_scope;
v8::Local<v8::Context> context = frame->GetScriptContext();
DCHECK(!context.IsEmpty());
- // TODO(mpcomplete): register it
+ DCHECK(bindings_utils::FindContext(context) == GetContexts().end());
+
+ GURL url = frame->GetView()->GetMainFrame()->GetURL();
+ std::string extension_id;
+ if (url.SchemeIs(chrome::kExtensionScheme))
+ extension_id = url.host();
+
+ v8::Persistent<v8::Context> persistent_context =
+ v8::Persistent<v8::Context>::New(context);
+ GetContexts().push_back(linked_ptr<ContextInfo>(
+ new ContextInfo(persistent_context, extension_id)));
}
// static
void EventBindings::HandleContextDestroyed(WebFrame* frame) {
+ if (!bindings_registered)
+ return;
+
v8::HandleScope handle_scope;
v8::Local<v8::Context> context = frame->GetScriptContext();
DCHECK(!context.IsEmpty());
- // TODO(mpcomplete): unregister it, dispatch event
+
+ 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);
}
+// static
void EventBindings::CallFunction(const std::string& function_name,
int argc, v8::Handle<v8::Value>* argv) {
- for (ContextList::iterator it = GetRegisteredContexts().begin();
- it != GetRegisteredContexts().end(); ++it) {
- CallFunctionInContext(*it, function_name, argc, argv);
+ v8::HandleScope handle_scope;
+ for (ContextList::iterator it = GetContexts().begin();
+ it != GetContexts().end(); ++it) {
+ CallFunctionInContext((*it)->context, function_name, argc, argv);
}
}
+
+// static
+void EventBindings::HandleResponse(int request_id, bool success,
+ const std::string& response,
+ const std::string& error) {
+ PendingRequest* request = GetPendingRequestMap()[request_id].get();
+ if (!request)
+ return; // The frame went away.
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Value> argv[5];
+ argv[0] = v8::Integer::New(request_id);
+ argv[1] = v8::String::New(request->name.c_str());
+ argv[2] = v8::Boolean::New(success);
+ argv[3] = v8::String::New(response.c_str());
+ argv[4] = v8::String::New(error.c_str());
+ CallFunctionInContext(
+ request->context, "handleResponse", arraysize(argv), argv);
+
+ GetPendingRequestMap().erase(request_id);
+}
« no previous file with comments | « chrome/renderer/extensions/event_bindings.h ('k') | chrome/renderer/extensions/extension_api_client_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698