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