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( |