Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / extensions / renderer / extension_helper.cc
blob915097ba66d506273ac79160e013a090a8b91963
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/renderer/extension_helper.h"
7 #include "base/lazy_instance.h"
8 #include "content/public/renderer/render_view.h"
9 #include "content/public/renderer/render_view_visitor.h"
10 #include "extensions/common/api/messaging/message.h"
11 #include "extensions/common/constants.h"
12 #include "extensions/common/extension_messages.h"
13 #include "extensions/renderer/console.h"
14 #include "extensions/renderer/dispatcher.h"
15 #include "extensions/renderer/messaging_bindings.h"
16 #include "extensions/renderer/user_script_scheduler.h"
17 #include "extensions/renderer/user_script_slave.h"
18 #include "third_party/WebKit/public/platform/WebURLRequest.h"
19 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
20 #include "third_party/WebKit/public/web/WebDocument.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
23 #include "third_party/WebKit/public/web/WebView.h"
25 using content::ConsoleMessageLevel;
26 using blink::WebConsoleMessage;
27 using blink::WebDataSource;
28 using blink::WebFrame;
29 using blink::WebLocalFrame;
30 using blink::WebURLRequest;
31 using blink::WebScopedUserGesture;
32 using blink::WebView;
34 namespace extensions {
36 namespace {
37 // Keeps a mapping from the frame pointer to a UserScriptScheduler object.
38 // We store this mapping per process, because a frame can jump from one
39 // document to another with adoptNode, and so having the object be a
40 // RenderViewObserver means it might miss some notifications after it moves.
41 typedef std::map<WebFrame*, UserScriptScheduler*> SchedulerMap;
42 static base::LazyInstance<SchedulerMap> g_schedulers =
43 LAZY_INSTANCE_INITIALIZER;
45 // A RenderViewVisitor class that iterates through the set of available
46 // views, looking for a view of the given type, in the given browser window
47 // and within the given extension.
48 // Used to accumulate the list of views associated with an extension.
49 class ViewAccumulator : public content::RenderViewVisitor {
50 public:
51 ViewAccumulator(const std::string& extension_id,
52 int browser_window_id,
53 ViewType view_type)
54 : extension_id_(extension_id),
55 browser_window_id_(browser_window_id),
56 view_type_(view_type) {
59 std::vector<content::RenderView*> views() { return views_; }
61 // Returns false to terminate the iteration.
62 virtual bool Visit(content::RenderView* render_view) OVERRIDE {
63 ExtensionHelper* helper = ExtensionHelper::Get(render_view);
64 if (!ViewTypeMatches(helper->view_type(), view_type_))
65 return true;
67 GURL url = render_view->GetWebView()->mainFrame()->document().url();
68 if (!url.SchemeIs(kExtensionScheme))
69 return true;
70 const std::string& extension_id = url.host();
71 if (extension_id != extension_id_)
72 return true;
74 if (browser_window_id_ != extension_misc::kUnknownWindowId &&
75 helper->browser_window_id() != browser_window_id_) {
76 return true;
79 views_.push_back(render_view);
81 if (view_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
82 return false; // There can be only one...
83 return true;
86 private:
87 // Returns true if |type| "isa" |match|.
88 static bool ViewTypeMatches(ViewType type, ViewType match) {
89 if (type == match)
90 return true;
92 // INVALID means match all.
93 if (match == VIEW_TYPE_INVALID)
94 return true;
96 return false;
99 std::string extension_id_;
100 int browser_window_id_;
101 ViewType view_type_;
102 std::vector<content::RenderView*> views_;
105 } // namespace
107 // static
108 std::vector<content::RenderView*> ExtensionHelper::GetExtensionViews(
109 const std::string& extension_id,
110 int browser_window_id,
111 ViewType view_type) {
112 ViewAccumulator accumulator(extension_id, browser_window_id, view_type);
113 content::RenderView::ForEach(&accumulator);
114 return accumulator.views();
117 // static
118 content::RenderView* ExtensionHelper::GetBackgroundPage(
119 const std::string& extension_id) {
120 ViewAccumulator accumulator(extension_id, extension_misc::kUnknownWindowId,
121 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
122 content::RenderView::ForEach(&accumulator);
123 CHECK_LE(accumulator.views().size(), 1u);
124 if (accumulator.views().size() == 0)
125 return NULL;
126 return accumulator.views()[0];
129 ExtensionHelper::ExtensionHelper(content::RenderView* render_view,
130 Dispatcher* dispatcher)
131 : content::RenderViewObserver(render_view),
132 content::RenderViewObserverTracker<ExtensionHelper>(render_view),
133 dispatcher_(dispatcher),
134 view_type_(VIEW_TYPE_INVALID),
135 tab_id_(-1),
136 browser_window_id_(-1) {
139 ExtensionHelper::~ExtensionHelper() {
142 bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) {
143 bool handled = true;
144 IPC_BEGIN_MESSAGE_MAP(ExtensionHelper, message)
145 IPC_MESSAGE_HANDLER(ExtensionMsg_Response, OnExtensionResponse)
146 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke)
147 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect,
148 OnExtensionDispatchOnConnect)
149 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnExtensionDeliverMessage)
150 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
151 OnExtensionDispatchOnDisconnect)
152 IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode)
153 IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabId, OnSetTabId)
154 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateBrowserWindowId,
155 OnUpdateBrowserWindowId)
156 IPC_MESSAGE_HANDLER(ExtensionMsg_NotifyRenderViewType,
157 OnNotifyRendererViewType)
158 IPC_MESSAGE_HANDLER(ExtensionMsg_AddMessageToConsole,
159 OnAddMessageToConsole)
160 IPC_MESSAGE_HANDLER(ExtensionMsg_AppWindowClosed,
161 OnAppWindowClosed);
162 IPC_MESSAGE_UNHANDLED(handled = false)
163 IPC_END_MESSAGE_MAP()
164 return handled;
167 void ExtensionHelper::DidFinishDocumentLoad(WebLocalFrame* frame) {
168 dispatcher_->user_script_slave()->InjectScripts(
169 frame, UserScript::DOCUMENT_END);
171 SchedulerMap::iterator i = g_schedulers.Get().find(frame);
172 if (i != g_schedulers.Get().end())
173 i->second->DidFinishDocumentLoad();
176 void ExtensionHelper::DidFinishLoad(blink::WebLocalFrame* frame) {
177 SchedulerMap::iterator i = g_schedulers.Get().find(frame);
178 if (i != g_schedulers.Get().end())
179 i->second->DidFinishLoad();
182 void ExtensionHelper::DidCreateDocumentElement(WebLocalFrame* frame) {
183 dispatcher_->user_script_slave()->InjectScripts(
184 frame, UserScript::DOCUMENT_START);
185 SchedulerMap::iterator i = g_schedulers.Get().find(frame);
186 if (i != g_schedulers.Get().end())
187 i->second->DidCreateDocumentElement();
189 dispatcher_->DidCreateDocumentElement(frame);
192 void ExtensionHelper::DidStartProvisionalLoad(blink::WebLocalFrame* frame) {
193 SchedulerMap::iterator i = g_schedulers.Get().find(frame);
194 if (i != g_schedulers.Get().end())
195 i->second->DidStartProvisionalLoad();
198 void ExtensionHelper::DraggableRegionsChanged(blink::WebFrame* frame) {
199 blink::WebVector<blink::WebDraggableRegion> webregions =
200 frame->document().draggableRegions();
201 std::vector<DraggableRegion> regions;
202 for (size_t i = 0; i < webregions.size(); ++i) {
203 DraggableRegion region;
204 region.bounds = webregions[i].bounds;
205 region.draggable = webregions[i].draggable;
206 regions.push_back(region);
208 Send(new ExtensionHostMsg_UpdateDraggableRegions(routing_id(), regions));
211 void ExtensionHelper::FrameDetached(WebFrame* frame) {
212 // This could be called before DidCreateDataSource, in which case the frame
213 // won't be in the map.
214 SchedulerMap::iterator i = g_schedulers.Get().find(frame);
215 if (i == g_schedulers.Get().end())
216 return;
218 delete i->second;
219 g_schedulers.Get().erase(i);
222 void ExtensionHelper::DidMatchCSS(
223 blink::WebLocalFrame* frame,
224 const blink::WebVector<blink::WebString>& newly_matching_selectors,
225 const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
226 dispatcher_->DidMatchCSS(
227 frame, newly_matching_selectors, stopped_matching_selectors);
230 void ExtensionHelper::DidCreateDataSource(WebLocalFrame* frame,
231 WebDataSource* ds) {
232 // Check first if we created a scheduler for the frame, since this function
233 // gets called for navigations within the document.
234 if (g_schedulers.Get().count(frame))
235 return;
237 g_schedulers.Get()[frame] = new UserScriptScheduler(frame, dispatcher_);
240 void ExtensionHelper::OnExtensionResponse(int request_id,
241 bool success,
242 const base::ListValue& response,
243 const std::string& error) {
244 dispatcher_->OnExtensionResponse(request_id,
245 success,
246 response,
247 error);
250 void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id,
251 const std::string& module_name,
252 const std::string& function_name,
253 const base::ListValue& args,
254 bool user_gesture) {
255 dispatcher_->InvokeModuleSystemMethod(
256 render_view(), extension_id, module_name, function_name, args,
257 user_gesture);
260 void ExtensionHelper::OnExtensionDispatchOnConnect(
261 int target_port_id,
262 const std::string& channel_name,
263 const base::DictionaryValue& source_tab,
264 const ExtensionMsg_ExternalConnectionInfo& info,
265 const std::string& tls_channel_id) {
266 MessagingBindings::DispatchOnConnect(
267 dispatcher_->script_context_set().GetAll(),
268 target_port_id,
269 channel_name,
270 source_tab,
271 info.source_id,
272 info.target_id,
273 info.source_url,
274 tls_channel_id,
275 render_view());
278 void ExtensionHelper::OnExtensionDeliverMessage(int target_id,
279 const Message& message) {
280 MessagingBindings::DeliverMessage(dispatcher_->script_context_set().GetAll(),
281 target_id,
282 message,
283 render_view());
286 void ExtensionHelper::OnExtensionDispatchOnDisconnect(
287 int port_id,
288 const std::string& error_message) {
289 MessagingBindings::DispatchOnDisconnect(
290 dispatcher_->script_context_set().GetAll(),
291 port_id,
292 error_message,
293 render_view());
296 void ExtensionHelper::OnExecuteCode(
297 const ExtensionMsg_ExecuteCode_Params& params) {
298 WebView* webview = render_view()->GetWebView();
299 WebFrame* main_frame = webview->mainFrame();
300 if (!main_frame) {
301 base::ListValue val;
302 Send(new ExtensionHostMsg_ExecuteCodeFinished(routing_id(),
303 params.request_id,
304 "No main frame",
306 GURL(std::string()),
307 val));
308 return;
311 // chrome.tabs.executeScript() only supports execution in either the top frame
312 // or all frames. We handle both cases in the top frame.
313 SchedulerMap::iterator i = g_schedulers.Get().find(main_frame);
314 if (i != g_schedulers.Get().end())
315 i->second->ExecuteCode(params);
318 void ExtensionHelper::OnNotifyRendererViewType(ViewType type) {
319 view_type_ = type;
322 void ExtensionHelper::OnSetTabId(int init_tab_id) {
323 CHECK_EQ(tab_id_, -1);
324 CHECK_GE(init_tab_id, 0);
325 tab_id_ = init_tab_id;
328 void ExtensionHelper::OnUpdateBrowserWindowId(int window_id) {
329 browser_window_id_ = window_id;
332 void ExtensionHelper::OnAddMessageToConsole(ConsoleMessageLevel level,
333 const std::string& message) {
334 console::AddMessage(render_view(), level, message);
337 void ExtensionHelper::OnAppWindowClosed() {
338 v8::HandleScope scope(v8::Isolate::GetCurrent());
339 v8::Handle<v8::Context> v8_context =
340 render_view()->GetWebView()->mainFrame()->mainWorldScriptContext();
341 ScriptContext* script_context =
342 dispatcher_->script_context_set().GetByV8Context(v8_context);
343 if (!script_context)
344 return;
345 script_context->module_system()->CallModuleMethod("app.window",
346 "onAppWindowClosed");
349 } // namespace extensions