Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: chrome/renderer/extensions/user_script_idle_scheduler.cc

Issue 9456037: Adding run_at to chrome.tabs.executeScript/insertCss. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "chrome/renderer/extensions/user_script_idle_scheduler.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop.h"
9 #include "chrome/common/extensions/extension_error_utils.h"
10 #include "chrome/common/extensions/extension_messages.h"
11 #include "chrome/renderer/extensions/extension_dispatcher.h"
12 #include "chrome/renderer/extensions/extension_groups.h"
13 #include "chrome/renderer/extensions/extension_helper.h"
14 #include "chrome/renderer/extensions/user_script_slave.h"
15 #include "content/public/renderer/render_view.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
20
21 namespace {
22 // The length of time to wait after the DOM is complete to try and run user
23 // scripts.
24 const int kUserScriptIdleTimeoutMs = 200;
25 }
26
27 using WebKit::WebDocument;
28 using WebKit::WebFrame;
29 using WebKit::WebString;
30 using WebKit::WebView;
31
32 UserScriptIdleScheduler::UserScriptIdleScheduler(
33 WebFrame* frame, ExtensionDispatcher* extension_dispatcher)
34 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
35 frame_(frame),
36 has_run_(false),
37 extension_dispatcher_(extension_dispatcher) {
38 }
39
40 UserScriptIdleScheduler::~UserScriptIdleScheduler() {
41 }
42
43 void UserScriptIdleScheduler::ExecuteCode(
44 const ExtensionMsg_ExecuteCode_Params& params) {
45 if (!has_run_) {
46 pending_code_execution_queue_.push(
47 linked_ptr<ExtensionMsg_ExecuteCode_Params>(
48 new ExtensionMsg_ExecuteCode_Params(params)));
49 return;
50 }
51
52 ExecuteCodeImpl(params);
53 }
54
55 void UserScriptIdleScheduler::DidFinishDocumentLoad() {
56 MessageLoop::current()->PostDelayedTask(
57 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun,
58 weak_factory_.GetWeakPtr()),
59 base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs));
60 }
61
62 void UserScriptIdleScheduler::DidFinishLoad() {
63 // Ensure that running scripts does not keep any progress UI running.
64 MessageLoop::current()->PostTask(
65 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun,
66 weak_factory_.GetWeakPtr()));
67 }
68
69 void UserScriptIdleScheduler::DidStartProvisionalLoad() {
70 // The frame is navigating, so reset the state since we'll want to inject
71 // scripts once the load finishes.
72 has_run_ = false;
73 weak_factory_.InvalidateWeakPtrs();
74 while (!pending_code_execution_queue_.empty())
75 pending_code_execution_queue_.pop();
76 }
77
78 void UserScriptIdleScheduler::MaybeRun() {
79 if (has_run_)
80 return;
81
82 // Note: we must set this before calling ExecuteCodeImpl, because that may
83 // result in a synchronous call back into MaybeRun if there is a pending task
84 // currently in the queue.
85 // http://code.google.com/p/chromium/issues/detail?id=29644
86 has_run_ = true;
87
88 extension_dispatcher_->user_script_slave()->InjectScripts(
89 frame_, UserScript::DOCUMENT_IDLE);
90
91 while (!pending_code_execution_queue_.empty()) {
92 linked_ptr<ExtensionMsg_ExecuteCode_Params>& params =
93 pending_code_execution_queue_.front();
94 ExecuteCodeImpl(*params);
95 pending_code_execution_queue_.pop();
96 }
97 }
98
99 void UserScriptIdleScheduler::ExecuteCodeImpl(
100 const ExtensionMsg_ExecuteCode_Params& params) {
101 const Extension* extension = extension_dispatcher_->extensions()->GetByID(
102 params.extension_id);
103 content::RenderView* render_view =
104 content::RenderView::FromWebView(frame_->view());
105
106 // Since extension info is sent separately from user script info, they can
107 // be out of sync. We just ignore this situation.
108 if (!extension) {
109 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
110 render_view->GetRoutingID(), params.request_id, true, ""));
111 return;
112 }
113
114 std::vector<WebFrame*> frame_vector;
115 frame_vector.push_back(frame_);
116 if (params.all_frames)
117 GetAllChildFrames(frame_, &frame_vector);
118
119 for (std::vector<WebFrame*>::iterator frame_it = frame_vector.begin();
120 frame_it != frame_vector.end(); ++frame_it) {
121 WebFrame* frame = *frame_it;
122 if (params.is_javascript) {
123 // We recheck access here in the renderer for extra safety against races
124 // with navigation.
125 //
126 // But different frames can have different URLs, and the extension might
127 // only have access to a subset of them. For the top frame, we can
128 // immediately send an error and stop because the browser process
129 // considers that an error too.
130 //
131 // For child frames, we just skip ones the extension doesn't have access
132 // to and carry on.
133 if (!extension->CanExecuteScriptOnPage(frame->document().url(),
134 NULL, NULL)) {
135 if (frame->parent()) {
136 continue;
137 } else {
138 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
139 render_view->GetRoutingID(), params.request_id, false,
140 ExtensionErrorUtils::FormatErrorMessage(
141 extension_manifest_errors::kCannotAccessPage,
142 frame->document().url().spec())));
143 return;
144 }
145 }
146
147 WebScriptSource source(WebString::fromUTF8(params.code));
148 if (params.in_main_world) {
149 frame->executeScript(source);
150 } else {
151 std::vector<WebScriptSource> sources;
152 sources.push_back(source);
153 frame->executeScriptInIsolatedWorld(
154 extension_dispatcher_->user_script_slave()->
155 GetIsolatedWorldIdForExtension(extension, frame),
156 &sources.front(), sources.size(), EXTENSION_GROUP_CONTENT_SCRIPTS);
157 }
158 } else {
159 frame->document().insertUserStyleSheet(
160 WebString::fromUTF8(params.code),
161 // Author level is consistent with WebView::addUserStyleSheet.
162 WebDocument::UserStyleAuthorLevel);
163 }
164 }
165
166 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
167 render_view->GetRoutingID(), params.request_id, true, ""));
168 }
169
170 bool UserScriptIdleScheduler::GetAllChildFrames(
171 WebFrame* parent_frame,
172 std::vector<WebFrame*>* frames_vector) const {
173 if (!parent_frame)
174 return false;
175
176 for (WebFrame* child_frame = parent_frame->firstChild(); child_frame;
177 child_frame = child_frame->nextSibling()) {
178 frames_vector->push_back(child_frame);
179 GetAllChildFrames(child_frame, frames_vector);
180 }
181 return true;
182 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698