[Storage] Blob Storage Refactoring pt 1:
[chromium-blink-merge.git] / chrome / browser / printing / print_preview_dialog_controller.cc
blob1f5afab214180bb44c010b454da8c862eeb0c887
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 "chrome/browser/printing/print_preview_dialog_controller.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/auto_reset.h"
12 #include "base/path_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
17 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
18 #include "chrome/browser/printing/print_view_manager.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_finder.h"
21 #include "chrome/browser/ui/browser_navigator.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/host_desktop.h"
24 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
25 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
26 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
27 #include "chrome/common/chrome_content_client.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chrome/common/url_constants.h"
30 #include "components/web_modal/web_contents_modal_dialog_host.h"
31 #include "content/public/browser/navigation_controller.h"
32 #include "content/public/browser/navigation_details.h"
33 #include "content/public/browser/navigation_entry.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_source.h"
36 #include "content/public/browser/plugin_service.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/browser/web_contents_delegate.h"
42 #include "content/public/common/webplugininfo.h"
43 #include "extensions/browser/guest_view/guest_view_base.h"
44 #include "ui/web_dialogs/web_dialog_delegate.h"
46 using content::NavigationController;
47 using content::WebContents;
48 using content::WebUIMessageHandler;
50 namespace {
52 void EnableInternalPDFPluginForContents(WebContents* preview_dialog) {
53 // Always enable the internal PDF plugin for the print preview page.
54 base::FilePath pdf_plugin_path;
55 if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_plugin_path))
56 return;
58 content::WebPluginInfo pdf_plugin;
59 if (!content::PluginService::GetInstance()->GetPluginInfoByPath(
60 pdf_plugin_path, &pdf_plugin))
61 return;
63 ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
64 preview_dialog->GetRenderProcessHost()->GetID(),
65 preview_dialog->GetMainFrame()->GetRoutingID(),
66 GURL(), pdf_plugin);
69 // A ui::WebDialogDelegate that specifies the print preview dialog appearance.
70 class PrintPreviewDialogDelegate : public ui::WebDialogDelegate {
71 public:
72 explicit PrintPreviewDialogDelegate(WebContents* initiator);
73 ~PrintPreviewDialogDelegate() override;
75 ui::ModalType GetDialogModalType() const override;
76 base::string16 GetDialogTitle() const override;
77 GURL GetDialogContentURL() const override;
78 void GetWebUIMessageHandlers(
79 std::vector<WebUIMessageHandler*>* handlers) const override;
80 void GetDialogSize(gfx::Size* size) const override;
81 std::string GetDialogArgs() const override;
82 void OnDialogClosed(const std::string& json_retval) override;
83 void OnCloseContents(WebContents* source, bool* out_close_dialog) override;
84 bool ShouldShowDialogTitle() const override;
86 private:
87 WebContents* initiator_;
89 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDelegate);
92 PrintPreviewDialogDelegate::PrintPreviewDialogDelegate(WebContents* initiator)
93 : initiator_(initiator) {
96 PrintPreviewDialogDelegate::~PrintPreviewDialogDelegate() {
99 ui::ModalType PrintPreviewDialogDelegate::GetDialogModalType() const {
100 // Not used, returning dummy value.
101 NOTREACHED();
102 return ui::MODAL_TYPE_WINDOW;
105 base::string16 PrintPreviewDialogDelegate::GetDialogTitle() const {
106 // Only used on Windows? UI folks prefer no title.
107 return base::string16();
110 GURL PrintPreviewDialogDelegate::GetDialogContentURL() const {
111 return GURL(chrome::kChromeUIPrintURL);
114 void PrintPreviewDialogDelegate::GetWebUIMessageHandlers(
115 std::vector<WebUIMessageHandler*>* /* handlers */) const {
116 // PrintPreviewUI adds its own message handlers.
119 void PrintPreviewDialogDelegate::GetDialogSize(gfx::Size* size) const {
120 DCHECK(size);
121 const gfx::Size kMinDialogSize(800, 480);
122 const int kBorder = 25;
123 *size = kMinDialogSize;
125 web_modal::WebContentsModalDialogHost* host = NULL;
126 content::WebContents* outermost_web_contents = initiator_;
127 const extensions::GuestViewBase* guest_view =
128 extensions::GuestViewBase::FromWebContents(outermost_web_contents);
129 while (guest_view && guest_view->attached()) {
130 outermost_web_contents = guest_view->embedder_web_contents();
131 guest_view =
132 extensions::GuestViewBase::FromWebContents(outermost_web_contents);
134 Browser* browser = chrome::FindBrowserWithWebContents(outermost_web_contents);
135 if (browser)
136 host = browser->window()->GetWebContentsModalDialogHost();
138 if (host) {
139 size->SetToMax(host->GetMaximumDialogSize());
140 size->Enlarge(-2 * kBorder, -kBorder);
141 } else {
142 size->SetToMax(outermost_web_contents->GetContainerBounds().size());
143 size->Enlarge(-2 * kBorder, -2 * kBorder);
146 #if defined(OS_MACOSX)
147 // Limit the maximum size on MacOS X.
148 // http://crbug.com/105815
149 const gfx::Size kMaxDialogSize(1000, 660);
150 size->SetToMin(kMaxDialogSize);
151 #endif
154 std::string PrintPreviewDialogDelegate::GetDialogArgs() const {
155 return std::string();
158 void PrintPreviewDialogDelegate::OnDialogClosed(
159 const std::string& /* json_retval */) {
162 void PrintPreviewDialogDelegate::OnCloseContents(WebContents* /* source */,
163 bool* out_close_dialog) {
164 if (out_close_dialog)
165 *out_close_dialog = true;
168 bool PrintPreviewDialogDelegate::ShouldShowDialogTitle() const {
169 return false;
172 } // namespace
174 namespace printing {
176 PrintPreviewDialogController::PrintPreviewDialogController()
177 : waiting_for_new_preview_page_(false),
178 is_creating_print_preview_dialog_(false) {
181 // static
182 PrintPreviewDialogController* PrintPreviewDialogController::GetInstance() {
183 if (!g_browser_process)
184 return NULL;
185 return g_browser_process->print_preview_dialog_controller();
188 // static
189 void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
190 if (initiator->ShowingInterstitialPage())
191 return;
193 PrintPreviewDialogController* dialog_controller = GetInstance();
194 if (!dialog_controller)
195 return;
196 if (!dialog_controller->GetOrCreatePreviewDialog(initiator))
197 PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
200 WebContents* PrintPreviewDialogController::GetOrCreatePreviewDialog(
201 WebContents* initiator) {
202 DCHECK(initiator);
204 // Get the print preview dialog for |initiator|.
205 WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
206 if (!preview_dialog)
207 return CreatePrintPreviewDialog(initiator);
209 // Show the initiator holding the existing preview dialog.
210 initiator->GetDelegate()->ActivateContents(initiator);
211 return preview_dialog;
214 WebContents* PrintPreviewDialogController::GetPrintPreviewForContents(
215 WebContents* contents) const {
216 // |preview_dialog_map_| is keyed by the preview dialog, so if find()
217 // succeeds, then |contents| is the preview dialog.
218 PrintPreviewDialogMap::const_iterator it = preview_dialog_map_.find(contents);
219 if (it != preview_dialog_map_.end())
220 return contents;
222 for (it = preview_dialog_map_.begin();
223 it != preview_dialog_map_.end();
224 ++it) {
225 // If |contents| is an initiator.
226 if (contents == it->second) {
227 // Return the associated preview dialog.
228 return it->first;
231 return NULL;
234 WebContents* PrintPreviewDialogController::GetInitiator(
235 WebContents* preview_dialog) {
236 PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
237 return (it != preview_dialog_map_.end()) ? it->second : NULL;
240 void PrintPreviewDialogController::Observe(
241 int type,
242 const content::NotificationSource& source,
243 const content::NotificationDetails& details) {
244 if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
245 OnRendererProcessClosed(
246 content::Source<content::RenderProcessHost>(source).ptr());
247 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
248 OnWebContentsDestroyed(content::Source<WebContents>(source).ptr());
249 } else {
250 DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type);
251 WebContents* contents =
252 content::Source<NavigationController>(source)->GetWebContents();
253 OnNavEntryCommitted(
254 contents,
255 content::Details<content::LoadCommittedDetails>(details).ptr());
259 void PrintPreviewDialogController::ForEachPreviewDialog(
260 base::Callback<void(content::WebContents*)> callback) {
261 for (PrintPreviewDialogMap::const_iterator it = preview_dialog_map_.begin();
262 it != preview_dialog_map_.end();
263 ++it) {
264 callback.Run(it->first);
268 // static
269 bool PrintPreviewDialogController::IsPrintPreviewDialog(WebContents* contents) {
270 return IsPrintPreviewURL(contents->GetURL());
273 // static
274 bool PrintPreviewDialogController::IsPrintPreviewURL(const GURL& url) {
275 return (url.SchemeIs(content::kChromeUIScheme) &&
276 url.host() == chrome::kChromeUIPrintHost);
279 void PrintPreviewDialogController::EraseInitiatorInfo(
280 WebContents* preview_dialog) {
281 PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
282 if (it == preview_dialog_map_.end())
283 return;
285 RemoveObservers(it->second);
286 preview_dialog_map_[preview_dialog] = NULL;
289 PrintPreviewDialogController::~PrintPreviewDialogController() {}
291 void PrintPreviewDialogController::OnRendererProcessClosed(
292 content::RenderProcessHost* rph) {
293 // Store contents in a vector and deal with them after iterating through
294 // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|.
295 std::vector<WebContents*> closed_initiators;
296 std::vector<WebContents*> closed_preview_dialogs;
297 for (PrintPreviewDialogMap::iterator iter = preview_dialog_map_.begin();
298 iter != preview_dialog_map_.end(); ++iter) {
299 WebContents* preview_dialog = iter->first;
300 WebContents* initiator = iter->second;
301 if (preview_dialog->GetRenderProcessHost() == rph) {
302 closed_preview_dialogs.push_back(preview_dialog);
303 } else if (initiator &&
304 initiator->GetRenderProcessHost() == rph) {
305 closed_initiators.push_back(initiator);
309 for (size_t i = 0; i < closed_preview_dialogs.size(); ++i) {
310 RemovePreviewDialog(closed_preview_dialogs[i]);
311 if (content::WebUI* web_ui = closed_preview_dialogs[i]->GetWebUI()) {
312 PrintPreviewUI* print_preview_ui =
313 static_cast<PrintPreviewUI*>(web_ui->GetController());
314 if (print_preview_ui)
315 print_preview_ui->OnPrintPreviewDialogClosed();
319 for (size_t i = 0; i < closed_initiators.size(); ++i)
320 RemoveInitiator(closed_initiators[i]);
323 void PrintPreviewDialogController::OnWebContentsDestroyed(
324 WebContents* contents) {
325 WebContents* preview_dialog = GetPrintPreviewForContents(contents);
326 if (!preview_dialog) {
327 NOTREACHED();
328 return;
331 if (contents == preview_dialog)
332 RemovePreviewDialog(contents);
333 else
334 RemoveInitiator(contents);
337 void PrintPreviewDialogController::OnNavEntryCommitted(
338 WebContents* contents, content::LoadCommittedDetails* details) {
339 WebContents* preview_dialog = GetPrintPreviewForContents(contents);
340 if (!preview_dialog) {
341 NOTREACHED();
342 return;
345 if (contents == preview_dialog) {
346 // Preview dialog navigated.
347 if (details) {
348 ui::PageTransition transition_type =
349 details->entry->GetTransitionType();
350 content::NavigationType nav_type = details->type;
352 // New |preview_dialog| is created. Don't update/erase map entry.
353 if (waiting_for_new_preview_page_ &&
354 transition_type == ui::PAGE_TRANSITION_AUTO_TOPLEVEL &&
355 nav_type == content::NAVIGATION_TYPE_NEW_PAGE) {
356 waiting_for_new_preview_page_ = false;
357 SaveInitiatorTitle(preview_dialog);
358 return;
361 // Cloud print sign-in causes a reload.
362 if (!waiting_for_new_preview_page_ &&
363 transition_type == ui::PAGE_TRANSITION_RELOAD &&
364 nav_type == content::NAVIGATION_TYPE_EXISTING_PAGE &&
365 IsPrintPreviewURL(details->previous_url)) {
366 return;
369 NOTREACHED();
370 return;
373 RemoveInitiator(contents);
376 WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog(
377 WebContents* initiator) {
378 base::AutoReset<bool> auto_reset(&is_creating_print_preview_dialog_, true);
380 // The dialog delegates are deleted when the dialog is closed.
381 ConstrainedWebDialogDelegate* web_dialog_delegate =
382 ShowConstrainedWebDialog(initiator->GetBrowserContext(),
383 new PrintPreviewDialogDelegate(initiator),
384 initiator);
386 WebContents* preview_dialog = web_dialog_delegate->GetWebContents();
387 EnableInternalPDFPluginForContents(preview_dialog);
388 PrintViewManager::CreateForWebContents(preview_dialog);
389 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
390 preview_dialog);
392 // Add an entry to the map.
393 preview_dialog_map_[preview_dialog] = initiator;
394 waiting_for_new_preview_page_ = true;
396 AddObservers(initiator);
397 AddObservers(preview_dialog);
399 return preview_dialog;
402 void PrintPreviewDialogController::SaveInitiatorTitle(
403 WebContents* preview_dialog) {
404 WebContents* initiator = GetInitiator(preview_dialog);
405 if (initiator && preview_dialog->GetWebUI()) {
406 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
407 preview_dialog->GetWebUI()->GetController());
408 print_preview_ui->SetInitiatorTitle(
409 PrintViewManager::FromWebContents(initiator)->RenderSourceName());
413 void PrintPreviewDialogController::AddObservers(WebContents* contents) {
414 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
415 content::Source<WebContents>(contents));
416 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
417 content::Source<NavigationController>(&contents->GetController()));
419 // Multiple sites may share the same RenderProcessHost, so check if this
420 // notification has already been added.
421 content::Source<content::RenderProcessHost> rph_source(
422 contents->GetRenderProcessHost());
423 if (!registrar_.IsRegistered(this,
424 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) {
425 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
426 rph_source);
430 void PrintPreviewDialogController::RemoveObservers(WebContents* contents) {
431 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
432 content::Source<WebContents>(contents));
433 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
434 content::Source<NavigationController>(&contents->GetController()));
436 // Multiple sites may share the same RenderProcessHost, so check if this
437 // notification has already been added.
438 content::Source<content::RenderProcessHost> rph_source(
439 contents->GetRenderProcessHost());
440 if (registrar_.IsRegistered(this,
441 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) {
442 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
443 rph_source);
447 void PrintPreviewDialogController::RemoveInitiator(
448 WebContents* initiator) {
449 WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
450 DCHECK(preview_dialog);
451 // Update the map entry first, so when the print preview dialog gets destroyed
452 // and reaches RemovePreviewDialog(), it does not attempt to also remove the
453 // initiator's observers.
454 preview_dialog_map_[preview_dialog] = NULL;
455 RemoveObservers(initiator);
457 PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
459 // initiator is closed. Close the print preview dialog too.
460 if (content::WebUI* web_ui = preview_dialog->GetWebUI()) {
461 PrintPreviewUI* print_preview_ui =
462 static_cast<PrintPreviewUI*>(web_ui->GetController());
463 if (print_preview_ui)
464 print_preview_ui->OnInitiatorClosed();
468 void PrintPreviewDialogController::RemovePreviewDialog(
469 WebContents* preview_dialog) {
470 // Remove the initiator's observers before erasing the mapping.
471 WebContents* initiator = GetInitiator(preview_dialog);
472 if (initiator) {
473 RemoveObservers(initiator);
474 PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
477 // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to abort
478 // the initiator preview request.
479 if (content::WebUI* web_ui = preview_dialog->GetWebUI()) {
480 PrintPreviewUI* print_preview_ui =
481 static_cast<PrintPreviewUI*>(web_ui->GetController());
482 if (print_preview_ui)
483 print_preview_ui->OnPrintPreviewDialogDestroyed();
486 preview_dialog_map_.erase(preview_dialog);
487 RemoveObservers(preview_dialog);
490 } // namespace printing