OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/extensions/user_script_idle_scheduler.h" | 5 #include "chrome/renderer/extensions/user_script_scheduler.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "chrome/common/extensions/extension_error_utils.h" | 9 #include "chrome/common/extensions/extension_error_utils.h" |
10 #include "chrome/common/extensions/extension_manifest_constants.h" | 10 #include "chrome/common/extensions/extension_manifest_constants.h" |
11 #include "chrome/common/extensions/extension_messages.h" | 11 #include "chrome/common/extensions/extension_messages.h" |
12 #include "chrome/renderer/extensions/extension_dispatcher.h" | 12 #include "chrome/renderer/extensions/extension_dispatcher.h" |
13 #include "chrome/renderer/extensions/extension_groups.h" | 13 #include "chrome/renderer/extensions/extension_groups.h" |
14 #include "chrome/renderer/extensions/extension_helper.h" | 14 #include "chrome/renderer/extensions/extension_helper.h" |
15 #include "chrome/renderer/extensions/user_script_slave.h" | 15 #include "chrome/renderer/extensions/user_script_slave.h" |
16 #include "content/public/renderer/render_view.h" | 16 #include "content/public/renderer/render_view.h" |
| 17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" |
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
21 | 21 |
22 namespace { | 22 namespace { |
23 // The length of time to wait after the DOM is complete to try and run user | 23 // The length of time to wait after the DOM is complete to try and run user |
24 // scripts. | 24 // scripts. |
25 const int kUserScriptIdleTimeoutMs = 200; | 25 const int kUserScriptIdleTimeoutMs = 200; |
26 } | 26 } |
27 | 27 |
28 using WebKit::WebDocument; | 28 using WebKit::WebDocument; |
29 using WebKit::WebFrame; | 29 using WebKit::WebFrame; |
30 using WebKit::WebString; | 30 using WebKit::WebString; |
31 using WebKit::WebView; | 31 using WebKit::WebView; |
32 | 32 |
33 UserScriptIdleScheduler::UserScriptIdleScheduler( | 33 UserScriptScheduler::UserScriptScheduler( |
34 WebFrame* frame, ExtensionDispatcher* extension_dispatcher) | 34 WebFrame* frame, ExtensionDispatcher* extension_dispatcher) |
35 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 35 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
36 frame_(frame), | 36 frame_(frame), |
37 has_run_(false), | 37 current_location_(UserScript::UNDEFINED), |
| 38 has_run_idle_(false), |
38 extension_dispatcher_(extension_dispatcher) { | 39 extension_dispatcher_(extension_dispatcher) { |
| 40 for (int i = UserScript::UNDEFINED; i < UserScript::RUN_LOCATION_LAST; ++i) |
| 41 pending_execution_map_[static_cast<UserScript::RunLocation>(i)] = |
| 42 std::queue<linked_ptr<ExtensionMsg_ExecuteCode_Params> >(); |
39 } | 43 } |
40 | 44 |
41 UserScriptIdleScheduler::~UserScriptIdleScheduler() { | 45 UserScriptScheduler::~UserScriptScheduler() { |
42 } | 46 } |
43 | 47 |
44 void UserScriptIdleScheduler::ExecuteCode( | 48 void UserScriptScheduler::ExecuteCode( |
45 const ExtensionMsg_ExecuteCode_Params& params) { | 49 const ExtensionMsg_ExecuteCode_Params& params) { |
46 if (!has_run_) { | 50 UserScript::RunLocation run_at = |
47 pending_code_execution_queue_.push( | 51 static_cast<UserScript::RunLocation>(params.run_at); |
| 52 if (current_location_ < run_at) { |
| 53 pending_execution_map_[run_at].push( |
48 linked_ptr<ExtensionMsg_ExecuteCode_Params>( | 54 linked_ptr<ExtensionMsg_ExecuteCode_Params>( |
49 new ExtensionMsg_ExecuteCode_Params(params))); | 55 new ExtensionMsg_ExecuteCode_Params(params))); |
50 return; | 56 return; |
51 } | 57 } |
52 | 58 |
53 ExecuteCodeImpl(params); | 59 ExecuteCodeImpl(params); |
54 } | 60 } |
55 | 61 |
56 void UserScriptIdleScheduler::DidFinishDocumentLoad() { | 62 void UserScriptScheduler::DidCreateDocumentElement() { |
| 63 current_location_ = UserScript::DOCUMENT_START; |
| 64 MaybeRun(); |
| 65 } |
| 66 |
| 67 void UserScriptScheduler::DidFinishDocumentLoad() { |
| 68 current_location_ = UserScript::DOCUMENT_END; |
| 69 MaybeRun(); |
| 70 // Schedule a run for DOCUMENT_IDLE |
57 MessageLoop::current()->PostDelayedTask( | 71 MessageLoop::current()->PostDelayedTask( |
58 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun, | 72 FROM_HERE, base::Bind(&UserScriptScheduler::IdleTimeout, |
59 weak_factory_.GetWeakPtr()), | 73 weak_factory_.GetWeakPtr()), |
60 base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs)); | 74 base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs)); |
61 } | 75 } |
62 | 76 |
63 void UserScriptIdleScheduler::DidFinishLoad() { | 77 void UserScriptScheduler::DidFinishLoad() { |
| 78 current_location_ = UserScript::DOCUMENT_IDLE; |
64 // Ensure that running scripts does not keep any progress UI running. | 79 // Ensure that running scripts does not keep any progress UI running. |
65 MessageLoop::current()->PostTask( | 80 MessageLoop::current()->PostTask( |
66 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun, | 81 FROM_HERE, base::Bind(&UserScriptScheduler::MaybeRun, |
67 weak_factory_.GetWeakPtr())); | 82 weak_factory_.GetWeakPtr())); |
68 } | 83 } |
69 | 84 |
70 void UserScriptIdleScheduler::DidStartProvisionalLoad() { | 85 void UserScriptScheduler::DidStartProvisionalLoad() { |
71 // The frame is navigating, so reset the state since we'll want to inject | 86 // The frame is navigating, so reset the state since we'll want to inject |
72 // scripts once the load finishes. | 87 // scripts once the load finishes. |
73 has_run_ = false; | 88 current_location_ = UserScript::UNDEFINED; |
| 89 has_run_idle_ = false; |
74 weak_factory_.InvalidateWeakPtrs(); | 90 weak_factory_.InvalidateWeakPtrs(); |
75 while (!pending_code_execution_queue_.empty()) | 91 std::map<UserScript::RunLocation, ExecutionQueue>::iterator itr = |
76 pending_code_execution_queue_.pop(); | 92 pending_execution_map_.begin(); |
77 } | 93 for (itr = pending_execution_map_.begin(); |
78 | 94 itr != pending_execution_map_.end(); ++itr) { |
79 void UserScriptIdleScheduler::MaybeRun() { | 95 while (!itr->second.empty()) |
80 if (has_run_) | 96 itr->second.pop(); |
81 return; | |
82 | |
83 // Note: we must set this before calling ExecuteCodeImpl, because that may | |
84 // result in a synchronous call back into MaybeRun if there is a pending task | |
85 // currently in the queue. | |
86 // http://code.google.com/p/chromium/issues/detail?id=29644 | |
87 has_run_ = true; | |
88 | |
89 extension_dispatcher_->user_script_slave()->InjectScripts( | |
90 frame_, UserScript::DOCUMENT_IDLE); | |
91 | |
92 while (!pending_code_execution_queue_.empty()) { | |
93 linked_ptr<ExtensionMsg_ExecuteCode_Params>& params = | |
94 pending_code_execution_queue_.front(); | |
95 ExecuteCodeImpl(*params); | |
96 pending_code_execution_queue_.pop(); | |
97 } | 97 } |
98 } | 98 } |
99 | 99 |
100 void UserScriptIdleScheduler::ExecuteCodeImpl( | 100 void UserScriptScheduler::IdleTimeout() { |
| 101 current_location_ = UserScript::DOCUMENT_IDLE; |
| 102 MaybeRun(); |
| 103 } |
| 104 |
| 105 void UserScriptScheduler::MaybeRun() { |
| 106 if (current_location_ == UserScript::UNDEFINED) |
| 107 return; |
| 108 |
| 109 if (!has_run_idle_ && current_location_ == UserScript::DOCUMENT_IDLE) { |
| 110 extension_dispatcher_->user_script_slave()->InjectScripts( |
| 111 frame_, UserScript::DOCUMENT_IDLE); |
| 112 has_run_idle_ = true; |
| 113 } |
| 114 |
| 115 // Run all tasks from the current time and earlier. |
| 116 for (int i = UserScript::DOCUMENT_START; |
| 117 i <= current_location_; ++i) { |
| 118 UserScript::RunLocation run_time = static_cast<UserScript::RunLocation>(i); |
| 119 while (!pending_execution_map_[run_time].empty()) { |
| 120 linked_ptr<ExtensionMsg_ExecuteCode_Params>& params = |
| 121 pending_execution_map_[run_time].front(); |
| 122 ExecuteCodeImpl(*params); |
| 123 pending_execution_map_[run_time].pop(); |
| 124 } |
| 125 } |
| 126 } |
| 127 |
| 128 void UserScriptScheduler::ExecuteCodeImpl( |
101 const ExtensionMsg_ExecuteCode_Params& params) { | 129 const ExtensionMsg_ExecuteCode_Params& params) { |
102 const Extension* extension = extension_dispatcher_->extensions()->GetByID( | 130 const Extension* extension = extension_dispatcher_->extensions()->GetByID( |
103 params.extension_id); | 131 params.extension_id); |
104 content::RenderView* render_view = | 132 content::RenderView* render_view = |
105 content::RenderView::FromWebView(frame_->view()); | 133 content::RenderView::FromWebView(frame_->view()); |
106 | 134 |
107 // Since extension info is sent separately from user script info, they can | 135 // Since extension info is sent separately from user script info, they can |
108 // be out of sync. We just ignore this situation. | 136 // be out of sync. We just ignore this situation. |
109 if (!extension) { | 137 if (!extension) { |
110 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( | 138 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 WebString::fromUTF8(params.code), | 189 WebString::fromUTF8(params.code), |
162 // Author level is consistent with WebView::addUserStyleSheet. | 190 // Author level is consistent with WebView::addUserStyleSheet. |
163 WebDocument::UserStyleAuthorLevel); | 191 WebDocument::UserStyleAuthorLevel); |
164 } | 192 } |
165 } | 193 } |
166 | 194 |
167 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( | 195 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
168 render_view->GetRoutingID(), params.request_id, true, "")); | 196 render_view->GetRoutingID(), params.request_id, true, "")); |
169 } | 197 } |
170 | 198 |
171 bool UserScriptIdleScheduler::GetAllChildFrames( | 199 bool UserScriptScheduler::GetAllChildFrames( |
172 WebFrame* parent_frame, | 200 WebFrame* parent_frame, |
173 std::vector<WebFrame*>* frames_vector) const { | 201 std::vector<WebFrame*>* frames_vector) const { |
174 if (!parent_frame) | 202 if (!parent_frame) |
175 return false; | 203 return false; |
176 | 204 |
177 for (WebFrame* child_frame = parent_frame->firstChild(); child_frame; | 205 for (WebFrame* child_frame = parent_frame->firstChild(); child_frame; |
178 child_frame = child_frame->nextSibling()) { | 206 child_frame = child_frame->nextSibling()) { |
179 frames_vector->push_back(child_frame); | 207 frames_vector->push_back(child_frame); |
180 GetAllChildFrames(child_frame, frames_vector); | 208 GetAllChildFrames(child_frame, frames_vector); |
181 } | 209 } |
182 return true; | 210 return true; |
183 } | 211 } |
OLD | NEW |