diff options
21 files changed, 294 insertions, 8 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 1b6b4d7..f892bd4 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -589,6 +589,24 @@ void ChromeContentBrowserClient::RenderViewHostCreated( new extensions::MessageHandler(render_view_host); } +void ChromeContentBrowserClient::GuestWebContentsCreated( + WebContents* guest_web_contents, WebContents* embedder_web_contents) { + Profile* profile = Profile::FromBrowserContext( + embedder_web_contents->GetBrowserContext()); + ExtensionService* service = + extensions::ExtensionSystem::Get(profile)->extension_service(); + if (!service) + return; + const GURL& url = embedder_web_contents->GetSiteInstance()->GetSiteURL(); + const Extension* extension = service->extensions()-> + GetExtensionOrAppByURL(ExtensionURLInfo(url)); + if (!extension) + return; + std::vector<ExtensionMsg_Loaded_Params> extensions; + extensions.push_back(ExtensionMsg_Loaded_Params(extension)); + guest_web_contents->Send(new ExtensionMsg_Loaded(extensions)); +} + void ChromeContentBrowserClient::RenderProcessHostCreated( content::RenderProcessHost* host) { int id = host->GetID(); diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 7f83ed9..11ab133 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -59,6 +59,9 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { content::WebContents* web_contents) OVERRIDE; virtual void RenderViewHostCreated( content::RenderViewHost* render_view_host) OVERRIDE; + virtual void GuestWebContentsCreated( + content::WebContents* guest_web_contents, + content::WebContents* embedder_web_contents) OVERRIDE; virtual void RenderProcessHostCreated( content::RenderProcessHost* host) OVERRIDE; virtual content::WebUIControllerFactory* GetWebUIControllerFactory() OVERRIDE; diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index 441f422..e7e92f7 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc @@ -1388,6 +1388,7 @@ bool TabsUpdateFunction::UpdateURLIfPresent(DictionaryValue* update_props, ScriptExecutor::TOP_FRAME, extensions::UserScript::DOCUMENT_IDLE, ScriptExecutor::MAIN_WORLD, + false /* is_web_view */, base::Bind(&TabsUpdateFunction::OnExecuteCodeFinished, this)); *is_async = true; @@ -2131,6 +2132,7 @@ bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) { frame_scope, run_at, ScriptExecutor::ISOLATED_WORLD, + false /* is_web_view */, base::Bind(&ExecuteCodeInTabFunction::OnExecuteCodeFinished, this)); return true; } diff --git a/chrome/browser/extensions/api/webview/webview_api.cc b/chrome/browser/extensions/api/webview/webview_api.cc new file mode 100644 index 0000000..5457891 --- /dev/null +++ b/chrome/browser/extensions/api/webview/webview_api.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2013 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/browser/extensions/api/webview/webview_api.h" + +#include "chrome/common/extensions/api/webview.h" +#include "content/public/browser/render_view_host.h" + +using namespace extensions::api::webview; + +WebviewExecuteScriptFunction::WebviewExecuteScriptFunction() { +} + +WebviewExecuteScriptFunction::~WebviewExecuteScriptFunction() { +} + +bool WebviewExecuteScriptFunction::RunImpl() { + scoped_ptr<ExecuteScript::Params> params( + extensions::api::webview::ExecuteScript::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + content::RenderViewHost* guest_rvh = + content::RenderViewHost::FromID(params->process_id, params->route_id); + // If we haven't loaded a guest yet, then this will be NULL. + if (!guest_rvh) + return false; + content::WebContents* guest_web_contents = + content::WebContents::FromRenderViewHost(guest_rvh); + CHECK(guest_web_contents); + + ObserverList<extensions::TabHelper::ScriptExecutionObserver> + script_observers; + scoped_ptr<extensions::ScriptExecutor> script_executor( + new extensions::ScriptExecutor(guest_web_contents, &script_observers)); + + extensions::ScriptExecutor::FrameScope frame_scope = + params->details.all_frames.get() && *params->details.all_frames ? + extensions::ScriptExecutor::ALL_FRAMES : + extensions::ScriptExecutor::TOP_FRAME; + + extensions::UserScript::RunLocation run_at = + extensions::UserScript::UNDEFINED; + switch (params->details.run_at) { + case InjectDetails::RUN_AT_NONE: + case InjectDetails::RUN_AT_DOCUMENT_IDLE: + run_at = extensions::UserScript::DOCUMENT_IDLE; + break; + case InjectDetails::RUN_AT_DOCUMENT_START: + run_at = extensions::UserScript::DOCUMENT_START; + break; + case InjectDetails::RUN_AT_DOCUMENT_END: + run_at = extensions::UserScript::DOCUMENT_END; + break; + } + CHECK_NE(extensions::UserScript::UNDEFINED, run_at); + + script_executor->ExecuteScript( + GetExtension()->id(), + extensions::ScriptExecutor::JAVASCRIPT, + *params->details.code.get(), + frame_scope, + run_at, + extensions::ScriptExecutor::ISOLATED_WORLD, + true /* is_web_view */, + base::Bind( + &WebviewExecuteScriptFunction::OnExecuteCodeFinished, + this)); + + // Balanced in OnExecuteCodeFinished. + AddRef(); + return true; +} + +void WebviewExecuteScriptFunction::OnExecuteCodeFinished( + const std::string& error, + int32 on_page_id, + const GURL& on_url, + const ListValue& result) { + if (error.empty()) { + SetResult(result.DeepCopy()); + } else { + SetError(error); + } + SendResponse(error.empty()); + Release(); // Added in RunImpl(). +} + diff --git a/chrome/browser/extensions/api/webview/webview_api.h b/chrome/browser/extensions/api/webview/webview_api.h new file mode 100644 index 0000000..794232f --- /dev/null +++ b/chrome/browser/extensions/api/webview/webview_api.h @@ -0,0 +1,31 @@ +// Copyright (c) 2013 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_BROWSER_EXTENSIONS_API_WEBVIEW_WEBVIEW_API_H_ +#define CHROME_BROWSER_EXTENSIONS_API_WEBVIEW_WEBVIEW_API_H_ + +#include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/extensions/script_executor.h" + +class WebviewExecuteScriptFunction : public AsyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("webview.executeScript", WEBVIEW_EXECUTESCRIPT) + + WebviewExecuteScriptFunction(); + + protected: + virtual ~WebviewExecuteScriptFunction(); + + // ExtensionFunction implementation. + virtual bool RunImpl() OVERRIDE; + + private: + + void OnExecuteCodeFinished(const std::string& error, + int32 on_page_id, + const GURL& on_url, + const ListValue& result); + +}; +#endif // CHROME_BROWSER_EXTENSIONS_API_WEBVIEW_WEBVIEW_API_H_ diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h index 799c91a..8a2053e 100644 --- a/chrome/browser/extensions/extension_function_histogram_value.h +++ b/chrome/browser/extensions/extension_function_histogram_value.h @@ -409,6 +409,7 @@ enum HistogramValue { COOKIES_GETALLCOOKIESTORES, MEDIAGALLERIESPRIVATE_ADDGALLERYWATCH, MEDIAGALLERIESPRIVATE_REMOVEGALLERYWATCH, + WEBVIEW_EXECUTESCRIPT, ENUM_BOUNDARY // Last entry: Add new entries above. }; diff --git a/chrome/browser/extensions/script_executor.cc b/chrome/browser/extensions/script_executor.cc index 724c9a2..c5ed09f 100644 --- a/chrome/browser/extensions/script_executor.cc +++ b/chrome/browser/extensions/script_executor.cc @@ -115,6 +115,7 @@ void ScriptExecutor::ExecuteScript( ScriptExecutor::FrameScope frame_scope, UserScript::RunLocation run_at, ScriptExecutor::WorldType world_type, + bool is_web_view, const ExecuteScriptCallback& callback) { ExtensionMsg_ExecuteCode_Params params; params.request_id = next_request_id_++; @@ -124,6 +125,7 @@ void ScriptExecutor::ExecuteScript( params.all_frames = (frame_scope == ALL_FRAMES); params.run_at = static_cast<int>(run_at); params.in_main_world = (world_type == MAIN_WORLD); + params.is_web_view = is_web_view; // Handler handles IPCs and deletes itself on completion. new Handler(script_observers_, web_contents_, params, callback); diff --git a/chrome/browser/extensions/script_executor.h b/chrome/browser/extensions/script_executor.h index 4e2971d..7bfbf79 100644 --- a/chrome/browser/extensions/script_executor.h +++ b/chrome/browser/extensions/script_executor.h @@ -73,6 +73,7 @@ class ScriptExecutor { FrameScope frame_scope, UserScript::RunLocation run_at, WorldType world_type, + bool is_web_view, const ExecuteScriptCallback& callback); private: diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 3348b50..b7f33a9 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -431,6 +431,8 @@ 'browser/extensions/api/web_socket_proxy_private/web_socket_proxy_private_api.h', 'browser/extensions/api/webstore_private/webstore_private_api.cc', 'browser/extensions/api/webstore_private/webstore_private_api.h', + 'browser/extensions/api/webview/webview_api.cc', + 'browser/extensions/api/webview/webview_api.h', 'browser/extensions/app_host_installer_win.cc', 'browser/extensions/app_host_installer_win.h', 'browser/extensions/app_launcher.cc', diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp index 1e7d843..2fa847f 100644 --- a/chrome/common/extensions/api/api.gyp +++ b/chrome/common/extensions/api/api.gyp @@ -67,6 +67,7 @@ 'tab_capture.idl', 'tabs.json', 'usb.idl', + 'webview.json', 'web_navigation.json', 'web_request.json', 'windows.json', diff --git a/chrome/common/extensions/api/webview.json b/chrome/common/extensions/api/webview.json new file mode 100644 index 0000000..c6539ab --- /dev/null +++ b/chrome/common/extensions/api/webview.json @@ -0,0 +1,72 @@ +// Copyright (c) 2013 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. + +[ + { + "namespace": "webview", + "nodoc": true, + "dependencies": [ "extension", "tabs" ], + "types": [ + // TODO(fsamuel): We should be usng tabs.InjectDetails. However, due to a + // bug in the JSON compiler, we are currently copying-and-pasting this + // type: https://crbug.com/171726. + { + "id": "InjectDetails", + "type": "object", + "description": "Details of the script or CSS to inject. Either the code or the file property must be set, but both may not be set at the same time.", + "properties": { + "code": {"type": "string", "optional": true, "description": "JavaScript or CSS code to inject."}, + "file": {"type": "string", "optional": true, "description": "JavaScript or CSS file to inject."}, + "allFrames": {"type": "boolean", "optional": true, "description": "If allFrames is <code>true</code>, implies that the JavaScript or CSS should be injected into all frames of current page. By default, it's <code>false</code> and will only be injected into the top frame."}, + "runAt": { + "type": "string", + "optional": true, + "enum": ["document_start", "document_end", "document_idle"], + "description": "The soonest that the JavaScript or CSS will be injected into the tab. Defaults to \"document_idle\"." + } + } + } + ], + "functions": [ + { + "name": "executeScript", + "type": "function", + "description": "Injects JavaScript code into a <webview> page.", + "parameters": [ + { + "type": "integer", + "name": "processId", + "description": "The process ID of the guest <webview> process." + }, + { + "type": "integer", + "name": "routeId", + "description": "The route ID of the guest <webview> renderer." + }, + { + "$ref": "webview.InjectDetails", + "name": "details", + "description": "Details of the script to run." + }, + { + "type": "function", + "name": "callback", + "optional": true, + "description": "Called after all the JavaScript has been executed.", + "parameters": [ + { + "name": "result", + "optional": true, + "type": "array", + "items": {"type": "any", "minimum": 0}, + "description": "The result of the script in every injected frame." + } + ] + } + ] + } + ] + } +] + diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h index 1ab9de0..7927ba5 100644 --- a/chrome/common/extensions/extension_messages.h +++ b/chrome/common/extensions/extension_messages.h @@ -83,6 +83,9 @@ IPC_STRUCT_BEGIN(ExtensionMsg_ExecuteCode_Params) // Whether to execute code in the main world (as opposed to an isolated // world). IPC_STRUCT_MEMBER(bool, in_main_world) + + // Whether the request is coming from a <webview>. + IPC_STRUCT_MEMBER(bool, is_web_view) IPC_STRUCT_END() IPC_STRUCT_TRAITS_BEGIN(WebApplicationInfo::IconInfo) diff --git a/chrome/renderer/extensions/user_script_scheduler.cc b/chrome/renderer/extensions/user_script_scheduler.cc index 96da900..0e6f766 100644 --- a/chrome/renderer/extensions/user_script_scheduler.cc +++ b/chrome/renderer/extensions/user_script_scheduler.cc @@ -175,7 +175,8 @@ void UserScriptScheduler::ExecuteCodeImpl( // // For child frames, we just skip ones the extension doesn't have access // to and carry on. - if (!extension->CanExecuteScriptOnPage(child_frame->document().url(), + if (!params.is_web_view && + !extension->CanExecuteScriptOnPage(child_frame->document().url(), frame_->document().url(), extension_helper->tab_id(), NULL, diff --git a/chrome/renderer/resources/extensions/web_view.js b/chrome/renderer/resources/extensions/web_view.js index 71023e2..a91ada9 100644 --- a/chrome/renderer/resources/extensions/web_view.js +++ b/chrome/renderer/resources/extensions/web_view.js @@ -71,6 +71,13 @@ function WebView(node) { }; }, this); + node['executeScript'] = function(var_args) { + var args = [self.objectNode_.getProcessId(), + self.objectNode_.getRouteId()].concat( + Array.prototype.slice.call(arguments)); + chrome.webview.executeScript.apply(null, args); + } + // Map attribute modifications on the <webview> tag to property changes in // the underlying <object> node. var handleMutation = this.handleMutation_.bind(this); diff --git a/chrome/test/data/extensions/platform_apps/web_view/main.js b/chrome/test/data/extensions/platform_apps/web_view/main.js index d17f7bd..4589acb 100644 --- a/chrome/test/data/extensions/platform_apps/web_view/main.js +++ b/chrome/test/data/extensions/platform_apps/web_view/main.js @@ -205,6 +205,21 @@ onload = function() { chrome.test.succeed(); } }, 0); + }, + + function webViewExecuteScript() { + var webview = document.createElement('webview'); + webview.addEventListener('loadstop', function() { + webview.executeScript( + {code:'document.body.style.backgroundColor = "red";'}, + function(results) { + chrome.test.assertEq(1, results.length); + chrome.test.assertEq('red', results[0]); + chrome.test.succeed(); + }); + }); + webview.setAttribute('src', 'data:text/html,trigger navigation'); + document.body.appendChild(webview); } ]); }; diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index c6c2522..f58b8a7 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc @@ -18,6 +18,7 @@ #include "content/common/drag_messages.h" #include "content/common/view_messages.h" #include "content/port/browser/render_view_host_delegate_view.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" @@ -98,6 +99,9 @@ void BrowserPluginGuest::Initialize( content::Source<content::WebContents>(web_contents())); OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params); + + GetContentClient()->browser()->GuestWebContentsCreated( + web_contents(), embedder_web_contents_); } BrowserPluginGuest::~BrowserPluginGuest() { @@ -303,6 +307,7 @@ void BrowserPluginGuest::DidCommitProvisionalLoadForFrame( params.url = url; params.is_top_level = is_main_frame; params.process_id = render_view_host->GetProcess()->GetID(); + params.route_id = render_view_host->GetRoutingID(); params.current_entry_index = web_contents()->GetController().GetCurrentEntryIndex(); params.entry_count = diff --git a/content/common/browser_plugin_messages.h b/content/common/browser_plugin_messages.h index f20be30..5d33460 100644 --- a/content/common/browser_plugin_messages.h +++ b/content/common/browser_plugin_messages.h @@ -67,8 +67,10 @@ IPC_STRUCT_BEGIN(BrowserPluginMsg_LoadCommit_Params) IPC_STRUCT_MEMBER(GURL, url) // Indicates whether the navigation was on the top-level frame. IPC_STRUCT_MEMBER(bool, is_top_level) - // Chrome's process ID for the guest. + // The browser's process ID for the guest. IPC_STRUCT_MEMBER(int, process_id) + // The browser's routing ID for the guest's RenderView. + IPC_STRUCT_MEMBER(int, route_id) // The index of the current navigation entry after this navigation was // committed. IPC_STRUCT_MEMBER(int, current_entry_index) @@ -283,7 +285,7 @@ IPC_MESSAGE_ROUTED4(BrowserPluginMsg_LoadRedirect, bool /* is_top_level */) // When the guest commits a navigation, the browser process informs -// the embedder through the BrowserPluginMsg_DidCommit message. +// the embedder through the BrowserPluginMsg_LoadCommit message. IPC_MESSAGE_ROUTED2(BrowserPluginMsg_LoadCommit, int /* instance_id */, BrowserPluginMsg_LoadCommit_Params) diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 5c0dd67..170f3fe 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -110,6 +110,10 @@ class CONTENT_EXPORT ContentBrowserClient { // Notifies that a new RenderHostView has been created. virtual void RenderViewHostCreated(RenderViewHost* render_view_host) {} + // Notifies that a <webview> guest WebContents has been created. + virtual void GuestWebContentsCreated(WebContents* guest_web_contents, + WebContents* embedder_web_contents) {} + // Notifies that a RenderProcessHost has been created. This is called before // the content layer adds its own BrowserMessageFilters, so that the // embedder's IPC filters have priority. diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index 7098405..eb9068a 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc @@ -125,7 +125,8 @@ BrowserPlugin::BrowserPlugin( max_width_(0), min_height_(0), min_width_(0), - process_id_(-1), + guest_process_id_(-1), + guest_route_id_(-1), persist_storage_(false), valid_partition_id_(true), content_window_routing_id_(MSG_ROUTING_NONE), @@ -429,7 +430,8 @@ void BrowserPlugin::OnLoadCommit( src_ = params.url.spec(); UpdateDOMAttribute(kSrc, src_.c_str()); } - process_id_ = params.process_id; + guest_process_id_ = params.process_id; + guest_route_id_ = params.route_id; current_nav_entry_index_ = params.current_entry_index; nav_entry_count_ = params.entry_count; diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index 466826a..88f92e1 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h @@ -77,7 +77,10 @@ class CONTENT_EXPORT BrowserPlugin : NPObject* GetContentWindow() const; // Returns Chrome's process ID for the current guest. - int process_id() const { return process_id_; } + int guest_process_id() const { return guest_process_id_; } + // Returns Chrome's route ID for the current guest. + int guest_route_id() const { return guest_route_id_; } + // The partition identifier string is stored as UTF-8. std::string GetPartitionAttribute() const; // Query whether the guest can navigate back to the previous entry. @@ -302,7 +305,8 @@ class CONTENT_EXPORT BrowserPlugin : int max_width_; int min_height_; int min_width_; - int process_id_; + int guest_process_id_; + int guest_route_id_; std::string storage_partition_id_; bool persist_storage_; bool valid_partition_id_; diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc index e0daeee..984fb66 100644 --- a/content/renderer/browser_plugin/browser_plugin_bindings.cc +++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc @@ -42,6 +42,7 @@ const char kMethodCanGoBack[] = "canGoBack"; const char kMethodCanGoForward[] = "canGoForward"; const char kMethodForward[] = "forward"; const char kMethodGetProcessId[] = "getProcessId"; +const char kMethodGetRouteId[] = "getRouteId"; const char kMethodGo[] = "go"; const char kMethodReload[] = "reload"; const char kMethodStop[] = "stop"; @@ -301,6 +302,26 @@ class BrowserPluginBindingForward : public BrowserPluginMethodBinding { DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingForward); }; +// Note: This is a method that is used internally by the <webview> shim only. +// This should not be exposed to developers. +class BrowserPluginBindingGetRouteID : public BrowserPluginMethodBinding { + public: + BrowserPluginBindingGetRouteID() + : BrowserPluginMethodBinding(kMethodGetRouteId, 0) { + } + + virtual bool Invoke(BrowserPluginBindings* bindings, + const NPVariant* args, + NPVariant* result) OVERRIDE { + int route_id = bindings->instance()->guest_route_id(); + INT32_TO_NPVARIANT(route_id, *result); + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingGetRouteID); +}; + class BrowserPluginBindingGetProcessID : public BrowserPluginMethodBinding { public: BrowserPluginBindingGetProcessID() @@ -310,7 +331,7 @@ class BrowserPluginBindingGetProcessID : public BrowserPluginMethodBinding { virtual bool Invoke(BrowserPluginBindings* bindings, const NPVariant* args, NPVariant* result) OVERRIDE { - int process_id = bindings->instance()->process_id(); + int process_id = bindings->instance()->guest_process_id(); INT32_TO_NPVARIANT(process_id, *result); return true; } @@ -689,6 +710,7 @@ BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance) method_bindings_.push_back(new BrowserPluginBindingCanGoForward); method_bindings_.push_back(new BrowserPluginBindingForward); method_bindings_.push_back(new BrowserPluginBindingGetProcessID); + method_bindings_.push_back(new BrowserPluginBindingGetRouteID); method_bindings_.push_back(new BrowserPluginBindingGo); method_bindings_.push_back(new BrowserPluginBindingReload); method_bindings_.push_back(new BrowserPluginBindingStop); |