diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 00:06:47 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 00:06:47 +0000 |
commit | 2f25d7b91d75afea74cf4ba9e3b2a2db0d853f50 (patch) | |
tree | f6d95141295b9b03d4961ad8063c44f2c09e8cce | |
parent | 661feb7cadf6362ddd34f85b887ec8f4d24eeee9 (diff) | |
download | chromium_src-2f25d7b91d75afea74cf4ba9e3b2a2db0d853f50.zip chromium_src-2f25d7b91d75afea74cf4ba9e3b2a2db0d853f50.tar.gz chromium_src-2f25d7b91d75afea74cf4ba9e3b2a2db0d853f50.tar.bz2 |
Change the extension callback system to work more like events, where we track
contexts rather than frames.
Also change the way we call through to javascript, to avoid a v8::Compile.
This is so we don't skew the histogram stats on our script cache.
BUG=?
TEST=none
Review URL: http://codereview.chromium.org/119369
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18001 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/renderer/extensions/bindings_utils.cc | 23 | ||||
-rw-r--r-- | chrome/renderer/extensions/bindings_utils.h | 8 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_bindings.cc | 15 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_api_client_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_process_bindings.cc | 125 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_process_bindings.h | 16 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 47 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 6 |
8 files changed, 119 insertions, 126 deletions
diff --git a/chrome/renderer/extensions/bindings_utils.cc b/chrome/renderer/extensions/bindings_utils.cc index 097c8d0..81e2058 100644 --- a/chrome/renderer/extensions/bindings_utils.cc +++ b/chrome/renderer/extensions/bindings_utils.cc @@ -4,6 +4,7 @@ #include "chrome/renderer/extensions/bindings_utils.h" +#include "base/string_util.h" #include "chrome/renderer/render_view.h" #include "webkit/glue/webframe.h" @@ -21,3 +22,25 @@ RenderView* GetRenderViewForCurrentContext() { DCHECK(renderview) << "Encountered a WebView without a WebViewDelegate"; return renderview; } + +void CallFunctionInContext(v8::Handle<v8::Context> context, + const std::string& function_name, int argc, + v8::Handle<v8::Value>* argv) { + v8::Context::Scope context_scope(context); + + // Look up the function name, which may be a sub-property like + // "chrome.handleResponse_" in the global variable. + v8::Local<v8::Value> value = context->Global(); + std::vector<std::string> components; + SplitStringDontTrim(function_name, '.', &components); + for (size_t i = 0; i < components.size(); ++i) { + if (value->IsObject()) + value = value->ToObject()->Get(v8::String::New(components[i].c_str())); + } + if (!value->IsFunction()) + return; + + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value); + if (!function.IsEmpty()) + function->Call(v8::Object::New(), argc, argv); +} diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h index 7596952..b498cc5 100644 --- a/chrome/renderer/extensions/bindings_utils.h +++ b/chrome/renderer/extensions/bindings_utils.h @@ -8,6 +8,7 @@ #include "app/resource_bundle.h" #include "base/singleton.h" #include "base/string_piece.h" +#include "v8/include/v8.h" #include <string> @@ -32,4 +33,11 @@ const char* GetStringResource() { // an error to call this when not in a V8 context. RenderView* GetRenderViewForCurrentContext(); +// Call the named javascript function with the given arguments in a context. +// The function name should be reachable from the global object, and can be a +// sub-property like "chrome.handleResponse_". +void CallFunctionInContext(v8::Handle<v8::Context> context, + const std::string& function_name, int argc, + v8::Handle<v8::Value>* argv); + #endif // CHROME_RENDERER_EXTENSIONS_BINDINGS_UTILS_H_ diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 19a9245..576beba 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -168,19 +168,6 @@ 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) { - DCHECK(!it->IsEmpty()); - v8::Context::Scope context_scope(*it); - v8::Local<v8::Object> global = (*it)->Global(); - - v8::Local<v8::Script> script = v8::Script::Compile( - v8::String::New(function_name.c_str())); - v8::Local<v8::Value> function_obj = script->Run(); - if (!function_obj->IsFunction()) - continue; - - v8::Local<v8::Function> function = - v8::Local<v8::Function>::Cast(function_obj); - if (!function.IsEmpty()) - function->Call(v8::Object::New(), argc, argv); + CallFunctionInContext(*it, function_name, argc, argv); } } diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc index ddc7c42..dd95e83 100644 --- a/chrome/renderer/extensions/extension_api_client_unittest.cc +++ b/chrome/renderer/extensions/extension_api_client_unittest.cc @@ -91,9 +91,8 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) { ASSERT_TRUE(callback_id >= 0); // Now send the callback a response - ExtensionProcessBindings::CallContext call(GetMainFrame(), "CreateTab"); - ExtensionProcessBindings::ExecuteResponseInFrame( - &call, callback_id, true, "{\"foo\":\"bar\"}", ""); + ExtensionProcessBindings::HandleResponse( + callback_id, true, "{\"foo\":\"bar\"}", ""); // And verify that it worked ASSERT_EQ("pass", GetConsoleMessage()); diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index 6057a3e..1ce7ea2 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -5,6 +5,7 @@ #include "chrome/renderer/extensions/extension_process_bindings.h" #include "base/singleton.h" +#include "base/stl_util-inl.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "chrome/renderer/extensions/bindings_utils.h" @@ -33,10 +34,41 @@ const char* kExtensionDeps[] = { // |extension_id| -> <List of v8 Contexts for the "views" of that extension> typedef std::list< v8::Persistent<v8::Context> > ContextList; typedef std::map<std::string, ContextList> ExtensionIdContextsMap; -struct ExtensionViewContexts { + +// Contains info relevant to a pending request. +struct CallContext { + public : + CallContext(v8::Persistent<v8::Context> context, const std::string& name) + : context(context), name(name) { + } + v8::Persistent<v8::Context> context; + std::string name; +}; +typedef std::map<int, CallContext*> PendingRequestMap; + +struct SingletonData { + std::set<std::string> function_names_; ExtensionIdContextsMap contexts; + PendingRequestMap pending_requests; + + ~SingletonData() { + STLDeleteContainerPairSecondPointers(pending_requests.begin(), + pending_requests.end()); + } }; +static std::set<std::string>* GetFunctionNameSet() { + return &Singleton<SingletonData>()->function_names_; +} + +static ContextList& GetRegisteredContexts(std::string extension_id) { + return Singleton<SingletonData>::get()->contexts[extension_id]; +} + +static PendingRequestMap& GetPendingRequestMap() { + return Singleton<SingletonData>::get()->pending_requests; +} + class ExtensionImpl : public v8::Extension { public: ExtensionImpl() : v8::Extension( @@ -69,18 +101,6 @@ class ExtensionImpl : public v8::Extension { } private: - struct SingletonData { - std::set<std::string> function_names_; - }; - - static std::set<std::string>* GetFunctionNameSet() { - return &Singleton<SingletonData>()->function_names_; - } - - static ContextList& GetRegisteredContexts(std::string extension_id) { - return Singleton<ExtensionViewContexts>::get()->contexts[extension_id]; - } - static v8::Handle<v8::Value> RegisterExtension(const v8::Arguments& args) { RenderView* renderview = GetRenderViewForCurrentContext(); DCHECK(renderview); @@ -100,11 +120,24 @@ class ExtensionImpl : public v8::Extension { DCHECK_EQ(args.Length(), 1); DCHECK(args[0]->IsString()); - std::string extension_id(*v8::String::Utf8Value(args[0])); - ContextList& contexts = GetRegisteredContexts(extension_id); v8::Local<v8::Context> current_context = v8::Context::GetCurrent(); DCHECK(!current_context.IsEmpty()); + // 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 == current_context) { + current->second->context.Dispose(); + current->second->context.Clear(); + delete current->second; + pending_requests.erase(current); + } + } + + std::string extension_id(*v8::String::Utf8Value(args[0])); + ContextList& contexts = GetRegisteredContexts(extension_id); ContextList::iterator it = std::find(contexts.begin(), contexts.end(), current_context); if (it == contexts.end()) { @@ -149,22 +182,26 @@ class ExtensionImpl : public v8::Extension { static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) { // Get the current RenderView so that we can send a routed IPC message from // the correct source. - WebFrame* webframe = WebFrame::RetrieveFrameForCurrentContext(); RenderView* renderview = GetRenderViewForCurrentContext(); - if (!webframe || !renderview) + if (!renderview) return v8::Undefined(); if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsInt32() || !args[2]->IsBoolean()) return v8::Undefined(); + std::string name = *v8::String::AsciiValue(args.Data()); + std::string json_args = *v8::String::Utf8Value(args[0]); int request_id = args[1]->Int32Value(); bool has_callback = args[2]->BooleanValue(); - renderview->SendExtensionRequest( - std::string(*v8::String::AsciiValue(args.Data())), - std::string(*v8::String::Utf8Value(args[0])), - request_id, has_callback, webframe); + v8::Persistent<v8::Context> current_context = + v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); + DCHECK(!current_context.IsEmpty()); + GetPendingRequestMap()[request_id] = + new CallContext(current_context, *v8::String::AsciiValue(args.Data())); + + renderview->SendExtensionRequest(name, json_args, request_id, has_callback); return v8::Undefined(); } @@ -186,31 +223,23 @@ void ExtensionProcessBindings::RegisterExtensionContext(WebFrame* frame) { "chrome.self.register_();"))); } -void ExtensionProcessBindings::ExecuteResponseInFrame( - CallContext *call, int request_id, bool success, - const std::string& response, - const std::string& error) { - std::string code = "chrome.handleResponse_("; - code += IntToString(request_id); - - code += ", '" + call->name_; - - if (success) - code += "', true"; - else - code += "', false"; - - code += ", '"; - size_t offset = code.length(); - code += response; - ReplaceSubstringsAfterOffset(&code, offset, "\\", "\\\\"); - ReplaceSubstringsAfterOffset(&code, offset, "'", "\\'"); - code += "', '"; - offset = code.length(); - code += error; - ReplaceSubstringsAfterOffset(&code, offset, "\\", "\\\\"); - ReplaceSubstringsAfterOffset(&code, offset, "'", "\\'"); - code += "')"; - - call->frame_->ExecuteScript(WebScriptSource(WebString::fromUTF8(code))); +void ExtensionProcessBindings::HandleResponse(int request_id, bool success, + const std::string& response, + const std::string& error) { + CallContext* call = GetPendingRequestMap()[request_id]; + if (!call) + 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(call->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(call->context, "chrome.handleResponse_", + arraysize(argv), argv); + + GetPendingRequestMap().erase(request_id); + delete call; } diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h index d5798cd..9639090 100644 --- a/chrome/renderer/extensions/extension_process_bindings.h +++ b/chrome/renderer/extensions/extension_process_bindings.h @@ -16,22 +16,12 @@ class WebFrame; class ExtensionProcessBindings { public: - struct CallContext { - public : - CallContext(WebFrame *frame, const std::string& name) - : frame_(frame), - name_(name) {} - WebFrame* frame_; - std::string name_; - }; - static void SetFunctionNames(const std::vector<std::string>& names); static v8::Extension* Get(); static void RegisterExtensionContext(WebFrame* frame); - static void ExecuteResponseInFrame(CallContext *call, int request_id, - bool success, - const std::string& response, - const std::string& error); + static void HandleResponse(int request_id, bool success, + const std::string& response, + const std::string& error); }; #endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 7882860..557bc0d 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -207,13 +207,6 @@ RenderView::~RenderView() { it = plugin_delegates_.erase(it); } - // Clear any pending extension api call requests. - IDMap<ExtensionProcessBindings::CallContext>::const_iterator call = - pending_extension_requests_.begin(); - for (; call != pending_extension_requests_.end(); ++call) { - delete call->second; - } - render_thread_->RemoveFilter(debug_message_handler_); render_thread_->RemoveFilter(audio_message_filter_); } @@ -1344,23 +1337,6 @@ void RenderView::DidCancelClientRedirect(WebView* webview, } void RenderView::WillCloseFrame(WebView* view, WebFrame* frame) { - // Remove all the pending extension callbacks for this frame. - if (pending_extension_requests_.IsEmpty()) - return; - - std::vector<int> orphaned_requests; - for (IDMap<ExtensionProcessBindings::CallContext>::const_iterator iter = - pending_extension_requests_.begin(); - iter != pending_extension_requests_.end(); ++iter) { - if (iter->second->frame_ == frame) - orphaned_requests.push_back(iter->first); - } - - for (std::vector<int>::const_iterator iter = orphaned_requests.begin(); - iter != orphaned_requests.end(); ++iter) { - delete pending_extension_requests_.Lookup(*iter); - pending_extension_requests_.Remove(*iter); - } } void RenderView::DidCompleteClientRedirect(WebView* webview, @@ -2747,32 +2723,17 @@ void RenderView::OnSetBackground(const SkBitmap& background) { void RenderView::SendExtensionRequest(const std::string& name, const std::string& args, int request_id, - bool has_callback, - WebFrame* request_frame) { - DCHECK(request_frame) << "Request specified without frame"; - pending_extension_requests_.AddWithID( - new ExtensionProcessBindings::CallContext(request_frame, name), - request_id); - + bool has_callback) { Send(new ViewHostMsg_ExtensionRequest(routing_id_, name, args, request_id, - has_callback)); + has_callback)); } void RenderView::OnExtensionResponse(int request_id, bool success, const std::string& response, const std::string& error) { - ExtensionProcessBindings::CallContext* call = - pending_extension_requests_.Lookup(request_id); - - if (!call) - return; // The frame went away. - - ExtensionProcessBindings::ExecuteResponseInFrame(call, request_id, - success, response, - error); - pending_extension_requests_.Remove(request_id); - delete call; + ExtensionProcessBindings::HandleResponse(request_id, success, response, + error); } // Dump all load time histograms. diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 926ea72..a1928ba 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -380,8 +380,7 @@ class RenderView : public RenderWidget, void OnClearFocusedNode(); void SendExtensionRequest(const std::string& name, const std::string& args, - int request_id, bool has_callback, - WebFrame* web_frame); + int request_id, bool has_callback); void OnExtensionResponse(int request_id, bool success, const std::string& response, const std::string& error); @@ -775,9 +774,6 @@ class RenderView : public RenderWidget, // change but is overridden by tests. int delay_seconds_for_form_state_sync_; - // Maps pending request IDs to their frames. - IDMap<ExtensionProcessBindings::CallContext> pending_extension_requests_; - scoped_refptr<AudioMessageFilter> audio_message_filter_; // The currently selected text. This is currently only updated on Linux, where |