diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-01 22:04:06 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-01 22:04:06 +0000 |
commit | b6cd47221942b3b7352a87d03dcce2855bed0e79 (patch) | |
tree | c027b9e8985f4a36db1cbcbecc91f366a06b54e1 /extensions | |
parent | bb1855136eab4e0ab80f204aab56b433d09f66be (diff) | |
download | chromium_src-b6cd47221942b3b7352a87d03dcce2855bed0e79.zip chromium_src-b6cd47221942b3b7352a87d03dcce2855bed0e79.tar.gz chromium_src-b6cd47221942b3b7352a87d03dcce2855bed0e79.tar.bz2 |
Move renderer ExtensionHelper into //extensions
This breaks another //extensions -> //chrome circular dependency.
* Split out Chrome-specific parts of ExtensionHelper to ChromeExtensionHelper
* Move ExtensionHelper to //extensions
* Move UserScriptScheduler to //extensions (a dependency of ExtensionHelper)
* Tighten DEPS
BUG=162530
TEST=compiles, existing browser_tests
TBR=bbudge@chromium.org for mechanical header file move touching chrome/renderer/pepper
Review URL: https://codereview.chromium.org/261733002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267647 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
-rw-r--r-- | extensions/DEPS | 1 | ||||
-rw-r--r-- | extensions/extensions.gyp | 14 | ||||
-rw-r--r-- | extensions/renderer/console.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/dispatcher.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/event_bindings.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/extension_helper.cc | 349 | ||||
-rw-r--r-- | extensions/renderer/extension_helper.h | 113 | ||||
-rw-r--r-- | extensions/renderer/lazy_background_page_native_handler.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/runtime_custom_bindings.cc | 2 | ||||
-rw-r--r-- | extensions/renderer/user_script_scheduler.cc | 280 | ||||
-rw-r--r-- | extensions/renderer/user_script_scheduler.h | 95 |
11 files changed, 851 insertions, 11 deletions
diff --git a/extensions/DEPS b/extensions/DEPS index 4dabc14..bb58d4f 100644 --- a/extensions/DEPS +++ b/extensions/DEPS @@ -13,7 +13,6 @@ include_rules = [ # # TODO(jamescook): Remove these. http://crbug.com/162530 "!chrome/browser/chrome_notification_types.h", - "!chrome/renderer/extensions/extension_helper.h", "!grit/common_resources.h", '!grit/extensions_api_resources.h', # This is needed for renderer JS sources which should eventually move to diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index faa7790..4411dae6 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -413,6 +413,11 @@ { 'target_name': 'extensions_renderer', 'type': 'static_library', + 'dependencies': [ + 'extensions_resources.gyp:extensions_resources', + '../chrome/chrome_resources.gyp:chrome_resources', + '../third_party/WebKit/public/blink.gyp:blink', + ], 'include_dirs': [ '..', ], @@ -448,6 +453,8 @@ 'renderer/dom_activity_logger.h', 'renderer/event_bindings.cc', 'renderer/event_bindings.h', + 'renderer/extension_helper.cc', + 'renderer/extension_helper.h', 'renderer/extensions_renderer_client.cc', 'renderer/extensions_renderer_client.h', 'renderer/extension_groups.h', @@ -498,6 +505,8 @@ 'renderer/test_features_native_handler.h', 'renderer/user_gestures_native_handler.cc', 'renderer/user_gestures_native_handler.h', + 'renderer/user_script_scheduler.cc', + 'renderer/user_script_scheduler.h', 'renderer/user_script_slave.cc', 'renderer/user_script_slave.h', 'renderer/utils_native_handler.cc', @@ -507,11 +516,6 @@ 'renderer/v8_schema_registry.cc', 'renderer/v8_schema_registry.h', ], - 'dependencies': [ - 'extensions_resources.gyp:extensions_resources', - '../chrome/chrome_resources.gyp:chrome_resources', - '../third_party/WebKit/public/blink.gyp:blink', - ], # Disable c4267 warnings until we fix size_t to int truncations. 'msvs_disabled_warnings': [ 4267, ], 'conditions': [ diff --git a/extensions/renderer/console.cc b/extensions/renderer/console.cc index f7ae995..7429104 100644 --- a/extensions/renderer/console.cc +++ b/extensions/renderer/console.cc @@ -10,10 +10,10 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/renderer/extensions/extension_helper.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view_visitor.h" #include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/extension_helper.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebView.h" diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 93fa434..75b2e43 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -13,7 +13,6 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/values.h" -#include "chrome/renderer/extensions/extension_helper.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" #include "content/public/renderer/render_thread.h" @@ -50,6 +49,7 @@ #include "extensions/renderer/dom_activity_logger.h" #include "extensions/renderer/event_bindings.h" #include "extensions/renderer/extension_groups.h" +#include "extensions/renderer/extension_helper.h" #include "extensions/renderer/extensions_renderer_client.h" #include "extensions/renderer/file_system_natives.h" #include "extensions/renderer/i18n_custom_bindings.h" diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc index 0ebd08e..331e6512 100644 --- a/extensions/renderer/event_bindings.cc +++ b/extensions/renderer/event_bindings.cc @@ -13,7 +13,6 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/memory/scoped_ptr.h" -#include "chrome/renderer/extensions/extension_helper.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/v8_value_converter.h" @@ -23,6 +22,7 @@ #include "extensions/common/manifest_handlers/background_info.h" #include "extensions/common/value_counter.h" #include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/extension_helper.h" #include "extensions/renderer/object_backed_native_handler.h" #include "url/gurl.h" #include "v8/include/v8.h" diff --git a/extensions/renderer/extension_helper.cc b/extensions/renderer/extension_helper.cc new file mode 100644 index 0000000..915097b --- /dev/null +++ b/extensions/renderer/extension_helper.cc @@ -0,0 +1,349 @@ +// Copyright 2014 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 "extensions/renderer/extension_helper.h" + +#include "base/lazy_instance.h" +#include "content/public/renderer/render_view.h" +#include "content/public/renderer/render_view_visitor.h" +#include "extensions/common/api/messaging/message.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension_messages.h" +#include "extensions/renderer/console.h" +#include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/messaging_bindings.h" +#include "extensions/renderer/user_script_scheduler.h" +#include "extensions/renderer/user_script_slave.h" +#include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/web/WebConsoleMessage.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebScopedUserGesture.h" +#include "third_party/WebKit/public/web/WebView.h" + +using content::ConsoleMessageLevel; +using blink::WebConsoleMessage; +using blink::WebDataSource; +using blink::WebFrame; +using blink::WebLocalFrame; +using blink::WebURLRequest; +using blink::WebScopedUserGesture; +using blink::WebView; + +namespace extensions { + +namespace { +// Keeps a mapping from the frame pointer to a UserScriptScheduler object. +// We store this mapping per process, because a frame can jump from one +// document to another with adoptNode, and so having the object be a +// RenderViewObserver means it might miss some notifications after it moves. +typedef std::map<WebFrame*, UserScriptScheduler*> SchedulerMap; +static base::LazyInstance<SchedulerMap> g_schedulers = + LAZY_INSTANCE_INITIALIZER; + +// A RenderViewVisitor class that iterates through the set of available +// views, looking for a view of the given type, in the given browser window +// and within the given extension. +// Used to accumulate the list of views associated with an extension. +class ViewAccumulator : public content::RenderViewVisitor { + public: + ViewAccumulator(const std::string& extension_id, + int browser_window_id, + ViewType view_type) + : extension_id_(extension_id), + browser_window_id_(browser_window_id), + view_type_(view_type) { + } + + std::vector<content::RenderView*> views() { return views_; } + + // Returns false to terminate the iteration. + virtual bool Visit(content::RenderView* render_view) OVERRIDE { + ExtensionHelper* helper = ExtensionHelper::Get(render_view); + if (!ViewTypeMatches(helper->view_type(), view_type_)) + return true; + + GURL url = render_view->GetWebView()->mainFrame()->document().url(); + if (!url.SchemeIs(kExtensionScheme)) + return true; + const std::string& extension_id = url.host(); + if (extension_id != extension_id_) + return true; + + if (browser_window_id_ != extension_misc::kUnknownWindowId && + helper->browser_window_id() != browser_window_id_) { + return true; + } + + views_.push_back(render_view); + + if (view_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) + return false; // There can be only one... + return true; + } + + private: + // Returns true if |type| "isa" |match|. + static bool ViewTypeMatches(ViewType type, ViewType match) { + if (type == match) + return true; + + // INVALID means match all. + if (match == VIEW_TYPE_INVALID) + return true; + + return false; + } + + std::string extension_id_; + int browser_window_id_; + ViewType view_type_; + std::vector<content::RenderView*> views_; +}; + +} // namespace + +// static +std::vector<content::RenderView*> ExtensionHelper::GetExtensionViews( + const std::string& extension_id, + int browser_window_id, + ViewType view_type) { + ViewAccumulator accumulator(extension_id, browser_window_id, view_type); + content::RenderView::ForEach(&accumulator); + return accumulator.views(); +} + +// static +content::RenderView* ExtensionHelper::GetBackgroundPage( + const std::string& extension_id) { + ViewAccumulator accumulator(extension_id, extension_misc::kUnknownWindowId, + VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); + content::RenderView::ForEach(&accumulator); + CHECK_LE(accumulator.views().size(), 1u); + if (accumulator.views().size() == 0) + return NULL; + return accumulator.views()[0]; +} + +ExtensionHelper::ExtensionHelper(content::RenderView* render_view, + Dispatcher* dispatcher) + : content::RenderViewObserver(render_view), + content::RenderViewObserverTracker<ExtensionHelper>(render_view), + dispatcher_(dispatcher), + view_type_(VIEW_TYPE_INVALID), + tab_id_(-1), + browser_window_id_(-1) { +} + +ExtensionHelper::~ExtensionHelper() { +} + +bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ExtensionHelper, message) + IPC_MESSAGE_HANDLER(ExtensionMsg_Response, OnExtensionResponse) + IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke) + IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, + OnExtensionDispatchOnConnect) + IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnExtensionDeliverMessage) + IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect, + OnExtensionDispatchOnDisconnect) + IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode) + IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabId, OnSetTabId) + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateBrowserWindowId, + OnUpdateBrowserWindowId) + IPC_MESSAGE_HANDLER(ExtensionMsg_NotifyRenderViewType, + OnNotifyRendererViewType) + IPC_MESSAGE_HANDLER(ExtensionMsg_AddMessageToConsole, + OnAddMessageToConsole) + IPC_MESSAGE_HANDLER(ExtensionMsg_AppWindowClosed, + OnAppWindowClosed); + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ExtensionHelper::DidFinishDocumentLoad(WebLocalFrame* frame) { + dispatcher_->user_script_slave()->InjectScripts( + frame, UserScript::DOCUMENT_END); + + SchedulerMap::iterator i = g_schedulers.Get().find(frame); + if (i != g_schedulers.Get().end()) + i->second->DidFinishDocumentLoad(); +} + +void ExtensionHelper::DidFinishLoad(blink::WebLocalFrame* frame) { + SchedulerMap::iterator i = g_schedulers.Get().find(frame); + if (i != g_schedulers.Get().end()) + i->second->DidFinishLoad(); +} + +void ExtensionHelper::DidCreateDocumentElement(WebLocalFrame* frame) { + dispatcher_->user_script_slave()->InjectScripts( + frame, UserScript::DOCUMENT_START); + SchedulerMap::iterator i = g_schedulers.Get().find(frame); + if (i != g_schedulers.Get().end()) + i->second->DidCreateDocumentElement(); + + dispatcher_->DidCreateDocumentElement(frame); +} + +void ExtensionHelper::DidStartProvisionalLoad(blink::WebLocalFrame* frame) { + SchedulerMap::iterator i = g_schedulers.Get().find(frame); + if (i != g_schedulers.Get().end()) + i->second->DidStartProvisionalLoad(); +} + +void ExtensionHelper::DraggableRegionsChanged(blink::WebFrame* frame) { + blink::WebVector<blink::WebDraggableRegion> webregions = + frame->document().draggableRegions(); + std::vector<DraggableRegion> regions; + for (size_t i = 0; i < webregions.size(); ++i) { + DraggableRegion region; + region.bounds = webregions[i].bounds; + region.draggable = webregions[i].draggable; + regions.push_back(region); + } + Send(new ExtensionHostMsg_UpdateDraggableRegions(routing_id(), regions)); +} + +void ExtensionHelper::FrameDetached(WebFrame* frame) { + // This could be called before DidCreateDataSource, in which case the frame + // won't be in the map. + SchedulerMap::iterator i = g_schedulers.Get().find(frame); + if (i == g_schedulers.Get().end()) + return; + + delete i->second; + g_schedulers.Get().erase(i); +} + +void ExtensionHelper::DidMatchCSS( + blink::WebLocalFrame* frame, + const blink::WebVector<blink::WebString>& newly_matching_selectors, + const blink::WebVector<blink::WebString>& stopped_matching_selectors) { + dispatcher_->DidMatchCSS( + frame, newly_matching_selectors, stopped_matching_selectors); +} + +void ExtensionHelper::DidCreateDataSource(WebLocalFrame* frame, + WebDataSource* ds) { + // Check first if we created a scheduler for the frame, since this function + // gets called for navigations within the document. + if (g_schedulers.Get().count(frame)) + return; + + g_schedulers.Get()[frame] = new UserScriptScheduler(frame, dispatcher_); +} + +void ExtensionHelper::OnExtensionResponse(int request_id, + bool success, + const base::ListValue& response, + const std::string& error) { + dispatcher_->OnExtensionResponse(request_id, + success, + response, + error); +} + +void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id, + const std::string& module_name, + const std::string& function_name, + const base::ListValue& args, + bool user_gesture) { + dispatcher_->InvokeModuleSystemMethod( + render_view(), extension_id, module_name, function_name, args, + user_gesture); +} + +void ExtensionHelper::OnExtensionDispatchOnConnect( + int target_port_id, + const std::string& channel_name, + const base::DictionaryValue& source_tab, + const ExtensionMsg_ExternalConnectionInfo& info, + const std::string& tls_channel_id) { + MessagingBindings::DispatchOnConnect( + dispatcher_->script_context_set().GetAll(), + target_port_id, + channel_name, + source_tab, + info.source_id, + info.target_id, + info.source_url, + tls_channel_id, + render_view()); +} + +void ExtensionHelper::OnExtensionDeliverMessage(int target_id, + const Message& message) { + MessagingBindings::DeliverMessage(dispatcher_->script_context_set().GetAll(), + target_id, + message, + render_view()); +} + +void ExtensionHelper::OnExtensionDispatchOnDisconnect( + int port_id, + const std::string& error_message) { + MessagingBindings::DispatchOnDisconnect( + dispatcher_->script_context_set().GetAll(), + port_id, + error_message, + render_view()); +} + +void ExtensionHelper::OnExecuteCode( + const ExtensionMsg_ExecuteCode_Params& params) { + WebView* webview = render_view()->GetWebView(); + WebFrame* main_frame = webview->mainFrame(); + if (!main_frame) { + base::ListValue val; + Send(new ExtensionHostMsg_ExecuteCodeFinished(routing_id(), + params.request_id, + "No main frame", + -1, + GURL(std::string()), + val)); + return; + } + + // chrome.tabs.executeScript() only supports execution in either the top frame + // or all frames. We handle both cases in the top frame. + SchedulerMap::iterator i = g_schedulers.Get().find(main_frame); + if (i != g_schedulers.Get().end()) + i->second->ExecuteCode(params); +} + +void ExtensionHelper::OnNotifyRendererViewType(ViewType type) { + view_type_ = type; +} + +void ExtensionHelper::OnSetTabId(int init_tab_id) { + CHECK_EQ(tab_id_, -1); + CHECK_GE(init_tab_id, 0); + tab_id_ = init_tab_id; +} + +void ExtensionHelper::OnUpdateBrowserWindowId(int window_id) { + browser_window_id_ = window_id; +} + +void ExtensionHelper::OnAddMessageToConsole(ConsoleMessageLevel level, + const std::string& message) { + console::AddMessage(render_view(), level, message); +} + +void ExtensionHelper::OnAppWindowClosed() { + v8::HandleScope scope(v8::Isolate::GetCurrent()); + v8::Handle<v8::Context> v8_context = + render_view()->GetWebView()->mainFrame()->mainWorldScriptContext(); + ScriptContext* script_context = + dispatcher_->script_context_set().GetByV8Context(v8_context); + if (!script_context) + return; + script_context->module_system()->CallModuleMethod("app.window", + "onAppWindowClosed"); +} + +} // namespace extensions diff --git a/extensions/renderer/extension_helper.h b/extensions/renderer/extension_helper.h new file mode 100644 index 0000000..486db54 --- /dev/null +++ b/extensions/renderer/extension_helper.h @@ -0,0 +1,113 @@ +// Copyright 2014 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 EXTENSIONS_RENDERER_EXTENSION_HELPER_H_ +#define EXTENSIONS_RENDERER_EXTENSION_HELPER_H_ + +#include <vector> + +#include "content/public/common/console_message_level.h" +#include "content/public/renderer/render_view_observer.h" +#include "content/public/renderer/render_view_observer_tracker.h" +#include "extensions/common/view_type.h" + +class GURL; +class SkBitmap; +struct ExtensionMsg_ExecuteCode_Params; +struct ExtensionMsg_ExternalConnectionInfo; + +namespace base { +class DictionaryValue; +class ListValue; +} + +namespace extensions { +class Dispatcher; +struct Message; + +// RenderView-level plumbing for extension features. +class ExtensionHelper + : public content::RenderViewObserver, + public content::RenderViewObserverTracker<ExtensionHelper> { + public: + // Returns a list of extension RenderViews that match the given filter + // criteria. If |browser_window_id| is not extension_misc::kUnknownWindowId, + // the list is restricted to views in that browser window. + static std::vector<content::RenderView*> GetExtensionViews( + const std::string& extension_id, + int browser_window_id, + ViewType view_type); + + // Returns the given extension's background page, or NULL if none. + static content::RenderView* GetBackgroundPage( + const std::string& extension_id); + + ExtensionHelper(content::RenderView* render_view, Dispatcher* dispatcher); + virtual ~ExtensionHelper(); + + int tab_id() const { return tab_id_; } + int browser_window_id() const { return browser_window_id_; } + ViewType view_type() const { return view_type_; } + Dispatcher* dispatcher() const { return dispatcher_; } + + private: + // RenderViewObserver implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; + virtual void DidFinishLoad(blink::WebLocalFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; + virtual void DidStartProvisionalLoad(blink::WebLocalFrame* frame) OVERRIDE; + virtual void FrameDetached(blink::WebFrame* frame) OVERRIDE; + virtual void DidMatchCSS( + blink::WebLocalFrame* frame, + const blink::WebVector<blink::WebString>& newly_matching_selectors, + const blink::WebVector<blink::WebString>& stopped_matching_selectors) + OVERRIDE; + virtual void DidCreateDataSource(blink::WebLocalFrame* frame, + blink::WebDataSource* ds) OVERRIDE; + virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; + + void OnExtensionResponse(int request_id, bool success, + const base::ListValue& response, + const std::string& error); + void OnExtensionMessageInvoke(const std::string& extension_id, + const std::string& module_name, + const std::string& function_name, + const base::ListValue& args, + bool user_gesture); + void OnExtensionDispatchOnConnect( + int target_port_id, + const std::string& channel_name, + const base::DictionaryValue& source_tab, + const ExtensionMsg_ExternalConnectionInfo& info, + const std::string& tls_channel_id); + void OnExtensionDeliverMessage(int target_port_id, + const Message& message); + void OnExtensionDispatchOnDisconnect(int port_id, + const std::string& error_message); + void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params); + void OnNotifyRendererViewType(ViewType view_type); + void OnSetTabId(int tab_id); + void OnUpdateBrowserWindowId(int window_id); + void OnAddMessageToConsole(content::ConsoleMessageLevel level, + const std::string& message); + void OnAppWindowClosed(); + + Dispatcher* dispatcher_; + + // Type of view attached with RenderView. + ViewType view_type_; + + // Id of the tab which the RenderView is attached to. + int tab_id_; + + // Id number of browser window which RenderView is attached to. + int browser_window_id_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionHelper); +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_EXTENSION_HELPER_H_ diff --git a/extensions/renderer/lazy_background_page_native_handler.cc b/extensions/renderer/lazy_background_page_native_handler.cc index b7c72cd..c8a31fe 100644 --- a/extensions/renderer/lazy_background_page_native_handler.cc +++ b/extensions/renderer/lazy_background_page_native_handler.cc @@ -5,10 +5,10 @@ #include "extensions/renderer/lazy_background_page_native_handler.h" #include "base/bind.h" -#include "chrome/renderer/extensions/extension_helper.h" #include "content/public/renderer/render_view.h" #include "extensions/common/extension_messages.h" #include "extensions/common/manifest_handlers/background_info.h" +#include "extensions/renderer/extension_helper.h" #include "extensions/renderer/script_context.h" namespace extensions { diff --git a/extensions/renderer/runtime_custom_bindings.cc b/extensions/renderer/runtime_custom_bindings.cc index 7ed2ad2..3815abc 100644 --- a/extensions/renderer/runtime_custom_bindings.cc +++ b/extensions/renderer/runtime_custom_bindings.cc @@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" -#include "chrome/renderer/extensions/extension_helper.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/v8_value_converter.h" #include "extensions/common/extension.h" @@ -16,6 +15,7 @@ #include "extensions/common/features/feature_provider.h" #include "extensions/common/manifest.h" #include "extensions/renderer/api_activity_logger.h" +#include "extensions/renderer/extension_helper.h" #include "extensions/renderer/script_context.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" diff --git a/extensions/renderer/user_script_scheduler.cc b/extensions/renderer/user_script_scheduler.cc new file mode 100644 index 0000000..9c82fb7a --- /dev/null +++ b/extensions/renderer/user_script_scheduler.cc @@ -0,0 +1,280 @@ +// Copyright 2014 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 "extensions/renderer/user_script_scheduler.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "content/public/renderer/render_view.h" +#include "content/public/renderer/v8_value_converter.h" +#include "extensions/common/error_utils.h" +#include "extensions/common/extension_messages.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/permissions/permissions_data.h" +#include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/dom_activity_logger.h" +#include "extensions/renderer/extension_groups.h" +#include "extensions/renderer/extension_helper.h" +#include "extensions/renderer/script_context.h" +#include "extensions/renderer/user_script_slave.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebScopedUserGesture.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "v8/include/v8.h" + +namespace { +// The length of time to wait after the DOM is complete to try and run user +// scripts. +const int kUserScriptIdleTimeoutMs = 200; +} + +using blink::WebDocument; +using blink::WebFrame; +using blink::WebString; +using blink::WebVector; +using blink::WebView; + +namespace extensions { + +UserScriptScheduler::UserScriptScheduler(WebFrame* frame, + Dispatcher* dispatcher) + : weak_factory_(this), + frame_(frame), + current_location_(UserScript::UNDEFINED), + has_run_idle_(false), + dispatcher_(dispatcher) { + for (int i = UserScript::UNDEFINED; i < UserScript::RUN_LOCATION_LAST; ++i) { + pending_execution_map_[static_cast<UserScript::RunLocation>(i)] = + std::queue<linked_ptr<ExtensionMsg_ExecuteCode_Params> >(); + } +} + +UserScriptScheduler::~UserScriptScheduler() { +} + +void UserScriptScheduler::ExecuteCode( + const ExtensionMsg_ExecuteCode_Params& params) { + UserScript::RunLocation run_at = + static_cast<UserScript::RunLocation>(params.run_at); + if (current_location_ < run_at) { + pending_execution_map_[run_at].push( + linked_ptr<ExtensionMsg_ExecuteCode_Params>( + new ExtensionMsg_ExecuteCode_Params(params))); + return; + } + + ExecuteCodeImpl(params); +} + +void UserScriptScheduler::DidCreateDocumentElement() { + current_location_ = UserScript::DOCUMENT_START; + MaybeRun(); +} + +void UserScriptScheduler::DidFinishDocumentLoad() { + current_location_ = UserScript::DOCUMENT_END; + MaybeRun(); + // Schedule a run for DOCUMENT_IDLE + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&UserScriptScheduler::IdleTimeout, weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs)); +} + +void UserScriptScheduler::DidFinishLoad() { + current_location_ = UserScript::DOCUMENT_IDLE; + // Ensure that running scripts does not keep any progress UI running. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&UserScriptScheduler::MaybeRun, weak_factory_.GetWeakPtr())); +} + +void UserScriptScheduler::DidStartProvisionalLoad() { + // The frame is navigating, so reset the state since we'll want to inject + // scripts once the load finishes. + current_location_ = UserScript::UNDEFINED; + has_run_idle_ = false; + weak_factory_.InvalidateWeakPtrs(); + std::map<UserScript::RunLocation, ExecutionQueue>::iterator itr = + pending_execution_map_.begin(); + for (itr = pending_execution_map_.begin(); + itr != pending_execution_map_.end(); ++itr) { + while (!itr->second.empty()) + itr->second.pop(); + } +} + +void UserScriptScheduler::IdleTimeout() { + current_location_ = UserScript::DOCUMENT_IDLE; + MaybeRun(); +} + +void UserScriptScheduler::MaybeRun() { + if (current_location_ == UserScript::UNDEFINED) + return; + + if (!has_run_idle_ && current_location_ == UserScript::DOCUMENT_IDLE) { + has_run_idle_ = true; + dispatcher_->user_script_slave()->InjectScripts( + frame_, UserScript::DOCUMENT_IDLE); + } + + // Run all tasks from the current time and earlier. + for (int i = UserScript::DOCUMENT_START; + i <= current_location_; ++i) { + UserScript::RunLocation run_time = static_cast<UserScript::RunLocation>(i); + while (!pending_execution_map_[run_time].empty()) { + linked_ptr<ExtensionMsg_ExecuteCode_Params>& params = + pending_execution_map_[run_time].front(); + ExecuteCodeImpl(*params); + pending_execution_map_[run_time].pop(); + } + } +} + +void UserScriptScheduler::ExecuteCodeImpl( + const ExtensionMsg_ExecuteCode_Params& params) { + const Extension* extension = dispatcher_->extensions()->GetByID( + params.extension_id); + content::RenderView* render_view = + content::RenderView::FromWebView(frame_->view()); + ExtensionHelper* extension_helper = ExtensionHelper::Get(render_view); + base::ListValue execution_results; + + // Since extension info is sent separately from user script info, they can + // be out of sync. We just ignore this situation. + if (!extension) { + render_view->Send( + new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), + params.request_id, + std::string(), // no error + -1, + GURL(std::string()), + execution_results)); + return; + } + + std::vector<WebFrame*> frame_vector; + frame_vector.push_back(frame_); + if (params.all_frames) + GetAllChildFrames(frame_, &frame_vector); + + std::string error; + + scoped_ptr<blink::WebScopedUserGesture> gesture; + if (params.user_gesture) + gesture.reset(new blink::WebScopedUserGesture); + + GURL top_url = frame_->document().url(); + + for (std::vector<WebFrame*>::iterator frame_it = frame_vector.begin(); + frame_it != frame_vector.end(); ++frame_it) { + WebFrame* child_frame = *frame_it; + CHECK(child_frame) << top_url; + + // We recheck access here in the renderer for extra safety against races + // with navigation. + // + // But different frames can have different URLs, and the extension might + // only have access to a subset of them. For the top frame, we can + // immediately send an error and stop because the browser process + // considers that an error too. + // + // For child frames, we just skip ones the extension doesn't have access + // to and carry on. + + bool can_execute_script = + PermissionsData::CanExecuteScriptOnPage(extension, + child_frame->document().url(), + top_url, + extension_helper->tab_id(), + NULL, + -1, + NULL); + if ((!params.is_web_view && !can_execute_script) || + (params.is_web_view && + child_frame->document().url() != params.webview_src)) { + if (child_frame->parent()) { + continue; + } else { + error = ErrorUtils::FormatErrorMessage( + manifest_errors::kCannotAccessPage, + child_frame->document().url().spec()); + break; + } + } + + if (params.is_javascript) { + WebScriptSource source(WebString::fromUTF8(params.code), params.file_url); + v8::HandleScope scope(v8::Isolate::GetCurrent()); + + scoped_ptr<content::V8ValueConverter> v8_converter( + content::V8ValueConverter::create()); + v8::Local<v8::Value> script_value; + + if (params.in_main_world) { + DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId, + extension->id()); + script_value = child_frame->executeScriptAndReturnValue(source); + } else { + blink::WebVector<v8::Local<v8::Value> > results; + std::vector<WebScriptSource> sources; + sources.push_back(source); + int isolated_world_id = + dispatcher_->user_script_slave()->GetIsolatedWorldIdForExtension( + extension, child_frame); + DOMActivityLogger::AttachToWorld(isolated_world_id, extension->id()); + child_frame->executeScriptInIsolatedWorld( + isolated_world_id, &sources.front(), + sources.size(), EXTENSION_GROUP_CONTENT_SCRIPTS, &results); + // We only expect one value back since we only pushed one source + if (results.size() == 1 && !results[0].IsEmpty()) + script_value = results[0]; + } + + if (params.wants_result && !script_value.IsEmpty()) { + // It's safe to always use the main world context when converting here. + // V8ValueConverterImpl shouldn't actually care about the context scope, + // and it switches to v8::Object's creation context when encountered. + v8::Local<v8::Context> context = child_frame->mainWorldScriptContext(); + base::Value* result = v8_converter->FromV8Value(script_value, context); + // Always append an execution result (i.e. no result == null result) so + // that |execution_results| lines up with the frames. + execution_results.Append( + result ? result : base::Value::CreateNullValue()); + } + } else { + child_frame->document().insertStyleSheet( + WebString::fromUTF8(params.code)); + } + } + + render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( + render_view->GetRoutingID(), + params.request_id, + error, + render_view->GetPageId(), + ScriptContext::GetDataSourceURLForFrame(frame_), + execution_results)); +} + +bool UserScriptScheduler::GetAllChildFrames( + WebFrame* parent_frame, + std::vector<WebFrame*>* frames_vector) const { + if (!parent_frame) + return false; + + for (WebFrame* child_frame = parent_frame->firstChild(); child_frame; + child_frame = child_frame->nextSibling()) { + frames_vector->push_back(child_frame); + GetAllChildFrames(child_frame, frames_vector); + } + return true; +} + +} // namespace extensions diff --git a/extensions/renderer/user_script_scheduler.h b/extensions/renderer/user_script_scheduler.h new file mode 100644 index 0000000..4e8a45b --- /dev/null +++ b/extensions/renderer/user_script_scheduler.h @@ -0,0 +1,95 @@ +// Copyright 2014 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 EXTENSIONS_RENDERER_USER_SCRIPT_SCHEDULER_H_ +#define EXTENSIONS_RENDERER_USER_SCRIPT_SCHEDULER_H_ + +#include <map> +#include <queue> + +#include "base/memory/linked_ptr.h" +#include "base/memory/weak_ptr.h" +#include "extensions/common/user_script.h" + +class RenderView; +struct ExtensionMsg_ExecuteCode_Params; + +namespace blink { +class WebFrame; +} + +namespace extensions { +class Dispatcher; + +// Implements support for injecting scripts at different times in the document +// loading process. The different possible time are described in +// UserScript::RunLocation. +// +// Currently, determining idleness is simple: it is whichever of the following +// happens first: +// +// a) When the initial DOM for a page is complete + kUserScriptIdleTimeout, +// b) or when the page has completely loaded including all subresources. +// +// The intent of this mechanism is to prevent user scripts from slowing down +// fast pages (run after load), while still allowing them to run relatively +// timely for pages with lots of slow subresources. +// +// NOTE: this class does not inherit from RenderViewObserver on purpose. The +// reason is that this object is per frame, and a frame can move across +// RenderViews thanks to adoptNode. So we have each RenderView's +// ExtensionHelper proxy these calls to the renderer process' Dispatcher, +// which contains the mapping from WebFrame to us. +class UserScriptScheduler { + public: + UserScriptScheduler(blink::WebFrame* frame, Dispatcher* dispatcher); + ~UserScriptScheduler(); + + void ExecuteCode(const ExtensionMsg_ExecuteCode_Params& params); + void DidCreateDocumentElement(); + void DidFinishDocumentLoad(); + void DidFinishLoad(); + void DidStartProvisionalLoad(); + + private: + typedef + std::queue<linked_ptr<ExtensionMsg_ExecuteCode_Params> > + ExecutionQueue; + + // Run user scripts, except if they've already run for this frame, or the + // frame has been destroyed. + void MaybeRun(); + + // Backend for the IPC Message ExecuteCode in addition to being used + // internally. + void ExecuteCodeImpl(const ExtensionMsg_ExecuteCode_Params& params); + + // Get all child frames of parent_frame, returned by frames_vector. + bool GetAllChildFrames(blink::WebFrame* parent_frame, + std::vector<blink::WebFrame*>* frames_vector) const; + + // Call to signify thet the idle timeout has expired. + void IdleTimeout(); + + base::WeakPtrFactory<UserScriptScheduler> weak_factory_; + + // The Frame we will run scripts in. + blink::WebFrame* frame_; + + // The current location in the document loading process. + // Will be UserScript::UNDEFINED if it is before any scripts should be run. + UserScript::RunLocation current_location_; + + // Whether we have already run the idle scripts. + bool has_run_idle_; + + // This is only used if we're for the main frame. + std::map<UserScript::RunLocation, ExecutionQueue> pending_execution_map_; + + Dispatcher* dispatcher_; +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_USER_SCRIPT_SCHEDULER_H_ |