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