| 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 |