| Index: extensions/renderer/script_injection_manager.cc
|
| diff --git a/extensions/renderer/script_injection_manager.cc b/extensions/renderer/script_injection_manager.cc
|
| index 326452b8fad2de0a6aa183c2d2434fa0cd083b5d..0b7c777625731fc9ba0d5f3ce439ba8a14561dc6 100644
|
| --- a/extensions/renderer/script_injection_manager.cc
|
| +++ b/extensions/renderer/script_injection_manager.cc
|
| @@ -85,24 +85,21 @@ class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
|
|
|
| // Indicate that the frame is no longer valid because it is starting
|
| // a new load or closing.
|
| - void InvalidateFrame();
|
| + void InvalidateAndResetFrame();
|
|
|
| // The owning ScriptInjectionManager.
|
| ScriptInjectionManager* manager_;
|
|
|
| - // The set of frames that we are about to notify for DOCUMENT_IDLE. We keep
|
| - // a set of those that are valid, so we don't notify that an invalid frame
|
| - // became idle.
|
| - std::set<content::RenderFrame*> pending_idle_frames_;
|
| + bool should_run_idle_;
|
|
|
| base::WeakPtrFactory<RFOHelper> weak_factory_;
|
| };
|
|
|
| -ScriptInjectionManager::RFOHelper::RFOHelper(
|
| - content::RenderFrame* render_frame,
|
| - ScriptInjectionManager* manager)
|
| +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
|
| + ScriptInjectionManager* manager)
|
| : content::RenderFrameObserver(render_frame),
|
| manager_(manager),
|
| + should_run_idle_(true),
|
| weak_factory_(this) {
|
| }
|
|
|
| @@ -130,7 +127,7 @@ void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
|
| // page was loaded, e.g. by navigating to a javascript: URL before the page
|
| // has loaded.
|
| if (manager_->frame_statuses_.count(render_frame()) != 0)
|
| - InvalidateFrame();
|
| + InvalidateAndResetFrame();
|
| }
|
|
|
| void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
|
| @@ -139,7 +136,6 @@ void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
|
|
|
| void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
|
| manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_END);
|
| - pending_idle_frames_.insert(render_frame());
|
| // We try to run idle in two places: here and DidFinishLoad.
|
| // DidFinishDocumentLoad() corresponds to completing the document's load,
|
| // whereas DidFinishLoad corresponds to completing the document and all
|
| @@ -156,10 +152,6 @@ void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
|
|
|
| void ScriptInjectionManager::RFOHelper::DidFinishLoad() {
|
| // Ensure that we don't block any UI progress by running scripts.
|
| - // We *don't* add the frame to |pending_idle_frames_| here because
|
| - // DidFinishDocumentLoad should strictly come before DidFinishLoad, so the
|
| - // first posted task to RunIdle() pops it out of the set. This ensures we
|
| - // don't try to run idle twice.
|
| content::RenderThread::Get()->GetTaskRunner()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle,
|
| @@ -168,7 +160,7 @@ void ScriptInjectionManager::RFOHelper::DidFinishLoad() {
|
|
|
| void ScriptInjectionManager::RFOHelper::FrameDetached() {
|
| // The frame is closing - invalidate.
|
| - InvalidateFrame();
|
| + InvalidateAndResetFrame();
|
| }
|
|
|
| void ScriptInjectionManager::RFOHelper::OnDestruct() {
|
| @@ -205,14 +197,18 @@ void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection(
|
| void ScriptInjectionManager::RFOHelper::RunIdle() {
|
| // Only notify the manager if the frame hasn't either been removed or already
|
| // had idle run since the task to RunIdle() was posted.
|
| - if (pending_idle_frames_.count(render_frame()) > 0) {
|
| + if (should_run_idle_) {
|
| + should_run_idle_ = false;
|
| manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
|
| - pending_idle_frames_.erase(render_frame());
|
| }
|
| }
|
|
|
| -void ScriptInjectionManager::RFOHelper::InvalidateFrame() {
|
| - pending_idle_frames_.erase(render_frame());
|
| +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame() {
|
| + // Invalidate any pending idle injections, and reset the frame inject on idle.
|
| + weak_factory_.InvalidateWeakPtrs();
|
| + // We reset to inject on idle, because the frame can be reused (in the case of
|
| + // navigation).
|
| + should_run_idle_ = true;
|
| manager_->InvalidateForFrame(render_frame());
|
| }
|
|
|
| @@ -281,6 +277,10 @@ void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
|
| }
|
|
|
| void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
|
| + // If the frame invalidated is the frame being injected into, we need to
|
| + // note it.
|
| + active_injection_frames_.erase(frame);
|
| +
|
| for (ScopedVector<ScriptInjection>::iterator iter =
|
| pending_injections_.begin();
|
| iter != pending_injections_.end();) {
|
| @@ -349,13 +349,24 @@ void ScriptInjectionManager::InjectScripts(
|
| user_script_set_manager_->GetAllInjections(
|
| &frame_injections, frame, tab_id, run_location);
|
|
|
| - ScriptsRunInfo scripts_run_info;
|
| + // Note that we are running in |frame|.
|
| + active_injection_frames_.insert(frame);
|
| +
|
| + ScriptsRunInfo scripts_run_info(frame, run_location);
|
| std::vector<ScriptInjection*> released_injections;
|
| frame_injections.release(&released_injections);
|
| - for (ScriptInjection* injection : released_injections)
|
| + for (ScriptInjection* injection : released_injections) {
|
| + // It's possible for the frame to be invalidated in the course of injection
|
| + // (if a script removes its own frame, for example). If this happens, abort.
|
| + if (!active_injection_frames_.count(frame))
|
| + break;
|
| TryToInject(make_scoped_ptr(injection), run_location, &scripts_run_info);
|
| + }
|
| +
|
| + // We are done running in the frame.
|
| + active_injection_frames_.erase(frame);
|
|
|
| - scripts_run_info.LogRun(frame->GetWebFrame(), run_location);
|
| + scripts_run_info.LogRun();
|
| }
|
|
|
| void ScriptInjectionManager::TryToInject(
|
| @@ -405,13 +416,12 @@ void ScriptInjectionManager::HandleExecuteCode(
|
| static_cast<UserScript::RunLocation>(params.run_at),
|
| ExtensionFrameHelper::Get(render_frame)->tab_id()));
|
|
|
| - ScriptsRunInfo scripts_run_info;
|
| FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame);
|
| + UserScript::RunLocation run_location =
|
| + iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second;
|
|
|
| - TryToInject(
|
| - injection.Pass(),
|
| - iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second,
|
| - &scripts_run_info);
|
| + ScriptsRunInfo scripts_run_info(render_frame, run_location);
|
| + TryToInject(injection.Pass(), run_location, &scripts_run_info);
|
| }
|
|
|
| void ScriptInjectionManager::HandleExecuteDeclarativeScript(
|
| @@ -428,14 +438,13 @@ void ScriptInjectionManager::HandleExecuteDeclarativeScript(
|
| url,
|
| extension_id);
|
| if (injection.get()) {
|
| - ScriptsRunInfo scripts_run_info;
|
| + ScriptsRunInfo scripts_run_info(render_frame, UserScript::BROWSER_DRIVEN);
|
| // TODO(markdittmer): Use return value of TryToInject for error handling.
|
| TryToInject(injection.Pass(),
|
| UserScript::BROWSER_DRIVEN,
|
| &scripts_run_info);
|
|
|
| - scripts_run_info.LogRun(render_frame->GetWebFrame(),
|
| - UserScript::BROWSER_DRIVEN);
|
| + scripts_run_info.LogRun();
|
| }
|
| }
|
|
|
| @@ -459,13 +468,13 @@ void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
|
| scoped_ptr<ScriptInjection> injection(*iter);
|
| pending_injections_.weak_erase(iter);
|
|
|
| - ScriptsRunInfo scripts_run_info;
|
| + ScriptsRunInfo scripts_run_info(injection->render_frame(),
|
| + UserScript::RUN_DEFERRED);
|
| ScriptInjection::InjectionResult res = injection->OnPermissionGranted(
|
| &scripts_run_info);
|
| if (res == ScriptInjection::INJECTION_BLOCKED)
|
| running_injections_.push_back(injection.Pass());
|
| - scripts_run_info.LogRun(injection->render_frame()->GetWebFrame(),
|
| - UserScript::RUN_DEFERRED);
|
| + scripts_run_info.LogRun();
|
| }
|
|
|
| } // namespace extensions
|
|
|