Commit 24730168 authored by dgozman@chromium.org's avatar dgozman@chromium.org

[DevTools] Add explicit closing state in DevToolsWindow life time.

Previously, DevToolsWindow relied on DevToolsClientHost life time,
which is error prone and introduced quite a few bugs.

BUG=392180

Review URL: https://codereview.chromium.org/371363005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282000 0039d316-1c4b-4281-b951-d872f2087c98
parent 645f633a
...@@ -363,13 +363,13 @@ content::WebContents* DevToolsWindow::GetInTabWebContents( ...@@ -363,13 +363,13 @@ content::WebContents* DevToolsWindow::GetInTabWebContents(
DevToolsContentsResizingStrategy* out_strategy) { DevToolsContentsResizingStrategy* out_strategy) {
DevToolsWindow* window = GetInstanceForInspectedWebContents( DevToolsWindow* window = GetInstanceForInspectedWebContents(
inspected_web_contents); inspected_web_contents);
if (!window) if (!window || window->life_stage_ == kClosing)
return NULL; return NULL;
// Not yet loaded window is treated as docked, but we should not present it // Not yet loaded window is treated as docked, but we should not present it
// until we decided on docking. // until we decided on docking.
bool is_docked_set = window->load_state_ == kLoadCompleted || bool is_docked_set = window->life_stage_ == kLoadCompleted ||
window->load_state_ == kIsDockedSet; window->life_stage_ == kIsDockedSet;
if (!is_docked_set) if (!is_docked_set)
return NULL; return NULL;
...@@ -539,7 +539,7 @@ void DevToolsWindow::InspectElement(content::RenderViewHost* inspected_rvh, ...@@ -539,7 +539,7 @@ void DevToolsWindow::InspectElement(content::RenderViewHost* inspected_rvh,
} }
void DevToolsWindow::ScheduleShow(const DevToolsToggleAction& action) { void DevToolsWindow::ScheduleShow(const DevToolsToggleAction& action) {
if (load_state_ == kLoadCompleted) { if (life_stage_ == kLoadCompleted) {
Show(action); Show(action);
return; return;
} }
...@@ -555,6 +555,9 @@ void DevToolsWindow::ScheduleShow(const DevToolsToggleAction& action) { ...@@ -555,6 +555,9 @@ void DevToolsWindow::ScheduleShow(const DevToolsToggleAction& action) {
} }
void DevToolsWindow::Show(const DevToolsToggleAction& action) { void DevToolsWindow::Show(const DevToolsToggleAction& action) {
if (life_stage_ == kClosing)
return;
if (action.type() == DevToolsToggleAction::kNoOp) if (action.type() == DevToolsToggleAction::kNoOp)
return; return;
...@@ -629,7 +632,7 @@ bool DevToolsWindow::InterceptPageBeforeUnload(WebContents* contents) { ...@@ -629,7 +632,7 @@ bool DevToolsWindow::InterceptPageBeforeUnload(WebContents* contents) {
return false; return false;
// Not yet loaded frontend will not handle beforeunload. // Not yet loaded frontend will not handle beforeunload.
if (window->load_state_ != kLoadCompleted) if (window->life_stage_ != kLoadCompleted)
return false; return false;
window->intercepted_page_beforeunload_ = true; window->intercepted_page_beforeunload_ = true;
...@@ -692,12 +695,12 @@ DevToolsWindow::DevToolsWindow(Profile* profile, ...@@ -692,12 +695,12 @@ DevToolsWindow::DevToolsWindow(Profile* profile,
// This initialization allows external front-end to work without changes. // This initialization allows external front-end to work without changes.
// We don't wait for docking call, but instead immediately show undocked. // We don't wait for docking call, but instead immediately show undocked.
// Passing "dockSide=undocked" parameter ensures proper UI. // Passing "dockSide=undocked" parameter ensures proper UI.
load_state_(can_dock ? kNotLoaded : kIsDockedSet), life_stage_(can_dock ? kNotLoaded : kIsDockedSet),
action_on_load_(DevToolsToggleAction::NoOp()), action_on_load_(DevToolsToggleAction::NoOp()),
ignore_set_is_docked_(false), ignore_set_is_docked_(false),
intercepted_page_beforeunload_(false) { intercepted_page_beforeunload_(false) {
// Set up delegate, so we get fully-functional window immediately. // Set up delegate, so we get fully-functional window immediately.
// It will not appear in UI though until |load_state_ == kLoadCompleted|. // It will not appear in UI though until |life_stage_ == kLoadCompleted|.
main_web_contents_->SetDelegate(this); main_web_contents_->SetDelegate(this);
bindings_ = new DevToolsUIBindings( bindings_ = new DevToolsUIBindings(
main_web_contents_, main_web_contents_,
...@@ -871,14 +874,7 @@ void DevToolsWindow::WebContentsCreated(WebContents* source_contents, ...@@ -871,14 +874,7 @@ void DevToolsWindow::WebContentsCreated(WebContents* source_contents,
void DevToolsWindow::CloseContents(WebContents* source) { void DevToolsWindow::CloseContents(WebContents* source) {
CHECK(is_docked_); CHECK(is_docked_);
// Do this first so that when GetDockedInstanceForInspectedTab is called life_stage_ = kClosing;
// from UpdateDevTools it won't return this instance
// see crbug.com/372504
content::DevToolsManager::GetInstance()->ClientHostClosing(
bindings_->frontend_host());
// This will prevent any activity after frontend is loaded.
action_on_load_ = DevToolsToggleAction::NoOp();
ignore_set_is_docked_ = true;
UpdateBrowserWindow(); UpdateBrowserWindow();
// In case of docked main_web_contents_, we own it so delete here. // In case of docked main_web_contents_, we own it so delete here.
// Embedding DevTools window will be deleted as a result of // Embedding DevTools window will be deleted as a result of
...@@ -987,9 +983,7 @@ void DevToolsWindow::ActivateWindow() { ...@@ -987,9 +983,7 @@ void DevToolsWindow::ActivateWindow() {
void DevToolsWindow::CloseWindow() { void DevToolsWindow::CloseWindow() {
DCHECK(is_docked_); DCHECK(is_docked_);
// This will prevent any activity after frontend is loaded. life_stage_ = kClosing;
action_on_load_ = DevToolsToggleAction::NoOp();
ignore_set_is_docked_ = true;
main_web_contents_->DispatchBeforeUnload(false); main_web_contents_->DispatchBeforeUnload(false);
} }
...@@ -1030,24 +1024,25 @@ void DevToolsWindow::MoveWindow(int x, int y) { ...@@ -1030,24 +1024,25 @@ void DevToolsWindow::MoveWindow(int x, int y) {
void DevToolsWindow::SetIsDockedAndShowImmediatelyForTest(bool is_docked) { void DevToolsWindow::SetIsDockedAndShowImmediatelyForTest(bool is_docked) {
DCHECK(!is_docked || can_dock_); DCHECK(!is_docked || can_dock_);
if (load_state_ == kLoadCompleted) { DCHECK(life_stage_ != kClosing);
if (life_stage_ == kLoadCompleted) {
SetIsDocked(is_docked); SetIsDocked(is_docked);
} else { } else {
is_docked_ = is_docked; is_docked_ = is_docked;
// Load is completed when both kIsDockedSet and kOnLoadFired happened. // Load is completed when both kIsDockedSet and kOnLoadFired happened.
// Note that kIsDockedSet may be already set when can_dock_ is false. // Note that kIsDockedSet may be already set when can_dock_ is false.
load_state_ = load_state_ == kOnLoadFired ? kLoadCompleted : kIsDockedSet; life_stage_ = life_stage_ == kOnLoadFired ? kLoadCompleted : kIsDockedSet;
// Note that action_on_load_ will be performed after the load is actually // Note that action_on_load_ will be performed after the load is actually
// completed. For now, just show the window. // completed. For now, just show the window.
Show(DevToolsToggleAction::Show()); Show(DevToolsToggleAction::Show());
if (load_state_ == kLoadCompleted) if (life_stage_ == kLoadCompleted)
LoadCompleted(); LoadCompleted();
} }
ignore_set_is_docked_ = true; ignore_set_is_docked_ = true;
} }
void DevToolsWindow::SetIsDocked(bool dock_requested) { void DevToolsWindow::SetIsDocked(bool dock_requested) {
if (ignore_set_is_docked_) if (ignore_set_is_docked_ || life_stage_ == kClosing)
return; return;
DCHECK(can_dock_ || !dock_requested); DCHECK(can_dock_ || !dock_requested);
...@@ -1057,10 +1052,10 @@ void DevToolsWindow::SetIsDocked(bool dock_requested) { ...@@ -1057,10 +1052,10 @@ void DevToolsWindow::SetIsDocked(bool dock_requested) {
bool was_docked = is_docked_; bool was_docked = is_docked_;
is_docked_ = dock_requested; is_docked_ = dock_requested;
if (load_state_ != kLoadCompleted) { if (life_stage_ != kLoadCompleted) {
// This is a first time call we waited for to initialize. // This is a first time call we waited for to initialize.
load_state_ = load_state_ == kOnLoadFired ? kLoadCompleted : kIsDockedSet; life_stage_ = life_stage_ == kOnLoadFired ? kLoadCompleted : kIsDockedSet;
if (load_state_ == kLoadCompleted) if (life_stage_ == kLoadCompleted)
LoadCompleted(); LoadCompleted();
return; return;
} }
...@@ -1119,9 +1114,7 @@ void DevToolsWindow::SetWhitelistedShortcuts( ...@@ -1119,9 +1114,7 @@ void DevToolsWindow::SetWhitelistedShortcuts(
void DevToolsWindow::InspectedContentsClosing() { void DevToolsWindow::InspectedContentsClosing() {
intercepted_page_beforeunload_ = false; intercepted_page_beforeunload_ = false;
// This will prevent any activity after frontend is loaded. life_stage_ = kClosing;
action_on_load_ = DevToolsToggleAction::NoOp();
ignore_set_is_docked_ = true;
main_web_contents_->GetRenderViewHost()->ClosePage(); main_web_contents_->GetRenderViewHost()->ClosePage();
} }
...@@ -1152,13 +1145,16 @@ void DevToolsWindow::OnLoadCompleted() { ...@@ -1152,13 +1145,16 @@ void DevToolsWindow::OnLoadCompleted() {
} }
} }
if (life_stage_ == kClosing)
return;
// We could be in kLoadCompleted state already if frontend reloads itself. // We could be in kLoadCompleted state already if frontend reloads itself.
if (load_state_ != kLoadCompleted) { if (life_stage_ != kLoadCompleted) {
// Load is completed when both kIsDockedSet and kOnLoadFired happened. // Load is completed when both kIsDockedSet and kOnLoadFired happened.
// Here we set kOnLoadFired. // Here we set kOnLoadFired.
load_state_ = load_state_ == kIsDockedSet ? kLoadCompleted : kOnLoadFired; life_stage_ = life_stage_ == kIsDockedSet ? kLoadCompleted : kOnLoadFired;
} }
if (load_state_ == kLoadCompleted) if (life_stage_ == kLoadCompleted)
LoadCompleted(); LoadCompleted();
} }
...@@ -1257,7 +1253,7 @@ void DevToolsWindow::LoadCompleted() { ...@@ -1257,7 +1253,7 @@ void DevToolsWindow::LoadCompleted() {
} }
void DevToolsWindow::SetLoadCompletedCallback(const base::Closure& closure) { void DevToolsWindow::SetLoadCompletedCallback(const base::Closure& closure) {
if (load_state_ == kLoadCompleted) { if (life_stage_ == kLoadCompleted) {
if (!closure.is_null()) if (!closure.is_null())
closure.Run(); closure.Run();
return; return;
......
...@@ -186,7 +186,7 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate, ...@@ -186,7 +186,7 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate,
friend class DevToolsSanityTest; friend class DevToolsSanityTest;
friend class BrowserWindowControllerTest; friend class BrowserWindowControllerTest;
// DevTools initialization typically follows this way: // DevTools lifecycle typically follows this way:
// - Toggle/Open: client call; // - Toggle/Open: client call;
// - Create; // - Create;
// - ScheduleShow: setup window to be functional, but not yet show; // - ScheduleShow: setup window to be functional, but not yet show;
...@@ -194,12 +194,17 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate, ...@@ -194,12 +194,17 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate,
// - SetIsDocked: frontend decided on docking state; // - SetIsDocked: frontend decided on docking state;
// - OnLoadCompleted: ready to present frontend; // - OnLoadCompleted: ready to present frontend;
// - Show: actually placing frontend WebContents to a Browser or docked place; // - Show: actually placing frontend WebContents to a Browser or docked place;
// - DoAction: perform action passed in Toggle/Open. // - DoAction: perform action passed in Toggle/Open;
enum LoadState { // - ...;
// - CloseWindow: initiates before unload handling;
// - CloseContents: destroys frontend;
// - DevToolsWindow is dead once it's main_web_contents dies.
enum LifeStage {
kNotLoaded, kNotLoaded,
kOnLoadFired, // Implies SetIsDocked was not yet called. kOnLoadFired, // Implies SetIsDocked was not yet called.
kIsDockedSet, // Implies DocumentOnLoadCompleted was not yet called. kIsDockedSet, // Implies DocumentOnLoadCompleted was not yet called.
kLoadCompleted kLoadCompleted,
kClosing
}; };
DevToolsWindow(Profile* profile, DevToolsWindow(Profile* profile,
...@@ -306,7 +311,7 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate, ...@@ -306,7 +311,7 @@ class DevToolsWindow : public DevToolsUIBindings::Delegate,
Browser* browser_; Browser* browser_;
bool is_docked_; bool is_docked_;
const bool can_dock_; const bool can_dock_;
LoadState load_state_; LifeStage life_stage_;
DevToolsToggleAction action_on_load_; DevToolsToggleAction action_on_load_;
bool ignore_set_is_docked_; bool ignore_set_is_docked_;
DevToolsContentsResizingStrategy contents_resizing_strategy_; DevToolsContentsResizingStrategy contents_resizing_strategy_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment