diff options
author | koz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-09 04:36:01 +0000 |
---|---|---|
committer | koz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-09 04:36:01 +0000 |
commit | 7b0c3f536f8ef4c248d03084a7e4ef9747cfc8c0 (patch) | |
tree | cb4afa76ecae3987687d70062aa136801ba93318 /chrome/renderer | |
parent | 1b9ab79cf95ef6956b56c06ba3466f4f14ee3b39 (diff) | |
download | chromium_src-7b0c3f536f8ef4c248d03084a7e4ef9747cfc8c0.zip chromium_src-7b0c3f536f8ef4c248d03084a7e4ef9747cfc8c0.tar.gz chromium_src-7b0c3f536f8ef4c248d03084a7e4ef9747cfc8c0.tar.bz2 |
Implement a module system for the extension bindings JS.
BUG=104100
TEST=existing browser tests
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=125132
Review URL: http://codereview.chromium.org/9386001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125801 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
82 files changed, 861 insertions, 1075 deletions
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc index 21ee438..34c8047 100644 --- a/chrome/renderer/extensions/app_bindings.cc +++ b/chrome/renderer/extensions/app_bindings.cc @@ -53,93 +53,41 @@ const char* kMissingClientIdError = "Missing clientId parameter"; const char* kInvalidClientIdError = "Invalid clientId"; const char* kInvalidCallbackIdError = "Invalid callbackId"; - -class AppBindingsHandler : public ChromeV8ExtensionHandler { - public: - AppBindingsHandler(ExtensionDispatcher* dispatcher, ChromeV8Context* context); - - // ChromeV8ExtensionHandler - virtual v8::Handle<v8::Value> HandleNativeFunction( - const std::string& name, - const v8::Arguments& arguments) OVERRIDE; - - // IPC::Channel::Listener - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - - private: - v8::Handle<v8::Value> GetIsInstalled(const v8::Arguments& args); - v8::Handle<v8::Value> Install(const v8::Arguments& args); - v8::Handle<v8::Value> GetDetails(const v8::Arguments& args); - v8::Handle<v8::Value> GetDetailsForFrame(const v8::Arguments& args); - v8::Handle<v8::Value> GetAppNotifyChannel(const v8::Arguments& args); - - v8::Handle<v8::Value> GetDetailsForFrameImpl(WebKit::WebFrame* frame); - - void OnGetAppNotifyChannelResponse(const std::string& channel_id, - const std::string& error, - int callback_id); - - ExtensionDispatcher* dispatcher_; - DISALLOW_COPY_AND_ASSIGN(AppBindingsHandler); -}; - } // namespace -AppBindings::AppBindings(ExtensionDispatcher* dispatcher) - : ChromeV8Extension("extensions/app.js", IDR_APP_BINDINGS_JS, - dispatcher) { -} - -ChromeV8ExtensionHandler* AppBindings::CreateHandler( - ChromeV8Context* context) { - return new AppBindingsHandler(extension_dispatcher(), context); -} - - - -AppBindingsHandler::AppBindingsHandler(ExtensionDispatcher* dispatcher, - ChromeV8Context* context) - : ChromeV8ExtensionHandler(context), - dispatcher_(dispatcher) { +AppBindings::AppBindings(ExtensionDispatcher* dispatcher, + ChromeV8Context* context) + : ChromeV8Extension(dispatcher), + ChromeV8ExtensionHandler(context) { + RouteFunction("GetIsInstalled", + base::Bind(&AppBindings::GetIsInstalled, base::Unretained(this))); + RouteFunction("Install", + base::Bind(&AppBindings::Install, base::Unretained(this))); + RouteFunction("GetDetails", + base::Bind(&AppBindings::GetDetails, base::Unretained(this))); + RouteFunction("GetDetailsForFrame", + base::Bind(&AppBindings::GetDetailsForFrame, base::Unretained(this))); + RouteFunction("GetAppNotifyChannel", + base::Bind(&AppBindings::GetAppNotifyChannel, base::Unretained(this))); } -v8::Handle<v8::Value> AppBindingsHandler::HandleNativeFunction( - const std::string& name, const v8::Arguments& args) { - // TODO(aa): Create a helper map of callback that can be used in either - // extensions or handlers. - if (name == "GetIsInstalled") { - return GetIsInstalled(args); - } else if (name == "Install") { - return Install(args); - } else if (name == "GetDetails") { - return GetDetails(args); - } else if (name == "GetDetailsForFrame") { - return GetDetailsForFrame(args); - } else if (name == "GetAppNotifyChannel") { - return GetAppNotifyChannel(args); - } else { - CHECK(false) << "Unknown native function: " << name; - } - - return v8::Undefined(); -} -v8::Handle<v8::Value> AppBindingsHandler::GetIsInstalled( +v8::Handle<v8::Value> AppBindings::GetIsInstalled( const v8::Arguments& args) { // TODO(aa): Hm, maybe ExtensionBindingsContext should have GetExtension() // afterall? const ::Extension* extension = - dispatcher_->extensions()->GetByID(context_->extension_id()); + extension_dispatcher_->extensions()->GetByID(context_->extension_id()); // TODO(aa): Why only hosted app? // TODO(aa): GARRR - why is there IsExtensionActive and IsApplicationActive!? bool result = extension && extension->is_hosted_app() && - dispatcher_->IsApplicationActive(extension->id()); + extension_dispatcher_->IsApplicationActive(extension->id()); return v8::Boolean::New(result); } -v8::Handle<v8::Value> AppBindingsHandler::Install(const v8::Arguments& args) { +v8::Handle<v8::Value> AppBindings::Install(const v8::Arguments& args) { content::RenderView* render_view = context_->GetRenderView(); CHECK(render_view); @@ -153,13 +101,13 @@ v8::Handle<v8::Value> AppBindingsHandler::Install(const v8::Arguments& args) { return v8::Undefined(); } -v8::Handle<v8::Value> AppBindingsHandler::GetDetails( +v8::Handle<v8::Value> AppBindings::GetDetails( const v8::Arguments& args) { CHECK(context_->web_frame()); return GetDetailsForFrameImpl(context_->web_frame()); } -v8::Handle<v8::Value> AppBindingsHandler::GetDetailsForFrame( +v8::Handle<v8::Value> AppBindings::GetDetailsForFrame( const v8::Arguments& args) { CHECK(context_->web_frame()); if (!CheckAccessToAppDetails(context_->web_frame())) @@ -186,12 +134,12 @@ v8::Handle<v8::Value> AppBindingsHandler::GetDetailsForFrame( return GetDetailsForFrameImpl(target_frame); } -v8::Handle<v8::Value> AppBindingsHandler::GetDetailsForFrameImpl( +v8::Handle<v8::Value> AppBindings::GetDetailsForFrameImpl( WebFrame* frame) { const ::Extension* extension = - dispatcher_->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo( - frame->document().securityOrigin(), - frame->document().url())); + extension_dispatcher_->extensions()->GetExtensionOrAppByURL( + ExtensionURLInfo(frame->document().securityOrigin(), + frame->document().url())); if (!extension) return v8::Null(); @@ -203,7 +151,7 @@ v8::Handle<v8::Value> AppBindingsHandler::GetDetailsForFrameImpl( frame->mainWorldScriptContext()); } -v8::Handle<v8::Value> AppBindingsHandler::GetAppNotifyChannel( +v8::Handle<v8::Value> AppBindings::GetAppNotifyChannel( const v8::Arguments& args) { // Read the required 'clientId' value out of the object at args[0]. std::string client_id; @@ -242,8 +190,8 @@ v8::Handle<v8::Value> AppBindingsHandler::GetAppNotifyChannel( return v8::Undefined(); } -bool AppBindingsHandler::OnMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(AppBindingsHandler, message) +bool AppBindings::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(AppBindings, message) IPC_MESSAGE_HANDLER(ExtensionMsg_GetAppNotifyChannelResponse, OnGetAppNotifyChannelResponse) IPC_MESSAGE_UNHANDLED(CHECK(false) << "Unhandled IPC message") @@ -251,7 +199,7 @@ bool AppBindingsHandler::OnMessageReceived(const IPC::Message& message) { return true; } -void AppBindingsHandler::OnGetAppNotifyChannelResponse( +void AppBindings::OnGetAppNotifyChannelResponse( const std::string& channel_id, const std::string& error, int callback_id) { v8::HandleScope handle_scope; v8::Context::Scope context_scope(context_->v8_context()); diff --git a/chrome/renderer/extensions/app_bindings.h b/chrome/renderer/extensions/app_bindings.h index 9455ba2..e27c770 100644 --- a/chrome/renderer/extensions/app_bindings.h +++ b/chrome/renderer/extensions/app_bindings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,21 +14,34 @@ #include "base/compiler_specific.h" #include "chrome/renderer/extensions/chrome_v8_extension.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" class ChromeV8Context; // Implements the chrome.app JavaScript object. // // TODO(aa): Add unit testing for this class. -class AppBindings : public ChromeV8Extension { +class AppBindings : public ChromeV8Extension, public ChromeV8ExtensionHandler { public: - explicit AppBindings(ExtensionDispatcher* dispatcher); - - protected: - virtual ChromeV8ExtensionHandler* CreateHandler( - ChromeV8Context* context) OVERRIDE; + explicit AppBindings(ExtensionDispatcher* dispatcher, + ChromeV8Context* context); private: + // IPC::Channel::Listener + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + v8::Handle<v8::Value> GetIsInstalled(const v8::Arguments& args); + v8::Handle<v8::Value> Install(const v8::Arguments& args); + v8::Handle<v8::Value> GetDetails(const v8::Arguments& args); + v8::Handle<v8::Value> GetDetailsForFrame(const v8::Arguments& args); + v8::Handle<v8::Value> GetAppNotifyChannel(const v8::Arguments& args); + + v8::Handle<v8::Value> GetDetailsForFrameImpl(WebKit::WebFrame* frame); + + void OnGetAppNotifyChannelResponse(const std::string& channel_id, + const std::string& error, + int callback_id); + DISALLOW_COPY_AND_ASSIGN(AppBindings); }; diff --git a/chrome/renderer/extensions/chrome_private_custom_bindings.cc b/chrome/renderer/extensions/chrome_private_custom_bindings.cc index a1e4fbb..2e8aa86 100644 --- a/chrome/renderer/extensions/chrome_private_custom_bindings.cc +++ b/chrome/renderer/extensions/chrome_private_custom_bindings.cc @@ -18,15 +18,10 @@ namespace extensions { ChromePrivateCustomBindings::ChromePrivateCustomBindings( - int dependency_count, - const char** dependencies, ExtensionDispatcher* extension_dispatcher) - : ChromeV8Extension( - "extensions/chrome_private_custom_bindings.js", - IDR_CHROME_PRIVATE_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - extension_dispatcher) {} + : ChromeV8Extension(extension_dispatcher) { + RouteStaticFunction("DecodeJPEG", &DecodeJPEG); +} // static v8::Handle<v8::Value> ChromePrivateCustomBindings::DecodeJPEG( @@ -87,12 +82,4 @@ v8::Handle<v8::Value> ChromePrivateCustomBindings::DecodeJPEG( return bitmap_array; } -v8::Handle<v8::FunctionTemplate> ChromePrivateCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("DecodeJPEG"))) - return v8::FunctionTemplate::New(DecodeJPEG, v8::External::New(this)); - - return ChromeV8Extension::GetNativeFunction(name); -} - } // namespace extensions diff --git a/chrome/renderer/extensions/chrome_private_custom_bindings.h b/chrome/renderer/extensions/chrome_private_custom_bindings.h index d1bfdb9..0d6fd5e 100644 --- a/chrome/renderer/extensions/chrome_private_custom_bindings.h +++ b/chrome/renderer/extensions/chrome_private_custom_bindings.h @@ -15,14 +15,9 @@ namespace extensions { // Implements custom bindings for the chromePrivate API. class ChromePrivateCustomBindings : public ChromeV8Extension { public: - ChromePrivateCustomBindings( - int dependency_count, - const char** dependencies, + explicit ChromePrivateCustomBindings( ExtensionDispatcher* extension_dispatcher); - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; - private: // Decodes supplied JPEG byte array to image pixel array. static v8::Handle<v8::Value> DecodeJPEG(const v8::Arguments& args); diff --git a/chrome/renderer/extensions/chrome_v8_context.h b/chrome/renderer/extensions/chrome_v8_context.h index 11a4a87..3faf9d2 100644 --- a/chrome/renderer/extensions/chrome_v8_context.h +++ b/chrome/renderer/extensions/chrome_v8_context.h @@ -9,6 +9,7 @@ #include <string> #include "base/basictypes.h" +#include "chrome/renderer/module_system.h" #include "v8/include/v8.h" namespace WebKit { @@ -60,6 +61,10 @@ class ChromeV8Context { return context_type_; } + void set_module_system(scoped_ptr<ModuleSystem> module_system) { + module_system_ = module_system.Pass(); + } + // Returns a special Chrome-specific hidden object that is associated with a // context, but not reachable from the JavaScript in that context. This is // used by our v8::Extension implementations as a way to share code and as a @@ -113,6 +118,9 @@ class ChromeV8Context { // The type of context. ContextType context_type_; + // Owns and structures the JS that is injected to set up extension bindings. + scoped_ptr<ModuleSystem> module_system_; + DISALLOW_COPY_AND_ASSIGN(ChromeV8Context); }; diff --git a/chrome/renderer/extensions/chrome_v8_extension.cc b/chrome/renderer/extensions/chrome_v8_extension.cc index 35b5153..791b1f5 100644 --- a/chrome/renderer/extensions/chrome_v8_extension.cc +++ b/chrome/renderer/extensions/chrome_v8_extension.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -33,11 +33,6 @@ static base::LazyInstance<ChromeV8Extension::InstanceSet> g_instances = // static -base::StringPiece ChromeV8Extension::GetStringResource(int resource_id) { - return ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); -} - -// static content::RenderView* ChromeV8Extension::GetCurrentRenderView() { WebFrame* webframe = WebFrame::frameForCurrentContext(); DCHECK(webframe) << "RetrieveCurrentFrame called when not in a V8 context."; @@ -53,27 +48,8 @@ content::RenderView* ChromeV8Extension::GetCurrentRenderView() { return renderview; } -ChromeV8Extension::ChromeV8Extension(const char* name, int resource_id, - ExtensionDispatcher* extension_dispatcher) - : v8::Extension(name, - GetStringResource(resource_id).data(), - 0, // num dependencies - NULL, // dependencies array - GetStringResource(resource_id).size()), // source length - extension_dispatcher_(extension_dispatcher) { - g_instances.Get().insert(this); -} - -ChromeV8Extension::ChromeV8Extension(const char* name, int resource_id, - int dependency_count, - const char** dependencies, - ExtensionDispatcher* extension_dispatcher) - : v8::Extension(name, - GetStringResource(resource_id).data(), - dependency_count, - dependencies, - GetStringResource(resource_id).size()), - extension_dispatcher_(extension_dispatcher) { +ChromeV8Extension::ChromeV8Extension(ExtensionDispatcher* extension_dispatcher) + : extension_dispatcher_(extension_dispatcher) { g_instances.Get().insert(this); } @@ -86,19 +62,6 @@ const ChromeV8Extension::InstanceSet& ChromeV8Extension::GetAll() { return g_instances.Get(); } -void ChromeV8Extension::ContextWillBeReleased(ChromeV8Context* context) { - handlers_.erase(context); -} - -ChromeV8ExtensionHandler* ChromeV8Extension::GetHandler( - ChromeV8Context* context) const { - HandlerMap::const_iterator iter = handlers_.find(context); - if (iter == handlers_.end()) - return NULL; - else - return iter->second.get(); -} - const Extension* ChromeV8Extension::GetExtensionForCurrentRenderView() const { content::RenderView* renderview = GetCurrentRenderView(); if (!renderview) @@ -152,61 +115,3 @@ bool ChromeV8Extension::CheckCurrentContextAccessToExtensionAPI( return true; } - -v8::Handle<v8::FunctionTemplate> - ChromeV8Extension::GetNativeFunction(v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetChromeHidden"))) { - return v8::FunctionTemplate::New(GetChromeHidden); - } - - if (name->Equals(v8::String::New("Print"))) { - return v8::FunctionTemplate::New(Print); - } - - return v8::FunctionTemplate::New(HandleNativeFunction, - v8::External::New(this)); -} - -// static -v8::Handle<v8::Value> ChromeV8Extension::HandleNativeFunction( - const v8::Arguments& arguments) { - ChromeV8Extension* self = GetFromArguments<ChromeV8Extension>(arguments); - ChromeV8Context* context = - self->extension_dispatcher()->v8_context_set().GetCurrent(); - CHECK(context) << "Unknown V8 context. Maybe a native function is getting " - << "called during parse of a v8 extension, before the context " - << "has been registered."; - - ChromeV8ExtensionHandler* handler = self->GetHandler(context); - if (!handler) { - handler = self->CreateHandler(context); - if (handler) - self->handlers_[context] = linked_ptr<ChromeV8ExtensionHandler>(handler); - } - CHECK(handler) << "No handler for v8 extension: " << self->name(); - - std::string name = *v8::String::AsciiValue(arguments.Callee()->GetName()); - return handler->HandleNativeFunction(name, arguments); -} - -ChromeV8ExtensionHandler* ChromeV8Extension::CreateHandler( - ChromeV8Context* context) { - return NULL; -} - -v8::Handle<v8::Value> ChromeV8Extension::GetChromeHidden( - const v8::Arguments& args) { - return ChromeV8Context::GetOrCreateChromeHidden(v8::Context::GetCurrent()); -} - -v8::Handle<v8::Value> ChromeV8Extension::Print(const v8::Arguments& args) { - if (args.Length() < 1) - return v8::Undefined(); - - std::vector<std::string> components; - for (int i = 0; i < args.Length(); ++i) - components.push_back(*v8::String::Utf8Value(args[i]->ToString())); - - LOG(ERROR) << JoinString(components, ','); - return v8::Undefined(); -} diff --git a/chrome/renderer/extensions/chrome_v8_extension.h b/chrome/renderer/extensions/chrome_v8_extension.h index 511273f..7e4b8e8 100644 --- a/chrome/renderer/extensions/chrome_v8_extension.h +++ b/chrome/renderer/extensions/chrome_v8_extension.h @@ -10,6 +10,7 @@ #include "base/memory/linked_ptr.h" #include "base/string_piece.h" #include "chrome/renderer/extensions/chrome_v8_extension_handler.h" +#include "chrome/renderer/native_handler.h" #include "v8/include/v8.h" #include <map> @@ -26,31 +27,17 @@ class RenderView; // This is a base class for chrome extension bindings. Common features that // are shared by different modules go here. -class ChromeV8Extension : public v8::Extension { +// TODO(koz): Rename this to ExtensionNativeModule. +class ChromeV8Extension : public NativeHandler { public: typedef std::set<ChromeV8Extension*> InstanceSet; static const InstanceSet& GetAll(); - ChromeV8Extension(const char* name, - int resource_id, - ExtensionDispatcher* extension_dispatcher); - ChromeV8Extension(const char* name, - int resource_id, - int dependency_count, - const char** dependencies, - ExtensionDispatcher* extension_dispatcher); + explicit ChromeV8Extension(ExtensionDispatcher* extension_dispatcher); virtual ~ChromeV8Extension(); ExtensionDispatcher* extension_dispatcher() { return extension_dispatcher_; } - void ContextWillBeReleased(ChromeV8Context* context); - - // Derived classes should call this at the end of their implementation in - // order to expose common native functions, like GetChromeHidden, to the - // v8 extension. - virtual v8::Handle<v8::FunctionTemplate> - GetNativeFunction(v8::Handle<v8::String> name) OVERRIDE; - protected: template<class T> static T* GetFromArguments(const v8::Arguments& args) { @@ -73,32 +60,12 @@ class ChromeV8Extension : public v8::Extension { bool CheckCurrentContextAccessToExtensionAPI( const std::string& function_name) const; - // Create a handler for |context|. If a subclass of ChromeV8Extension wishes - // to support handlers, it should override this. - virtual ChromeV8ExtensionHandler* CreateHandler(ChromeV8Context* context); - // Returns the chromeHidden object for the current context. static v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args); ExtensionDispatcher* extension_dispatcher_; private: - static base::StringPiece GetStringResource(int resource_id); - - // Helper to print from bindings javascript. - static v8::Handle<v8::Value> Print(const v8::Arguments& args); - - // Handle a native function call from JavaScript. - static v8::Handle<v8::Value> HandleNativeFunction(const v8::Arguments& args); - - // Get the handler instance for |context|, or NULL if no such context exists. - ChromeV8ExtensionHandler* GetHandler(ChromeV8Context* context) const; - - // Map of all current handlers. - typedef std::map<ChromeV8Context*, - linked_ptr<ChromeV8ExtensionHandler> > HandlerMap; - HandlerMap handlers_; - DISALLOW_COPY_AND_ASSIGN(ChromeV8Extension); }; diff --git a/chrome/renderer/extensions/chrome_v8_extension_handler.h b/chrome/renderer/extensions/chrome_v8_extension_handler.h index f933fc9..301b9f6 100644 --- a/chrome/renderer/extensions/chrome_v8_extension_handler.h +++ b/chrome/renderer/extensions/chrome_v8_extension_handler.h @@ -15,11 +15,10 @@ class ChromeV8Context; // Base class for context-scoped handlers used with ChromeV8Extension. +// TODO(koz): Rename/refactor this somehow. Maybe just pull it into +// ChromeV8Extension. class ChromeV8ExtensionHandler : public IPC::Channel::Listener { public: - virtual v8::Handle<v8::Value> HandleNativeFunction( - const std::string& name, - const v8::Arguments& arguments) = 0; virtual ~ChromeV8ExtensionHandler(); // IPC::Channel::Listener diff --git a/chrome/renderer/extensions/context_menus_custom_bindings.cc b/chrome/renderer/extensions/context_menus_custom_bindings.cc index bfb6114..db3b3d9 100644 --- a/chrome/renderer/extensions/context_menus_custom_bindings.cc +++ b/chrome/renderer/extensions/context_menus_custom_bindings.cc @@ -7,19 +7,9 @@ #include "grit/renderer_resources.h" #include "v8/include/v8.h" -namespace extensions { +namespace { -ContextMenusCustomBindings::ContextMenusCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension( - "extensions/context_menus_custom_bindings.js", - IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} - -static v8::Handle<v8::Value> GetNextContextMenuId(const v8::Arguments& args) { +v8::Handle<v8::Value> GetNextContextMenuId(const v8::Arguments& args) { // Note: this works because contextMenus.create() only works in the // extension process. If that API is opened up to content scripts, this // will need to change. See crbug.com/77023 @@ -27,12 +17,13 @@ static v8::Handle<v8::Value> GetNextContextMenuId(const v8::Arguments& args) { return v8::Integer::New(next_context_menu_id++); } -v8::Handle<v8::FunctionTemplate> ContextMenusCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetNextContextMenuId"))) - return v8::FunctionTemplate::New(GetNextContextMenuId); +} // namespace + +namespace extensions { - return ChromeV8Extension::GetNativeFunction(name); +ContextMenusCustomBindings::ContextMenusCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetNextContextMenuId", &GetNextContextMenuId); } } // extensions diff --git a/chrome/renderer/extensions/context_menus_custom_bindings.h b/chrome/renderer/extensions/context_menus_custom_bindings.h index 1b31e50..18d3b38 100644 --- a/chrome/renderer/extensions/context_menus_custom_bindings.h +++ b/chrome/renderer/extensions/context_menus_custom_bindings.h @@ -13,10 +13,7 @@ namespace extensions { // Implements custom bindings for the contextMenus API. class ContextMenusCustomBindings : public ChromeV8Extension { public: - ContextMenusCustomBindings(int dependency_count, const char** dependencies); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + ContextMenusCustomBindings(); }; } // extensions diff --git a/chrome/renderer/extensions/custom_bindings_util.cc b/chrome/renderer/extensions/custom_bindings_util.cc index b9dfa84..5de0470b 100644 --- a/chrome/renderer/extensions/custom_bindings_util.cc +++ b/chrome/renderer/extensions/custom_bindings_util.cc @@ -31,83 +31,6 @@ namespace extensions { namespace custom_bindings_util { -std::vector<v8::Extension*> GetAll(ExtensionDispatcher* extension_dispatcher) { - // Must match kResourceIDs. - static const char* kJavascriptFiles[] = { - "extensions/browser_action_custom_bindings.js", - "extensions/content_settings_custom_bindings.js", - "extensions/experimental.declarative_custom_bindings.js", - "extensions/devtools_custom_bindings.js", - "extensions/input.ime_custom_bindings.js", - "extensions/omnibox_custom_bindings.js", - "extensions/page_action_custom_bindings.js", - "extensions/storage_custom_bindings.js", - "extensions/tts_engine_custom_bindings.js", - "extensions/types_custom_bindings.js", - }; - static const size_t kJavascriptFilesSize = arraysize(kJavascriptFiles); - - // Must match kJavascriptFiles. - static const int kResourceIDs[] = { - IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS, - IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS, - IDR_EXPERIMENTAL_DECLARATIVE_CUSTOM_BINDINGS_JS, - IDR_DEVTOOLS_CUSTOM_BINDINGS_JS, - IDR_INPUT_IME_CUSTOM_BINDINGS_JS, - IDR_OMNIBOX_CUSTOM_BINDINGS_JS, - IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS, - IDR_STORAGE_CUSTOM_BINDINGS_JS, - IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS, - IDR_TYPES_CUSTOM_BINDINGS_JS, - }; - static const size_t kResourceIDsSize = arraysize(kResourceIDs); - - static const char* kDependencies[] = { - "extensions/schema_generated_bindings.js", - }; - static const size_t kDependencyCount = arraysize(kDependencies); - - std::vector<v8::Extension*> result; - - // Custom bindings that have native code parts. - result.push_back(new ChromePrivateCustomBindings( - kDependencyCount, kDependencies, extension_dispatcher)); - result.push_back(new ContextMenusCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new ExtensionCustomBindings( - kDependencyCount, kDependencies, extension_dispatcher)); - result.push_back(new ExperimentalSocketCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new FileBrowserHandlerCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new FileBrowserPrivateCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new I18NCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new PageActionsCustomBindings( - kDependencyCount, kDependencies, extension_dispatcher)); - result.push_back(new PageCaptureCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new TabsCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new TTSCustomBindings( - kDependencyCount, kDependencies)); - result.push_back(new WebRequestCustomBindings( - kDependencyCount, kDependencies)); - - // Pure JavaScript custom bindings. - CHECK_EQ(kJavascriptFilesSize, kResourceIDsSize); - for (size_t i = 0; i < kJavascriptFilesSize; ++i) { - result.push_back(new ChromeV8Extension( - kJavascriptFiles[i], - kResourceIDs[i], - kDependencyCount, kDependencies, - NULL)); - } - - return result; -} - // Extracts the name of an API from the name of the V8 extension which contains // custom bindings for it (see kCustomBindingNames). std::string GetAPIName(const std::string& v8_extension_name) { diff --git a/chrome/renderer/extensions/custom_bindings_util.h b/chrome/renderer/extensions/custom_bindings_util.h index f4d6fe3..73d026d 100644 --- a/chrome/renderer/extensions/custom_bindings_util.h +++ b/chrome/renderer/extensions/custom_bindings_util.h @@ -24,9 +24,6 @@ namespace extensions { // bindings. namespace custom_bindings_util { -// Creates V8 extensions for all custom bindings. -std::vector<v8::Extension*> GetAll(ExtensionDispatcher* extension_dispatcher); - // Extracts the name of an API from the name of the V8 extension which contains // custom bindings for it. // Returns an empty string if the extension is not for a custom binding. diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 9bab21a..f187f27 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -39,25 +39,26 @@ using content::RenderThread; namespace { +// A map of event names to the number of contexts listening to that event. +// We notify the browser about event listeners when we transition between 0 +// and 1. +typedef std::map<std::string, int> EventListenerCounts; + +// A map of extension IDs to listener counts for that extension. +base::LazyInstance<std::map<std::string, EventListenerCounts> > + g_listener_counts = LAZY_INSTANCE_INITIALIZER; + +// TODO(koz): Merge this into EventBindings. class ExtensionImpl : public ChromeV8Extension { public: + explicit ExtensionImpl(ExtensionDispatcher* dispatcher) - : ChromeV8Extension("extensions/event.js", - IDR_EVENT_BINDINGS_JS, - dispatcher) { + : ChromeV8Extension(dispatcher) { + RouteStaticFunction("AttachEvent", &AttachEvent); + RouteStaticFunction("DetachEvent", &DetachEvent); } ~ExtensionImpl() {} - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("AttachEvent"))) { - return v8::FunctionTemplate::New(AttachEvent, v8::External::New(this)); - } else if (name->Equals(v8::String::New("DetachEvent"))) { - return v8::FunctionTemplate::New(DetachEvent, v8::External::New(this)); - } - return ChromeV8Extension::GetNativeFunction(name); - } - // Attach an event name to an object. static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { DCHECK(args.Length() == 1); @@ -76,7 +77,7 @@ class ExtensionImpl : public ChromeV8Extension { return v8::Undefined(); EventListenerCounts& listener_counts = - self->listener_counts_[context->extension_id()]; + g_listener_counts.Get()[context->extension_id()]; if (++listener_counts[event_name] == 1) { content::RenderThread::Get()->Send( new ExtensionHostMsg_AddListener(context->extension_id(), @@ -110,7 +111,7 @@ class ExtensionImpl : public ChromeV8Extension { return v8::Undefined(); EventListenerCounts& listener_counts = - self->listener_counts_[context->extension_id()]; + g_listener_counts.Get()[context->extension_id()]; std::string event_name(*v8::String::AsciiValue(args[0])); bool is_manual = args[1]->BooleanValue(); @@ -135,10 +136,6 @@ class ExtensionImpl : public ChromeV8Extension { } private: - // A map of event names to the number of contexts listening to that event. - // We notify the browser about event listeners when we transition between 0 - // and 1. - typedef std::map<std::string, int> EventListenerCounts; bool IsLazyBackgroundPage(const std::string& extension_id) { content::RenderView* render_view = GetCurrentRenderView(); @@ -151,14 +148,10 @@ class ExtensionImpl : public ChromeV8Extension { return (extension && !extension->background_page_persists() && helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); } - - // A map of extension IDs to listener counts for that extension. - std::map<std::string, EventListenerCounts> listener_counts_; }; } // namespace -v8::Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { - static v8::Extension* extension = new ExtensionImpl(dispatcher); - return extension; +ChromeV8Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { + return new ExtensionImpl(dispatcher); } diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h index 64ada22..baa2004 100644 --- a/chrome/renderer/extensions/event_bindings.h +++ b/chrome/renderer/extensions/event_bindings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #define CHROME_RENDERER_EXTENSIONS_EVENT_BINDINGS_H_ #pragma once +class ChromeV8Extension; class ExtensionDispatcher; namespace v8 { @@ -15,7 +16,7 @@ class Extension; // This class deals with the javascript bindings related to Event objects. class EventBindings { public: - static v8::Extension* Get(ExtensionDispatcher* dispatcher); + static ChromeV8Extension* Get(ExtensionDispatcher* dispatcher); }; #endif // CHROME_RENDERER_EXTENSIONS_EVENT_BINDINGS_H_ diff --git a/chrome/renderer/extensions/experimental.socket_custom_bindings.cc b/chrome/renderer/extensions/experimental.socket_custom_bindings.cc index 11d34bb..8dd096b 100644 --- a/chrome/renderer/extensions/experimental.socket_custom_bindings.cc +++ b/chrome/renderer/extensions/experimental.socket_custom_bindings.cc @@ -11,32 +11,22 @@ #include "grit/renderer_resources.h" #include "v8/include/v8.h" -namespace extensions { +namespace { -ExperimentalSocketCustomBindings::ExperimentalSocketCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension( - "extensions/experimental.socket_custom_bindings.js", - IDR_EXPERIMENTAL_SOCKET_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} - -static v8::Handle<v8::Value> GetNextSocketEventId(const v8::Arguments& args) { +v8::Handle<v8::Value> GetNextSocketEventId(const v8::Arguments& args) { // Note: this works because the socket API only works in the extension // process, not content scripts. static int next_event_id = 1; return v8::Integer::New(next_event_id++); } -v8::Handle<v8::FunctionTemplate> -ExperimentalSocketCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetNextSocketEventId"))) - return v8::FunctionTemplate::New(GetNextSocketEventId); +} // namespace + +namespace extensions { - return ChromeV8Extension::GetNativeFunction(name); +ExperimentalSocketCustomBindings::ExperimentalSocketCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetNextSocketEventId", &GetNextSocketEventId); } } // extensions diff --git a/chrome/renderer/extensions/experimental.socket_custom_bindings.h b/chrome/renderer/extensions/experimental.socket_custom_bindings.h index a444fa1..32a7f7d 100644 --- a/chrome/renderer/extensions/experimental.socket_custom_bindings.h +++ b/chrome/renderer/extensions/experimental.socket_custom_bindings.h @@ -13,11 +13,7 @@ namespace extensions { // Implements custom bindings for the experimental.socket API. class ExperimentalSocketCustomBindings : public ChromeV8Extension { public: - ExperimentalSocketCustomBindings( - int dependency_count, const char** dependencies); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + ExperimentalSocketCustomBindings(); }; } // extensions diff --git a/chrome/renderer/extensions/extension_custom_bindings.cc b/chrome/renderer/extensions/extension_custom_bindings.cc index 6c9947c..c4895cd 100644 --- a/chrome/renderer/extensions/extension_custom_bindings.cc +++ b/chrome/renderer/extensions/extension_custom_bindings.cc @@ -111,15 +111,11 @@ class ExtensionViewAccumulator : public content::RenderViewVisitor { } // namespace ExtensionCustomBindings::ExtensionCustomBindings( - int dependency_count, - const char** dependencies, ExtensionDispatcher* extension_dispatcher) - : ChromeV8Extension( - "extensions/extension_custom_bindings.js", - IDR_EXTENSION_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - extension_dispatcher) {} + : ChromeV8Extension(extension_dispatcher) { + RouteStaticFunction("GetExtensionViews", &GetExtensionViews); + RouteStaticFunction("OpenChannelToExtension", &OpenChannelToExtension); +} // static v8::Handle<v8::Value> ExtensionCustomBindings::GetExtensionViews( @@ -172,18 +168,6 @@ v8::Handle<v8::Value> ExtensionCustomBindings::GetExtensionViews( return accumulator.views(); } -v8::Handle<v8::FunctionTemplate> ExtensionCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetExtensionViews"))) { - return v8::FunctionTemplate::New(GetExtensionViews, - v8::External::New(this)); - } else if (name->Equals(v8::String::New("OpenChannelToExtension"))) { - return v8::FunctionTemplate::New(OpenChannelToExtension); - } - - return ChromeV8Extension::GetNativeFunction(name); -} - // static v8::Handle<v8::Value> ExtensionCustomBindings::OpenChannelToExtension( const v8::Arguments& args) { diff --git a/chrome/renderer/extensions/extension_custom_bindings.h b/chrome/renderer/extensions/extension_custom_bindings.h index d8ac77c..59cf77a 100644 --- a/chrome/renderer/extensions/extension_custom_bindings.h +++ b/chrome/renderer/extensions/extension_custom_bindings.h @@ -15,13 +15,7 @@ namespace extensions { // Implements custom bindings for the extension API. class ExtensionCustomBindings : public ChromeV8Extension { public: - ExtensionCustomBindings( - int dependency_count, - const char** dependencies, - ExtensionDispatcher* extension_dispatcher); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + explicit ExtensionCustomBindings(ExtensionDispatcher* extension_dispatcher); private: static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args); diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index 841ca21..0d12b18 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -4,7 +4,10 @@ #include "chrome/renderer/extensions/extension_dispatcher.h" +#include "base/callback.h" #include "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "base/string_piece.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -22,6 +25,9 @@ #include "chrome/renderer/extensions/schema_generated_bindings.h" #include "chrome/renderer/extensions/user_script_slave.h" #include "chrome/renderer/extensions/webstore_bindings.h" +#include "chrome/renderer/module_system.h" +#include "chrome/renderer/native_handler.h" +#include "chrome/renderer/resource_bundle_source_map.h" #include "content/public/renderer/render_thread.h" #include "grit/renderer_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" @@ -35,6 +41,19 @@ #include "ui/base/resource/resource_bundle.h" #include "v8/include/v8.h" +#include "chrome/renderer/extensions/chrome_private_custom_bindings.h" +#include "chrome/renderer/extensions/context_menus_custom_bindings.h" +#include "chrome/renderer/extensions/experimental.socket_custom_bindings.h" +#include "chrome/renderer/extensions/extension_custom_bindings.h" +#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h" +#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h" +#include "chrome/renderer/extensions/i18n_custom_bindings.h" +#include "chrome/renderer/extensions/page_actions_custom_bindings.h" +#include "chrome/renderer/extensions/page_capture_custom_bindings.h" +#include "chrome/renderer/extensions/tabs_custom_bindings.h" +#include "chrome/renderer/extensions/tts_custom_bindings.h" +#include "chrome/renderer/extensions/web_request_custom_bindings.h" + namespace { static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000; @@ -46,6 +65,75 @@ ChromeV8Context::ContextType ExtensionGroupToContextType(int extension_group) { return ChromeV8Context::OTHER; } +class ChromeHiddenNativeHandler : public NativeHandler { + public: + ChromeHiddenNativeHandler() { + RouteFunction("GetChromeHidden", + base::Bind(&ChromeHiddenNativeHandler::GetChromeHidden, + base::Unretained(this))); + } + + v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args) { + return ChromeV8Context::GetOrCreateChromeHidden(v8::Context::GetCurrent()); + } +}; + +class PrintNativeHandler : public NativeHandler { + public: + PrintNativeHandler() { + RouteFunction("Print", + base::Bind(&PrintNativeHandler::Print, + base::Unretained(this))); + } + + v8::Handle<v8::Value> Print(const v8::Arguments& args) { + if (args.Length() < 1) + return v8::Undefined(); + + std::vector<std::string> components; + for (int i = 0; i < args.Length(); ++i) + components.push_back(*v8::String::Utf8Value(args[i]->ToString())); + + LOG(ERROR) << JoinString(components, ','); + return v8::Undefined(); + } +}; + +class ContextInfoNativeHandler : public NativeHandler { + public: + explicit ContextInfoNativeHandler(ExtensionDispatcher* extension_dispatcher, + bool is_bindings_allowed, + WebKit::WebFrame* frame, + int world_id) + : extension_dispatcher_(extension_dispatcher), + is_bindings_allowed_(is_bindings_allowed), + frame_(frame), + world_id_(world_id) { + RouteFunction("IsBindingsAllowed", + base::Bind(&ContextInfoNativeHandler::IsBindingsAllowed, + base::Unretained(this))); + RouteFunction("IsAPIAllowed", + base::Bind(&ContextInfoNativeHandler::IsAPIAllowed, + base::Unretained(this))); + } + + v8::Handle<v8::Value> IsBindingsAllowed(const v8::Arguments& args) { + return v8::Boolean::New(is_bindings_allowed_); + } + + v8::Handle<v8::Value> IsAPIAllowed(const v8::Arguments& args) { + std::string custom_api_name = *v8::String::AsciiValue(args[0]->ToString()); + return v8::Boolean::New(extension_dispatcher_->AllowCustomAPI( + frame_, custom_api_name, world_id_)); + } + + private: + ExtensionDispatcher* extension_dispatcher_; + bool is_bindings_allowed_; + WebKit::WebFrame* frame_; + int world_id_; +}; + } using namespace extensions; @@ -64,7 +152,8 @@ ExtensionDispatcher::ExtensionDispatcher() : is_webkit_initialized_(false), webrequest_adblock_(false), webrequest_adblock_plus_(false), - webrequest_other_(false) { + webrequest_other_(false), + source_map_(&ResourceBundle::GetSharedInstance()) { const CommandLine& command_line = *(CommandLine::ForCurrentProcess()); is_extension_process_ = command_line.HasSwitch(switches::kExtensionProcess) || @@ -76,6 +165,7 @@ ExtensionDispatcher::ExtensionDispatcher() } user_script_slave_.reset(new UserScriptSlave(&extensions_)); + PopulateSourceMap(); } ExtensionDispatcher::~ExtensionDispatcher() { @@ -113,25 +203,6 @@ void ExtensionDispatcher::WebKitInitialized() { RenderThread::Get(), &RenderThread::IdleHandler); } - RegisterExtension(new AppBindings(this), false); - RegisterExtension(new WebstoreBindings(this), false); - - // Add v8 extensions related to chrome extensions. - RegisterExtension(new ChromeV8Extension( - "extensions/json_schema.js", IDR_JSON_SCHEMA_JS, NULL), true); - RegisterExtension(EventBindings::Get(this), true); - RegisterExtension(MiscellaneousBindings::Get(this), true); - RegisterExtension(SchemaGeneratedBindings::Get(this), true); - RegisterExtension(new ChromeV8Extension( - "extensions/apitest.js", IDR_EXTENSION_APITEST_JS, NULL), true); - - std::vector<v8::Extension*> custom_bindings = - custom_bindings_util::GetAll(this); - for (std::vector<v8::Extension*>::iterator it = custom_bindings.begin(); - it != custom_bindings.end(); ++it) { - RegisterExtension(*it, true); - } - // Initialize host permissions for any extensions that were activated before // WebKit was initialized. for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); @@ -299,55 +370,121 @@ bool ExtensionDispatcher::AllowScriptExtension( int extension_group, int world_id) { g_hack_extension_group = extension_group; + return true; +} - // NULL in unit tests. - if (!RenderThread::Get()) - return true; - - // If we don't know about it, it was added by WebCore, so we should allow it. - if (!RenderThread::Get()->IsRegisteredExtension(v8_extension_name)) - return true; - - // If the V8 extension is not restricted, allow it to run anywhere. - if (!restricted_v8_extensions_.count(v8_extension_name)) - return true; - - // Extension-only bindings should be restricted to content scripts and - // extension-blessed URLs. - ChromeV8Context::ContextType context_type = - ExtensionGroupToContextType(extension_group); - - if (context_type == ChromeV8Context::CONTENT_SCRIPT || - extensions_.ExtensionBindingsAllowed(ExtensionURLInfo( - frame->document().securityOrigin(), - UserScriptSlave::GetDataSourceURLForFrame(frame)))) { - // If the extension is a custom API binding, only allow if the extension - // has permission to use the API. - std::string custom_binding_api_name = - custom_bindings_util::GetAPIName(v8_extension_name); - if (!custom_binding_api_name.empty()) { - std::string extension_id = GetExtensionID(frame, world_id); - const Extension* extension = extensions_.GetByID(extension_id); - if (!extension) { - // This can happen when a resource is blocked due to CSP; a valid - // chrome-extension:// URL is navigated to, so it passes the initial - // checks, but the URL gets changed to "chrome-extension://invalid" - // afterwards (see chrome_content_renderer_client.cc). An extension - // page still gets loaded, just for the extension with ID "invalid", - // which of course isn't found so GetById extension will be NULL. - // - // Reference: http://crbug.com/111614. - CHECK_EQ("invalid", extension_id); - return false; - } - return custom_bindings_util::AllowAPIInjection( - custom_binding_api_name, *extension, this); - } - +bool ExtensionDispatcher::AllowCustomAPI( + WebFrame* frame, + const std::string& custom_binding_api_name, + int world_id) { + std::string extension_id = GetExtensionID(frame, world_id); + if (test_extension_id_ == extension_id) return true; + const Extension* extension = extensions_.GetByID(extension_id); + if (!extension) { + // This can happen when a resource is blocked due to CSP; a valid + // chrome-extension:// URL is navigated to, so it passes the initial + // checks, but the URL gets changed to "chrome-extension://invalid" + // afterwards (see chrome_content_renderer_client.cc). An extension + // page still gets loaded, just for the extension with ID "invalid", + // which of course isn't found so GetById extension will be NULL. + // + // Reference: http://crbug.com/111614. + CHECK_EQ("invalid", extension_id); + return false; } - - return false; + return custom_bindings_util::AllowAPIInjection( + custom_binding_api_name, *extension, this); +} + +void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system, + ChromeV8Context* context) { + module_system->RegisterNativeHandler("app", + scoped_ptr<NativeHandler>(new AppBindings(this, context))); + module_system->RegisterNativeHandler("webstore", + scoped_ptr<NativeHandler>(new WebstoreBindings(this, context))); + module_system->RegisterNativeHandler("event_bindings", + scoped_ptr<NativeHandler>(EventBindings::Get(this))); + module_system->RegisterNativeHandler("miscellaneous_bindings", + scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this))); + module_system->RegisterNativeHandler("schema_generated_bindings", + scoped_ptr<NativeHandler>(SchemaGeneratedBindings::Get(this))); + + // Custom bindings. + module_system->RegisterNativeHandler("chrome_private", + scoped_ptr<NativeHandler>( + new ChromePrivateCustomBindings(this))); + module_system->RegisterNativeHandler("context_menus", + scoped_ptr<NativeHandler>(new ContextMenusCustomBindings())); + module_system->RegisterNativeHandler("extension", + scoped_ptr<NativeHandler>( + new ExtensionCustomBindings(this))); + module_system->RegisterNativeHandler("experimental_socket", + scoped_ptr<NativeHandler>(new ExperimentalSocketCustomBindings())); + module_system->RegisterNativeHandler("file_browser_handler", + scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings())); + module_system->RegisterNativeHandler("file_browser_private", + scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings())); + module_system->RegisterNativeHandler("i18n", + scoped_ptr<NativeHandler>(new I18NCustomBindings())); + module_system->RegisterNativeHandler("page_actions", + scoped_ptr<NativeHandler>( + new PageActionsCustomBindings(this))); + module_system->RegisterNativeHandler("page_capture", + scoped_ptr<NativeHandler>(new PageCaptureCustomBindings())); + module_system->RegisterNativeHandler("tabs", + scoped_ptr<NativeHandler>(new TabsCustomBindings())); + module_system->RegisterNativeHandler("tts", + scoped_ptr<NativeHandler>(new TTSCustomBindings())); + module_system->RegisterNativeHandler("web_request", + scoped_ptr<NativeHandler>(new WebRequestCustomBindings())); +} + +void ExtensionDispatcher::PopulateSourceMap() { + source_map_.RegisterSource("app", IDR_APP_BINDINGS_JS); + source_map_.RegisterSource("webstore", IDR_WEBSTORE_BINDINGS_JS); + source_map_.RegisterSource("event_bindings", IDR_EVENT_BINDINGS_JS); + source_map_.RegisterSource("miscellaneous_bindings", + IDR_MISCELLANEOUS_BINDINGS_JS); + source_map_.RegisterSource("schema_generated_bindings", + IDR_SCHEMA_GENERATED_BINDINGS_JS); + source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS); + source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS); + source_map_.RegisterSource("setup_bindings", IDR_SETUP_BINDINGS_JS); + + // Custom bindings. + source_map_.RegisterSource("browserAction", + IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("chromePrivate", + IDR_CHROME_PRIVATE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("contentSettings", + IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("contextMenus", + IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("devtools", IDR_DEVTOOLS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("experimental.declarative", + IDR_EXPERIMENTAL_DECLARATIVE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("experimental.socket", + IDR_EXPERIMENTAL_SOCKET_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("fileBrowserHandler", + IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("fileBrowserPrivate", + IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("pageActions", + IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("pageCapture", + IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("storage", IDR_STORAGE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("types", IDR_TYPES_CUSTOM_BINDINGS_JS); + source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS); } void ExtensionDispatcher::DidCreateScriptContext( @@ -356,19 +493,49 @@ void ExtensionDispatcher::DidCreateScriptContext( // TODO(koz): If the caller didn't pass extension_group, use the last value. if (extension_group == -1) extension_group = g_hack_extension_group; + + std::string extension_id = GetExtensionID(frame, world_id); ChromeV8Context* context = new ChromeV8Context( v8_context, frame, - GetExtensionID(frame, world_id), + extension_id, ExtensionGroupToContextType(extension_group)); v8_context_set_.Add(context); + scoped_ptr<ModuleSystem> module_system(new ModuleSystem(&source_map_)); + RegisterNativeHandlers(module_system.get(), context); + + bool is_bindings_allowed = + IsTestExtensionId(extension_id) || + context->context_type() == ChromeV8Context::CONTENT_SCRIPT || + extensions_.ExtensionBindingsAllowed(ExtensionURLInfo( + frame->document().securityOrigin(), + UserScriptSlave::GetDataSourceURLForFrame(frame))); + + module_system->RegisterNativeHandler("chrome_hidden", + scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler())); + module_system->RegisterNativeHandler("context_info", + scoped_ptr<NativeHandler>(new ContextInfoNativeHandler( + this, + is_bindings_allowed, + frame, + world_id))); + module_system->RegisterNativeHandler("print", + scoped_ptr<NativeHandler>(new PrintNativeHandler())); + const Extension* extension = extensions_.GetByID(context->extension_id()); int manifest_version = 1; if (extension) manifest_version = extension->manifest_version(); + module_system->RunString("var chrome; chrome = chrome || {};", + "setup-chrome-object"); + module_system->Require("setup_bindings"); + module_system->set_natives_enabled(false); + + context->set_module_system(module_system.Pass()); + context->DispatchOnLoadEvent( is_extension_process_, ChromeRenderProcessObserver::is_incognito_process(), @@ -399,12 +566,6 @@ void ExtensionDispatcher::WillReleaseScriptContext( context->DispatchOnUnloadEvent(); - ChromeV8Extension::InstanceSet extensions = ChromeV8Extension::GetAll(); - for (ChromeV8Extension::InstanceSet::const_iterator iter = extensions.begin(); - iter != extensions.end(); ++iter) { - (*iter)->ContextWillBeReleased(context); - } - v8_context_set_.Remove(context); VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); } @@ -414,7 +575,7 @@ void ExtensionDispatcher::SetTestExtensionId(const std::string& id) { } bool ExtensionDispatcher::IsTestExtensionId(const std::string& id) { - return id == test_extension_id_; + return !test_extension_id_.empty() && id == test_extension_id_; } void ExtensionDispatcher::OnActivateApplication( diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h index e72c269..b1dfb40 100644 --- a/chrome/renderer/extensions/extension_dispatcher.h +++ b/chrome/renderer/extensions/extension_dispatcher.h @@ -15,8 +15,10 @@ #include "content/public/renderer/render_process_observer.h" #include "chrome/common/extensions/extension_set.h" #include "chrome/renderer/extensions/chrome_v8_context_set.h" +#include "chrome/renderer/resource_bundle_source_map.h" #include "v8/include/v8.h" +class ModuleSystem; class GURL; class URLPattern; class UserScriptSlave; @@ -55,12 +57,18 @@ class ExtensionDispatcher : public content::RenderProcessObserver { bool IsApplicationActive(const std::string& extension_id) const; bool IsExtensionActive(const std::string& extension_id) const; + // Whether or not we should set up custom bindings for this api. + bool AllowCustomAPI(WebKit::WebFrame* frame, + const std::string& custom_binding_api_name, + int world_id); + // See WebKit::WebPermissionClient::allowScriptExtension // TODO(koz): Remove once WebKit no longer calls this. bool AllowScriptExtension(WebKit::WebFrame* frame, const std::string& v8_extension_name, int extension_group); + // TODO(koz): Remove once WebKit no longer calls this. bool AllowScriptExtension(WebKit::WebFrame* frame, const std::string& v8_extension_name, int extension_group, @@ -137,6 +145,12 @@ class ExtensionDispatcher : public content::RenderProcessObserver { const Extension* extension, const URLPatternSet& origins); + void RegisterNativeHandlers(ModuleSystem* module_system, + ChromeV8Context* context); + + // Inserts static source code into |source_map_|. + void PopulateSourceMap(); + // Finds the extension ID for the current context. This is determined from // |world_id| if it's non-zero, or the URL in |frame| if it is. std::string GetExtensionID(WebKit::WebFrame* frame, int world_id); @@ -182,6 +196,8 @@ class ExtensionDispatcher : public content::RenderProcessObserver { bool webrequest_adblock_plus_; bool webrequest_other_; + ResourceBundleSourceMap source_map_; + DISALLOW_COPY_AND_ASSIGN(ExtensionDispatcher); }; diff --git a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc index 0688839..015d0b5 100644 --- a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc +++ b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc @@ -13,18 +13,9 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" -namespace extensions { - -FileBrowserHandlerCustomBindings::FileBrowserHandlerCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension("extensions/file_browser_handler_custom_bindings.js", - IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} +namespace { -static v8::Handle<v8::Value> GetExternalFileEntry(const v8::Arguments& args) { +v8::Handle<v8::Value> GetExternalFileEntry(const v8::Arguments& args) { // TODO(zelidrag): Make this magic work on other platforms when file browser // matures enough on ChromeOS. #if defined(OS_CHROMEOS) @@ -54,13 +45,14 @@ static v8::Handle<v8::Value> GetExternalFileEntry(const v8::Arguments& args) { #endif } -v8::Handle<v8::FunctionTemplate> -FileBrowserHandlerCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetExternalFileEntry"))) - return v8::FunctionTemplate::New(GetExternalFileEntry); - else - return ChromeV8Extension::GetNativeFunction(name); +} // namespace + +namespace extensions { + +FileBrowserHandlerCustomBindings::FileBrowserHandlerCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetExternalFileEntry", &GetExternalFileEntry); } + } // namespace extensions diff --git a/chrome/renderer/extensions/file_browser_handler_custom_bindings.h b/chrome/renderer/extensions/file_browser_handler_custom_bindings.h index 23ec5a8..354686b 100644 --- a/chrome/renderer/extensions/file_browser_handler_custom_bindings.h +++ b/chrome/renderer/extensions/file_browser_handler_custom_bindings.h @@ -14,13 +14,9 @@ namespace extensions { // Custom bindings for the fileBrowserHandler API. class FileBrowserHandlerCustomBindings : public ChromeV8Extension { public: - FileBrowserHandlerCustomBindings( - int dependency_count, const char** dependencies); + FileBrowserHandlerCustomBindings(); private: - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; - DISALLOW_COPY_AND_ASSIGN(FileBrowserHandlerCustomBindings); }; diff --git a/chrome/renderer/extensions/file_browser_private_custom_bindings.cc b/chrome/renderer/extensions/file_browser_private_custom_bindings.cc index a36e606..1731552 100644 --- a/chrome/renderer/extensions/file_browser_private_custom_bindings.cc +++ b/chrome/renderer/extensions/file_browser_private_custom_bindings.cc @@ -13,16 +13,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" -namespace extensions { - -FileBrowserPrivateCustomBindings::FileBrowserPrivateCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension("extensions/file_browser_private_custom_bindings.js", - IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} +namespace { static v8::Handle<v8::Value> GetLocalFileSystem( const v8::Arguments& args) { @@ -40,13 +31,13 @@ static v8::Handle<v8::Value> GetLocalFileSystem( WebKit::WebString::fromUTF8(path.c_str())); } -v8::Handle<v8::FunctionTemplate> -FileBrowserPrivateCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetLocalFileSystem"))) - return v8::FunctionTemplate::New(GetLocalFileSystem); +} // namespace + +namespace extensions { - return ChromeV8Extension::GetNativeFunction(name); +FileBrowserPrivateCustomBindings::FileBrowserPrivateCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetLocalFileSystem", &GetLocalFileSystem); } } // namespace extensions diff --git a/chrome/renderer/extensions/file_browser_private_custom_bindings.h b/chrome/renderer/extensions/file_browser_private_custom_bindings.h index d987a06..191c0dd 100644 --- a/chrome/renderer/extensions/file_browser_private_custom_bindings.h +++ b/chrome/renderer/extensions/file_browser_private_custom_bindings.h @@ -14,13 +14,9 @@ namespace extensions { // Custom bindings for the fileBrowserPrivate API. class FileBrowserPrivateCustomBindings : public ChromeV8Extension { public: - FileBrowserPrivateCustomBindings( - int dependency_count, const char** dependencies); + FileBrowserPrivateCustomBindings(); private: - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; - DISALLOW_COPY_AND_ASSIGN(FileBrowserPrivateCustomBindings); }; diff --git a/chrome/renderer/extensions/i18n_custom_bindings.cc b/chrome/renderer/extensions/i18n_custom_bindings.cc index 982acbf..afd4be7 100644 --- a/chrome/renderer/extensions/i18n_custom_bindings.cc +++ b/chrome/renderer/extensions/i18n_custom_bindings.cc @@ -12,21 +12,9 @@ namespace extensions { -I18NCustomBindings::I18NCustomBindings( - int dependency_count, const char** dependencies) - : ChromeV8Extension( - "extensions/i18n_custom_bindings.js", - IDR_I18N_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} - -v8::Handle<v8::FunctionTemplate> I18NCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetL10nMessage"))) - return v8::FunctionTemplate::New(GetL10nMessage); - - return ChromeV8Extension::GetNativeFunction(name); +I18NCustomBindings::I18NCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetL10nMessage", &GetL10nMessage); } // static diff --git a/chrome/renderer/extensions/i18n_custom_bindings.h b/chrome/renderer/extensions/i18n_custom_bindings.h index 1cc8743..e0ca0df 100644 --- a/chrome/renderer/extensions/i18n_custom_bindings.h +++ b/chrome/renderer/extensions/i18n_custom_bindings.h @@ -13,10 +13,7 @@ namespace extensions { // Implements custom bindings for the i18n API. class I18NCustomBindings : public ChromeV8Extension { public: - I18NCustomBindings(int dependency_count, const char** dependencies); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + I18NCustomBindings(); private: static v8::Handle<v8::Value> GetL10nMessage(const v8::Arguments& args); diff --git a/chrome/renderer/extensions/json_schema_unittest.cc b/chrome/renderer/extensions/json_schema_unittest.cc index 1e76b41..c4b0614 100644 --- a/chrome/renderer/extensions/json_schema_unittest.cc +++ b/chrome/renderer/extensions/json_schema_unittest.cc @@ -25,15 +25,14 @@ class JsonSchemaTest : public V8UnitTest { std::string code = ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_JSON_SCHEMA_JS).as_string(); - // This is a nasty hack, but it is easier to test the code if we don't use - // it as a v8 extension. So replace the only bit that relies on that with a - // more easily testable implementation. - ReplaceFirstSubstringAfterOffset(&code, 0, - "native function GetChromeHidden();", - "function GetChromeHidden() {\n" - " if (!this.chromeHidden) this.chromeHidden = {};\n" - " return this.chromeHidden;\n" - "}"); + // json_schema.js expects to have requireNative() defined. + ExecuteScriptInContext( + "function requireNative(id) {" + " return {" + " GetChromeHidden: function() { return {}; }," + " };" + "}", + "test-code"); ExecuteScriptInContext(code, kJsonSchema); // Add the test functions to the context. diff --git a/chrome/renderer/extensions/miscellaneous_bindings.cc b/chrome/renderer/extensions/miscellaneous_bindings.cc index 31a8923..25fc895 100644 --- a/chrome/renderer/extensions/miscellaneous_bindings.cc +++ b/chrome/renderer/extensions/miscellaneous_bindings.cc @@ -62,31 +62,18 @@ static void ClearPortData(int port_id) { } const char kPortClosedError[] = "Attempting to use a disconnected port object"; -const char* kExtensionDeps[] = { "extensions/event.js" }; class ExtensionImpl : public ChromeV8Extension { public: explicit ExtensionImpl(ExtensionDispatcher* dispatcher) - : ChromeV8Extension("extensions/miscellaneous_bindings.js", - IDR_MISCELLANEOUS_BINDINGS_JS, - arraysize(kExtensionDeps), kExtensionDeps, - dispatcher) { + : ChromeV8Extension(dispatcher) { + RouteStaticFunction("CloseChannel", &CloseChannel); + RouteStaticFunction("PortAddRef", &PortAddRef); + RouteStaticFunction("PortRelease", &PortRelease); + RouteStaticFunction("PostMessage", &PostMessage); } - ~ExtensionImpl() {} - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("PostMessage"))) { - return v8::FunctionTemplate::New(PostMessage); - } else if (name->Equals(v8::String::New("CloseChannel"))) { - return v8::FunctionTemplate::New(CloseChannel); - } else if (name->Equals(v8::String::New("PortAddRef"))) { - return v8::FunctionTemplate::New(PortAddRef); - } else if (name->Equals(v8::String::New("PortRelease"))) { - return v8::FunctionTemplate::New(PortRelease); - } - return ChromeV8Extension::GetNativeFunction(name); - } + ~ExtensionImpl() {} // Sends a message along the given channel. static v8::Handle<v8::Value> PostMessage(const v8::Arguments& args) { @@ -155,9 +142,8 @@ class ExtensionImpl : public ChromeV8Extension { namespace extensions { -v8::Extension* MiscellaneousBindings::Get(ExtensionDispatcher* dispatcher) { - static v8::Extension* extension = new ExtensionImpl(dispatcher); - return extension; +ChromeV8Extension* MiscellaneousBindings::Get(ExtensionDispatcher* dispatcher) { + return new ExtensionImpl(dispatcher); } void MiscellaneousBindings::DeliverMessage( diff --git a/chrome/renderer/extensions/miscellaneous_bindings.h b/chrome/renderer/extensions/miscellaneous_bindings.h index 1db641b..0df26fa 100644 --- a/chrome/renderer/extensions/miscellaneous_bindings.h +++ b/chrome/renderer/extensions/miscellaneous_bindings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,7 @@ #include "chrome/renderer/extensions/chrome_v8_context_set.h" +class ChromeV8Extension; class ExtensionDispatcher; namespace content { @@ -30,7 +31,7 @@ namespace extensions { class MiscellaneousBindings { public: // Creates an instance of the extension. - static v8::Extension* Get(ExtensionDispatcher* dispatcher); + static ChromeV8Extension* Get(ExtensionDispatcher* dispatcher); // Delivers a message sent using content script messaging to some of the // contexts in |bindings_context_set|. If |restrict_to_render_view| is diff --git a/chrome/renderer/extensions/page_actions_custom_bindings.cc b/chrome/renderer/extensions/page_actions_custom_bindings.cc index 0d9d61a..b6e86ee 100644 --- a/chrome/renderer/extensions/page_actions_custom_bindings.cc +++ b/chrome/renderer/extensions/page_actions_custom_bindings.cc @@ -14,15 +14,10 @@ namespace extensions { PageActionsCustomBindings::PageActionsCustomBindings( - int dependency_count, - const char** dependencies, ExtensionDispatcher* extension_dispatcher) - : ChromeV8Extension( - "extensions/page_actions_custom_bindings.js", - IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - extension_dispatcher) {} + : ChromeV8Extension(extension_dispatcher) { + RouteStaticFunction("GetCurrentPageActions", &GetCurrentPageActions); +} // static v8::Handle<v8::Value> PageActionsCustomBindings::GetCurrentPageActions( @@ -45,15 +40,4 @@ v8::Handle<v8::Value> PageActionsCustomBindings::GetCurrentPageActions( return page_action_vector; } - -v8::Handle<v8::FunctionTemplate> PageActionsCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetCurrentPageActions"))) { - return v8::FunctionTemplate::New(GetCurrentPageActions, - v8::External::New(this)); - } - - return ChromeV8Extension::GetNativeFunction(name); -} - } // extensions diff --git a/chrome/renderer/extensions/page_actions_custom_bindings.h b/chrome/renderer/extensions/page_actions_custom_bindings.h index 09e68d9..1faad35 100644 --- a/chrome/renderer/extensions/page_actions_custom_bindings.h +++ b/chrome/renderer/extensions/page_actions_custom_bindings.h @@ -15,13 +15,7 @@ namespace extensions { // Implements custom bindings for the pageActions API. class PageActionsCustomBindings : public ChromeV8Extension { public: - PageActionsCustomBindings( - int dependency_count, - const char** dependencies, - ExtensionDispatcher* extension_dispatcher); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + explicit PageActionsCustomBindings(ExtensionDispatcher* extension_dispatcher); private: static v8::Handle<v8::Value> GetCurrentPageActions(const v8::Arguments& args); diff --git a/chrome/renderer/extensions/page_capture_custom_bindings.cc b/chrome/renderer/extensions/page_capture_custom_bindings.cc index e37cdab..c7e41ea 100644 --- a/chrome/renderer/extensions/page_capture_custom_bindings.cc +++ b/chrome/renderer/extensions/page_capture_custom_bindings.cc @@ -13,18 +13,15 @@ namespace extensions { -PageCaptureCustomBindings::PageCaptureCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension( - "extensions/page_capture_custom_bindings.js", - IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} - -// Creates a Blob with the content of the specified file. -static v8::Handle<v8::Value> CreateBlob(const v8::Arguments& args) { +PageCaptureCustomBindings::PageCaptureCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("CreateBlob", &CreateBlob); + RouteStaticFunction("SendResponseAck", &SendResponseAck); +} + +// static +v8::Handle<v8::Value> PageCaptureCustomBindings::CreateBlob( + const v8::Arguments& args) { CHECK(args.Length() == 2); CHECK(args[0]->IsString()); CHECK(args[1]->IsInt32()); @@ -48,15 +45,4 @@ v8::Handle<v8::Value> PageCaptureCustomBindings::SendResponseAck( return v8::Undefined(); } -v8::Handle<v8::FunctionTemplate> PageCaptureCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("CreateBlob"))) { - return v8::FunctionTemplate::New(CreateBlob, v8::External::New(this)); - } else if (name->Equals(v8::String::New("SendResponseAck"))) { - return v8::FunctionTemplate::New(SendResponseAck, v8::External::New(this)); - } - - return ChromeV8Extension::GetNativeFunction(name); -} - } // namespace extensions diff --git a/chrome/renderer/extensions/page_capture_custom_bindings.h b/chrome/renderer/extensions/page_capture_custom_bindings.h index a6ec433..4796e13 100644 --- a/chrome/renderer/extensions/page_capture_custom_bindings.h +++ b/chrome/renderer/extensions/page_capture_custom_bindings.h @@ -13,12 +13,11 @@ namespace extensions { // Implements custom bindings for the pageCapture API. class PageCaptureCustomBindings : public ChromeV8Extension { public: - PageCaptureCustomBindings(int dependency_count, const char** dependencies); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + PageCaptureCustomBindings(); private: + // Creates a Blob with the content of the specified file. + static v8::Handle<v8::Value> CreateBlob(const v8::Arguments& args); static v8::Handle<v8::Value> SendResponseAck(const v8::Arguments& args); }; diff --git a/chrome/renderer/extensions/schema_generated_bindings.cc b/chrome/renderer/extensions/schema_generated_bindings.cc index c0e0725..eda15d8 100644 --- a/chrome/renderer/extensions/schema_generated_bindings.cc +++ b/chrome/renderer/extensions/schema_generated_bindings.cc @@ -51,13 +51,6 @@ using WebKit::WebSecurityOrigin; namespace { -const char* kExtensionDeps[] = { - "extensions/event.js", - "extensions/json_schema.js", - "extensions/miscellaneous_bindings.js", - "extensions/apitest.js" -}; - // Contains info relevant to a pending API request. struct PendingRequest { public : @@ -77,11 +70,12 @@ base::LazyInstance<PendingRequestMap> g_pending_requests = class ExtensionImpl : public ChromeV8Extension { public: explicit ExtensionImpl(ExtensionDispatcher* extension_dispatcher) - : ChromeV8Extension("extensions/schema_generated_bindings.js", - IDR_SCHEMA_GENERATED_BINDINGS_JS, - arraysize(kExtensionDeps), - kExtensionDeps, - extension_dispatcher) { + : ChromeV8Extension(extension_dispatcher) { + RouteStaticFunction("GetExtensionAPIDefinition", + &GetExtensionAPIDefinition); + RouteStaticFunction("GetNextRequestId", &GetNextRequestId); + RouteStaticFunction("StartRequest", &StartRequest); + RouteStaticFunction("SetIconCommon", &SetIconCommon); } ~ExtensionImpl() { @@ -94,24 +88,6 @@ class ExtensionImpl : public ChromeV8Extension { } } - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE { - if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { - return v8::FunctionTemplate::New(GetExtensionAPIDefinition, - v8::External::New(this)); - } else if (name->Equals(v8::String::New("GetNextRequestId"))) { - return v8::FunctionTemplate::New(GetNextRequestId); - } else if (name->Equals(v8::String::New("StartRequest"))) { - return v8::FunctionTemplate::New(StartRequest, - v8::External::New(this)); - } else if (name->Equals(v8::String::New("SetIconCommon"))) { - return v8::FunctionTemplate::New(SetIconCommon, - v8::External::New(this)); - } - - return ChromeV8Extension::GetNativeFunction(name); - } - private: static v8::Handle<v8::Value> GetV8SchemaForAPI( ExtensionImpl* self, @@ -347,12 +323,9 @@ class ExtensionImpl : public ChromeV8Extension { namespace extensions { -v8::Extension* SchemaGeneratedBindings::Get( +ChromeV8Extension* SchemaGeneratedBindings::Get( ExtensionDispatcher* extension_dispatcher) { - static v8::Extension* extension = new ExtensionImpl(extension_dispatcher); - CHECK_EQ(extension_dispatcher, - static_cast<ExtensionImpl*>(extension)->extension_dispatcher()); - return extension; + return new ExtensionImpl(extension_dispatcher); } // static diff --git a/chrome/renderer/extensions/schema_generated_bindings.h b/chrome/renderer/extensions/schema_generated_bindings.h index 1785171..e50ed96 100644 --- a/chrome/renderer/extensions/schema_generated_bindings.h +++ b/chrome/renderer/extensions/schema_generated_bindings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,7 @@ class ExtensionDispatcher; class ChromeV8ContextSet; +class ChromeV8Extension; namespace v8 { class Extension; @@ -21,7 +22,7 @@ namespace extensions { // declarations in chrome/common/extensions/api/. class SchemaGeneratedBindings { public: - static v8::Extension* Get(ExtensionDispatcher* extension_dispatcher); + static ChromeV8Extension* Get(ExtensionDispatcher* extension_dispatcher); // Handles a response to an API request. Sets |extension_id|. static void HandleResponse(const ChromeV8ContextSet& contexts, diff --git a/chrome/renderer/extensions/tabs_custom_bindings.cc b/chrome/renderer/extensions/tabs_custom_bindings.cc index abb2262..3d908bb 100644 --- a/chrome/renderer/extensions/tabs_custom_bindings.cc +++ b/chrome/renderer/extensions/tabs_custom_bindings.cc @@ -15,14 +15,10 @@ namespace extensions { -TabsCustomBindings::TabsCustomBindings( - int dependency_count, const char** dependencies) - : ChromeV8Extension( - "extensions/tabs_custom_bindings.js", - IDR_TABS_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} +TabsCustomBindings::TabsCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("OpenChannelToTab", &OpenChannelToTab); +} // static v8::Handle<v8::Value> TabsCustomBindings::OpenChannelToTab( @@ -47,12 +43,4 @@ v8::Handle<v8::Value> TabsCustomBindings::OpenChannelToTab( return v8::Undefined(); } -v8::Handle<v8::FunctionTemplate> TabsCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("OpenChannelToTab"))) - return v8::FunctionTemplate::New(OpenChannelToTab); - - return ChromeV8Extension::GetNativeFunction(name); -} - } // extensions diff --git a/chrome/renderer/extensions/tabs_custom_bindings.h b/chrome/renderer/extensions/tabs_custom_bindings.h index 0700a43..ec06979 100644 --- a/chrome/renderer/extensions/tabs_custom_bindings.h +++ b/chrome/renderer/extensions/tabs_custom_bindings.h @@ -13,10 +13,7 @@ namespace extensions { // Implements custom bindings for the tabs API. class TabsCustomBindings : public ChromeV8Extension { public: - TabsCustomBindings(int dependency_count, const char** dependencies); - - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + TabsCustomBindings(); private: // Creates a new messaging channel to the tab with the given ID. diff --git a/chrome/renderer/extensions/tts_custom_bindings.cc b/chrome/renderer/extensions/tts_custom_bindings.cc index dca526a..33e1887 100644 --- a/chrome/renderer/extensions/tts_custom_bindings.cc +++ b/chrome/renderer/extensions/tts_custom_bindings.cc @@ -13,30 +13,18 @@ namespace extensions { -TTSCustomBindings::TTSCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension( - "extensions/tts_custom_bindings.js", - IDR_TTS_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} +TTSCustomBindings::TTSCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetNextTTSEventId", &GetNextTTSEventId); +} -static v8::Handle<v8::Value> GetNextTTSEventId(const v8::Arguments& args) { +// static +v8::Handle<v8::Value> TTSCustomBindings::GetNextTTSEventId( + const v8::Arguments& args) { // Note: this works because the TTS API only works in the // extension process, not content scripts. static int next_tts_event_id = 1; return v8::Integer::New(next_tts_event_id++); } -v8::Handle<v8::FunctionTemplate> -TTSCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetNextTTSEventId"))) - return v8::FunctionTemplate::New(GetNextTTSEventId); - - return ChromeV8Extension::GetNativeFunction(name); -} - } // extensions diff --git a/chrome/renderer/extensions/tts_custom_bindings.h b/chrome/renderer/extensions/tts_custom_bindings.h index c7598eb..c99a03a 100644 --- a/chrome/renderer/extensions/tts_custom_bindings.h +++ b/chrome/renderer/extensions/tts_custom_bindings.h @@ -13,10 +13,10 @@ namespace extensions { // Implements custom bindings for the tts API. class TTSCustomBindings : public ChromeV8Extension { public: - TTSCustomBindings(int dependency_count, const char** dependencies); + TTSCustomBindings(); - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + private: + static v8::Handle<v8::Value> GetNextTTSEventId(const v8::Arguments& args); }; } // extensions diff --git a/chrome/renderer/extensions/web_request_custom_bindings.cc b/chrome/renderer/extensions/web_request_custom_bindings.cc index 3246926..83f716c 100644 --- a/chrome/renderer/extensions/web_request_custom_bindings.cc +++ b/chrome/renderer/extensions/web_request_custom_bindings.cc @@ -12,18 +12,15 @@ namespace extensions { -WebRequestCustomBindings::WebRequestCustomBindings( - int dependency_count, - const char** dependencies) - : ChromeV8Extension( - "extensions/web_request_custom_bindings.js", - IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS, - dependency_count, - dependencies, - NULL) {} +WebRequestCustomBindings::WebRequestCustomBindings() + : ChromeV8Extension(NULL) { + RouteStaticFunction("GetUniqueSubEventName", &GetUniqueSubEventName); +} // Attach an event name to an object. -static v8::Handle<v8::Value> GetUniqueSubEventName(const v8::Arguments& args) { +// static +v8::Handle<v8::Value> WebRequestCustomBindings::GetUniqueSubEventName( + const v8::Arguments& args) { static int next_event_id = 0; DCHECK(args.Length() == 1); DCHECK(args[0]->IsString()); @@ -33,13 +30,5 @@ static v8::Handle<v8::Value> GetUniqueSubEventName(const v8::Arguments& args) { return v8::String::New(unique_event_name.c_str()); } -v8::Handle<v8::FunctionTemplate> WebRequestCustomBindings::GetNativeFunction( - v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetUniqueSubEventName"))) - return v8::FunctionTemplate::New(GetUniqueSubEventName); - - return ChromeV8Extension::GetNativeFunction(name); -} - } // extensions diff --git a/chrome/renderer/extensions/web_request_custom_bindings.h b/chrome/renderer/extensions/web_request_custom_bindings.h index 285ae88..028c37d 100644 --- a/chrome/renderer/extensions/web_request_custom_bindings.h +++ b/chrome/renderer/extensions/web_request_custom_bindings.h @@ -13,10 +13,10 @@ namespace extensions { // Implements custom bindings for the webRequest API. class WebRequestCustomBindings : public ChromeV8Extension { public: - WebRequestCustomBindings(int dependency_count, const char** dependencies); + WebRequestCustomBindings(); - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<v8::String> name) OVERRIDE; + private: + static v8::Handle<v8::Value> GetUniqueSubEventName(const v8::Arguments& args); }; } // extensions diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc index 5991e6a..7214db9 100644 --- a/chrome/renderer/extensions/webstore_bindings.cc +++ b/chrome/renderer/extensions/webstore_bindings.cc @@ -13,7 +13,6 @@ #include "grit/renderer_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h" #include "v8/include/v8.h" @@ -48,69 +47,17 @@ const char kInvalidWebstoreItemUrlError[] = // (successful or not) via OnInlineWebstoreInstallResponse. int g_next_install_id = 0; -class WebstoreBindingsHandler : public ChromeV8ExtensionHandler { - public: - WebstoreBindingsHandler( - ExtensionDispatcher* dispatcher, ChromeV8Context* context); - - // ChromeV8ExtensionHandler - virtual v8::Handle<v8::Value> HandleNativeFunction( - const std::string& name, - const v8::Arguments& arguments) OVERRIDE; - - // IPC::Channel::Listener - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - - private: - v8::Handle<v8::Value> Install(const v8::Arguments& args); - - void OnInlineWebstoreInstallResponse( - int install_id, bool success, const std::string& error); - - // Extracts a Web Store item ID from a <link rel="chrome-webstore-item" - // href="https://chrome.google.com/webstore/detail/id"> node found in the - // frame. On success, true will be returned and the |webstore_item_id| - // parameter will be populated with the ID. On failure, false will be returned - // and |error| will be populated with the error. - static bool GetWebstoreItemIdFromFrame( - WebFrame* frame, const std::string& preferred_store_link_url, - std::string* webstore_item_id, std::string* error); - - ExtensionDispatcher* dispatcher_; - DISALLOW_COPY_AND_ASSIGN(WebstoreBindingsHandler); -}; - } // anonymous namespace -WebstoreBindings::WebstoreBindings(ExtensionDispatcher* dispatcher) - : ChromeV8Extension("extensions/webstore.js", IDR_WEBSTORE_BINDINGS_JS, - dispatcher) { -} - -ChromeV8ExtensionHandler* WebstoreBindings::CreateHandler( - ChromeV8Context* context) { - return new WebstoreBindingsHandler(extension_dispatcher(), context); -} - -WebstoreBindingsHandler::WebstoreBindingsHandler( - ExtensionDispatcher* dispatcher, +WebstoreBindings::WebstoreBindings(ExtensionDispatcher* dispatcher, ChromeV8Context* context) - : ChromeV8ExtensionHandler(context), - dispatcher_(dispatcher) { -} - -v8::Handle<v8::Value> WebstoreBindingsHandler::HandleNativeFunction( - const std::string& name, const v8::Arguments& args) { - if (name == "Install") { - return Install(args); - } else { - CHECK(false) << "Unknown native function: " << name; - } - - return v8::Undefined(); + : ChromeV8Extension(dispatcher), + ChromeV8ExtensionHandler(context) { + RouteFunction("Install", + base::Bind(&WebstoreBindings::Install, base::Unretained(this))); } -v8::Handle<v8::Value> WebstoreBindingsHandler::Install( +v8::Handle<v8::Value> WebstoreBindings::Install( const v8::Arguments& args) { WebFrame* frame = WebFrame::frameForCurrentContext(); if (!frame || !frame->view()) @@ -161,7 +108,7 @@ v8::Handle<v8::Value> WebstoreBindingsHandler::Install( } // static -bool WebstoreBindingsHandler::GetWebstoreItemIdFromFrame( +bool WebstoreBindings::GetWebstoreItemIdFromFrame( WebFrame* frame, const std::string& preferred_store_link_url, std::string* webstore_item_id, std::string* error) { if (frame != frame->top()) { @@ -247,8 +194,8 @@ bool WebstoreBindingsHandler::GetWebstoreItemIdFromFrame( return false; } -bool WebstoreBindingsHandler::OnMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(WebstoreBindingsHandler, message) +bool WebstoreBindings::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(WebstoreBindings, message) IPC_MESSAGE_HANDLER(ExtensionMsg_InlineWebstoreInstallResponse, OnInlineWebstoreInstallResponse) IPC_MESSAGE_UNHANDLED(CHECK(false) << "Unhandled IPC message") @@ -256,7 +203,7 @@ bool WebstoreBindingsHandler::OnMessageReceived(const IPC::Message& message) { return true; } -void WebstoreBindingsHandler::OnInlineWebstoreInstallResponse( +void WebstoreBindings::OnInlineWebstoreInstallResponse( int install_id, bool success, const std::string& error) { diff --git a/chrome/renderer/extensions/webstore_bindings.h b/chrome/renderer/extensions/webstore_bindings.h index 098f888..33ac48e 100644 --- a/chrome/renderer/extensions/webstore_bindings.h +++ b/chrome/renderer/extensions/webstore_bindings.h @@ -8,21 +8,37 @@ #include "base/compiler_specific.h" #include "chrome/renderer/extensions/chrome_v8_extension.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" class ChromeV8Context; // A V8 extension that creates an object at window.chrome.webstore. This object // allows JavaScript to initiate inline installs of apps that are listed in the // Chrome Web Store (CWS). -class WebstoreBindings : public ChromeV8Extension { +class WebstoreBindings : public ChromeV8Extension, + public ChromeV8ExtensionHandler { public: - explicit WebstoreBindings(ExtensionDispatcher* dispatcher); + explicit WebstoreBindings(ExtensionDispatcher* dispatcher, + ChromeV8Context* context); - protected: - virtual ChromeV8ExtensionHandler* CreateHandler( - ChromeV8Context* context) OVERRIDE; + // IPC::Channel::Listener + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; private: + v8::Handle<v8::Value> Install(const v8::Arguments& args); + + void OnInlineWebstoreInstallResponse( + int install_id, bool success, const std::string& error); + + // Extracts a Web Store item ID from a <link rel="chrome-webstore-item" + // href="https://chrome.google.com/webstore/detail/id"> node found in the + // frame. On success, true will be returned and the |webstore_item_id| + // parameter will be populated with the ID. On failure, false will be returned + // and |error| will be populated with the error. + static bool GetWebstoreItemIdFromFrame( + WebKit::WebFrame* frame, const std::string& preferred_store_link_url, + std::string* webstore_item_id, std::string* error); + DISALLOW_COPY_AND_ASSIGN(WebstoreBindings); }; diff --git a/chrome/renderer/module_system.cc b/chrome/renderer/module_system.cc index 6c685f3..30f5906 100644 --- a/chrome/renderer/module_system.cc +++ b/chrome/renderer/module_system.cc @@ -11,18 +11,11 @@ namespace { -v8::Handle<v8::String> GetResource(int resourceId) { - const ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance(); - return v8::String::NewExternal(new StaticV8ExternalAsciiStringResource( - resource_bundle.GetRawDataResource(resourceId))); -} - } // namespace -ModuleSystem::ModuleSystem(const std::map<std::string, std::string>* source_map) - : source_map_(source_map) { - RouteFunction("Run", - base::Bind(&ModuleSystem::Run, base::Unretained(this))); +ModuleSystem::ModuleSystem(SourceMap* source_map) + : source_map_(source_map), + natives_enabled_(true) { RouteFunction("GetSource", base::Bind(&ModuleSystem::GetSource, base::Unretained(this))); RouteFunction("GetNative", @@ -47,12 +40,21 @@ void ModuleSystem::RegisterNativeHandler(const std::string& name, linked_ptr<NativeHandler>(native_handler.release()); } +void ModuleSystem::RunString(const std::string& code, const std::string& name) { + v8::HandleScope handle_scope; + RunString(v8::String::New(code.c_str()), v8::String::New(name.c_str())); +} + void ModuleSystem::EnsureRequireLoaded() { v8::HandleScope handle_scope; if (!require_.IsEmpty()) return; v8::Handle<v8::Object> bootstrap = NewInstance(); - v8::Handle<v8::Value> result = RunString(GetResource(IDR_REQUIRE_JS)); + // NOTE v8 takes ownership of the StaticV8ExternalAsciiStringResource. + v8::Handle<v8::String> source = v8::String::NewExternal( + new StaticV8ExternalAsciiStringResource(GetResource(IDR_REQUIRE_JS))); + v8::Handle<v8::Value> result = RunString(source, + v8::String::New("require.js")); v8::Handle<v8::Function> require_factory = v8::Handle<v8::Function>::Cast(result); CHECK(!require_factory.IsEmpty()) @@ -67,32 +69,38 @@ void ModuleSystem::EnsureRequireLoaded() { v8::Handle<v8::Function>::Cast(require)); } -v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code) { +v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code, + v8::Handle<v8::String> name) { v8::HandleScope handle_scope; - return handle_scope.Close(v8::Script::New(code)->Run()); -} - -v8::Handle<v8::Value> ModuleSystem::Run(const v8::Arguments& args) { - CHECK_EQ(1, args.Length()); - v8::HandleScope handle_scope; - return handle_scope.Close(v8::Script::New(args[0]->ToString())->Run()); + return handle_scope.Close(v8::Script::New(code, name)->Run()); } v8::Handle<v8::Value> ModuleSystem::GetSource(const v8::Arguments& args) { CHECK_EQ(1, args.Length()); + + v8::HandleScope handle_scope; std::string module_name = *v8::String::AsciiValue(args[0]->ToString()); - std::map<std::string, std::string>::const_iterator p = - source_map_->find(module_name); - if (p == source_map_->end()) + if (!source_map_->Contains(module_name)) return v8::Undefined(); - return v8::String::New(p->second.c_str()); + return handle_scope.Close(source_map_->GetSource(module_name)); } v8::Handle<v8::Value> ModuleSystem::GetNative(const v8::Arguments& args) { CHECK_EQ(1, args.Length()); + if (!natives_enabled_) + return ThrowException("Natives disabled"); std::string native_name = *v8::String::AsciiValue(args[0]->ToString()); NativeHandlerMap::iterator i = native_handler_map_.find(native_name); if (i == native_handler_map_.end()) return v8::Undefined(); return i->second->NewInstance(); } + +base::StringPiece ModuleSystem::GetResource(int resourceId) { + const ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance(); + return resource_bundle.GetRawDataResource(resourceId); +} + +v8::Handle<v8::Value> ModuleSystem::ThrowException(const std::string& message) { + return v8::ThrowException(v8::String::New(message.c_str())); +} diff --git a/chrome/renderer/module_system.h b/chrome/renderer/module_system.h index b29d8d6..da93423 100644 --- a/chrome/renderer/module_system.h +++ b/chrome/renderer/module_system.h @@ -9,12 +9,15 @@ #include "base/compiler_specific.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" +#include "base/string_piece.h" #include "chrome/renderer/native_handler.h" #include "v8/include/v8.h" #include <map> #include <string> +class SourceMap; + // A module system for JS similar to node.js' require() function. // Each module has three variables in the global scope: // - exports, an object returned to dependencies who require() this @@ -27,10 +30,20 @@ // // Each module in a ModuleSystem is executed at most once and its exports // object cached. +// +// Note that a ModuleSystem must be used only in conjunction with a single +// v8::Context. +// TODO(koz): Rename this to JavaScriptModuleSystem. class ModuleSystem : public NativeHandler { public: + class SourceMap { + public: + virtual v8::Handle<v8::Value> GetSource(const std::string& name) = 0; + virtual bool Contains(const std::string& name) = 0; + }; + // |source_map| is a weak pointer. - explicit ModuleSystem(const std::map<std::string, std::string>* source_map); + explicit ModuleSystem(SourceMap* source_map); virtual ~ModuleSystem(); // Require the specified module. This is the equivalent of calling @@ -41,18 +54,27 @@ class ModuleSystem : public NativeHandler { // calls to requireNative(|name|) from JS will return a new object created by // |native_handler|. void RegisterNativeHandler(const std::string& name, - scoped_ptr<NativeHandler> native_handler); + scoped_ptr<NativeHandler> native_handler); + + // Executes |code| in the current context with |name| as the filename. + void RunString(const std::string& code, const std::string& name); + + // When false |natives_enabled_| causes calls to GetNative() (the basis of + // requireNative() in JS) to throw an exception. + void set_natives_enabled(bool natives_enabled) { + natives_enabled_ = natives_enabled; + } private: + typedef std::map<std::string, linked_ptr<NativeHandler> > NativeHandlerMap; + // Ensure that require_ has been evaluated from require.js. void EnsureRequireLoaded(); - // Run |code| in the current context. - v8::Handle<v8::Value> RunString(v8::Handle<v8::String> code); - - // Run the given code in the current context. - // |args[0]| - the code to execute. - v8::Handle<v8::Value> Run(const v8::Arguments& args); + // Run |code| in the current context with the name |name| used for stack + // traces. + v8::Handle<v8::Value> RunString(v8::Handle<v8::String> code, + v8::Handle<v8::String> name); // Return the named source file stored in the source map. // |args[0]| - the name of a source file in source_map_. @@ -63,12 +85,17 @@ class ModuleSystem : public NativeHandler { // |args[0]| - the name of a native handler object. v8::Handle<v8::Value> GetNative(const v8::Arguments& args); + base::StringPiece GetResource(int resource_id); + + // Throws an exception in the calling JS context. + v8::Handle<v8::Value> ThrowException(const std::string& message); + // A map from module names to the JS source for that module. GetSource() // performs a lookup on this map. - const std::map<std::string, std::string>* source_map_; - typedef std::map<std::string, linked_ptr<NativeHandler> > NativeHandlerMap; + SourceMap* source_map_; NativeHandlerMap native_handler_map_; v8::Handle<v8::Function> require_; + bool natives_enabled_; }; #endif // CHROME_RENDERER_MODULE_SYSTEM_H_ diff --git a/chrome/renderer/module_system_unittest.cc b/chrome/renderer/module_system_unittest.cc index bed8a27..47584a3 100644 --- a/chrome/renderer/module_system_unittest.cc +++ b/chrome/renderer/module_system_unittest.cc @@ -4,12 +4,14 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" +#include "base/string_piece.h" #include "chrome/renderer/module_system.h" #include "testing/gtest/include/gtest/gtest.h" #include <map> #include <string> +// Native JS functions for doing asserts. class AssertNatives : public NativeHandler { public: AssertNatives() @@ -33,22 +35,69 @@ class AssertNatives : public NativeHandler { bool failed_; }; +class StringSourceMap : public ModuleSystem::SourceMap { + public: + StringSourceMap() {} + + v8::Handle<v8::Value> GetSource(const std::string& name) OVERRIDE { + if (source_map_.count(name) == 0) + return v8::Undefined(); + return v8::String::New(source_map_[name].c_str()); + } + + bool Contains(const std::string& name) OVERRIDE { + return source_map_.count(name); + } + + void RegisterModule(const std::string& name, const std::string& source) { + source_map_[name] = source; + } + + private: + std::map<std::string, std::string> source_map_; +}; + +// Native JS functions for disabling injection in ModuleSystem. +class DisableNativesHandler : public NativeHandler { + public: + explicit DisableNativesHandler(ModuleSystem* module_system) + : module_system_(module_system) { + RouteFunction("DisableNatives", + base::Bind(&DisableNativesHandler::DisableNatives, + base::Unretained(this))); + } + + v8::Handle<v8::Value> DisableNatives(const v8::Arguments& args) { + module_system_->set_natives_enabled(false); + return v8::Undefined(); + } + + private: + ModuleSystem* module_system_; +}; + class ModuleSystemTest : public testing::Test { public: ModuleSystemTest() : context_(v8::Context::New()), - assert_natives_(new AssertNatives()) { + handle_scope_(), + assert_natives_(new AssertNatives()), + source_map_(new StringSourceMap()), + module_system_(new ModuleSystem(source_map_)) { context_->Enter(); - source_map_["add"] = "exports.Add = function(x, y) { return x + y; };"; - module_system_.reset(new ModuleSystem(&source_map_)); module_system_->RegisterNativeHandler("assert", scoped_ptr<NativeHandler>( assert_natives_)); + RegisterModule("add", "exports.Add = function(x, y) { return x + y; };"); } ~ModuleSystemTest() { context_.Dispose(); } + void RegisterModule(const std::string& name, const std::string& code) { + source_map_->RegisterModule(name, code); + } + virtual void TearDown() { // All tests must call a native function at least once. ASSERT_TRUE(assert_natives_->native_function_called()); @@ -56,45 +105,63 @@ class ModuleSystemTest : public testing::Test { ASSERT_FALSE(try_catch_.HasCaught()); } + v8::Persistent<v8::Context> context_; v8::HandleScope handle_scope_; v8::TryCatch try_catch_; - v8::Persistent<v8::Context> context_; AssertNatives* assert_natives_; - std::map<std::string, std::string> source_map_; + StringSourceMap* source_map_; scoped_ptr<ModuleSystem> module_system_; }; TEST_F(ModuleSystemTest, TestRequire) { - source_map_["test"] = + RegisterModule("test", "var Add = require('add').Add;" - "requireNative('assert').AssertTrue(Add(3, 5) == 8);"; + "requireNative('assert').AssertTrue(Add(3, 5) == 8);"); module_system_->Require("test"); } TEST_F(ModuleSystemTest, TestNestedRequire) { - source_map_["double"] = + RegisterModule("double", "var Add = require('add').Add;" - "exports.Double = function(x) { return Add(x, x); };"; - source_map_["test"] = + "exports.Double = function(x) { return Add(x, x); };"); + RegisterModule("test", "var Double = require('double').Double;" - "requireNative('assert').AssertTrue(Double(3) == 6);"; + "requireNative('assert').AssertTrue(Double(3) == 6);"); module_system_->Require("test"); } TEST_F(ModuleSystemTest, TestModuleInsulation) { - source_map_["x"] = + RegisterModule("x", "var x = 10;" - "exports.X = function() { return x; };"; - source_map_["y"] = + "exports.X = function() { return x; };"); + RegisterModule("y", "var x = 15;" "require('x');" - "exports.Y = function() { return x; };"; - source_map_["test"] = + "exports.Y = function() { return x; };"); + RegisterModule("test", "var Y = require('y').Y;" "var X = require('x').X;" "var assert = requireNative('assert');" "assert.AssertTrue(!this.hasOwnProperty('x'));" "assert.AssertTrue(Y() == 15);" - "assert.AssertTrue(X() == 10);"; + "assert.AssertTrue(X() == 10);"); + module_system_->Require("test"); +} + +TEST_F(ModuleSystemTest, TestDisableNativesPreventsNativeModulesBeingLoaded) { + module_system_->RegisterNativeHandler("disable", + scoped_ptr<NativeHandler>( + new DisableNativesHandler(module_system_.get()))); + RegisterModule("test", + "var assert = requireNative('assert');" + "var disable = requireNative('disable');" + "disable.DisableNatives();" + "var caught = false;" + "try {" + " requireNative('assert');" + "} catch (e) {" + " caught = true;" + "}" + "assert.AssertTrue(caught);"); module_system_->Require("test"); } diff --git a/chrome/renderer/native_handler.cc b/chrome/renderer/native_handler.cc index 614df08..afa21ff 100644 --- a/chrome/renderer/native_handler.cc +++ b/chrome/renderer/native_handler.cc @@ -28,9 +28,18 @@ v8::Handle<v8::Value> NativeHandler::Router(const v8::Arguments& args) { void NativeHandler::RouteFunction(const std::string& name, const HandlerFunction& handler_function) { linked_ptr<HandlerFunction> function(new HandlerFunction(handler_function)); + // TODO(koz): Investigate using v8's MakeWeak() function instead of holding + // on to these pointers here. handler_functions_.push_back(function); v8::Handle<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(Router, v8::External::New(function.get())); object_template_->Set(name.c_str(), function_template); } + +void NativeHandler::RouteStaticFunction(const std::string& name, + const HandlerFunc handler_func) { + v8::Handle<v8::FunctionTemplate> function_template = + v8::FunctionTemplate::New(handler_func, v8::External::New(this)); + object_template_->Set(name.c_str(), function_template); +} diff --git a/chrome/renderer/native_handler.h b/chrome/renderer/native_handler.h index b4d3078..f595a0d 100644 --- a/chrome/renderer/native_handler.h +++ b/chrome/renderer/native_handler.h @@ -16,6 +16,12 @@ // A NativeHandler is a factory for JS objects with functions on them that map // to native C++ functions. Subclasses should call RouteFunction() in their // constructor to define functions on the created JS objects. +// +// NativeHandlers are intended to be used with a ModuleSystem. The ModuleSystem +// will assume ownership of the NativeHandler, and as a ModuleSystem is tied to +// a single v8::Context, this implies that NativeHandlers will also be tied to +// a single v8::context. +// TODO(koz): Rename this to NativeJavaScriptModule. class NativeHandler { public: explicit NativeHandler(); @@ -26,6 +32,7 @@ class NativeHandler { v8::Handle<v8::Object> NewInstance(); protected: + typedef v8::Handle<v8::Value> (*HandlerFunc)(const v8::Arguments&); typedef base::Callback<v8::Handle<v8::Value>(const v8::Arguments&)> HandlerFunction; @@ -35,6 +42,9 @@ class NativeHandler { void RouteFunction(const std::string& name, const HandlerFunction& handler_function); + void RouteStaticFunction(const std::string& name, + const HandlerFunc handler_func); + private: static v8::Handle<v8::Value> Router(const v8::Arguments& args); diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index 82ecee7..99cd777 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -26,6 +26,7 @@ without changes to the corresponding grd file. fb9 --> <include name="IDR_REQUIRE_JS" file="resources\require.js" type="BINDATA" /> <include name="IDR_SAD_PLUGIN" file="resources\sadplugin.png" type="BINDATA" /> <include name="IDR_SCHEMA_GENERATED_BINDINGS_JS" file="resources\extensions\schema_generated_bindings.js" type="BINDATA" /> + <include name="IDR_SETUP_BINDINGS_JS" file="resources\extensions\setup_bindings.js" type="BINDATA" /> <include name="IDR_WEBSTORE_BINDINGS_JS" file="resources\extensions\webstore.js" type="BINDATA" /> <!-- Custom bindings for extension APIs. --> diff --git a/chrome/renderer/resource_bundle_source_map.cc b/chrome/renderer/resource_bundle_source_map.cc new file mode 100644 index 0000000..2c06b7b --- /dev/null +++ b/chrome/renderer/resource_bundle_source_map.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/resource_bundle_source_map.h" + +#include "ui/base/resource/resource_bundle.h" + +ResourceBundleSourceMap::ResourceBundleSourceMap( + const ui::ResourceBundle* resource_bundle) + : resource_bundle_(resource_bundle) { +} + +ResourceBundleSourceMap::~ResourceBundleSourceMap() { +} + +void ResourceBundleSourceMap::RegisterSource(const std::string& name, + int resource_id) { + resource_id_map_[name] = resource_id; +} + +v8::Handle<v8::Value> ResourceBundleSourceMap::GetSource( + const std::string& name) { + if (!Contains(name)) + return v8::Undefined(); + int resource_id = resource_id_map_[name]; + return ConvertString(resource_bundle_->GetRawDataResource(resource_id)); +} + +bool ResourceBundleSourceMap::Contains(const std::string& name) { + return resource_id_map_.count(name) > 0; +} + +v8::Handle<v8::String> ResourceBundleSourceMap::ConvertString( + const base::StringPiece& string) { + // v8 takes ownership of the StaticV8ExternalAsciiStringResource (see + // v8::String::NewExternal()). + return v8::String::NewExternal( + new StaticV8ExternalAsciiStringResource(string)); +} diff --git a/chrome/renderer/resource_bundle_source_map.h b/chrome/renderer/resource_bundle_source_map.h new file mode 100644 index 0000000..142930c --- /dev/null +++ b/chrome/renderer/resource_bundle_source_map.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_RESOURCE_BUNDLE_SOURCE_MAP_H_ +#define CHROME_RENDERER_RESOURCE_BUNDLE_SOURCE_MAP_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/memory/linked_ptr.h" +#include "base/string_piece.h" +#include "chrome/renderer/module_system.h" +#include "chrome/renderer/static_v8_external_string_resource.h" +#include "v8/include/v8.h" + +#include <map> +#include <string> + +namespace ui { + class ResourceBundle; +} + +class ResourceBundleSourceMap : public ModuleSystem::SourceMap { + public: + explicit ResourceBundleSourceMap(const ui::ResourceBundle* resource_bundle); + ~ResourceBundleSourceMap(); + + virtual v8::Handle<v8::Value> GetSource(const std::string& name) OVERRIDE; + virtual bool Contains(const std::string& name) OVERRIDE; + + void RegisterSource(const std::string& name, int resource_id); + + private: + v8::Handle<v8::String> ConvertString(const base::StringPiece& string); + + const ui::ResourceBundle* resource_bundle_; + std::map<std::string, int> resource_id_map_; +}; + +#endif // CHROME_RENDERER_RESOURCE_BUNDLE_SOURCE_MAP_H_ diff --git a/chrome/renderer/resources/extensions/apitest.js b/chrome/renderer/resources/extensions/apitest.js index 7e7e62f..6f015ef 100644 --- a/chrome/renderer/resources/extensions/apitest.js +++ b/chrome/renderer/resources/extensions/apitest.js @@ -1,12 +1,10 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // extension_apitest.js // mini-framework for ExtensionApiTest browser tests -var chrome = chrome || {}; -(function() { chrome.test = chrome.test || {}; chrome.test.tests = chrome.test.tests || []; @@ -275,4 +273,3 @@ var chrome = chrome || {}; chrome.test.tests = tests; chrome.test.runNextTest(); }; -})(); diff --git a/chrome/renderer/resources/extensions/app.js b/chrome/renderer/resources/extensions/app.js index 8fbce65..7337d86 100644 --- a/chrome/renderer/resources/extensions/app.js +++ b/chrome/renderer/resources/extensions/app.js @@ -1,17 +1,15 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var chrome = chrome || {}; -(function() { - native function GetChromeHidden(); - native function GetIsInstalled(); - native function Install(); - native function GetDetails(); - native function GetDetailsForFrame(); - native function GetAppNotifyChannel(); + var natives = requireNative('app'); + var GetIsInstalled = natives.GetIsInstalled; + var Install = natives.Install; + var GetDetails = natives.GetDetails; + var GetDetailsForFrame = natives.GetDetailsForFrame; + var GetAppNotifyChannel = natives.GetAppNotifyChannel; - var chromeHidden = GetChromeHidden(); + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); var callbacks = {}; var nextCallbackId = 1; @@ -41,4 +39,3 @@ var chrome = chrome || {}; delete callbacks[callbackId]; } }; -})(); diff --git a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js index 8b791a7..137da5b 100644 --- a/chrome/renderer/resources/extensions/browser_action_custom_bindings.js +++ b/chrome/renderer/resources/extensions/browser_action_custom_bindings.js @@ -4,11 +4,9 @@ // Custom bindings for the browserAction API. -(function() { +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -native function GetChromeHidden(); - -GetChromeHidden().registerCustomHook('browserAction', function(bindingsAPI) { +chromeHidden.registerCustomHook('browserAction', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; var setIcon = bindingsAPI.setIcon; @@ -16,5 +14,3 @@ GetChromeHidden().registerCustomHook('browserAction', function(bindingsAPI) { setIcon(details, this.name, this.definition.parameters, 'browser action'); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/chrome_private_custom_bindings.js b/chrome/renderer/resources/extensions/chrome_private_custom_bindings.js index c3f712b..b50bbee 100644 --- a/chrome/renderer/resources/extensions/chrome_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/chrome_private_custom_bindings.js @@ -4,17 +4,15 @@ // Custom bindings for the chromePrivate API. -(function() { +var chromePrivate = requireNative('chrome_private'); +var DecodeJPEG = chromePrivate.DecodeJPEG; -native function GetChromeHidden(); -native function DecodeJPEG(jpegImage); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -GetChromeHidden().registerCustomHook('chromePrivate', function(bindingsAPI) { +chromeHidden.registerCustomHook('chromePrivate', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; apiFunctions.setHandleRequest('decodeJPEG', function(jpeg_image) { return DecodeJPEG(jpeg_image); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/content_settings_custom_bindings.js b/chrome/renderer/resources/extensions/content_settings_custom_bindings.js index 14bc91c..bc98a90 100644 --- a/chrome/renderer/resources/extensions/content_settings_custom_bindings.js +++ b/chrome/renderer/resources/extensions/content_settings_custom_bindings.js @@ -4,11 +4,7 @@ // Custom bindings for the contentSettings API. -(function() { - -native function GetChromeHidden(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomType('ContentSetting', function(typesAPI) { var sendRequest = typesAPI.sendRequest; @@ -54,5 +50,3 @@ chromeHidden.registerCustomType('ContentSetting', function(typesAPI) { return ContentSetting; }); - -})(); diff --git a/chrome/renderer/resources/extensions/context_menus_custom_bindings.js b/chrome/renderer/resources/extensions/context_menus_custom_bindings.js index e4983e6..546140b 100644 --- a/chrome/renderer/resources/extensions/context_menus_custom_bindings.js +++ b/chrome/renderer/resources/extensions/context_menus_custom_bindings.js @@ -4,12 +4,10 @@ // Custom bindings for the contextMenus API. -(function() { +var contextMenus = requireNative('context_menus'); +var GetNextContextMenuId = contextMenus.GetNextContextMenuId; -native function GetChromeHidden(); -native function GetNextContextMenuId(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('contextMenus', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; @@ -87,5 +85,3 @@ chromeHidden.registerCustomHook('contextMenus', function(bindingsAPI) { chromeHidden.contextMenus.handlers = {}; }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/devtools_custom_bindings.js b/chrome/renderer/resources/extensions/devtools_custom_bindings.js index d1ad34c..9d1d8eb 100644 --- a/chrome/renderer/resources/extensions/devtools_custom_bindings.js +++ b/chrome/renderer/resources/extensions/devtools_custom_bindings.js @@ -4,11 +4,9 @@ // Custom bindings for the devtools API. -(function() { +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -native function GetChromeHidden(); - -GetChromeHidden().registerCustomHook('devtools', function(bindingsAPI) { +chromeHidden.registerCustomHook('devtools', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; apiFunctions.setHandleRequest('getTabEvents', function(tabId) { @@ -23,5 +21,3 @@ GetChromeHidden().registerCustomHook('devtools', function(bindingsAPI) { return tabIdProxy; }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/event.js b/chrome/renderer/resources/extensions/event.js index 2cf78a8..c8a05cf 100644 --- a/chrome/renderer/resources/extensions/event.js +++ b/chrome/renderer/resources/extensions/event.js @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var chrome = chrome || {}; -(function () { - native function GetChromeHidden(); - native function AttachEvent(eventName); - native function DetachEvent(eventName, manual); - native function Print(); + var eventBindingsNatives = requireNative('event_bindings'); + var AttachEvent = eventBindingsNatives.AttachEvent; + var DetachEvent = eventBindingsNatives.DetachEvent; + var Print = eventBindingsNatives.Print; - var chromeHidden = GetChromeHidden(); + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); // Local implementation of JSON.parse & JSON.stringify that protect us // from being clobbered by an extension. @@ -311,4 +309,3 @@ var chrome = chrome || {}; chromeHidden.dispatchError = function(msg) { console.error(msg); }; -})(); diff --git a/chrome/renderer/resources/extensions/experimental.declarative_custom_bindings.js b/chrome/renderer/resources/extensions/experimental.declarative_custom_bindings.js index de47b6c..73d4642 100644 --- a/chrome/renderer/resources/extensions/experimental.declarative_custom_bindings.js +++ b/chrome/renderer/resources/extensions/experimental.declarative_custom_bindings.js @@ -4,11 +4,7 @@ // Custom bindings for the declarative API. -(function() { - -native function GetChromeHidden(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('experimental.declarative', function(bindingsAPI) { @@ -78,5 +74,3 @@ chromeHidden.registerCustomHook('experimental.declarative', this.definition.parameters); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/experimental.socket_custom_bindings.js b/chrome/renderer/resources/extensions/experimental.socket_custom_bindings.js index 52a8659..a5b2568 100644 --- a/chrome/renderer/resources/extensions/experimental.socket_custom_bindings.js +++ b/chrome/renderer/resources/extensions/experimental.socket_custom_bindings.js @@ -4,11 +4,10 @@ // Custom bindings for the experimental.socket API. -(function() { - native function GetChromeHidden(); - native function GetNextSocketEventId(); + var experimentalSocketNatives = requireNative('experimental_socket'); + var GetNextSocketEventId = experimentalSocketNatives.GetNextSocketEventId; - var chromeHidden = GetChromeHidden(); + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('experimental.socket', function(api) { var apiFunctions = api.apiFunctions; @@ -56,5 +55,3 @@ } }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/extension_custom_bindings.js b/chrome/renderer/resources/extensions/extension_custom_bindings.js index f746e2a..970e11f 100644 --- a/chrome/renderer/resources/extensions/extension_custom_bindings.js +++ b/chrome/renderer/resources/extensions/extension_custom_bindings.js @@ -4,13 +4,11 @@ // Custom bindings for the extension API. -(function() { +var extensionNatives = requireNative('extension'); +var GetExtensionViews = extensionNatives.GetExtensionViews; +var OpenChannelToExtension = extensionNatives.OpenChannelToExtension; -native function GetChromeHidden(); -native function GetExtensionViews(); -native function OpenChannelToExtension(sourceId, targetId, name); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); // This should match chrome.windows.WINDOW_ID_NONE. // @@ -144,5 +142,3 @@ chromeHidden.registerCustomHook('extension', throw new Error('Error connecting to extension ' + targetId); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/file_browser_handler_custom_bindings.js b/chrome/renderer/resources/extensions/file_browser_handler_custom_bindings.js index 9fb152c..44d1539 100644 --- a/chrome/renderer/resources/extensions/file_browser_handler_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_browser_handler_custom_bindings.js @@ -4,12 +4,11 @@ // Custom bindings for the fileBrowserHandler API. -(function() { +var fileBrowserNatives = requireNative('file_browser_handler'); +var GetExternalFileEntry = fileBrowserNatives.GetExternalFileEntry; -native function GetChromeHidden(); -native function GetExternalFileEntry(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -var chromeHidden = GetChromeHidden(); chromeHidden.Event.registerArgumentMassager('fileBrowserHandler.onExecute', function(args) { if (args.length < 2) @@ -23,5 +22,3 @@ chromeHidden.Event.registerArgumentMassager('fileBrowserHandler.onExecute', for (var i = 0; i < fileList.length; i++) fileList[i] = GetExternalFileEntry(fileList[i]); }); - -})(); diff --git a/chrome/renderer/resources/extensions/file_browser_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_browser_private_custom_bindings.js index 7b483b5..2423cfb 100644 --- a/chrome/renderer/resources/extensions/file_browser_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_browser_private_custom_bindings.js @@ -4,12 +4,10 @@ // Custom bindings for the fileBrowserPrivate API. -(function() { +var fileBrowserPrivateNatives = requireNative('file_browser_private'); +var GetLocalFileSystem = fileBrowserPrivateNatives.GetLocalFileSystem; -native function GetChromeHidden(); -native function GetLocalFileSystem(name, path); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('fileBrowserPrivate', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; @@ -25,5 +23,3 @@ chromeHidden.registerCustomHook('fileBrowserPrivate', function(bindingsAPI) { request.callback = null; }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/i18n_custom_bindings.js b/chrome/renderer/resources/extensions/i18n_custom_bindings.js index 8f9ca30..a9fa5a2 100644 --- a/chrome/renderer/resources/extensions/i18n_custom_bindings.js +++ b/chrome/renderer/resources/extensions/i18n_custom_bindings.js @@ -4,12 +4,12 @@ // Custom bindings for the i18n API. -(function() { +var i18nNatives = requireNative('i18n'); +var GetL10nMessage = i18nNatives.GetL10nMessage; -native function GetChromeHidden(); -native function GetL10nMessage(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -GetChromeHidden().registerCustomHook('i18n', +chromeHidden.registerCustomHook('i18n', function(bindingsAPI, extensionId) { var apiFunctions = bindingsAPI.apiFunctions; @@ -18,5 +18,3 @@ GetChromeHidden().registerCustomHook('i18n', return GetL10nMessage(messageName, substitutions, extensionId); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js index c6bbbfc..8f400c7 100644 --- a/chrome/renderer/resources/extensions/input.ime_custom_bindings.js +++ b/chrome/renderer/resources/extensions/input.ime_custom_bindings.js @@ -5,11 +5,9 @@ // Custom bindings for the input ime API. Only injected into the // v8 contexts for extensions which have permission for the API. -(function() { +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -native function GetChromeHidden(); - -GetChromeHidden().registerCustomHook('input.ime', function() { +chromeHidden.registerCustomHook('input.ime', function() { chrome.input.ime.onKeyEvent.dispatch = function(engineID, keyData) { var args = Array.prototype.slice.call(arguments); if (this.validate_) { @@ -36,5 +34,3 @@ GetChromeHidden().registerCustomHook('input.ime', function() { } }; }); - -})(); diff --git a/chrome/renderer/resources/extensions/json_schema.js b/chrome/renderer/resources/extensions/json_schema.js index f1fdf9e..bc51d97 100644 --- a/chrome/renderer/resources/extensions/json_schema.js +++ b/chrome/renderer/resources/extensions/json_schema.js @@ -38,9 +38,7 @@ // additional properties will be validated. //============================================================================== -(function() { -native function GetChromeHidden(); -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); function isInstanceOfClass(instance, className) { if (!instance) @@ -498,5 +496,3 @@ chromeHidden.JSONSchemaValidator.prototype.addError = chromeHidden.JSONSchemaValidator.prototype.resetErrors = function() { this.errors = []; }; - -})(); diff --git a/chrome/renderer/resources/extensions/miscellaneous_bindings.js b/chrome/renderer/resources/extensions/miscellaneous_bindings.js index 6bcfc11..a2d284d 100644 --- a/chrome/renderer/resources/extensions/miscellaneous_bindings.js +++ b/chrome/renderer/resources/extensions/miscellaneous_bindings.js @@ -7,16 +7,15 @@ // scripts or background pages. // See user_script_slave.cc for script that is loaded by content scripts only. -var chrome = chrome || {}; -(function () { - native function CloseChannel(portId, notifyBrowser); - native function PortAddRef(portId); - native function PortRelease(portId); - native function PostMessage(portId, msg); - native function GetChromeHidden(); - native function Print(); - - var chromeHidden = GetChromeHidden(); + require('json_schema'); + require('event_bindings'); + var miscNatives = requireNative('miscellaneous_bindings'); + var CloseChannel = miscNatives.CloseChannel; + var PortAddRef = miscNatives.PortAddRef; + var PortRelease = miscNatives.PortRelease; + var PostMessage = miscNatives.PostMessage; + + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); var manifestVersion; var extensionId; @@ -210,4 +209,3 @@ var chrome = chrome || {}; chrome.extension.inIncognitoContext = inIncognitoContext; }); -})(); diff --git a/chrome/renderer/resources/extensions/omnibox_custom_bindings.js b/chrome/renderer/resources/extensions/omnibox_custom_bindings.js index 13a3c61..37f8d92 100644 --- a/chrome/renderer/resources/extensions/omnibox_custom_bindings.js +++ b/chrome/renderer/resources/extensions/omnibox_custom_bindings.js @@ -5,9 +5,7 @@ // Custom bindings for the omnibox API. Only injected into the v8 contexts // for extensions which have permission for the omnibox API. -(function() { - -native function GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); // Remove invalid characters from |text| so that it is suitable to use // for |AutocompleteMatch::contents|. @@ -79,7 +77,7 @@ function parseOmniboxDescription(input) { return result; } -GetChromeHidden().registerCustomHook('omnibox', function(bindingsAPI) { +chromeHidden.registerCustomHook('omnibox', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; var sendRequest = bindingsAPI.sendRequest; @@ -108,5 +106,3 @@ GetChromeHidden().registerCustomHook('omnibox', function(bindingsAPI) { chrome.Event.prototype.dispatch.apply(this, [text, suggestCallback]); }; }); - -})(); diff --git a/chrome/renderer/resources/extensions/page_action_custom_bindings.js b/chrome/renderer/resources/extensions/page_action_custom_bindings.js index 722a57b..13336b1d 100644 --- a/chrome/renderer/resources/extensions/page_action_custom_bindings.js +++ b/chrome/renderer/resources/extensions/page_action_custom_bindings.js @@ -4,11 +4,9 @@ // Custom bindings for the pageAction API. -(function() { +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -native function GetChromeHidden(); - -GetChromeHidden().registerCustomHook('pageAction', function(bindingsAPI) { +chromeHidden.registerCustomHook('pageAction', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; var setIcon = bindingsAPI.setIcon; @@ -16,5 +14,3 @@ GetChromeHidden().registerCustomHook('pageAction', function(bindingsAPI) { setIcon(details, this.name, this.definition.parameters, 'page action'); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/page_actions_custom_bindings.js b/chrome/renderer/resources/extensions/page_actions_custom_bindings.js index 2a7a2de..d5ec888 100644 --- a/chrome/renderer/resources/extensions/page_actions_custom_bindings.js +++ b/chrome/renderer/resources/extensions/page_actions_custom_bindings.js @@ -4,13 +4,13 @@ // Custom bindings for the pageActions API. -(function() { +var pageActionsNatives = requireNative('page_actions'); +var GetCurrentPageActions = pageActionsNatives.GetCurrentPageActions; -native function GetChromeHidden(); -native function GetCurrentPageActions(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -GetChromeHidden().registerCustomHook('pageActions', - function(bindingsAPI, extensionId) { +chromeHidden.registerCustomHook('pageActions', + function(bindingsAPI, extensionId) { var pageActions = GetCurrentPageActions(extensionId); var oldStyleEventName = 'pageActions'; for (var i = 0; i < pageActions.length; ++i) { @@ -18,5 +18,3 @@ GetChromeHidden().registerCustomHook('pageActions', chrome.pageActions[pageActions[i]] = new chrome.Event(oldStyleEventName); } }); - -})(); diff --git a/chrome/renderer/resources/extensions/page_capture_custom_bindings.js b/chrome/renderer/resources/extensions/page_capture_custom_bindings.js index e8a7af4..0bcbb0b 100644 --- a/chrome/renderer/resources/extensions/page_capture_custom_bindings.js +++ b/chrome/renderer/resources/extensions/page_capture_custom_bindings.js @@ -4,13 +4,11 @@ // Custom bindings for the pageCapture API. -(function() { +var pageCaptureNatives = requireNative('page_capture'); +var CreateBlob = pageCaptureNatives.CreateBlob; +var SendResponseAck = pageCaptureNatives.SendResponseAck; -native function GetChromeHidden(); -native function CreateBlob(filePath); -native function SendResponseAck(requestId); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('pageCapture', function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; @@ -30,5 +28,3 @@ chromeHidden.registerCustomHook('pageCapture', function(bindingsAPI) { SendResponseAck(request.id); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/schema_generated_bindings.js b/chrome/renderer/resources/extensions/schema_generated_bindings.js index bc057d2..ab11923 100644 --- a/chrome/renderer/resources/extensions/schema_generated_bindings.js +++ b/chrome/renderer/resources/extensions/schema_generated_bindings.js @@ -5,15 +5,15 @@ // This script contains privileged chrome extension related javascript APIs. // It is loaded by pages whose URL has the chrome-extension protocol. -var chrome = chrome || {}; -(function() { - native function GetChromeHidden(); - native function GetExtensionAPIDefinition(); - native function GetNextRequestId(); - native function StartRequest(); - native function SetIconCommon(); + require('json_schema'); + require('event_bindings'); + var natives = requireNative('schema_generated_bindings'); + var GetExtensionAPIDefinition = natives.GetExtensionAPIDefinition; + var GetNextRequestId = natives.GetNextRequestId; + var StartRequest = natives.StartRequest; + var SetIconCommon = natives.SetIconCommon; - var chromeHidden = GetChromeHidden(); + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); // The object to generate the bindings for "internal" APIs in, so that // extensions can't directly call them (without access to chromeHidden), @@ -753,4 +753,3 @@ var chrome = chrome || {}; if (chrome.test) chrome.test.getApiDefinitions = GetExtensionAPIDefinition; }); -})(); diff --git a/chrome/renderer/resources/extensions/setup_bindings.js b/chrome/renderer/resources/extensions/setup_bindings.js new file mode 100644 index 0000000..86b0cd5 --- /dev/null +++ b/chrome/renderer/resources/extensions/setup_bindings.js @@ -0,0 +1,21 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var contextInfo = requireNative('context_info'); +var sgb = requireNative('schema_generated_bindings'); + +require('app'); +require('webstore'); + +if (contextInfo.IsBindingsAllowed()) { + require('miscellaneous_bindings'); + require('schema_generated_bindings'); + require('apitest'); + + // Load the custom bindings for each API. + sgb.GetExtensionAPIDefinition().forEach(function(apiDef) { + if (contextInfo.IsAPIAllowed(apiDef.namespace)) + require(apiDef.namespace); + }); +} diff --git a/chrome/renderer/resources/extensions/storage_custom_bindings.js b/chrome/renderer/resources/extensions/storage_custom_bindings.js index 1d358c2..a3c8a54 100644 --- a/chrome/renderer/resources/extensions/storage_custom_bindings.js +++ b/chrome/renderer/resources/extensions/storage_custom_bindings.js @@ -4,11 +4,7 @@ // Custom bindings for the storage API. -(function() { - -native function GetChromeHidden(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomType('StorageArea', function(typesAPI) { var sendRequest = typesAPI.sendRequest; @@ -43,5 +39,3 @@ chromeHidden.registerCustomType('StorageArea', function(typesAPI) { return StorageArea; }); - -})(); diff --git a/chrome/renderer/resources/extensions/tabs_custom_bindings.js b/chrome/renderer/resources/extensions/tabs_custom_bindings.js index dd66481..e0cc59c 100644 --- a/chrome/renderer/resources/extensions/tabs_custom_bindings.js +++ b/chrome/renderer/resources/extensions/tabs_custom_bindings.js @@ -4,12 +4,10 @@ // Custom bindings for the tabs API. -(function() { +var tabsNatives = requireNative('tabs'); +var OpenChannelToTab = tabsNatives.OpenChannelToTab; -native function GetChromeHidden(); -native function OpenChannelToTab(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('tabs', function(bindingsAPI, extensionId) { var apiFunctions = bindingsAPI.apiFunctions; @@ -44,5 +42,3 @@ chromeHidden.registerCustomHook('tabs', function(bindingsAPI, extensionId) { }); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/tts_custom_bindings.js b/chrome/renderer/resources/extensions/tts_custom_bindings.js index ef8011a..dee01d3 100644 --- a/chrome/renderer/resources/extensions/tts_custom_bindings.js +++ b/chrome/renderer/resources/extensions/tts_custom_bindings.js @@ -4,12 +4,10 @@ // Custom bindings for the tts API. -(function() { +var ttsNatives = requireNative('tts'); +var GetNextTTSEventId = ttsNatives.GetNextTTSEventId; -native function GetChromeHidden(); -native function GetNextTTSEventId(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomHook('tts', function(api) { var apiFunctions = api.apiFunctions; @@ -42,5 +40,3 @@ chromeHidden.registerCustomHook('tts', function(api) { return id; }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/tts_engine_custom_bindings.js b/chrome/renderer/resources/extensions/tts_engine_custom_bindings.js index 85e36b0..7c0067b 100644 --- a/chrome/renderer/resources/extensions/tts_engine_custom_bindings.js +++ b/chrome/renderer/resources/extensions/tts_engine_custom_bindings.js @@ -4,11 +4,9 @@ // Custom bindings for the ttsEngine API. -(function() { +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); -native function GetChromeHidden(); - -GetChromeHidden().registerCustomHook('ttsEngine', function() { +chromeHidden.registerCustomHook('ttsEngine', function() { chrome.ttsEngine.onSpeak.dispatch = function(text, options, requestId) { var sendTtsEvent = function(event) { chrome.ttsEngine.sendTtsEvent(requestId, event); @@ -17,5 +15,3 @@ GetChromeHidden().registerCustomHook('ttsEngine', function() { this, [text, options, sendTtsEvent]); }; }); - -})(); diff --git a/chrome/renderer/resources/extensions/types_custom_bindings.js b/chrome/renderer/resources/extensions/types_custom_bindings.js index 62dbe0a..48eba8a 100644 --- a/chrome/renderer/resources/extensions/types_custom_bindings.js +++ b/chrome/renderer/resources/extensions/types_custom_bindings.js @@ -4,11 +4,7 @@ // Custom bindings for the types API. -(function() { - -native function GetChromeHidden(); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); chromeHidden.registerCustomType('ChromeSetting', function(typesAPI) { var sendRequest = typesAPI.sendRequest; @@ -48,5 +44,3 @@ chromeHidden.registerCustomType('ChromeSetting', function(typesAPI) { return ChromeSetting; }); - -})(); diff --git a/chrome/renderer/resources/extensions/web_request_custom_bindings.js b/chrome/renderer/resources/extensions/web_request_custom_bindings.js index 564251e..392f66c 100644 --- a/chrome/renderer/resources/extensions/web_request_custom_bindings.js +++ b/chrome/renderer/resources/extensions/web_request_custom_bindings.js @@ -4,12 +4,10 @@ // Custom bindings for the webRequest API. -(function() { +var webRequestNatives = requireNative('web_request'); +var GetUniqueSubEventName = webRequestNatives.GetUniqueSubEventName; -native function GetChromeHidden(); -native function GetUniqueSubEventName(eventName); - -var chromeHidden = GetChromeHidden(); +var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); // WebRequestEvent object. This is used for special webRequest events with // extra parameters. Each invocation of addListener creates a new named @@ -172,5 +170,3 @@ chromeHidden.registerCustomHook('webRequest', function(api) { {forIOThread: true}); }); }); - -})(); diff --git a/chrome/renderer/resources/extensions/webstore.js b/chrome/renderer/resources/extensions/webstore.js index b387c46..14bacc5 100644 --- a/chrome/renderer/resources/extensions/webstore.js +++ b/chrome/renderer/resources/extensions/webstore.js @@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var chrome = chrome || {}; -(function() { - native function GetChromeHidden(); - native function Install(preferredStoreUrl, onSuccess, onFailure); + var webstoreNatives = requireNative('webstore'); + var Install = webstoreNatives.Install; - var chromeHidden = GetChromeHidden(); + var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); var pendingInstalls = {}; chrome.webstore = new function() { this.install = function( @@ -41,4 +39,3 @@ var chrome = chrome || {}; delete pendingInstall[installId]; } } -})(); diff --git a/chrome/renderer/resources/require.js b/chrome/renderer/resources/require.js index 34f3543..7108616 100644 --- a/chrome/renderer/resources/require.js +++ b/chrome/renderer/resources/require.js @@ -15,15 +15,9 @@ // // |bootstrap| contains the following fields: // - GetSource(module): returns the source code for |module| -// - Run(source): runs the string os JS |source| // - GetNative(nativeName): returns the named native object (function(bootstrap) { -function wrap(source) { - return "(function(require, requireNative, exports) {" + source + - "\n})"; -} - function ModuleLoader() { this.cache_ = {}; }; @@ -33,9 +27,8 @@ ModuleLoader.prototype.run = function(id) { if (!source) { return null; } - var wrappedSource = wrap(source); - var f = bootstrap.Run(wrappedSource); var exports = {}; + var f = new Function("require", "requireNative", "exports", source); f(require, requireNative, exports); return exports; }; @@ -53,7 +46,11 @@ ModuleLoader.prototype.load = function(id) { var moduleLoader = new ModuleLoader(); function requireNative(nativeName) { - return bootstrap.GetNative(nativeName); + var result = bootstrap.GetNative(nativeName); + if (!result) { + throw "No such native object: '" + nativeName + "'"; + } + return result; } function require(moduleId) { |