Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / printing / print_preview_dialog_controller.cc
blobe190f01be432ef9ea56a5327c3e6c14d5a1c2669
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>
10 #include "base/auto_reset.h"
11 #include "base/path_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
16 #include "chrome/browser/printing/print_view_manager.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/browser_navigator.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/browser/ui/host_desktop.h"
23 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
24 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
25 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
26 #include "chrome/common/chrome_content_client.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/url_constants.h"
29 #include "components/web_modal/web_contents_modal_dialog_host.h"
30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/navigation_details.h"
32 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/plugin_service.h"
34 #include "content/public/browser/render_frame_host.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/render_process_host_observer.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/browser/web_contents_observer.h"
41 #include "content/public/browser/web_contents_view.h"
42 #include "content/public/common/webplugininfo.h"
43 #include "ui/web_dialogs/web_dialog_delegate.h"
44 #include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
46 using content::NativeWebKeyboardEvent;
47 using content::NavigationController;
48 using content::RenderProcessHost;
49 using content::WebContents;
50 using content::WebUIMessageHandler;
51 using ui::WebDialogDelegate;
52 using ui::WebDialogWebContentsDelegate;
54 namespace {
56 void EnableInternalPDFPluginForContents(WebContents* preview_dialog) {
57 // Always enable the internal PDF plugin for the print preview page.
58 base::FilePath pdf_plugin_path;
59 if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_plugin_path))
60 return;
62 content::WebPluginInfo pdf_plugin;
63 if (!content::PluginService::GetInstance()->GetPluginInfoByPath(
64 pdf_plugin_path, &pdf_plugin))
65 return;
67 ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
68 preview_dialog->GetRenderProcessHost()->GetID(),
69 preview_dialog->GetMainFrame()->GetRoutingID(),
70 GURL(), pdf_plugin);
73 // WebDialogDelegate that specifies what the print preview dialog
74 // will look like.
75 class PrintPreviewDialogDelegate : public WebDialogDelegate {
76 public:
77 explicit PrintPreviewDialogDelegate(WebContents* initiator);
78 virtual ~PrintPreviewDialogDelegate();
80 virtual ui::ModalType GetDialogModalType() const OVERRIDE;
81 virtual base::string16 GetDialogTitle() const OVERRIDE;
82 virtual GURL GetDialogContentURL() const OVERRIDE;
83 virtual void GetWebUIMessageHandlers(
84 std::vector<WebUIMessageHandler*>* handlers) const OVERRIDE;
85 virtual void GetDialogSize(gfx::Size* size) const OVERRIDE;
86 virtual std::string GetDialogArgs() const OVERRIDE;
87 virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE;
88 virtual void OnCloseContents(WebContents* source,
89 bool* out_close_dialog) OVERRIDE;
90 virtual bool ShouldShowDialogTitle() const OVERRIDE;
92 private:
93 WebContents* initiator_;
95 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDelegate);
98 PrintPreviewDialogDelegate::PrintPreviewDialogDelegate(WebContents* initiator)
99 : initiator_(initiator) {
102 PrintPreviewDialogDelegate::~PrintPreviewDialogDelegate() {
105 ui::ModalType PrintPreviewDialogDelegate::GetDialogModalType() const {
106 // Not used, returning dummy value.
107 NOTREACHED();
108 return ui::MODAL_TYPE_WINDOW;
111 base::string16 PrintPreviewDialogDelegate::GetDialogTitle() const {
112 // Only used on Windows? UI folks prefer no title.
113 return base::string16();
116 GURL PrintPreviewDialogDelegate::GetDialogContentURL() const {
117 return GURL(chrome::kChromeUIPrintURL);
120 void PrintPreviewDialogDelegate::GetWebUIMessageHandlers(
121 std::vector<WebUIMessageHandler*>* /* handlers */) const {
122 // PrintPreviewUI adds its own message handlers.
125 void PrintPreviewDialogDelegate::GetDialogSize(gfx::Size* size) const {
126 DCHECK(size);
127 const gfx::Size kMinDialogSize(800, 480);
128 const int kBorder = 25;
129 *size = kMinDialogSize;
131 web_modal::WebContentsModalDialogHost* host = NULL;
132 Browser* browser = chrome::FindBrowserWithWebContents(initiator_);
133 if (browser)
134 host = browser->window()->GetWebContentsModalDialogHost();
136 if (host) {
137 size->SetToMax(host->GetMaximumDialogSize());
138 size->Enlarge(-2 * kBorder, -kBorder);
139 } else {
140 size->SetToMax(initiator_->GetView()->GetContainerSize());
141 size->Enlarge(-2 * kBorder, -2 * kBorder);
144 #if defined(OS_MACOSX)
145 // Limit the maximum size on MacOS X.
146 // http://crbug.com/105815
147 const gfx::Size kMaxDialogSize(1000, 660);
148 size->SetToMin(kMaxDialogSize);
149 #endif
152 std::string PrintPreviewDialogDelegate::GetDialogArgs() const {
153 return std::string();
156 void PrintPreviewDialogDelegate::OnDialogClosed(
157 const std::string& /* json_retval */) {
160 void PrintPreviewDialogDelegate::OnCloseContents(WebContents* /* source */,
161 bool* out_close_dialog) {
162 if (out_close_dialog)
163 *out_close_dialog = true;
166 bool PrintPreviewDialogDelegate::ShouldShowDialogTitle() const {
167 return false;
170 // WebContentsDelegate that forwards shortcut keys in the print preview
171 // renderer to the browser.
172 class PrintPreviewWebContentDelegate : public WebDialogWebContentsDelegate {
173 public:
174 PrintPreviewWebContentDelegate(Profile* profile, WebContents* initiator);
175 virtual ~PrintPreviewWebContentDelegate();
177 // Overridden from WebDialogWebContentsDelegate:
178 virtual void HandleKeyboardEvent(
179 WebContents* source,
180 const NativeWebKeyboardEvent& event) OVERRIDE;
182 private:
183 WebContents* initiator_;
185 DISALLOW_COPY_AND_ASSIGN(PrintPreviewWebContentDelegate);
188 PrintPreviewWebContentDelegate::PrintPreviewWebContentDelegate(
189 Profile* profile,
190 WebContents* initiator)
191 : WebDialogWebContentsDelegate(profile, new ChromeWebContentsHandler),
192 initiator_(initiator) {}
194 PrintPreviewWebContentDelegate::~PrintPreviewWebContentDelegate() {}
196 void PrintPreviewWebContentDelegate::HandleKeyboardEvent(
197 WebContents* source,
198 const NativeWebKeyboardEvent& event) {
199 // Disabled on Mac due to http://crbug.com/112173
200 #if !defined(OS_MACOSX)
201 Browser* current_browser = chrome::FindBrowserWithWebContents(initiator_);
202 if (!current_browser)
203 return;
204 current_browser->window()->HandleKeyboardEvent(event);
205 #endif
208 } // namespace
210 namespace printing {
212 struct PrintPreviewDialogController::Operation {
213 class Observer : public content::WebContentsObserver,
214 public content::RenderProcessHostObserver {
215 public:
216 Observer();
217 virtual ~Observer();
219 void StartObserving(PrintPreviewDialogController* owner,
220 WebContents* web_contents);
221 void StopObserving();
223 private:
224 // content::WebContentsObserver
225 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
226 virtual void NavigationEntryCommitted(
227 const content::LoadCommittedDetails& load_details) OVERRIDE;
228 // content::RenderProcessHostObserver
229 virtual void RenderProcessExited(RenderProcessHost* host,
230 base::ProcessHandle handle,
231 base::TerminationStatus status,
232 int exit_code) OVERRIDE;
233 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
235 PrintPreviewDialogController* owner_;
236 RenderProcessHost* host_;
239 Operation();
241 WebContents* preview_dialog;
242 WebContents* initiator;
243 Observer preview_dialog_observer;
244 Observer initiator_observer;
246 DISALLOW_COPY_AND_ASSIGN(Operation);
249 PrintPreviewDialogController::Operation::Operation() : preview_dialog(NULL),
250 initiator(NULL) {
253 PrintPreviewDialogController::Operation::Observer::Observer() : owner_(NULL),
254 host_(NULL) {
257 PrintPreviewDialogController::Operation::Observer::~Observer() {
258 StopObserving();
261 void PrintPreviewDialogController::Operation::Observer::StartObserving(
262 PrintPreviewDialogController* owner,
263 WebContents* web_contents) {
264 owner_ = owner;
265 Observe(web_contents);
266 host_ = web_contents->GetRenderProcessHost();
267 host_->AddObserver(this);
270 void PrintPreviewDialogController::Operation::Observer::StopObserving() {
271 Observe(NULL);
272 if (host_) {
273 host_->RemoveObserver(this);
274 host_ = NULL;
278 void PrintPreviewDialogController::Operation::Observer::WebContentsDestroyed(
279 WebContents* web_contents) {
280 owner_->OnWebContentsDestroyed(web_contents);
283 void
284 PrintPreviewDialogController::Operation::Observer::NavigationEntryCommitted(
285 const content::LoadCommittedDetails& load_details) {
286 owner_->OnNavigationEntryCommitted(web_contents(), &load_details);
289 void PrintPreviewDialogController::Operation::Observer::RenderProcessExited(
290 RenderProcessHost* host,
291 base::ProcessHandle handle,
292 base::TerminationStatus status,
293 int exit_code) {
294 owner_->OnRenderProcessExited(host);
297 void
298 PrintPreviewDialogController::Operation::Observer::RenderProcessHostDestroyed(
299 RenderProcessHost* host) {
300 host_ = NULL;
303 PrintPreviewDialogController::PrintPreviewDialogController()
304 : waiting_for_new_preview_page_(false),
305 is_creating_print_preview_dialog_(false) {
308 // static
309 PrintPreviewDialogController* PrintPreviewDialogController::GetInstance() {
310 if (!g_browser_process)
311 return NULL;
312 return g_browser_process->print_preview_dialog_controller();
315 // static
316 void PrintPreviewDialogController::PrintPreview(WebContents* initiator) {
317 if (initiator->ShowingInterstitialPage())
318 return;
320 PrintPreviewDialogController* dialog_controller = GetInstance();
321 if (!dialog_controller)
322 return;
323 if (!dialog_controller->GetOrCreatePreviewDialog(initiator))
324 PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
327 WebContents* PrintPreviewDialogController::GetOrCreatePreviewDialog(
328 WebContents* initiator) {
329 DCHECK(initiator);
331 // Get the print preview dialog for |initiator|.
332 WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
333 if (!preview_dialog)
334 return CreatePrintPreviewDialog(initiator);
336 // Show the initiator holding the existing preview dialog.
337 initiator->GetDelegate()->ActivateContents(initiator);
338 return preview_dialog;
341 WebContents* PrintPreviewDialogController::GetPrintPreviewForContents(
342 WebContents* contents) const {
343 for (size_t i = 0; i < preview_operations_.size(); ++i) {
344 Operation* operation = preview_operations_[i];
345 if (operation->preview_dialog == contents ||
346 operation->initiator == contents) {
347 return operation->preview_dialog;
350 return NULL;
353 WebContents* PrintPreviewDialogController::GetInitiator(
354 WebContents* preview_dialog) {
355 for (size_t i = 0; i < preview_operations_.size(); ++i) {
356 Operation* operation = preview_operations_[i];
357 if (operation->preview_dialog == preview_dialog)
358 return operation->initiator;
360 return NULL;
363 // static
364 bool PrintPreviewDialogController::IsPrintPreviewDialog(WebContents* contents) {
365 return IsPrintPreviewURL(contents->GetURL());
368 // static
369 bool PrintPreviewDialogController::IsPrintPreviewURL(const GURL& url) {
370 return (url.SchemeIs(chrome::kChromeUIScheme) &&
371 url.host() == chrome::kChromeUIPrintHost);
374 void PrintPreviewDialogController::EraseInitiatorInfo(
375 WebContents* preview_dialog) {
376 for (size_t i = 0; i < preview_operations_.size(); ++i) {
377 Operation* operation = preview_operations_[i];
378 if (operation->preview_dialog == preview_dialog) {
379 operation->initiator_observer.StopObserving();
380 operation->initiator = NULL;
381 return;
386 PrintPreviewDialogController::~PrintPreviewDialogController() {
387 DCHECK_EQ(0U, preview_operations_.size());
390 void PrintPreviewDialogController::OnRenderProcessExited(
391 RenderProcessHost* rph) {
392 // Store contents in a vector and deal with them after iterating through
393 // |preview_operations_| because RemoveFoo() can change |preview_operations_|.
394 std::vector<WebContents*> closed_initiators;
395 std::vector<WebContents*> closed_preview_dialogs;
396 for (size_t i = 0; i < preview_operations_.size(); ++i) {
397 Operation* operation = preview_operations_[i];
398 WebContents* preview_dialog = operation->preview_dialog;
399 WebContents* initiator = operation->initiator;
400 if (preview_dialog->GetRenderProcessHost() == rph) {
401 closed_preview_dialogs.push_back(preview_dialog);
402 } else if (initiator &&
403 initiator->GetRenderProcessHost() == rph) {
404 closed_initiators.push_back(initiator);
408 for (size_t i = 0; i < closed_preview_dialogs.size(); ++i) {
409 RemovePreviewDialog(closed_preview_dialogs[i]);
410 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
411 closed_preview_dialogs[i]->GetWebUI()->GetController());
412 if (print_preview_ui)
413 print_preview_ui->OnPrintPreviewDialogClosed();
416 for (size_t i = 0; i < closed_initiators.size(); ++i)
417 RemoveInitiator(closed_initiators[i]);
420 void PrintPreviewDialogController::OnWebContentsDestroyed(
421 WebContents* contents) {
422 WebContents* preview_dialog = GetPrintPreviewForContents(contents);
423 if (!preview_dialog) {
424 NOTREACHED();
425 return;
428 if (contents == preview_dialog)
429 RemovePreviewDialog(contents);
430 else
431 RemoveInitiator(contents);
434 void PrintPreviewDialogController::OnNavigationEntryCommitted(
435 WebContents* contents, const content::LoadCommittedDetails* details) {
436 WebContents* preview_dialog = GetPrintPreviewForContents(contents);
437 if (!preview_dialog) {
438 NOTREACHED();
439 return;
442 if (contents == preview_dialog) {
443 // Preview dialog navigated.
444 if (details) {
445 content::PageTransition transition_type =
446 details->entry->GetTransitionType();
447 content::NavigationType nav_type = details->type;
449 // New |preview_dialog| is created. Don't update/erase map entry.
450 if (waiting_for_new_preview_page_ &&
451 transition_type == content::PAGE_TRANSITION_AUTO_TOPLEVEL &&
452 nav_type == content::NAVIGATION_TYPE_NEW_PAGE) {
453 waiting_for_new_preview_page_ = false;
454 SaveInitiatorTitle(preview_dialog);
455 return;
458 // Cloud print sign-in causes a reload.
459 if (!waiting_for_new_preview_page_ &&
460 transition_type == content::PAGE_TRANSITION_RELOAD &&
461 nav_type == content::NAVIGATION_TYPE_EXISTING_PAGE &&
462 IsPrintPreviewURL(details->previous_url)) {
463 return;
466 NOTREACHED();
467 return;
470 RemoveInitiator(contents);
473 WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog(
474 WebContents* initiator) {
475 base::AutoReset<bool> auto_reset(&is_creating_print_preview_dialog_, true);
476 Profile* profile =
477 Profile::FromBrowserContext(initiator->GetBrowserContext());
479 // |web_dialog_ui_delegate| deletes itself in
480 // PrintPreviewDialogDelegate::OnDialogClosed().
481 WebDialogDelegate* web_dialog_delegate =
482 new PrintPreviewDialogDelegate(initiator);
483 // |web_dialog_delegate|'s owner is |constrained_delegate|.
484 PrintPreviewWebContentDelegate* pp_wcd =
485 new PrintPreviewWebContentDelegate(profile, initiator);
486 ConstrainedWebDialogDelegate* constrained_delegate =
487 CreateConstrainedWebDialog(profile,
488 web_dialog_delegate,
489 pp_wcd,
490 initiator);
491 WebContents* preview_dialog = constrained_delegate->GetWebContents();
492 EnableInternalPDFPluginForContents(preview_dialog);
493 PrintViewManager::CreateForWebContents(preview_dialog);
495 waiting_for_new_preview_page_ = true;
497 // Add an entry to the map.
498 Operation* operation = new Operation;
499 operation->preview_dialog = preview_dialog;
500 operation->initiator = initiator;
501 operation->preview_dialog_observer.StartObserving(this, preview_dialog);
502 operation->initiator_observer.StartObserving(this, initiator);
503 preview_operations_.push_back(operation);
505 return preview_dialog;
508 void PrintPreviewDialogController::SaveInitiatorTitle(
509 WebContents* preview_dialog) {
510 WebContents* initiator = GetInitiator(preview_dialog);
511 if (initiator && preview_dialog->GetWebUI()) {
512 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
513 preview_dialog->GetWebUI()->GetController());
514 print_preview_ui->SetInitiatorTitle(
515 PrintViewManager::FromWebContents(initiator)->RenderSourceName());
519 void PrintPreviewDialogController::RemoveInitiator(
520 WebContents* initiator) {
521 WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
522 DCHECK(preview_dialog);
524 // Update the map entry first, so when the print preview dialog gets destroyed
525 // and reaches RemovePreviewDialog(), it does not attempt to also remove the
526 // initiator's observers.
527 EraseInitiatorInfo(preview_dialog);
529 PrintViewManager::FromWebContents(initiator)->PrintPreviewDone();
531 // initiator is closed. Close the print preview dialog too.
532 PrintPreviewUI* print_preview_ui =
533 static_cast<PrintPreviewUI*>(preview_dialog->GetWebUI()->GetController());
534 if (print_preview_ui)
535 print_preview_ui->OnInitiatorClosed();
538 void PrintPreviewDialogController::RemovePreviewDialog(
539 WebContents* preview_dialog) {
540 for (size_t i = 0; i < preview_operations_.size(); ++i) {
541 Operation* operation = preview_operations_[i];
542 if (operation->preview_dialog == preview_dialog) {
543 // Remove the initiator's observers before erasing the mapping.
544 if (operation->initiator) {
545 operation->initiator_observer.StopObserving();
546 PrintViewManager::FromWebContents(operation->initiator)->
547 PrintPreviewDone();
550 // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to
551 // abort the initiator preview request.
552 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
553 preview_dialog->GetWebUI()->GetController());
554 if (print_preview_ui)
555 print_preview_ui->OnPrintPreviewDialogDestroyed();
557 preview_operations_.erase(preview_operations_.begin() + i);
558 delete operation;
560 return;
563 NOTREACHED();
566 } // namespace printing