Chromium Code Reviews| Index: chrome/renderer/extensions/dispatcher.cc |
| diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc |
| index 095c786c57f88dcc5a7f3efce787d41d69036e2f..4afb7df9276c6fa31dcf585668577dcba16a72ac 100644 |
| --- a/chrome/renderer/extensions/dispatcher.cc |
| +++ b/chrome/renderer/extensions/dispatcher.cc |
| @@ -718,72 +718,110 @@ v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( |
| return handle_scope.Close(new_object); |
| } |
| -void Dispatcher::RegisterSchemaGeneratedBindings( |
| - ModuleSystem* module_system, |
| - ChromeV8Context* context) { |
| +void Dispatcher::AddOrRemoveBindings(ChromeV8Context* context) { |
| + v8::HandleScope handle_scope; |
| + v8::Context::Scope(context->v8_context()); |
|
not at google - send to devlin
2013/06/05 19:03:44
nit: new line after the scope declarations make it
cduvall
2013/06/05 23:27:59
Done.
cduvall
2013/06/06 00:01:41
Strangely, if I take out the v8::Context::Scope, a
cduvall
2013/06/06 00:33:42
Wow, looks like I'm a dummy. This line should be:
|
| std::set<std::string> apis = |
| ExtensionAPI::GetSharedInstance()->GetAllAPINames(); |
| for (std::set<std::string>::iterator it = apis.begin(); |
| it != apis.end(); ++it) { |
| const std::string& api_name = *it; |
| - if (!context->IsAnyFeatureAvailableToContext(api_name)) |
| + if (!context->IsAnyFeatureAvailableToContext(api_name)) { |
| + DeregisterBinding(api_name, context); |
| continue; |
| + } |
| Feature* feature = |
| BaseFeatureProvider::GetByName("api")->GetFeature(api_name); |
| if (feature && feature->IsInternal()) |
| continue; |
| - std::vector<std::string> split; |
| - base::SplitString(api_name, '.', &split); |
| - |
| - v8::Handle<v8::Object> bind_object = |
| - GetOrCreateChrome(context->v8_context()); |
| - |
| - // Check if this API has an ancestor. If the API's ancestor is available and |
| - // the API is not available, don't install the bindings for this API. If |
| - // the API is available and its ancestor is not, delete the ancestor and |
| - // install the bindings for the API. This is to prevent loading the ancestor |
| - // API schema if it will not be needed. |
| - // |
| - // For example: |
| - // If app is available and app.window is not, just install app. |
| - // If app.window is available and app is not, delete app and install |
| - // app.window on a new object so app does not have to be loaded. |
| - std::string ancestor_name; |
| - bool only_ancestor_available = false; |
| - for (size_t i = 0; i < split.size() - 1; ++i) { |
| - ancestor_name += (i ? ".": "") + split[i]; |
| - if (!ancestor_name.empty() && |
| - context->GetAvailability(ancestor_name).is_available() && |
| - !context->GetAvailability(api_name).is_available()) { |
| - only_ancestor_available = true; |
| - break; |
| - } |
| - bind_object = GetOrCreateObject(bind_object, split[i]); |
| - } |
| - if (only_ancestor_available) |
| - continue; |
| + RegisterBinding(api_name, context); |
| + } |
| +} |
| - if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) { |
| - InstallBindings(module_system, context->v8_context(), api_name); |
| - } else if (!source_map_.Contains(api_name)) { |
| - module_system->RegisterNativeHandler( |
| - api_name, |
| - scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( |
| - module_system, |
| - api_name, |
| - "binding"))); |
| - module_system->SetNativeLazyField(bind_object, |
| - split.back(), |
| - api_name, |
| - "binding"); |
| - } else { |
| - module_system->SetLazyField(bind_object, |
| - split.back(), |
| - api_name, |
| - "binding"); |
| +void Dispatcher::DeregisterBinding(const std::string& api_name, |
| + ChromeV8Context* context) { |
| + v8::HandleScope handle_scope; |
|
not at google - send to devlin
2013/06/05 19:03:44
handle scope shouldn't be necessary here, callers
cduvall
2013/06/05 23:27:59
Done.
|
| + std::string bind_name; |
| + v8::Handle<v8::Object> bind_object = |
| + GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); |
| + v8::Handle<v8::String> v8_bind_name = v8::String::New(bind_name.c_str()); |
| + if (bind_object->HasRealNamedProperty(v8_bind_name)) |
| + bind_object->Delete(v8_bind_name); |
| +} |
| + |
| +v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( |
| + const std::string& api_name, |
| + std::string* bind_name, |
| + ChromeV8Context* context) { |
| + v8::HandleScope handle_scope; |
|
not at google - send to devlin
2013/06/05 19:03:44
handle scope shouldn't be necessary here, callers
cduvall
2013/06/05 23:27:59
Done.
|
| + std::vector<std::string> split; |
| + base::SplitString(api_name, '.', &split); |
| + |
| + v8::Handle<v8::Object> bind_object; |
| + |
| + // Check if this API has an ancestor. If the API's ancestor is available and |
| + // the API is not available, don't install the bindings for this API. If |
| + // the API is available and its ancestor is not, delete the ancestor and |
| + // install the bindings for the API. This is to prevent loading the ancestor |
| + // API schema if it will not be needed. |
| + // |
| + // For example: |
| + // If app is available and app.window is not, just install app. |
| + // If app.window is available and app is not, delete app and install |
| + // app.window on a new object so app does not have to be loaded. |
| + std::string ancestor_name; |
| + bool only_ancestor_available = false; |
| + for (size_t i = 0; i < split.size() - 1; ++i) { |
| + ancestor_name += (i ? ".": "") + split[i]; |
| + if (!ancestor_name.empty() && |
| + context->GetAvailability(ancestor_name).is_available() && |
| + !context->GetAvailability(api_name).is_available()) { |
| + only_ancestor_available = true; |
| + break; |
| } |
| + if (bind_object.IsEmpty()) |
| + bind_object = GetOrCreateChrome(context->v8_context()); |
| + bind_object = GetOrCreateObject(bind_object, split[i]); |
| + } |
| + if (only_ancestor_available) |
| + return handle_scope.Close(v8::Handle<v8::Object>()); |
| + if (bind_name) |
| + *bind_name = split.back(); |
| + |
| + return handle_scope.Close(bind_object.IsEmpty() ? |
| + GetOrCreateChrome(context->v8_context()) : bind_object); |
| +} |
| + |
| +void Dispatcher::RegisterBinding(const std::string& api_name, |
| + ChromeV8Context* context) { |
| + std::string bind_name; |
| + v8::Handle<v8::Object> bind_object = |
| + GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); |
| + if (bind_object.IsEmpty()) |
| + return; |
| + |
| + ModuleSystem* module_system = context->module_system(); |
| + CHECK(module_system); |
|
not at google - send to devlin
2013/06/05 19:03:44
myeh, no point CHECKing here. maybe a DCHECK if yo
cduvall
2013/06/05 23:27:59
Done.
|
| + if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) { |
| + InstallBindings(module_system, context->v8_context(), api_name); |
| + } else if (!source_map_.Contains(api_name)) { |
| + module_system->RegisterNativeHandler( |
| + api_name, |
| + scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( |
| + module_system, |
| + api_name, |
| + "binding"))); |
| + module_system->SetNativeLazyField(bind_object, |
| + bind_name, |
| + api_name, |
| + "binding"); |
| + } else { |
| + module_system->SetLazyField(bind_object, |
| + bind_name, |
| + api_name, |
| + "binding"); |
| } |
| } |
| @@ -1019,35 +1057,38 @@ void Dispatcher::DidCreateScriptContext( |
| scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, |
| &source_map_)); |
| + context->set_module_system(module_system.Pass()); |
|
not at google - send to devlin
2013/06/05 19:03:44
to prevent callers from using the module system ac
cduvall
2013/06/05 23:27:59
Done.
|
| + |
| // Enable natives in startup. |
| - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system.get()); |
| + ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| + context->module_system()); |
| - RegisterNativeHandlers(module_system.get(), context); |
| + RegisterNativeHandlers(context->module_system(), context); |
| - module_system->RegisterNativeHandler("chrome", |
| + context->module_system()->RegisterNativeHandler("chrome", |
| scoped_ptr<NativeHandler>(new ChromeNativeHandler(context))); |
| - module_system->RegisterNativeHandler("chrome_hidden", |
| + context->module_system()->RegisterNativeHandler("chrome_hidden", |
| scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler(context))); |
| - module_system->RegisterNativeHandler("print", |
| + context->module_system()->RegisterNativeHandler("print", |
| scoped_ptr<NativeHandler>(new PrintNativeHandler(context))); |
| - module_system->RegisterNativeHandler("lazy_background_page", |
| + context->module_system()->RegisterNativeHandler("lazy_background_page", |
| scoped_ptr<NativeHandler>( |
| new LazyBackgroundPageNativeHandler(this, context))); |
| - module_system->RegisterNativeHandler("logging", |
| + context->module_system()->RegisterNativeHandler("logging", |
| scoped_ptr<NativeHandler>(new LoggingNativeHandler(context))); |
| - module_system->RegisterNativeHandler("schema_registry", |
| + context->module_system()->RegisterNativeHandler("schema_registry", |
| scoped_ptr<NativeHandler>( |
| new SchemaRegistryNativeHandler(v8_schema_registry(), context))); |
| - module_system->RegisterNativeHandler("v8_context", |
| + context->module_system()->RegisterNativeHandler("v8_context", |
| scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this))); |
| - module_system->RegisterNativeHandler("test_features", |
| + context->module_system()->RegisterNativeHandler("test_features", |
| scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context))); |
| int manifest_version = extension ? extension->manifest_version() : 1; |
| bool send_request_disabled = |
| (extension && Manifest::IsUnpackedLocation(extension->location()) && |
| BackgroundInfo::HasLazyBackgroundPage(extension)); |
| - module_system->RegisterNativeHandler("process", |
| + context->module_system()->RegisterNativeHandler("process", |
| scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler( |
| this, context, context->GetExtensionID(), |
| context->GetContextTypeDescription(), |
| @@ -1062,26 +1103,29 @@ void Dispatcher::DidCreateScriptContext( |
| case Feature::UNSPECIFIED_CONTEXT: |
| case Feature::WEB_PAGE_CONTEXT: |
| // TODO(kalman): see comment below about ExtensionAPI. |
| - InstallBindings(module_system.get(), v8_context, "app"); |
| - InstallBindings(module_system.get(), v8_context, "webstore"); |
| + InstallBindings(context->module_system(), v8_context, "app"); |
| + InstallBindings(context->module_system(), v8_context, "webstore"); |
| break; |
| case Feature::BLESSED_EXTENSION_CONTEXT: |
| case Feature::UNBLESSED_EXTENSION_CONTEXT: |
| case Feature::CONTENT_SCRIPT_CONTEXT: |
| - module_system->Require("json"); // see paranoid comment in json.js |
| + if (extension && !extension->is_platform_app()) |
| + context->module_system()->Require("miscellaneous_bindings"); |
| + // See paranoid comment in json.js. |
| + context->module_system()->Require("json"); |
| // TODO(kalman): move this code back out of the switch and execute it |
| // regardless of |context_type|. ExtensionAPI knows how to return the |
| // correct APIs, however, until it doesn't have a 2MB overhead we can't |
| // load it in every process. |
| - RegisterSchemaGeneratedBindings(module_system.get(), context); |
| + AddOrRemoveBindings(context); |
| break; |
| } |
| bool is_within_platform_app = IsWithinPlatformApp(frame); |
| // Inject custom JS into the platform app context. |
| if (is_within_platform_app) |
| - module_system->Require("platformApp"); |
| + context->module_system()->Require("platformApp"); |
| // Only platform apps support the <webview> tag, because the "webView" and |
| // "denyWebView" modules will affect the performance of DOM modifications |
| @@ -1091,11 +1135,11 @@ void Dispatcher::DidCreateScriptContext( |
| // Note: setting up the WebView class here, not the chrome.webview API. |
| // The API will be automatically set up when first used. |
| if (extension->HasAPIPermission(APIPermission::kWebView)) { |
| - module_system->Require("webView"); |
| + context->module_system()->Require("webView"); |
| if (Feature::GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV) |
| - module_system->Require("webViewExperimental"); |
| + context->module_system()->Require("webViewExperimental"); |
| } else { |
| - module_system->Require("denyWebView"); |
| + context->module_system()->Require("denyWebView"); |
| } |
| } |
| @@ -1106,17 +1150,15 @@ void Dispatcher::DidCreateScriptContext( |
| if (extension->HasAPIPermission(APIPermission::kAdView)) { |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableAdviewSrcAttribute)) { |
| - module_system->Require("adViewCustom"); |
| + context->module_system()->Require("adViewCustom"); |
| } |
| - module_system->Require("adView"); |
| + context->module_system()->Require("adView"); |
| } else { |
| - module_system->Require("denyAdView"); |
| + context->module_system()->Require("denyAdView"); |
| } |
| } |
| } |
| - context->set_module_system(module_system.Pass()); |
| - |
| VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); |
| } |
| @@ -1279,6 +1321,10 @@ void Dispatcher::OnUpdatePermissions(int reason_id, |
| PermissionsData::SetActivePermissions(extension, new_active); |
| AddOrRemoveOriginPermissions(reason, extension, explicit_hosts); |
| + v8_context_set().ForEach( |
| + extension_id, |
| + NULL, |
| + base::Bind(&Dispatcher::AddOrRemoveBindings, base::Unretained(this))); |
| } |
| void Dispatcher::OnUpdateTabSpecificPermissions( |