Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / download / drag_download_file.cc
blob2014270e38c1a3190c6d034e8fe53c179d91431b
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
3 // found in the LICENSE file.
5 #include "content/browser/download/drag_download_file.h"
7 #include "base/bind.h"
8 #include "base/files/file.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "content/browser/download/download_stats.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/download_item.h"
16 #include "content/public/browser/download_save_info.h"
17 #include "content/public/browser/download_url_parameters.h"
19 namespace content {
21 namespace {
23 typedef base::Callback<void(bool)> OnCompleted;
25 } // namespace
27 // On windows, DragDownloadFile runs on a thread other than the UI thread.
28 // DownloadItem and DownloadManager may not be accessed on any thread other than
29 // the UI thread. DragDownloadFile may run on either the "drag" thread or the UI
30 // thread depending on the platform, but DragDownloadFileUI strictly always runs
31 // on the UI thread. On platforms where DragDownloadFile runs on the UI thread,
32 // none of the PostTasks are necessary, but it simplifies the code to do them
33 // anyway.
34 class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
35 public:
36 DragDownloadFileUI(const GURL& url,
37 const Referrer& referrer,
38 const std::string& referrer_encoding,
39 WebContents* web_contents,
40 base::MessageLoop* on_completed_loop,
41 const OnCompleted& on_completed)
42 : on_completed_loop_(on_completed_loop),
43 on_completed_(on_completed),
44 url_(url),
45 referrer_(referrer),
46 referrer_encoding_(referrer_encoding),
47 web_contents_(web_contents),
48 download_item_(NULL),
49 weak_ptr_factory_(this) {
50 DCHECK(on_completed_loop_);
51 DCHECK(!on_completed_.is_null());
52 DCHECK(web_contents_);
53 // May be called on any thread.
54 // Do not call weak_ptr_factory_.GetWeakPtr() outside the UI thread.
57 void InitiateDownload(base::File file,
58 const base::FilePath& file_path) {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI);
60 DownloadManager* download_manager =
61 BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext());
63 RecordDownloadSource(INITIATED_BY_DRAG_N_DROP);
64 scoped_ptr<content::DownloadUrlParameters> params(
65 DownloadUrlParameters::FromWebContents(web_contents_, url_));
66 params->set_referrer(referrer_);
67 params->set_referrer_encoding(referrer_encoding_);
68 params->set_callback(base::Bind(&DragDownloadFileUI::OnDownloadStarted,
69 weak_ptr_factory_.GetWeakPtr()));
70 params->set_file_path(file_path);
71 params->set_file(file.Pass()); // Nulls file.
72 download_manager->DownloadUrl(params.Pass());
75 void Cancel() {
76 DCHECK_CURRENTLY_ON(BrowserThread::UI);
77 if (download_item_)
78 download_item_->Cancel(true);
81 void Delete() {
82 DCHECK_CURRENTLY_ON(BrowserThread::UI);
83 delete this;
86 private:
87 ~DragDownloadFileUI() override {
88 DCHECK_CURRENTLY_ON(BrowserThread::UI);
89 if (download_item_)
90 download_item_->RemoveObserver(this);
93 void OnDownloadStarted(DownloadItem* item,
94 DownloadInterruptReason interrupt_reason) {
95 DCHECK_CURRENTLY_ON(BrowserThread::UI);
96 if (!item) {
97 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
98 on_completed_loop_->task_runner()->PostTask(
99 FROM_HERE, base::Bind(on_completed_, false));
100 return;
102 DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
103 download_item_ = item;
104 download_item_->AddObserver(this);
107 // DownloadItem::Observer:
108 void OnDownloadUpdated(DownloadItem* item) override {
109 DCHECK_CURRENTLY_ON(BrowserThread::UI);
110 DCHECK_EQ(download_item_, item);
111 DownloadItem::DownloadState state = download_item_->GetState();
112 if (state == DownloadItem::COMPLETE ||
113 state == DownloadItem::CANCELLED ||
114 state == DownloadItem::INTERRUPTED) {
115 if (!on_completed_.is_null()) {
116 on_completed_loop_->task_runner()->PostTask(
117 FROM_HERE,
118 base::Bind(on_completed_, state == DownloadItem::COMPLETE));
119 on_completed_.Reset();
121 download_item_->RemoveObserver(this);
122 download_item_ = NULL;
124 // Ignore other states.
127 void OnDownloadDestroyed(DownloadItem* item) override {
128 DCHECK_CURRENTLY_ON(BrowserThread::UI);
129 DCHECK_EQ(download_item_, item);
130 if (!on_completed_.is_null()) {
131 const bool is_complete =
132 download_item_->GetState() == DownloadItem::COMPLETE;
133 on_completed_loop_->task_runner()->PostTask(
134 FROM_HERE, base::Bind(on_completed_, is_complete));
135 on_completed_.Reset();
137 download_item_->RemoveObserver(this);
138 download_item_ = NULL;
141 base::MessageLoop* on_completed_loop_;
142 OnCompleted on_completed_;
143 GURL url_;
144 Referrer referrer_;
145 std::string referrer_encoding_;
146 WebContents* web_contents_;
147 DownloadItem* download_item_;
149 // Only used in the callback from DownloadManager::DownloadUrl().
150 base::WeakPtrFactory<DragDownloadFileUI> weak_ptr_factory_;
152 DISALLOW_COPY_AND_ASSIGN(DragDownloadFileUI);
155 DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
156 base::File file,
157 const GURL& url,
158 const Referrer& referrer,
159 const std::string& referrer_encoding,
160 WebContents* web_contents)
161 : file_path_(file_path),
162 file_(file.Pass()),
163 drag_message_loop_(base::MessageLoop::current()),
164 state_(INITIALIZED),
165 drag_ui_(NULL),
166 weak_ptr_factory_(this) {
167 drag_ui_ = new DragDownloadFileUI(
168 url,
169 referrer,
170 referrer_encoding,
171 web_contents,
172 drag_message_loop_,
173 base::Bind(&DragDownloadFile::DownloadCompleted,
174 weak_ptr_factory_.GetWeakPtr()));
175 DCHECK(!file_path_.empty());
178 DragDownloadFile::~DragDownloadFile() {
179 CheckThread();
181 // This is the only place that drag_ui_ can be deleted from. Post a message to
182 // the UI thread so that it calls RemoveObserver on the right thread, and so
183 // that this task will run after the InitiateDownload task runs on the UI
184 // thread.
185 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
186 &DragDownloadFileUI::Delete, base::Unretained(drag_ui_)));
187 drag_ui_ = NULL;
190 void DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
191 CheckThread();
193 if (state_ != INITIALIZED)
194 return;
195 state_ = STARTED;
197 DCHECK(!observer_.get());
198 observer_ = observer;
199 DCHECK(observer_.get());
201 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
202 &DragDownloadFileUI::InitiateDownload, base::Unretained(drag_ui_),
203 base::Passed(&file_), file_path_));
206 bool DragDownloadFile::Wait() {
207 CheckThread();
208 if (state_ == STARTED)
209 nested_loop_.Run();
210 return state_ == SUCCESS;
213 void DragDownloadFile::Stop() {
214 CheckThread();
215 if (drag_ui_) {
216 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
217 &DragDownloadFileUI::Cancel, base::Unretained(drag_ui_)));
221 void DragDownloadFile::DownloadCompleted(bool is_successful) {
222 CheckThread();
224 state_ = is_successful ? SUCCESS : FAILURE;
226 if (is_successful)
227 observer_->OnDownloadCompleted(file_path_);
228 else
229 observer_->OnDownloadAborted();
231 // Release the observer since we do not need it any more.
232 observer_ = NULL;
234 if (nested_loop_.running())
235 nested_loop_.Quit();
238 void DragDownloadFile::CheckThread() {
239 #if defined(OS_WIN)
240 DCHECK(drag_message_loop_ == base::MessageLoop::current());
241 #else
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
243 #endif
246 } // namespace content