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> >(); |
| 43 } |
39 } | 44 } |
40 | 45 |
41 UserScriptIdleScheduler::~UserScriptIdleScheduler() { | 46 UserScriptScheduler::~UserScriptScheduler() { |
42 } | 47 } |
43 | 48 |
44 void UserScriptIdleScheduler::ExecuteCode( | 49 void UserScriptScheduler::ExecuteCode( |
45 const ExtensionMsg_ExecuteCode_Params& params) { | 50 const ExtensionMsg_ExecuteCode_Params& params) { |
46 if (!has_run_) { | 51 UserScript::RunLocation run_at = |
47 pending_code_execution_queue_.push( | 52 static_cast<UserScript::RunLocation>(params.run_at); |
| 53 if (current_location_ < run_at) { |
| 54 pending_execution_map_[run_at].push( |
48 linked_ptr<ExtensionMsg_ExecuteCode_Params>( | 55 linked_ptr<ExtensionMsg_ExecuteCode_Params>( |
49 new ExtensionMsg_ExecuteCode_Params(params))); | 56 new ExtensionMsg_ExecuteCode_Params(params))); |
50 return; | 57 return; |
51 } | 58 } |
52 | 59 |
53 ExecuteCodeImpl(params); | 60 ExecuteCodeImpl(params); |
54 } | 61 } |
55 | 62 |
56 void UserScriptIdleScheduler::DidFinishDocumentLoad() { | 63 void UserScriptScheduler::DidCreateDocumentElement() { |
| 64 current_location_ = UserScript::DOCUMENT_START; |
| 65 MaybeRun(); |
| 66 } |
| 67 |
| 68 void UserScriptScheduler::DidFinishDocumentLoad() { |
| 69 current_location_ = UserScript::DOCUMENT_END; |
| 70 MaybeRun(); |
| 71 // Schedule a run for DOCUMENT_IDLE |
57 MessageLoop::current()->PostDelayedTask( | 72 MessageLoop::current()->PostDelayedTask( |
58 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun, | 73 FROM_HERE, base::Bind(&UserScriptScheduler::IdleTimeout, |
59 weak_factory_.GetWeakPtr()), | 74 weak_factory_.GetWeakPtr()), |
60 base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs)); | 75 base::TimeDelta::FromMilliseconds(kUserScriptIdleTimeoutMs)); |
61 } | 76 } |
62 | 77 |
63 void UserScriptIdleScheduler::DidFinishLoad() { | 78 void UserScriptScheduler::DidFinishLoad() { |
| 79 current_location_ = UserScript::DOCUMENT_IDLE; |
64 // Ensure that running scripts does not keep any progress UI running. | 80 // Ensure that running scripts does not keep any progress UI running. |
65 MessageLoop::current()->PostTask( | 81 MessageLoop::current()->PostTask( |
66 FROM_HERE, base::Bind(&UserScriptIdleScheduler::MaybeRun, | 82 FROM_HERE, base::Bind(&UserScriptScheduler::MaybeRun, |
67 weak_factory_.GetWeakPtr())); | 83 weak_factory_.GetWeakPtr())); |
68 } | 84 } |
69 | 85 |
70 void UserScriptIdleScheduler::DidStartProvisionalLoad() { | 86 void UserScriptScheduler::DidStartProvisionalLoad() { |
71 // The frame is navigating, so reset the state since we'll want to inject | 87 // The frame is navigating, so reset the state since we'll want to inject |
72 // scripts once the load finishes. | 88 // scripts once the load finishes. |
73 has_run_ = false; | 89 current_location_ = UserScript::UNDEFINED; |
| 90 has_run_idle_ = false; |
74 weak_factory_.InvalidateWeakPtrs(); | 91 weak_factory_.InvalidateWeakPtrs(); |
75 while (!pending_code_execution_queue_.empty()) | 92 std::map<UserScript::RunLocation, ExecutionQueue>::iterator itr = |
76 pending_code_execution_queue_.pop(); | 93 pending_execution_map_.begin(); |
77 } | 94 for (itr = pending_execution_map_.begin(); |
78 | 95 itr != pending_execution_map_.end(); ++itr) { |
79 void UserScriptIdleScheduler::MaybeRun() { | 96 while (!itr->second.empty()) |
80 if (has_run_) | 97 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 } | 98 } |
98 } | 99 } |
99 | 100 |
100 void UserScriptIdleScheduler::ExecuteCodeImpl( | 101 void UserScriptScheduler::IdleTimeout() { |
| 102 current_location_ = UserScript::DOCUMENT_IDLE; |
| 103 MaybeRun(); |
| 104 } |
| 105 |
| 106 void UserScriptScheduler::MaybeRun() { |
| 107 if (current_location_ == UserScript::UNDEFINED) |
| 108 return; |
| 109 |
| 110 if (!has_run_idle_ && current_location_ == UserScript::DOCUMENT_IDLE) { |
| 111 has_run_idle_ = true; |
| 112 extension_dispatcher_->user_script_slave()->InjectScripts( |
| 113 frame_, UserScript::DOCUMENT_IDLE); |
| 114 } |
| 115 |
| 116 // Run all tasks from the current time and earlier. |
| 117 for (int i = UserScript::DOCUMENT_START; |
| 118 i <= current_location_; ++i) { |
| 119 UserScript::RunLocation run_time = static_cast<UserScript::RunLocation>(i); |
| 120 while (!pending_execution_map_[run_time].empty()) { |
| 121 linked_ptr<ExtensionMsg_ExecuteCode_Params>& params = |
| 122 pending_execution_map_[run_time].front(); |
| 123 ExecuteCodeImpl(*params); |
| 124 pending_execution_map_[run_time].pop(); |
| 125 } |
| 126 } |
| 127 } |
| 128 |
| 129 void UserScriptScheduler::ExecuteCodeImpl( |
101 const ExtensionMsg_ExecuteCode_Params& params) { | 130 const ExtensionMsg_ExecuteCode_Params& params) { |
102 const Extension* extension = extension_dispatcher_->extensions()->GetByID( | 131 const Extension* extension = extension_dispatcher_->extensions()->GetByID( |
103 params.extension_id); | 132 params.extension_id); |
104 content::RenderView* render_view = | 133 content::RenderView* render_view = |
105 content::RenderView::FromWebView(frame_->view()); | 134 content::RenderView::FromWebView(frame_->view()); |
106 | 135 |
107 // Since extension info is sent separately from user script info, they can | 136 // Since extension info is sent separately from user script info, they can |
108 // be out of sync. We just ignore this situation. | 137 // be out of sync. We just ignore this situation. |
109 if (!extension) { | 138 if (!extension) { |
110 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( | 139 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 WebString::fromUTF8(params.code), | 190 WebString::fromUTF8(params.code), |
162 // Author level is consistent with WebView::addUserStyleSheet. | 191 // Author level is consistent with WebView::addUserStyleSheet. |
163 WebDocument::UserStyleAuthorLevel); | 192 WebDocument::UserStyleAuthorLevel); |
164 } | 193 } |
165 } | 194 } |
166 | 195 |
167 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( | 196 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished( |
168 render_view->GetRoutingID(), params.request_id, true, "")); | 197 render_view->GetRoutingID(), params.request_id, true, "")); |
169 } | 198 } |
170 | 199 |
171 bool UserScriptIdleScheduler::GetAllChildFrames( | 200 bool UserScriptScheduler::GetAllChildFrames( |
172 WebFrame* parent_frame, | 201 WebFrame* parent_frame, |
173 std::vector<WebFrame*>* frames_vector) const { | 202 std::vector<WebFrame*>* frames_vector) const { |
174 if (!parent_frame) | 203 if (!parent_frame) |
175 return false; | 204 return false; |
176 | 205 |
177 for (WebFrame* child_frame = parent_frame->firstChild(); child_frame; | 206 for (WebFrame* child_frame = parent_frame->firstChild(); child_frame; |
178 child_frame = child_frame->nextSibling()) { | 207 child_frame = child_frame->nextSibling()) { |
179 frames_vector->push_back(child_frame); | 208 frames_vector->push_back(child_frame); |
180 GetAllChildFrames(child_frame, frames_vector); | 209 GetAllChildFrames(child_frame, frames_vector); |
181 } | 210 } |
182 return true; | 211 return true; |
183 } | 212 } |
OLD | NEW |