Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / print_preview_handler.cc
blob80e6362420eccfdfe255036005208a99f03a7942
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/ui/webui/print_preview/print_preview_handler.h"
7 #include <ctype.h>
9 #include <string>
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/command_line.h"
15 #include "base/i18n/file_util_icu.h"
16 #include "base/i18n/number_formatting.h"
17 #include "base/json/json_reader.h"
18 #include "base/lazy_instance.h"
19 #include "base/memory/linked_ptr.h"
20 #include "base/memory/ref_counted_memory.h"
21 #include "base/metrics/histogram.h"
22 #include "base/path_service.h"
23 #include "base/prefs/pref_service.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/values.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/platform_util.h"
30 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
31 #include "chrome/browser/printing/print_dialog_cloud.h"
32 #include "chrome/browser/printing/print_error_dialog.h"
33 #include "chrome/browser/printing/print_job_manager.h"
34 #include "chrome/browser/printing/print_preview_dialog_controller.h"
35 #include "chrome/browser/printing/print_view_manager.h"
36 #include "chrome/browser/printing/printer_manager_dialog.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/signin/profile_oauth2_token_service.h"
39 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
40 #include "chrome/browser/signin/signin_manager.h"
41 #include "chrome/browser/signin/signin_manager_base.h"
42 #include "chrome/browser/signin/signin_manager_factory.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_tabstrip.h"
45 #include "chrome/browser/ui/chrome_select_file_policy.h"
46 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
47 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
48 #include "chrome/common/chrome_paths.h"
49 #include "chrome/common/chrome_switches.h"
50 #include "chrome/common/cloud_print/cloud_print_constants.h"
51 #include "chrome/common/crash_keys.h"
52 #include "chrome/common/pref_names.h"
53 #include "chrome/common/print_messages.h"
54 #include "content/public/browser/browser_context.h"
55 #include "content/public/browser/browser_thread.h"
56 #include "content/public/browser/navigation_controller.h"
57 #include "content/public/browser/navigation_entry.h"
58 #include "content/public/browser/render_view_host.h"
59 #include "content/public/browser/web_contents.h"
60 #include "content/public/browser/web_contents_view.h"
61 #include "content/public/browser/web_ui.h"
62 #include "google_apis/gaia/oauth2_token_service.h"
63 #include "printing/backend/print_backend.h"
64 #include "printing/metafile.h"
65 #include "printing/metafile_impl.h"
66 #include "printing/pdf_render_settings.h"
67 #include "printing/print_settings.h"
68 #include "printing/units.h"
69 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
71 #if defined(OS_CHROMEOS)
72 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
73 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
74 #endif
76 #if defined(ENABLE_MDNS)
77 #include "chrome/browser/local_discovery/privet_constants.h"
78 #endif
80 using content::BrowserThread;
81 using content::RenderViewHost;
82 using content::WebContents;
84 namespace {
86 enum UserActionBuckets {
87 PRINT_TO_PRINTER,
88 PRINT_TO_PDF,
89 CANCEL,
90 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
91 PREVIEW_FAILED,
92 PREVIEW_STARTED,
93 INITIATOR_CRASHED, // UNUSED
94 INITIATOR_CLOSED,
95 PRINT_WITH_CLOUD_PRINT,
96 PRINT_WITH_PRIVET,
97 USERACTION_BUCKET_BOUNDARY
100 enum PrintSettingsBuckets {
101 LANDSCAPE = 0,
102 PORTRAIT,
103 COLOR,
104 BLACK_AND_WHITE,
105 COLLATE,
106 SIMPLEX,
107 DUPLEX,
108 TOTAL,
109 HEADERS_AND_FOOTERS,
110 CSS_BACKGROUND,
111 SELECTION_ONLY,
112 PRINT_SETTINGS_BUCKET_BOUNDARY
115 enum UiBucketGroups {
116 DESTINATION_SEARCH,
117 GCP_PROMO,
118 UI_BUCKET_GROUP_BOUNDARY
121 enum PrintDestinationBuckets {
122 DESTINATION_SHOWN,
123 DESTINATION_CLOSED_CHANGED,
124 DESTINATION_CLOSED_UNCHANGED,
125 SIGNIN_PROMPT,
126 SIGNIN_TRIGGERED,
127 PRIVET_DUPLICATE_SELECTED,
128 CLOUD_DUPLICATE_SELECTED,
129 PRINT_DESTINATION_BUCKET_BOUNDARY
132 enum GcpPromoBuckets {
133 PROMO_SHOWN,
134 PROMO_CLOSED,
135 PROMO_CLICKED,
136 GCP_PROMO_BUCKET_BOUNDARY
139 void ReportUserActionHistogram(enum UserActionBuckets event) {
140 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
141 USERACTION_BUCKET_BOUNDARY);
144 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
145 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
146 PRINT_SETTINGS_BUCKET_BOUNDARY);
149 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event) {
150 UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event,
151 PRINT_DESTINATION_BUCKET_BOUNDARY);
154 void ReportGcpPromoHistogram(enum GcpPromoBuckets event) {
155 UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event,
156 GCP_PROMO_BUCKET_BOUNDARY);
159 // Name of a dictionary field holding cloud print related data;
160 const char kAppState[] = "appState";
161 // Name of a dictionary field holding the initiator title.
162 const char kInitiatorTitle[] = "initiatorTitle";
163 // Name of a dictionary field holding the measurement system according to the
164 // locale.
165 const char kMeasurementSystem[] = "measurementSystem";
166 // Name of a dictionary field holding the number format according to the locale.
167 const char kNumberFormat[] = "numberFormat";
168 // Name of a dictionary field specifying whether to print automatically in
169 // kiosk mode. See http://crbug.com/31395.
170 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
171 #if defined(OS_WIN)
172 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
173 #endif
174 // Name of a dictionary field holding the state of selection for document.
175 const char kDocumentHasSelection[] = "documentHasSelection";
177 // Additional printer capability setting keys.
178 const char kPrinterId[] = "printerId";
179 const char kDisableColorOption[] = "disableColorOption";
180 const char kSetDuplexAsDefault[] = "setDuplexAsDefault";
181 const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
182 #if defined(USE_CUPS)
183 const char kCUPSsColorModel[] = "cupsColorModel";
184 const char kCUPSsBWModel[] = "cupsBWModel";
185 #endif
187 // Get the print job settings dictionary from |args|. The caller takes
188 // ownership of the returned DictionaryValue. Returns NULL on failure.
189 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
190 std::string json_str;
191 if (!args->GetString(0, &json_str)) {
192 NOTREACHED() << "Could not read JSON argument";
193 return NULL;
195 if (json_str.empty()) {
196 NOTREACHED() << "Empty print job settings";
197 return NULL;
199 scoped_ptr<base::DictionaryValue> settings(
200 static_cast<base::DictionaryValue*>(
201 base::JSONReader::Read(json_str)));
202 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
203 NOTREACHED() << "Print job settings must be a dictionary.";
204 return NULL;
207 if (settings->empty()) {
208 NOTREACHED() << "Print job settings dictionary is empty";
209 return NULL;
212 return settings.release();
215 // Track the popularity of print settings and report the stats.
216 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
217 ReportPrintSettingHistogram(TOTAL);
219 bool landscape = false;
220 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
221 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
223 bool collate = false;
224 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
225 ReportPrintSettingHistogram(COLLATE);
227 int duplex_mode = 0;
228 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
229 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
231 int color_mode = 0;
232 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
233 ReportPrintSettingHistogram(
234 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
237 bool headers = false;
238 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
239 headers) {
240 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
243 bool css_background = false;
244 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
245 &css_background) && css_background) {
246 ReportPrintSettingHistogram(CSS_BACKGROUND);
249 bool selection_only = false;
250 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
251 &selection_only) && selection_only) {
252 ReportPrintSettingHistogram(SELECTION_ONLY);
256 // Callback that stores a PDF file on disk.
257 void PrintToPdfCallback(printing::Metafile* metafile,
258 const base::FilePath& path) {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
260 metafile->SaveTo(path);
261 // |metafile| must be deleted on the UI thread.
262 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, metafile);
265 std::string GetDefaultPrinterOnFileThread(
266 scoped_refptr<printing::PrintBackend> print_backend) {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
269 std::string default_printer = print_backend->GetDefaultPrinterName();
270 VLOG(1) << "Default Printer: " << default_printer;
271 return default_printer;
274 void EnumeratePrintersOnFileThread(
275 scoped_refptr<printing::PrintBackend> print_backend,
276 base::ListValue* printers) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
279 VLOG(1) << "Enumerate printers start";
280 printing::PrinterList printer_list;
281 print_backend->EnumeratePrinters(&printer_list);
283 for (printing::PrinterList::iterator it = printer_list.begin();
284 it != printer_list.end(); ++it) {
285 base::DictionaryValue* printer_info = new base::DictionaryValue;
286 std::string printer_name;
287 #if defined(OS_MACOSX)
288 // On Mac, |it->printer_description| specifies the printer name and
289 // |it->printer_name| specifies the device name / printer queue name.
290 printer_name = it->printer_description;
291 #else
292 printer_name = it->printer_name;
293 #endif
294 printer_info->SetString(printing::kSettingPrinterName, printer_name);
295 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
296 VLOG(1) << "Found printer " << printer_name
297 << " with device name " << it->printer_name;
298 printers->Append(printer_info);
300 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
301 << " printers";
304 typedef base::Callback<void(const base::DictionaryValue*)>
305 GetPrinterCapabilitiesSuccessCallback;
306 typedef base::Callback<void(const std::string&)>
307 GetPrinterCapabilitiesFailureCallback;
309 void GetPrinterCapabilitiesOnFileThread(
310 scoped_refptr<printing::PrintBackend> print_backend,
311 const std::string& printer_name,
312 const GetPrinterCapabilitiesSuccessCallback& success_cb,
313 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
315 DCHECK(!printer_name.empty());
317 VLOG(1) << "Get printer capabilities start for " << printer_name;
318 crash_keys::ScopedPrinterInfo crash_key(
319 print_backend->GetPrinterDriverInfo(printer_name));
321 if (!print_backend->IsValidPrinter(printer_name)) {
322 // TODO(gene): Notify explicitly if printer is not valid, instead of
323 // failed to get capabilities.
324 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
325 base::Bind(failure_cb, printer_name));
326 return;
329 printing::PrinterSemanticCapsAndDefaults info;
330 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
331 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
332 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
333 base::Bind(failure_cb, printer_name));
334 return;
337 scoped_ptr<base::DictionaryValue> settings_info(new base::DictionaryValue);
338 settings_info->SetString(kPrinterId, printer_name);
339 settings_info->SetBoolean(kDisableColorOption, !info.color_changeable);
340 settings_info->SetBoolean(printing::kSettingSetColorAsDefault,
341 info.color_default);
342 #if defined(USE_CUPS)
343 settings_info->SetInteger(kCUPSsColorModel, info.color_model);
344 settings_info->SetInteger(kCUPSsBWModel, info.bw_model);
345 #endif
347 // TODO(gene): Make new capabilities format for Print Preview
348 // that will suit semantic capabiltities better.
349 // Refactor pld API code below
350 bool default_duplex = info.duplex_capable ?
351 (info.duplex_default != printing::SIMPLEX) : false;
352 int duplex_value = info.duplex_capable ?
353 printing::LONG_EDGE : printing::UNKNOWN_DUPLEX_MODE;
354 settings_info->SetBoolean(kSetDuplexAsDefault, default_duplex);
355 settings_info->SetInteger(kPrinterDefaultDuplexValue, duplex_value);
357 BrowserThread::PostTask(
358 BrowserThread::UI, FROM_HERE,
359 base::Bind(success_cb, base::Owned(settings_info.release())));
362 base::LazyInstance<printing::StickySettings> g_sticky_settings =
363 LAZY_INSTANCE_INITIALIZER;
365 printing::StickySettings* GetStickySettings() {
366 return g_sticky_settings.Pointer();
369 } // namespace
371 #if defined(USE_CUPS)
372 struct PrintPreviewHandler::CUPSPrinterColorModels {
373 std::string printer_name;
374 printing::ColorModel color_model;
375 printing::ColorModel bw_model;
377 #endif
379 class PrintPreviewHandler::AccessTokenService
380 : public OAuth2TokenService::Consumer {
381 public:
382 explicit AccessTokenService(PrintPreviewHandler* handler)
383 : OAuth2TokenService::Consumer("print_preview"),
384 handler_(handler),
385 weak_factory_(this) {
388 void RequestToken(const std::string& type) {
389 if (requests_.find(type) != requests_.end())
390 return; // Already in progress.
392 OAuth2TokenService* service = NULL;
393 std::string account_id;
394 if (type == "profile") {
395 Profile* profile = Profile::FromWebUI(handler_->web_ui());
396 if (profile) {
397 ProfileOAuth2TokenService* token_service =
398 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
399 account_id = token_service->GetPrimaryAccountId();
400 service = token_service;
402 } else if (type == "device") {
403 #if defined(OS_CHROMEOS)
404 chromeos::DeviceOAuth2TokenServiceFactory::Get(
405 base::Bind(
406 &AccessTokenService::DidGetTokenService,
407 weak_factory_.GetWeakPtr(),
408 type));
409 return;
410 #endif
413 ContinueRequestToken(type, service, account_id);
416 #if defined(OS_CHROMEOS)
417 // Continuation of RequestToken().
418 void DidGetTokenService(const std::string& type,
419 chromeos::DeviceOAuth2TokenService* token_service) {
420 std::string account_id;
421 if (token_service)
422 account_id = token_service->GetRobotAccountId();
423 ContinueRequestToken(type,
424 token_service,
425 account_id);
427 #endif
429 // Continuation of RequestToken().
430 void ContinueRequestToken(const std::string& type,
431 OAuth2TokenService* service,
432 const std::string& account_id) {
433 if (service) {
434 OAuth2TokenService::ScopeSet oauth_scopes;
435 oauth_scopes.insert(cloud_print::kCloudPrintAuth);
436 scoped_ptr<OAuth2TokenService::Request> request(
437 service->StartRequest(account_id, oauth_scopes, this));
438 requests_[type].reset(request.release());
439 } else {
440 handler_->SendAccessToken(type, std::string()); // Unknown type.
444 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
445 const std::string& access_token,
446 const base::Time& expiration_time) OVERRIDE {
447 OnServiceResponce(request, access_token);
450 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
451 const GoogleServiceAuthError& error) OVERRIDE {
452 OnServiceResponce(request, std::string());
455 private:
456 void OnServiceResponce(const OAuth2TokenService::Request* request,
457 const std::string& access_token) {
458 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
459 if (i->second == request) {
460 handler_->SendAccessToken(i->first, access_token);
461 requests_.erase(i);
462 return;
465 NOTREACHED();
468 typedef std::map<std::string,
469 linked_ptr<OAuth2TokenService::Request> > Requests;
470 Requests requests_;
471 PrintPreviewHandler* handler_;
472 base::WeakPtrFactory<AccessTokenService> weak_factory_;
474 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
477 PrintPreviewHandler::PrintPreviewHandler()
478 : print_backend_(printing::PrintBackend::CreateInstance(NULL)),
479 regenerate_preview_request_count_(0),
480 manage_printers_dialog_request_count_(0),
481 manage_cloud_printers_dialog_request_count_(0),
482 reported_failed_preview_(false),
483 has_logged_printers_count_(false),
484 weak_factory_(this) {
485 ReportUserActionHistogram(PREVIEW_STARTED);
488 PrintPreviewHandler::~PrintPreviewHandler() {
489 if (select_file_dialog_.get())
490 select_file_dialog_->ListenerDestroyed();
493 void PrintPreviewHandler::RegisterMessages() {
494 web_ui()->RegisterMessageCallback("getPrinters",
495 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
496 base::Unretained(this)));
497 web_ui()->RegisterMessageCallback("getPreview",
498 base::Bind(&PrintPreviewHandler::HandleGetPreview,
499 base::Unretained(this)));
500 web_ui()->RegisterMessageCallback("print",
501 base::Bind(&PrintPreviewHandler::HandlePrint,
502 base::Unretained(this)));
503 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
504 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
505 base::Unretained(this)));
506 web_ui()->RegisterMessageCallback("showSystemDialog",
507 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
508 base::Unretained(this)));
509 web_ui()->RegisterMessageCallback("signIn",
510 base::Bind(&PrintPreviewHandler::HandleSignin,
511 base::Unretained(this)));
512 web_ui()->RegisterMessageCallback("getAccessToken",
513 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
514 base::Unretained(this)));
515 web_ui()->RegisterMessageCallback("manageCloudPrinters",
516 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
517 base::Unretained(this)));
518 web_ui()->RegisterMessageCallback("manageLocalPrinters",
519 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
520 base::Unretained(this)));
521 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
522 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
523 base::Unretained(this)));
524 web_ui()->RegisterMessageCallback("hidePreview",
525 base::Bind(&PrintPreviewHandler::HandleHidePreview,
526 base::Unretained(this)));
527 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
528 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
529 base::Unretained(this)));
530 web_ui()->RegisterMessageCallback("saveAppState",
531 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
532 base::Unretained(this)));
533 web_ui()->RegisterMessageCallback("getInitialSettings",
534 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
535 base::Unretained(this)));
536 web_ui()->RegisterMessageCallback("reportUiEvent",
537 base::Bind(&PrintPreviewHandler::HandleReportUiEvent,
538 base::Unretained(this)));
539 web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
540 base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
541 base::Unretained(this)));
542 web_ui()->RegisterMessageCallback("forceOpenNewTab",
543 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
544 base::Unretained(this)));
545 web_ui()->RegisterMessageCallback("getPrivetPrinters",
546 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
547 base::Unretained(this)));
548 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
549 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
550 base::Unretained(this)));
551 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
552 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
553 base::Unretained(this)));
556 bool PrintPreviewHandler::PrivetPrintingEnabled() {
557 #if defined(ENABLE_MDNS)
558 CommandLine* command_line = CommandLine::ForCurrentProcess();
559 return !command_line->HasSwitch(switches::kDisableDeviceDiscovery) &&
560 !command_line->HasSwitch(switches::kDisablePrivetLocalPrinting);
561 #else
562 return false;
563 #endif
566 WebContents* PrintPreviewHandler::preview_web_contents() const {
567 return web_ui()->GetWebContents();
570 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
571 base::ListValue* results = new base::ListValue;
572 BrowserThread::PostTaskAndReply(
573 BrowserThread::FILE, FROM_HERE,
574 base::Bind(&EnumeratePrintersOnFileThread, print_backend_,
575 base::Unretained(results)),
576 base::Bind(&PrintPreviewHandler::SetupPrinterList,
577 weak_factory_.GetWeakPtr(),
578 base::Owned(results)));
581 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
582 #if defined(ENABLE_MDNS)
583 if (PrivetPrintingEnabled()) {
584 Profile* profile = Profile::FromWebUI(web_ui());
585 service_discovery_client_ =
586 local_discovery::ServiceDiscoverySharedClient::GetInstance();
587 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
588 service_discovery_client_.get(),
589 profile->GetRequestContext(),
590 this));
591 printer_lister_->Start();
593 #endif
595 if (!PrivetPrintingEnabled()) {
596 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
600 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
601 const base::ListValue* args) {
602 #if defined(ENABLE_MDNS)
603 if (PrivetPrintingEnabled()) {
604 printer_lister_->Stop();
606 #endif
609 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
610 const base::ListValue* args) {
611 #if defined(ENABLE_MDNS)
612 std::string name;
613 bool success = args->GetString(0, &name);
614 DCHECK(success);
616 CreatePrivetHTTP(
617 name,
618 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
619 base::Unretained(this)));
620 #endif
623 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
624 DCHECK_EQ(3U, args->GetSize());
625 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
626 if (!settings.get())
627 return;
628 int request_id = -1;
629 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
630 return;
632 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
633 web_ui()->GetController());
634 print_preview_ui->OnPrintPreviewRequest(request_id);
635 // Add an additional key in order to identify |print_preview_ui| later on
636 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
637 // thread.
638 settings->SetInteger(printing::kPreviewUIID,
639 print_preview_ui->GetIDForPrintPreviewUI());
641 // Increment request count.
642 ++regenerate_preview_request_count_;
644 WebContents* initiator = GetInitiator();
645 if (!initiator) {
646 ReportUserActionHistogram(INITIATOR_CLOSED);
647 print_preview_ui->OnClosePrintPreviewDialog();
648 return;
651 // Retrieve the page title and url and send it to the renderer process if
652 // headers and footers are to be displayed.
653 bool display_header_footer = false;
654 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
655 &display_header_footer)) {
656 NOTREACHED();
658 if (display_header_footer) {
659 settings->SetString(printing::kSettingHeaderFooterTitle,
660 initiator->GetTitle());
661 std::string url;
662 content::NavigationEntry* entry =
663 initiator->GetController().GetLastCommittedEntry();
664 if (entry)
665 url = entry->GetVirtualURL().spec();
666 settings->SetString(printing::kSettingHeaderFooterURL, url);
669 bool generate_draft_data = false;
670 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
671 &generate_draft_data);
672 DCHECK(success);
674 if (!generate_draft_data) {
675 double draft_page_count_double = -1;
676 success = args->GetDouble(1, &draft_page_count_double);
677 DCHECK(success);
678 int draft_page_count = static_cast<int>(draft_page_count_double);
680 bool preview_modifiable = false;
681 success = args->GetBoolean(2, &preview_modifiable);
682 DCHECK(success);
684 if (draft_page_count != -1 && preview_modifiable &&
685 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
686 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
690 VLOG(1) << "Print preview request start";
691 RenderViewHost* rvh = initiator->GetRenderViewHost();
692 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
695 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
696 ReportStats();
698 // Record the number of times the user requests to regenerate preview data
699 // before printing.
700 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
701 regenerate_preview_request_count_);
703 WebContents* initiator = GetInitiator();
704 if (initiator) {
705 RenderViewHost* rvh = initiator->GetRenderViewHost();
706 rvh->Send(new PrintMsg_ResetScriptedPrintCount(rvh->GetRoutingID()));
709 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
710 if (!settings.get())
711 return;
713 // Never try to add headers/footers here. It's already in the generated PDF.
714 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
716 bool print_to_pdf = false;
717 bool is_cloud_printer = false;
718 bool print_with_privet = false;
720 bool open_pdf_in_preview = false;
721 #if defined(OS_MACOSX)
722 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
723 #endif
725 if (!open_pdf_in_preview) {
726 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
727 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
728 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
731 int page_count = 0;
732 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
734 if (print_to_pdf) {
735 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
736 ReportUserActionHistogram(PRINT_TO_PDF);
737 PrintToPdf();
738 return;
741 #if defined(ENABLE_MDNS)
742 if (print_with_privet && PrivetPrintingEnabled()) {
743 std::string printer_name;
744 std::string print_ticket;
745 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
746 ReportUserActionHistogram(PRINT_WITH_PRIVET);
748 int width = 0;
749 int height = 0;
750 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
751 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
752 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
753 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
754 width <= 0 || height <=0) {
755 NOTREACHED();
756 base::FundamentalValue http_code_value(-1);
757 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
758 return;
761 PrintToPrivetPrinter(printer_name, print_ticket, gfx::Size(width, height));
762 return;
764 #endif
766 scoped_refptr<base::RefCountedBytes> data;
767 base::string16 title;
768 if (!GetPreviewDataAndTitle(&data, &title)) {
769 // Nothing to print, no preview available.
770 return;
773 if (is_cloud_printer) {
774 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
775 page_count);
776 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
777 SendCloudPrintJob(data.get());
778 } else {
779 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
780 ReportUserActionHistogram(PRINT_TO_PRINTER);
781 ReportPrintSettingsStats(*settings);
783 // This tries to activate the initiator as well, so do not clear the
784 // association with the initiator yet.
785 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
786 web_ui()->GetController());
787 print_preview_ui->OnHidePreviewDialog();
789 // Do this so the initiator can open a new print preview dialog, while the
790 // current print preview dialog is still handling its print job.
791 ClearInitiatorDetails();
793 // The PDF being printed contains only the pages that the user selected,
794 // so ignore the page range and print all pages.
795 settings->Remove(printing::kSettingPageRange, NULL);
796 // Reset selection only flag for the same reason.
797 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
799 #if defined(USE_CUPS)
800 if (!open_pdf_in_preview) // We can get here even for cloud printers.
801 ConvertColorSettingToCUPSColorModel(settings.get());
802 #endif
804 // Set ID to know whether printing is for preview.
805 settings->SetInteger(printing::kPreviewUIID,
806 print_preview_ui->GetIDForPrintPreviewUI());
807 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
808 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
809 *settings));
811 // For all other cases above, the preview dialog will stay open until the
812 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
813 // called. In the case below, since the preview dialog will be hidden and
814 // not closed, we need to make this call.
815 if (initiator) {
816 printing::PrintViewManager* print_view_manager =
817 printing::PrintViewManager::FromWebContents(initiator);
818 print_view_manager->PrintPreviewDone();
823 void PrintPreviewHandler::PrintToPdf() {
824 if (!print_to_pdf_path_.empty()) {
825 // User has already selected a path, no need to show the dialog again.
826 PostPrintToPdfTask();
827 } else if (!select_file_dialog_.get() ||
828 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
829 preview_web_contents()->GetView()->GetNativeView()))) {
830 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
831 web_ui()->GetController());
832 // Pre-populating select file dialog with print job title.
833 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
835 #if defined(OS_WIN)
836 base::FilePath::StringType print_job_title(print_job_title_utf16);
837 #elif defined(OS_POSIX)
838 base::FilePath::StringType print_job_title =
839 base::UTF16ToUTF8(print_job_title_utf16);
840 #endif
842 file_util::ReplaceIllegalCharactersInPath(&print_job_title, '_');
843 base::FilePath default_filename(print_job_title);
844 default_filename =
845 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
847 SelectFile(default_filename);
851 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
852 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
853 web_ui()->GetController());
854 print_preview_ui->OnHidePreviewDialog();
857 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
858 const base::ListValue* /*args*/) {
859 WebContents* initiator = GetInitiator();
860 if (initiator)
861 ClearInitiatorDetails();
862 gfx::NativeWindow parent = initiator ?
863 initiator->GetView()->GetTopLevelNativeWindow() :
864 NULL;
865 chrome::ShowPrintErrorDialog(parent);
868 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
869 std::string data_to_save;
870 printing::StickySettings* sticky_settings = GetStickySettings();
871 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
872 sticky_settings->StoreAppState(data_to_save);
873 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
874 preview_web_contents()->GetBrowserContext())->GetPrefs());
877 void PrintPreviewHandler::HandleGetPrinterCapabilities(
878 const base::ListValue* args) {
879 std::string printer_name;
880 bool ret = args->GetString(0, &printer_name);
881 if (!ret || printer_name.empty())
882 return;
884 GetPrinterCapabilitiesSuccessCallback success_cb =
885 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
886 weak_factory_.GetWeakPtr());
887 GetPrinterCapabilitiesFailureCallback failure_cb =
888 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
889 weak_factory_.GetWeakPtr());
890 BrowserThread::PostTask(
891 BrowserThread::FILE, FROM_HERE,
892 base::Bind(&GetPrinterCapabilitiesOnFileThread,
893 print_backend_, printer_name, success_cb, failure_cb));
896 void PrintPreviewHandler::OnSigninComplete() {
897 PrintPreviewUI* print_preview_ui =
898 static_cast<PrintPreviewUI*>(web_ui()->GetController());
899 if (print_preview_ui)
900 print_preview_ui->OnReloadPrintersList();
903 void PrintPreviewHandler::HandleSignin(const base::ListValue* /*args*/) {
904 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
905 print_dialog_cloud::CreateCloudPrintSigninTab(
906 browser,
907 base::Bind(&PrintPreviewHandler::OnSigninComplete,
908 weak_factory_.GetWeakPtr()));
911 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
912 std::string type;
913 if (!args->GetString(0, &type))
914 return;
915 if (!token_service_)
916 token_service_.reset(new AccessTokenService(this));
917 token_service_->RequestToken(type);
920 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
921 // Record the number of times the user asks to print via cloud print
922 // instead of the print preview dialog.
923 ReportStats();
925 scoped_refptr<base::RefCountedBytes> data;
926 base::string16 title;
927 if (!GetPreviewDataAndTitle(&data, &title)) {
928 // Nothing to print, no preview available.
929 return;
932 gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
933 preview_web_contents()->GetView()->GetNativeView());
934 print_dialog_cloud::CreatePrintDialogForBytes(
935 preview_web_contents()->GetBrowserContext(),
936 modal_parent,
937 data.get(),
938 title,
939 base::string16(),
940 std::string("application/pdf"));
942 // Once the cloud print dialog comes up we're no longer in a background
943 // printing situation. Close the print preview.
944 // TODO(abodenha@chromium.org) The flow should be changed as described in
945 // http://code.google.com/p/chromium/issues/detail?id=44093
946 ClosePreviewDialog();
949 void PrintPreviewHandler::HandleManageCloudPrint(
950 const base::ListValue* /*args*/) {
951 ++manage_cloud_printers_dialog_request_count_;
952 Profile* profile = Profile::FromBrowserContext(
953 preview_web_contents()->GetBrowserContext());
954 preview_web_contents()->OpenURL(
955 content::OpenURLParams(
956 CloudPrintURL(profile).GetCloudPrintServiceManageURL(),
957 content::Referrer(),
958 NEW_FOREGROUND_TAB,
959 content::PAGE_TRANSITION_LINK,
960 false));
963 void PrintPreviewHandler::HandleShowSystemDialog(
964 const base::ListValue* /*args*/) {
965 ReportStats();
966 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
968 WebContents* initiator = GetInitiator();
969 if (!initiator)
970 return;
972 printing::PrintViewManager* print_view_manager =
973 printing::PrintViewManager::FromWebContents(initiator);
974 print_view_manager->set_observer(this);
975 print_view_manager->PrintForSystemDialogNow();
977 // Cancel the pending preview request if exists.
978 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
979 web_ui()->GetController());
980 print_preview_ui->OnCancelPendingPreviewRequest();
983 void PrintPreviewHandler::HandleManagePrinters(
984 const base::ListValue* /*args*/) {
985 ++manage_printers_dialog_request_count_;
986 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
989 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
990 const base::ListValue* args) {
991 int page_count = 0;
992 if (!args || !args->GetInteger(0, &page_count))
993 return;
994 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
995 page_count);
997 PrintWithCloudPrintDialog();
1000 void PrintPreviewHandler::HandleClosePreviewDialog(
1001 const base::ListValue* /*args*/) {
1002 ReportStats();
1003 ReportUserActionHistogram(CANCEL);
1005 // Record the number of times the user requests to regenerate preview data
1006 // before cancelling.
1007 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1008 regenerate_preview_request_count_);
1011 void PrintPreviewHandler::ReportStats() {
1012 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1013 manage_printers_dialog_request_count_);
1014 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1015 manage_cloud_printers_dialog_request_count_);
1018 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1019 base::DictionaryValue* settings) {
1021 // Getting the measurement system based on the locale.
1022 UErrorCode errorCode = U_ZERO_ERROR;
1023 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1024 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1025 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1026 system = UMS_SI;
1028 // Getting the number formatting based on the locale and writing to
1029 // dictionary.
1030 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1031 settings->SetInteger(kMeasurementSystem, system);
1034 void PrintPreviewHandler::HandleGetInitialSettings(
1035 const base::ListValue* /*args*/) {
1036 // Send before SendInitialSettings to allow cloud printer auto select.
1037 SendCloudPrintEnabled();
1038 BrowserThread::PostTaskAndReplyWithResult(
1039 BrowserThread::FILE, FROM_HERE,
1040 base::Bind(&GetDefaultPrinterOnFileThread, print_backend_),
1041 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1042 weak_factory_.GetWeakPtr()));
1045 void PrintPreviewHandler::HandleReportUiEvent(const base::ListValue* args) {
1046 int event_group, event_number;
1047 if (!args->GetInteger(0, &event_group) || !args->GetInteger(1, &event_number))
1048 return;
1050 enum UiBucketGroups ui_bucket_group =
1051 static_cast<enum UiBucketGroups>(event_group);
1052 if (ui_bucket_group >= UI_BUCKET_GROUP_BOUNDARY)
1053 return;
1055 switch (ui_bucket_group) {
1056 case DESTINATION_SEARCH: {
1057 enum PrintDestinationBuckets event =
1058 static_cast<enum PrintDestinationBuckets>(event_number);
1059 if (event >= PRINT_DESTINATION_BUCKET_BOUNDARY)
1060 return;
1061 ReportPrintDestinationHistogram(event);
1062 break;
1064 case GCP_PROMO: {
1065 enum GcpPromoBuckets event =
1066 static_cast<enum GcpPromoBuckets>(event_number);
1067 if (event >= GCP_PROMO_BUCKET_BOUNDARY)
1068 return;
1069 ReportGcpPromoHistogram(event);
1070 break;
1072 default:
1073 break;
1077 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1078 std::string url;
1079 if (!args->GetString(0, &url))
1080 return;
1081 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1082 if (!browser)
1083 return;
1084 chrome::AddSelectedTabWithURL(browser,
1085 GURL(url),
1086 content::PAGE_TRANSITION_LINK);
1089 void PrintPreviewHandler::SendInitialSettings(
1090 const std::string& default_printer) {
1091 PrintPreviewUI* print_preview_ui =
1092 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1094 base::DictionaryValue initial_settings;
1095 initial_settings.SetString(kInitiatorTitle,
1096 print_preview_ui->initiator_title());
1097 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1098 print_preview_ui->source_is_modifiable());
1099 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1100 initial_settings.SetBoolean(kDocumentHasSelection,
1101 print_preview_ui->source_has_selection());
1102 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1103 print_preview_ui->print_selection_only());
1104 printing::StickySettings* sticky_settings = GetStickySettings();
1105 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1106 preview_web_contents()->GetBrowserContext())->GetPrefs());
1107 if (sticky_settings->printer_app_state())
1108 initial_settings.SetString(kAppState,
1109 *sticky_settings->printer_app_state());
1111 CommandLine* cmdline = CommandLine::ForCurrentProcess();
1112 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1113 cmdline->HasSwitch(switches::kKioskModePrinting));
1114 #if defined(OS_WIN)
1115 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1116 // so will cause the browser to appear hung, so we don't show the link in
1117 // metro.
1118 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1119 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1120 #endif
1122 if (print_preview_ui->source_is_modifiable())
1123 GetNumberFormatAndMeasurementSystem(&initial_settings);
1124 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1127 void PrintPreviewHandler::ClosePreviewDialog() {
1128 PrintPreviewUI* print_preview_ui =
1129 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1130 print_preview_ui->OnClosePrintPreviewDialog();
1133 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1134 const std::string& access_token) {
1135 VLOG(1) << "Get getAccessToken finished";
1136 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1137 base::StringValue(type),
1138 base::StringValue(access_token));
1141 void PrintPreviewHandler::SendPrinterCapabilities(
1142 const base::DictionaryValue* settings_info) {
1143 VLOG(1) << "Get printer capabilities finished";
1145 #if defined(USE_CUPS)
1146 SaveCUPSColorSetting(settings_info);
1147 #endif
1149 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1150 *settings_info);
1153 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1154 const std::string& printer_name) {
1155 VLOG(1) << "Get printer capabilities failed";
1156 base::StringValue printer_name_value(printer_name);
1157 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1158 printer_name_value);
1161 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1162 if (!has_logged_printers_count_) {
1163 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1164 has_logged_printers_count_ = true;
1167 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1170 void PrintPreviewHandler::SendCloudPrintEnabled() {
1171 Profile* profile = Profile::FromBrowserContext(
1172 preview_web_contents()->GetBrowserContext());
1173 PrefService* prefs = profile->GetPrefs();
1174 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1175 GURL gcp_url(CloudPrintURL(profile).GetCloudPrintServiceURL());
1176 base::StringValue gcp_url_value(gcp_url.spec());
1177 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value);
1181 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1182 // BASE64 encode the job data.
1183 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1184 data->size());
1185 std::string base64_data;
1186 base::Base64Encode(raw_data, &base64_data);
1187 base::StringValue data_value(base64_data);
1189 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1192 WebContents* PrintPreviewHandler::GetInitiator() const {
1193 printing::PrintPreviewDialogController* dialog_controller =
1194 printing::PrintPreviewDialogController::GetInstance();
1195 if (!dialog_controller)
1196 return NULL;
1197 return dialog_controller->GetInitiator(preview_web_contents());
1200 void PrintPreviewHandler::OnPrintDialogShown() {
1201 ClosePreviewDialog();
1204 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1205 ui::SelectFileDialog::FileTypeInfo file_type_info;
1206 file_type_info.extensions.resize(1);
1207 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1209 // Initializing |save_path_| if it is not already initialized.
1210 printing::StickySettings* sticky_settings = GetStickySettings();
1211 if (!sticky_settings->save_path()) {
1212 // Allowing IO operation temporarily. It is ok to do so here because
1213 // the select file dialog performs IO anyway in order to display the
1214 // folders and also it is modal.
1215 base::ThreadRestrictions::ScopedAllowIO allow_io;
1216 base::FilePath file_path;
1217 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1218 sticky_settings->StoreSavePath(file_path);
1219 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1220 preview_web_contents()->GetBrowserContext())->GetPrefs());
1223 select_file_dialog_ = ui::SelectFileDialog::Create(
1224 this, new ChromeSelectFilePolicy(preview_web_contents())),
1225 select_file_dialog_->SelectFile(
1226 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1227 base::string16(),
1228 sticky_settings->save_path()->Append(default_filename),
1229 &file_type_info,
1231 base::FilePath::StringType(),
1232 platform_util::GetTopLevel(
1233 preview_web_contents()->GetView()->GetNativeView()),
1234 NULL);
1237 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1238 WebContents* initiator = GetInitiator();
1239 if (!initiator)
1240 return;
1242 printing::PrintViewManager* print_view_manager =
1243 printing::PrintViewManager::FromWebContents(initiator);
1244 print_view_manager->set_observer(NULL);
1247 void PrintPreviewHandler::OnPrintPreviewFailed() {
1248 if (reported_failed_preview_)
1249 return;
1250 reported_failed_preview_ = true;
1251 ReportUserActionHistogram(PREVIEW_FAILED);
1254 void PrintPreviewHandler::ShowSystemDialog() {
1255 HandleShowSystemDialog(NULL);
1258 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1259 int index, void* params) {
1260 // Updating |save_path_| to the newly selected folder.
1261 printing::StickySettings* sticky_settings = GetStickySettings();
1262 sticky_settings->StoreSavePath(path.DirName());
1263 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1264 preview_web_contents()->GetBrowserContext())->GetPrefs());
1265 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1266 print_to_pdf_path_ = path;
1267 PostPrintToPdfTask();
1270 void PrintPreviewHandler::PostPrintToPdfTask() {
1271 scoped_refptr<base::RefCountedBytes> data;
1272 base::string16 title;
1273 if (!GetPreviewDataAndTitle(&data, &title)) {
1274 NOTREACHED() << "Preview data was checked before file dialog.";
1275 return;
1277 scoped_ptr<printing::PreviewMetafile> metafile(new printing::PreviewMetafile);
1278 metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
1279 BrowserThread::PostTask(
1280 BrowserThread::FILE, FROM_HERE,
1281 base::Bind(&PrintToPdfCallback, metafile.release(), print_to_pdf_path_));
1282 print_to_pdf_path_ = base::FilePath();
1283 ClosePreviewDialog();
1286 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1287 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1288 web_ui()->GetController());
1289 print_preview_ui->OnFileSelectionCancelled();
1292 void PrintPreviewHandler::ClearInitiatorDetails() {
1293 WebContents* initiator = GetInitiator();
1294 if (!initiator)
1295 return;
1297 // We no longer require the initiator details. Remove those details associated
1298 // with the preview dialog to allow the initiator to create another preview
1299 // dialog.
1300 printing::PrintPreviewDialogController* dialog_controller =
1301 printing::PrintPreviewDialogController::GetInstance();
1302 if (dialog_controller)
1303 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1306 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1307 scoped_refptr<base::RefCountedBytes>* data,
1308 base::string16* title) const {
1309 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1310 web_ui()->GetController());
1311 scoped_refptr<base::RefCountedBytes> tmp_data;
1312 print_preview_ui->GetPrintPreviewDataForIndex(
1313 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1315 if (!tmp_data.get()) {
1316 // Nothing to print, no preview available.
1317 return false;
1319 DCHECK(tmp_data->size() && tmp_data->front());
1321 *data = tmp_data;
1322 *title = print_preview_ui->initiator_title();
1323 return true;
1326 #if defined(USE_CUPS)
1327 void PrintPreviewHandler::SaveCUPSColorSetting(
1328 const base::DictionaryValue* settings) {
1329 cups_printer_color_models_.reset(new CUPSPrinterColorModels);
1330 settings->GetString(kPrinterId, &cups_printer_color_models_->printer_name);
1331 settings->GetInteger(
1332 kCUPSsColorModel,
1333 reinterpret_cast<int*>(&cups_printer_color_models_->color_model));
1334 settings->GetInteger(
1335 kCUPSsBWModel,
1336 reinterpret_cast<int*>(&cups_printer_color_models_->bw_model));
1339 void PrintPreviewHandler::ConvertColorSettingToCUPSColorModel(
1340 base::DictionaryValue* settings) const {
1341 if (!cups_printer_color_models_)
1342 return;
1344 // Sanity check the printer name.
1345 std::string printer_name;
1346 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
1347 printer_name != cups_printer_color_models_->printer_name) {
1348 NOTREACHED();
1349 return;
1352 int color;
1353 if (!settings->GetInteger(printing::kSettingColor, &color)) {
1354 NOTREACHED();
1355 return;
1358 if (color == printing::GRAY) {
1359 if (cups_printer_color_models_->bw_model != printing::UNKNOWN_COLOR_MODEL) {
1360 settings->SetInteger(printing::kSettingColor,
1361 cups_printer_color_models_->bw_model);
1363 return;
1366 printing::ColorModel color_model = cups_printer_color_models_->color_model;
1367 if (color_model != printing::UNKNOWN_COLOR_MODEL)
1368 settings->SetInteger(printing::kSettingColor, color_model);
1371 #endif
1374 #if defined(ENABLE_MDNS)
1375 void PrintPreviewHandler::LocalPrinterChanged(
1376 bool added,
1377 const std::string& name,
1378 bool has_local_printing,
1379 const local_discovery::DeviceDescription& description) {
1380 base::DictionaryValue info;
1381 FillPrinterDescription(name, description, has_local_printing, &info);
1382 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1385 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1388 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1391 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1392 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1393 if (!PrivetUpdateClient(http_client.Pass()))
1394 return;
1396 privet_capabilities_operation_ =
1397 privet_http_client_->CreateCapabilitiesOperation(
1398 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1399 base::Unretained(this)));
1400 privet_capabilities_operation_->Start();
1403 bool PrintPreviewHandler::PrivetUpdateClient(
1404 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1405 if (!http_client) {
1406 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1407 privet_http_resolution_.reset();
1408 return false;
1411 privet_local_print_operation_.reset();
1412 privet_capabilities_operation_.reset();
1413 privet_http_client_ = http_client.Pass();
1415 privet_http_resolution_.reset();
1417 return true;
1420 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1421 std::string print_ticket,
1422 gfx::Size page_size,
1423 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1424 if (!PrivetUpdateClient(http_client.Pass()))
1425 return;
1427 StartPrivetLocalPrint(print_ticket, page_size);
1430 void PrintPreviewHandler::StartPrivetLocalPrint(
1431 const std::string& print_ticket,
1432 const gfx::Size& page_size) {
1433 privet_local_print_operation_ =
1434 privet_http_client_->CreateLocalPrintOperation(this);
1436 privet_local_print_operation_->SetTicket(print_ticket);
1438 scoped_refptr<base::RefCountedBytes> data;
1439 base::string16 title;
1441 if (!GetPreviewDataAndTitle(&data, &title)) {
1442 base::FundamentalValue http_code_value(-1);
1443 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1444 return;
1447 privet_local_print_operation_->SetJobname(
1448 base::UTF16ToUTF8(title));
1450 const int dpi = printing::kDefaultPdfDpi;
1451 double scale = dpi;
1452 scale /= printing::kPointsPerInch;
1453 // Make vertical rectangle to optimize streaming to printer. Fix orientation
1454 // by autorotate.
1455 gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale,
1456 std::max(page_size.width(), page_size.height()) * scale);
1457 privet_local_print_operation_->SetConversionSettings(
1458 printing::PdfRenderSettings(area, dpi, true));
1460 privet_local_print_operation_->SetData(data);
1462 Profile* profile = Profile::FromWebUI(web_ui());
1463 SigninManagerBase* signin_manager =
1464 SigninManagerFactory::GetForProfileIfExists(profile);
1466 if (signin_manager) {
1467 privet_local_print_operation_->SetUsername(
1468 signin_manager->GetAuthenticatedUsername());
1471 privet_local_print_operation_->Start();
1475 void PrintPreviewHandler::OnPrivetCapabilities(
1476 const base::DictionaryValue* capabilities) {
1477 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1479 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError)) {
1480 SendPrivetCapabilitiesError(name);
1481 return;
1484 base::DictionaryValue printer_info;
1485 const local_discovery::DeviceDescription* description =
1486 printer_lister_->GetDeviceDescription(name);
1488 if (!description) {
1489 SendPrivetCapabilitiesError(name);
1490 return;
1493 FillPrinterDescription(name, *description, true, &printer_info);
1495 web_ui()->CallJavascriptFunction(
1496 "onPrivetCapabilitiesSet",
1497 printer_info,
1498 *capabilities);
1500 privet_capabilities_operation_.reset();
1503 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1504 const std::string& device_name) {
1505 base::StringValue name_value(device_name);
1506 web_ui()->CallJavascriptFunction(
1507 "failedToGetPrivetPrinterCapabilities",
1508 name_value);
1511 void PrintPreviewHandler::PrintToPrivetPrinter(
1512 const std::string& device_name,
1513 const std::string& ticket,
1514 const gfx::Size& page_size) {
1515 CreatePrivetHTTP(
1516 device_name,
1517 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1518 base::Unretained(this), ticket, page_size));
1521 bool PrintPreviewHandler::CreatePrivetHTTP(
1522 const std::string& name,
1523 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1524 callback) {
1525 const local_discovery::DeviceDescription* device_description =
1526 printer_lister_->GetDeviceDescription(name);
1528 if (!device_description) {
1529 SendPrivetCapabilitiesError(name);
1530 return false;
1533 privet_http_factory_ =
1534 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1535 service_discovery_client_,
1536 Profile::FromWebUI(web_ui())->GetRequestContext());
1537 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1538 name,
1539 device_description->address,
1540 callback);
1541 privet_http_resolution_->Start();
1543 return true;
1546 void PrintPreviewHandler::OnPrivetPrintingDone(
1547 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1548 ClosePreviewDialog();
1551 void PrintPreviewHandler::OnPrivetPrintingError(
1552 const local_discovery::PrivetLocalPrintOperation* print_operation,
1553 int http_code) {
1554 base::FundamentalValue http_code_value(http_code);
1555 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1558 void PrintPreviewHandler::FillPrinterDescription(
1559 const std::string& name,
1560 const local_discovery::DeviceDescription& description,
1561 bool has_local_printing,
1562 base::DictionaryValue* printer_value) {
1563 printer_value->SetString("serviceName", name);
1564 printer_value->SetString("name", description.name);
1565 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1566 printer_value->SetBoolean(
1567 "isUnregistered",
1568 description.id.empty());
1569 printer_value->SetString("cloudID", description.id);
1572 #endif