1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/instant/instant_unload_handler.h"
#include <algorithm>
#include "base/message_loop.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
class InstantUnloadHandler::WebContentsDelegateImpl
: public content::WebContentsDelegate {
public:
WebContentsDelegateImpl(InstantUnloadHandler* handler,
scoped_ptr<content::WebContents> contents,
int index)
: handler_(handler),
contents_(contents.Pass()),
index_(index) {
contents_->SetDelegate(this);
contents_->GetRenderViewHost()->FirePageBeforeUnload(false);
}
// Overridden from content::WebContentsDelegate:
virtual void CloseContents(content::WebContents* source) OVERRIDE {
DCHECK_EQ(contents_, source);
// Remove ourselves as the delegate, so that CloseContents() won't be
// called twice, leading to double deletion (http://crbug.com/155848).
contents_->SetDelegate(NULL);
handler_->Destroy(this);
}
virtual void WillRunBeforeUnloadConfirm() OVERRIDE {
contents_->SetDelegate(NULL);
handler_->Activate(this, contents_.Pass(), index_);
}
virtual bool ShouldSuppressDialogs() OVERRIDE {
return true;
}
private:
InstantUnloadHandler* const handler_;
scoped_ptr<content::WebContents> contents_;
// The tab strip index |contents_| was originally at. If we add the tab back
// to the tabstrip, we add it at this index.
const int index_;
DISALLOW_COPY_AND_ASSIGN(WebContentsDelegateImpl);
};
InstantUnloadHandler::InstantUnloadHandler(Browser* browser)
: browser_(browser) {
}
InstantUnloadHandler::~InstantUnloadHandler() {
}
void InstantUnloadHandler::RunUnloadListenersOrDestroy(
scoped_ptr<content::WebContents> contents,
int index) {
DCHECK(!contents->GetDelegate());
if (!contents->NeedToFireBeforeUnload()) {
// Tab doesn't have any beforeunload listeners and can be safely deleted.
// However, the tab object should not be deleted immediately because when we
// get here from BrowserInstantController::TabDeactivated, other tab
// observers may still expect to interact with the tab before the event has
// finished propagating.
MessageLoop::current()->DeleteSoon(FROM_HERE, contents.release());
return;
}
// Tab has beforeunload listeners. Install a delegate to run them.
delegates_.push_back(
new WebContentsDelegateImpl(this, contents.Pass(), index));
}
void InstantUnloadHandler::Activate(WebContentsDelegateImpl* delegate,
scoped_ptr<content::WebContents> contents,
int index) {
// Remove (and delete) the delegate.
Destroy(delegate);
// Add the tab back in.
chrome::NavigateParams params(browser_, contents.release());
params.disposition = NEW_FOREGROUND_TAB;
params.tabstrip_index = index;
chrome::Navigate(¶ms);
}
void InstantUnloadHandler::Destroy(WebContentsDelegateImpl* delegate) {
ScopedVector<WebContentsDelegateImpl>::iterator i =
std::find(delegates_.begin(), delegates_.end(), delegate);
DCHECK(i != delegates_.end());
// The delegate's method is a caller on the stack, so schedule the deletion
// for later.
delegates_.weak_erase(i);
MessageLoop::current()->DeleteSoon(FROM_HERE, delegate);
}
|