summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlfg <lfg@chromium.org>2014-09-12 15:58:28 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-12 23:02:10 +0000
commit0330a7e9fc13f03380f86916b0b2cf718f36b1f8 (patch)
tree6af1c962b32253b78ddaa3a7de39d5c59e742c78
parent311ecdf7e9ba01b0a8ccbd1488e312e13cf398c5 (diff)
downloadchromium_src-0330a7e9fc13f03380f86916b0b2cf718f36b1f8.zip
chromium_src-0330a7e9fc13f03380f86916b0b2cf718f36b1f8.tar.gz
chromium_src-0330a7e9fc13f03380f86916b0b2cf718f36b1f8.tar.bz2
Enabling webview in app_shell.
This CL registers the webview tag in extensions, allowing it to be used inside app_shell. The webview browser sample should be working with this patch. For now, not all the webview APIs are supported, the APIs that are not supported are: contextMenus, webrequest, declarativeWebRequest and permissions (videoCapture, pointerLock, geolocation). BUG=352293 Review URL: https://codereview.chromium.org/566863004 Cr-Commit-Position: refs/heads/master@{#294689}
-rw-r--r--athena/resources/athena_resources.gyp1
-rw-r--r--chrome/common/extensions/api/_api_features.json16
-rw-r--r--chrome/common/extensions/api/_permission_features.json16
-rw-r--r--chrome/common/extensions/permissions/chrome_api_permissions.cc2
-rw-r--r--chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc2
-rw-r--r--chrome/renderer/resources/extensions/chrome_web_view.js91
-rw-r--r--extensions/BUILD.gn1
-rw-r--r--extensions/browser/api/extensions_api_client.cc3
-rw-r--r--extensions/common/api/_api_features.json18
-rw-r--r--extensions/common/api/_permission_features.json17
-rw-r--r--extensions/common/permissions/extensions_api_permissions.cc2
-rw-r--r--extensions/extensions.gyp1
-rw-r--r--extensions/renderer/dispatcher.cc12
-rw-r--r--extensions/renderer/resources/web_view.js6
-rw-r--r--extensions/renderer/resources/web_view_events.js92
-rw-r--r--extensions/shell/browser/shell_browser_context.cc6
-rw-r--r--extensions/shell/browser/shell_browser_context.h1
17 files changed, 159 insertions, 128 deletions
diff --git a/athena/resources/athena_resources.gyp b/athena/resources/athena_resources.gyp
index 08a59e1..4a9f953 100644
--- a/athena/resources/athena_resources.gyp
+++ b/athena/resources/athena_resources.gyp
@@ -49,7 +49,6 @@
'<(SHARED_INTERMEDIATE_DIR)/components/component_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/components/strings/components_strings_en-US.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/app/resources/content_resources_100_percent.pak',
- '<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak',
'<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_browser_resources_100_percent.pak',
'<(SHARED_INTERMEDIATE_DIR)/ui/chromeos/resources/ui_chromeos_resources_100_percent.pak',
'<(SHARED_INTERMEDIATE_DIR)/ui/chromeos/strings/ui_chromeos_strings_en-US.pak',
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 1fb304f..ddee4fc 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -437,22 +437,6 @@
"dependencies": ["permission:gcm"],
"contexts": ["blessed_extension"]
},
- "guestViewInternal": [{
- "internal": true,
- "channel": "stable",
- "contexts": ["blessed_extension"]
- }, {
- // Component extensions can use the guestViewInternal API from iframes.
- "location": "component",
- "internal": true,
- "dependencies": ["permission:webview"],
- "contexts": ["unblessed_extension"]
- }, {
- "internal": true,
- "channel": "trunk",
- "contexts": ["webui"],
- "matches": ["chrome://extensions-frame/*", "chrome://extensions/*"]
- }],
"hangoutsPrivate": {
"channel": "stable",
"contexts": ["blessed_extension"],
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 5c92e87..83719e2 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -1042,19 +1042,5 @@
"webRequestBlocking": {
"channel": "stable",
"extension_types": ["extension", "legacy_packaged_app"]
- },
- "webview": [{
- "channel": "stable",
- "extension_types": ["platform_app"]
- }, {
- // General support for webview in component extensions still in progress.
- // Only allowed for whitelisted extensions until all the caveats are
- // addressed. Tracked in crbug/285151.
- "channel": "stable",
- "extension_types": ["extension"],
- "location": "component",
- "whitelist": [
- "D519188F86D9ACCEE0412007B227D9936EB9676B" // GAIA Component Extension
- ]
- }]
+ }
}
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 02e34e3..e4c6ccb 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -161,8 +161,6 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions()
PermissionMessage::kTabs},
{APIPermission::kWebRequest, "webRequest"},
{APIPermission::kWebRequestBlocking, "webRequestBlocking"},
- {APIPermission::kWebView, "webview",
- APIPermissionInfo::kFlagCannotBeOptional},
// Register private permissions.
{APIPermission::kScreenlockPrivate, "screenlockPrivate",
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 5778452..9ec8246 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -276,8 +276,6 @@ void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
.is_available()) {
module_system->Require("chromeWebViewExperimental");
}
- } else if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
- module_system->Require("denyWebView");
}
if (extensions::FeatureSwitch::app_view()->IsEnabled() &&
diff --git a/chrome/renderer/resources/extensions/chrome_web_view.js b/chrome/renderer/resources/extensions/chrome_web_view.js
index badbf62..8028ff0 100644
--- a/chrome/renderer/resources/extensions/chrome_web_view.js
+++ b/chrome/renderer/resources/extensions/chrome_web_view.js
@@ -6,9 +6,17 @@
var ChromeWebView = require('chromeWebViewInternal').ChromeWebView;
var CreateEvent = require('webViewEvents').CreateEvent;
+var DeclarativeWebRequestSchema =
+ requireNative('schema_registry').GetSchema('declarativeWebRequest');
var EventBindings = require('event_bindings');
+var IdGenerator = requireNative('id_generator');
+var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
+var WebRequestSchema =
+ requireNative('schema_registry').GetSchema('webRequest');
var WebViewInternal = require('webView').WebViewInternal
+var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage');
+
var CHROME_WEB_VIEW_EVENTS = {
'contextmenu': {
evt: CreateEvent('chromeWebViewInternal.contextmenu'),
@@ -20,6 +28,25 @@ var CHROME_WEB_VIEW_EVENTS = {
}
};
+function DeclarativeWebRequestEvent(opt_eventName,
+ opt_argSchemas,
+ opt_eventOptions,
+ opt_webViewInstanceId) {
+ var subEventName = opt_eventName + '/' + IdGenerator.GetNextId();
+ EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions,
+ opt_webViewInstanceId);
+
+ // TODO(lazyboy): When do we dispose this listener?
+ WebRequestMessageEvent.addListener(function() {
+ // Re-dispatch to subEvent's listeners.
+ $Function.apply(this.dispatch, this, $Array.slice(arguments));
+ }.bind(this), {instanceId: opt_webViewInstanceId || 0});
+}
+
+DeclarativeWebRequestEvent.prototype = {
+ __proto__: EventBindings.Event.prototype
+};
+
/**
* Implemented when the ChromeWebView API is available.
* @private
@@ -41,3 +68,67 @@ WebViewInternal.prototype.maybeHandleContextMenu = function(e, webViewEvent) {
var params = undefined;
ChromeWebView.showContextMenu(this.guestInstanceId, requestId, params);
};
+
+WebViewInternal.prototype.maybeSetupChromeWebViewEvents = function() {
+ var request = {};
+ var createWebRequestEvent = function(webRequestEvent) {
+ return function() {
+ if (!this[webRequestEvent.name]) {
+ this[webRequestEvent.name] =
+ new WebRequestEvent(
+ 'webViewInternal.' + webRequestEvent.name,
+ webRequestEvent.parameters,
+ webRequestEvent.extraParameters, webRequestEvent.options,
+ this.viewInstanceId);
+ }
+ return this[webRequestEvent.name];
+ }.bind(this);
+ }.bind(this);
+
+ var createDeclarativeWebRequestEvent = function(webRequestEvent) {
+ return function() {
+ if (!this[webRequestEvent.name]) {
+ // The onMessage event gets a special event type because we want
+ // the listener to fire only for messages targeted for this particular
+ // <webview>.
+ var EventClass = webRequestEvent.name === 'onMessage' ?
+ DeclarativeWebRequestEvent : EventBindings.Event;
+ this[webRequestEvent.name] =
+ new EventClass(
+ 'webViewInternal.' + webRequestEvent.name,
+ webRequestEvent.parameters,
+ webRequestEvent.options,
+ this.viewInstanceId);
+ }
+ return this[webRequestEvent.name];
+ }.bind(this);
+ }.bind(this);
+
+ for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) {
+ var eventSchema = DeclarativeWebRequestSchema.events[i];
+ var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema);
+ Object.defineProperty(
+ request,
+ eventSchema.name,
+ {
+ get: webRequestEvent,
+ enumerable: true
+ }
+ );
+ }
+
+ // Populate the WebRequest events from the API definition.
+ for (var i = 0; i < WebRequestSchema.events.length; ++i) {
+ var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]);
+ Object.defineProperty(
+ request,
+ WebRequestSchema.events[i].name,
+ {
+ get: webRequestEvent,
+ enumerable: true
+ }
+ );
+ }
+
+ this.setRequestPropertyOnWebViewNode(request);
+};
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 2769bdb..80f3f44 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -118,6 +118,7 @@ repack("shell_and_test_pak") {
# from generated_resources_en-US.pak. http://crbug.com/397250
"$root_gen_dir/chrome/generated_resources_en-US.pak",
"$root_gen_dir/chrome/renderer_resources_100_percent.pak",
+ "$root_gen_dir/content/app/strings/content_strings_en-US.pak",
"$root_gen_dir/content/content_resources.pak",
"$root_gen_dir/content/shell/shell_resources.pak",
"$root_gen_dir/extensions/extensions_renderer_resources.pak",
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index d0bc081..3f5ccbd 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
+#include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h"
namespace extensions {
class AppViewGuestDelegate;
@@ -51,7 +52,7 @@ WebViewGuestDelegate* ExtensionsAPIClient::CreateWebViewGuestDelegate(
WebViewPermissionHelperDelegate* ExtensionsAPIClient::
CreateWebViewPermissionHelperDelegate(
WebViewPermissionHelper* web_view_permission_helper) const {
- return NULL;
+ return new WebViewPermissionHelperDelegate(web_view_permission_helper);
}
scoped_refptr<RulesRegistry> ExtensionsAPIClient::GetRulesRegistry(
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 929ea42..dd5b3a7 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -67,6 +67,24 @@
"extension_types": ["extension", "legacy_packaged_app", "platform_app"],
"contexts": ["blessed_extension"]
},
+ "guestViewInternal": [
+ {
+ "internal": true,
+ "channel": "stable",
+ "contexts": ["blessed_extension"]
+ }, {
+ // Component extensions can use the guestViewInternal API from iframes.
+ "location": "component",
+ "internal": true,
+ "dependencies": ["permission:webview"],
+ "contexts": ["unblessed_extension"]
+ }, {
+ "internal": true,
+ "channel": "trunk",
+ "contexts": ["webui"],
+ "matches": ["chrome://extensions-frame/*", "chrome://extensions/*"]
+ }
+ ],
"hid": {
"dependencies": ["permission:hid"],
"contexts": ["blessed_extension"]
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 8cddf76..40a4726 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -309,5 +309,22 @@
"A434B90223C3C52F2B69DB494736B63C612C774D"
]
}
+ ],
+ "webview": [
+ {
+ "channel": "stable",
+ "extension_types": ["platform_app"]
+ },
+ {
+ // General support for webview in component extensions still in progress.
+ // Only allowed for whitelisted extensions until all the caveats are
+ // addressed. Tracked in crbug/285151.
+ "channel": "stable",
+ "extension_types": ["extension"],
+ "location": "component",
+ "whitelist": [
+ "D519188F86D9ACCEE0412007B227D9936EB9676B" // GAIA Component Extension
+ ]
+ }
]
}
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc
index 679136e..b4b2ddf 100644
--- a/extensions/common/permissions/extensions_api_permissions.cc
+++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -65,6 +65,8 @@ std::vector<APIPermissionInfo*> ExtensionsAPIPermissions::GetAllPermissions()
{APIPermission::kVideoCapture, "videoCapture",
APIPermissionInfo::kFlagNone, IDS_EXTENSION_PROMPT_WARNING_VIDEO_CAPTURE,
PermissionMessage::kVideoCapture},
+ {APIPermission::kWebView, "webview",
+ APIPermissionInfo::kFlagCannotBeOptional},
{APIPermission::kWindowShape, "app.window.shape"},
};
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index acb5bf1..b286936 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -994,6 +994,7 @@
# from generated_resources_en-US.pak. http://crbug.com/397250
'<(SHARED_INTERMEDIATE_DIR)/chrome/generated_resources_en-US.pak',
'<(SHARED_INTERMEDIATE_DIR)/chrome/renderer_resources_100_percent.pak',
+ '<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/content/shell_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_renderer_resources.pak',
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 163218c..80ee4ec 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -323,6 +323,18 @@ void Dispatcher::DidCreateScriptContext(
module_system->Require("platformApp");
}
+ // Note: setting up the WebView class here, not the chrome.webview API.
+ // The API will be automatically set up when first used.
+ if (context->GetAvailability("webViewInternal").is_available()) {
+ module_system->Require("webView");
+ if (context->GetAvailability("webViewExperimentalInternal")
+ .is_available()) {
+ module_system->Require("webViewExperimental");
+ }
+ } else if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
+ module_system->Require("denyWebView");
+ }
+
delegate_->RequireAdditionalModules(context, is_within_platform_app);
VLOG(1) << "Num tracked contexts: " << script_context_set_.size();
diff --git a/extensions/renderer/resources/web_view.js b/extensions/renderer/resources/web_view.js
index 610c65f..85c588c 100644
--- a/extensions/renderer/resources/web_view.js
+++ b/extensions/renderer/resources/web_view.js
@@ -1017,6 +1017,12 @@ window.addEventListener('readystatechange', function listener(event) {
WebViewInternal.prototype.maybeGetChromeWebViewEvents = function() {};
/**
+ * Implemented when the ChromeWebView API is available.
+ * @private
+ */
+WebViewInternal.prototype.maybeSetupChromeWebViewEvents = function() {};
+
+/**
* Implemented when the experimental API is available.
* @private
*/
diff --git a/extensions/renderer/resources/web_view_events.js b/extensions/renderer/resources/web_view_events.js
index 32b500c..137baa2e 100644
--- a/extensions/renderer/resources/web_view_events.js
+++ b/extensions/renderer/resources/web_view_events.js
@@ -4,14 +4,8 @@
// Event management for WebViewInternal.
-var DeclarativeWebRequestSchema =
- requireNative('schema_registry').GetSchema('declarativeWebRequest');
var EventBindings = require('event_bindings');
-var IdGenerator = requireNative('id_generator');
var MessagingNatives = requireNative('messaging_natives');
-var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
-var WebRequestSchema =
- requireNative('schema_registry').GetSchema('webRequest');
var WebView = require('webViewInternal').WebView;
var CreateEvent = function(name) {
@@ -21,7 +15,6 @@ var CreateEvent = function(name) {
var FrameNameChangedEvent = CreateEvent('webViewInternal.onFrameNameChanged');
var PluginDestroyedEvent = CreateEvent('webViewInternal.onPluginDestroyed');
-var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage');
// WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their
// associated extension event descriptor objects.
@@ -155,25 +148,6 @@ var WEB_VIEW_EVENTS = {
}
};
-function DeclarativeWebRequestEvent(opt_eventName,
- opt_argSchemas,
- opt_eventOptions,
- opt_webViewInstanceId) {
- var subEventName = opt_eventName + '/' + IdGenerator.GetNextId();
- EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions,
- opt_webViewInstanceId);
-
- // TODO(lazyboy): When do we dispose this listener?
- WebRequestMessageEvent.addListener(function() {
- // Re-dispatch to subEvent's listeners.
- $Function.apply(this.dispatch, this, $Array.slice(arguments));
- }.bind(this), {instanceId: opt_webViewInstanceId || 0});
-}
-
-DeclarativeWebRequestEvent.prototype = {
- __proto__: EventBindings.Event.prototype
-};
-
// Constructor.
function WebViewEvents(webViewInternal, viewInstanceId) {
this.webViewInternal = webViewInternal;
@@ -185,7 +159,7 @@ function WebViewEvents(webViewInternal, viewInstanceId) {
WebViewEvents.prototype.setup = function() {
this.setupFrameNameChangedEvent();
this.setupPluginDestroyedEvent();
- this.setupWebRequestEvents();
+ this.webViewInternal.maybeSetupChromeWebViewEvents();
this.webViewInternal.setupExperimentalContextMenus();
var events = this.getEvents();
@@ -206,70 +180,6 @@ WebViewEvents.prototype.setupPluginDestroyedEvent = function() {
}.bind(this), {instanceId: this.viewInstanceId});
};
-WebViewEvents.prototype.setupWebRequestEvents = function() {
- var request = {};
- var createWebRequestEvent = function(webRequestEvent) {
- return function() {
- if (!this[webRequestEvent.name]) {
- this[webRequestEvent.name] =
- new WebRequestEvent(
- 'webViewInternal.' + webRequestEvent.name,
- webRequestEvent.parameters,
- webRequestEvent.extraParameters, webRequestEvent.options,
- this.viewInstanceId);
- }
- return this[webRequestEvent.name];
- }.bind(this);
- }.bind(this);
-
- var createDeclarativeWebRequestEvent = function(webRequestEvent) {
- return function() {
- if (!this[webRequestEvent.name]) {
- // The onMessage event gets a special event type because we want
- // the listener to fire only for messages targeted for this particular
- // <webview>.
- var EventClass = webRequestEvent.name === 'onMessage' ?
- DeclarativeWebRequestEvent : EventBindings.Event;
- this[webRequestEvent.name] =
- new EventClass(
- 'webViewInternal.' + webRequestEvent.name,
- webRequestEvent.parameters,
- webRequestEvent.options,
- this.viewInstanceId);
- }
- return this[webRequestEvent.name];
- }.bind(this);
- }.bind(this);
-
- for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) {
- var eventSchema = DeclarativeWebRequestSchema.events[i];
- var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema);
- Object.defineProperty(
- request,
- eventSchema.name,
- {
- get: webRequestEvent,
- enumerable: true
- }
- );
- }
-
- // Populate the WebRequest events from the API definition.
- for (var i = 0; i < WebRequestSchema.events.length; ++i) {
- var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]);
- Object.defineProperty(
- request,
- WebRequestSchema.events[i].name,
- {
- get: webRequestEvent,
- enumerable: true
- }
- );
- }
-
- this.webViewInternal.setRequestPropertyOnWebViewNode(request);
-};
-
WebViewEvents.prototype.getEvents = function() {
var experimentalEvents = this.webViewInternal.maybeGetExperimentalEvents();
for (var eventName in experimentalEvents) {
diff --git a/extensions/shell/browser/shell_browser_context.cc b/extensions/shell/browser/shell_browser_context.cc
index ed18aa2..33a08e3 100644
--- a/extensions/shell/browser/shell_browser_context.cc
+++ b/extensions/shell/browser/shell_browser_context.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "extensions/shell/browser/shell_browser_context.h"
+
+#include "extensions/browser/guest_view/guest_view_manager.h"
#include "extensions/shell/browser/shell_special_storage_policy.h"
namespace extensions {
@@ -17,6 +19,10 @@ ShellBrowserContext::ShellBrowserContext()
ShellBrowserContext::~ShellBrowserContext() {
}
+content::BrowserPluginGuestManager* ShellBrowserContext::GetGuestManager() {
+ return GuestViewManager::FromBrowserContext(this);
+}
+
storage::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() {
return storage_policy_.get();
}
diff --git a/extensions/shell/browser/shell_browser_context.h b/extensions/shell/browser/shell_browser_context.h
index d65fca4..305ab2b7 100644
--- a/extensions/shell/browser/shell_browser_context.h
+++ b/extensions/shell/browser/shell_browser_context.h
@@ -22,6 +22,7 @@ class ShellBrowserContext : public content::ShellBrowserContext {
virtual ~ShellBrowserContext();
// content::BrowserContext implementation.
+ virtual content::BrowserPluginGuestManager* GetGuestManager() OVERRIDE;
virtual storage::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE;
// HACK: Pad the virtual function table so we trip an assertion if someone