| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h" |
| |
| #include <ctype.h> |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/containers/flat_map.h" |
| #include "base/i18n/number_formatting.h" |
| #include "base/json/json_reader.h" |
| #include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/app_mode/app_mode_utils.h" |
| #include "chrome/browser/bad_message.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/printing/background_printing_manager.h" |
| #include "chrome/browser/printing/print_dialog_cloud.h" |
| #include "chrome/browser/printing/print_error_dialog.h" |
| #include "chrome/browser/printing/print_job_manager.h" |
| #include "chrome/browser/printing/print_preview_dialog_controller.h" |
| #include "chrome/browser/printing/print_view_manager.h" |
| #include "chrome/browser/printing/printer_manager_dialog.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" |
| #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" |
| #include "chrome/browser/ui/webui/print_preview/pdf_printer_handler.h" |
| #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" |
| #include "chrome/browser/ui/webui/print_preview/printer_handler.h" |
| #include "chrome/browser/ui/webui/print_preview/sticky_settings.h" |
| #include "chrome/common/buildflags.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/cloud_print/cloud_print_constants.h" |
| #include "chrome/common/crash_keys.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/webui_url_constants.h" |
| #include "components/cloud_devices/common/cloud_device_description.h" |
| #include "components/cloud_devices/common/cloud_devices_urls.h" |
| #include "components/cloud_devices/common/printer_description.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/printing/common/cloud_print_cdd_conversion.h" |
| #include "components/printing/common/print_messages.h" |
| #include "components/signin/core/browser/gaia_cookie_manager_service.h" |
| #include "components/signin/core/browser/profile_management_switches.h" |
| #include "components/signin/core/browser/profile_oauth2_token_service.h" |
| #include "components/signin/core/browser/signin_manager.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "google_apis/gaia/oauth2_token_service.h" |
| #include "net/base/url_util.h" |
| #include "printing/backend/print_backend.h" |
| #include "printing/backend/print_backend_consts.h" |
| #include "printing/features/features.h" |
| #include "printing/print_settings.h" |
| #include "third_party/icu/source/i18n/unicode/ulocdata.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" |
| #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h" |
| #include "chromeos/printing/printer_configuration.h" |
| #endif |
| |
| using content::RenderFrameHost; |
| using content::WebContents; |
| using printing::PrintViewManager; |
| using printing::PrinterType; |
| |
| namespace { |
| |
| // Max size for PDFs sent to Cloud Print. Server side limit is currently 80MB |
| // but PDF will double in size when sent to JS. See crbug.com/793506 and |
| // crbug.com/372240. |
| constexpr size_t kMaxCloudPrintPdfDataSizeInBytes = 80 * 1024 * 1024 / 2; |
| |
| // This enum is used to back an UMA histogram, and should therefore be treated |
| // as append only. |
| enum UserActionBuckets { |
| PRINT_TO_PRINTER, |
| PRINT_TO_PDF, |
| CANCEL, |
| FALLBACK_TO_ADVANCED_SETTINGS_DIALOG, |
| PREVIEW_FAILED, |
| PREVIEW_STARTED, |
| INITIATOR_CRASHED_UNUSED, |
| INITIATOR_CLOSED, |
| PRINT_WITH_CLOUD_PRINT, |
| PRINT_WITH_PRIVET, |
| PRINT_WITH_EXTENSION, |
| USERACTION_BUCKET_BOUNDARY |
| }; |
| |
| // This enum is used to back an UMA histogram, and should therefore be treated |
| // as append only. |
| enum PrintSettingsBuckets { |
| LANDSCAPE = 0, |
| PORTRAIT, |
| COLOR, |
| BLACK_AND_WHITE, |
| COLLATE, |
| SIMPLEX, |
| DUPLEX, |
| TOTAL, |
| HEADERS_AND_FOOTERS, |
| CSS_BACKGROUND, |
| SELECTION_ONLY, |
| EXTERNAL_PDF_PREVIEW, |
| PAGE_RANGE, |
| DEFAULT_MEDIA, |
| NON_DEFAULT_MEDIA, |
| COPIES, |
| NON_DEFAULT_MARGINS, |
| DISTILL_PAGE_UNUSED, |
| SCALING, |
| PRINT_AS_IMAGE, |
| PRINT_SETTINGS_BUCKET_BOUNDARY |
| }; |
| |
| // This enum is used to back an UMA histogram, and should therefore be treated |
| // as append only. |
| enum PrintDocumentTypeBuckets { |
| HTML_DOCUMENT = 0, |
| PDF_DOCUMENT, |
| PRINT_DOCUMENT_TYPE_BUCKET_BOUNDARY |
| }; |
| |
| void ReportUserActionHistogram(enum UserActionBuckets event) { |
| UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event, |
| USERACTION_BUCKET_BOUNDARY); |
| } |
| |
| void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) { |
| UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting, |
| PRINT_SETTINGS_BUCKET_BOUNDARY); |
| } |
| |
| void ReportPrintDocumentTypeHistogram(enum PrintDocumentTypeBuckets doctype) { |
| UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintDocumentType", doctype, |
| PRINT_DOCUMENT_TYPE_BUCKET_BOUNDARY); |
| } |
| |
| // Dictionary Fields for Print Preview initial settings. Keep in sync with |
| // field names for print_preview.NativeInitialSettings in |
| // chrome/browser/resources/print_preview/native_layer.js |
| // |
| // Name of a dictionary field specifying whether to print automatically in |
| // kiosk mode. See http://crbug.com/31395. |
| const char kIsInKioskAutoPrintMode[] = "isInKioskAutoPrintMode"; |
| // Dictionary field to indicate whether Chrome is running in forced app (app |
| // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above). |
| const char kIsInAppKioskMode[] = "isInAppKioskMode"; |
| // Name of a dictionary field holding the thousands delimeter according to the |
| // locale. |
| const char kThousandsDelimeter[] = "thousandsDelimeter"; |
| // Name of a dictionary field holding the decimal delimeter according to the |
| // locale. |
| const char kDecimalDelimeter[] = "decimalDelimeter"; |
| // Name of a dictionary field holding the measurement system according to the |
| // locale. |
| const char kUnitType[] = "unitType"; |
| // Name of a dictionary field holding the initiator title. |
| const char kDocumentTitle[] = "documentTitle"; |
| // Name of a dictionary field holding the state of selection for document. |
| const char kDocumentHasSelection[] = "documentHasSelection"; |
| // Name of a dictionary field holding saved print preview state |
| const char kAppState[] = "serializedAppStateStr"; |
| // Name of a dictionary field holding the default destination selection rules. |
| const char kDefaultDestinationSelectionRules[] = |
| "serializedDefaultDestinationSelectionRulesStr"; |
| |
| // Get the print job settings dictionary from |json_str|. Returns NULL on |
| // failure. |
| std::unique_ptr<base::DictionaryValue> GetSettingsDictionary( |
| const std::string& json_str) { |
| if (json_str.empty()) { |
| NOTREACHED() << "Empty print job settings"; |
| return NULL; |
| } |
| std::unique_ptr<base::DictionaryValue> settings = |
| base::DictionaryValue::From(base::JSONReader::Read(json_str)); |
| if (!settings) { |
| NOTREACHED() << "Print job settings must be a dictionary."; |
| return NULL; |
| } |
| |
| if (settings->empty()) { |
| NOTREACHED() << "Print job settings dictionary is empty"; |
| return NULL; |
| } |
| |
| return settings; |
| } |
| |
| // Track the popularity of print settings and report the stats. |
| void ReportPrintSettingsStats(const base::DictionaryValue& settings) { |
| ReportPrintSettingHistogram(TOTAL); |
| |
| const base::ListValue* page_range_array = NULL; |
| if (settings.GetList(printing::kSettingPageRange, &page_range_array) && |
| !page_range_array->empty()) { |
| ReportPrintSettingHistogram(PAGE_RANGE); |
| } |
| |
| const base::DictionaryValue* media_size_value = NULL; |
| if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) && |
| !media_size_value->empty()) { |
| bool is_default = false; |
| if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault, |
| &is_default) && |
| is_default) { |
| ReportPrintSettingHistogram(DEFAULT_MEDIA); |
| } else { |
| ReportPrintSettingHistogram(NON_DEFAULT_MEDIA); |
| } |
| } |
| |
| bool landscape = false; |
| if (settings.GetBoolean(printing::kSettingLandscape, &landscape)) |
| ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT); |
| |
| int copies = 1; |
| if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1) |
| ReportPrintSettingHistogram(COPIES); |
| |
| int scaling = 100; |
| if (settings.GetInteger(printing::kSettingScaleFactor, &scaling) && |
| scaling != 100) { |
| ReportPrintSettingHistogram(SCALING); |
| } |
| |
| bool collate = false; |
| if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate) |
| ReportPrintSettingHistogram(COLLATE); |
| |
| int duplex_mode = 0; |
| if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode)) |
| ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX); |
| |
| int color_mode = 0; |
| if (settings.GetInteger(printing::kSettingColor, &color_mode)) { |
| ReportPrintSettingHistogram( |
| printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE); |
| } |
| |
| int margins_type = 0; |
| if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) && |
| margins_type != 0) { |
| ReportPrintSettingHistogram(NON_DEFAULT_MARGINS); |
| } |
| |
| bool headers = false; |
| if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) && |
| headers) { |
| ReportPrintSettingHistogram(HEADERS_AND_FOOTERS); |
| } |
| |
| bool css_background = false; |
| if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds, |
| &css_background) && css_background) { |
| ReportPrintSettingHistogram(CSS_BACKGROUND); |
| } |
| |
| bool selection_only = false; |
| if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly, |
| &selection_only) && selection_only) { |
| ReportPrintSettingHistogram(SELECTION_ONLY); |
| } |
| |
| bool external_preview = false; |
| if (settings.GetBoolean(printing::kSettingOpenPDFInPreview, |
| &external_preview) && external_preview) { |
| ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW); |
| } |
| |
| bool rasterize = false; |
| if (settings.GetBoolean(printing::kSettingRasterizePdf, |
| &rasterize) && rasterize) { |
| ReportPrintSettingHistogram(PRINT_AS_IMAGE); |
| } |
| } |
| |
| base::LazyInstance<printing::StickySettings>::DestructorAtExit |
| g_sticky_settings = LAZY_INSTANCE_INITIALIZER; |
| |
| printing::StickySettings* GetStickySettings() { |
| return g_sticky_settings.Pointer(); |
| } |
| |
| } // namespace |
| |
| class PrintPreviewHandler::AccessTokenService |
| : public OAuth2TokenService::Consumer { |
| public: |
| explicit AccessTokenService(PrintPreviewHandler* handler) |
| : OAuth2TokenService::Consumer("print_preview"), |
| handler_(handler) { |
| } |
| |
| void RequestToken(const std::string& type, const std::string& callback_id) { |
| if (requests_.find(type) != requests_.end()) { |
| NOTREACHED(); // Should never happen, see cloud_print_interface.js |
| return; |
| } |
| |
| OAuth2TokenService* service = nullptr; |
| std::string account_id; |
| if (type == "profile") { |
| Profile* profile = Profile::FromWebUI(handler_->web_ui()); |
| if (profile) { |
| ProfileOAuth2TokenService* token_service = |
| ProfileOAuth2TokenServiceFactory::GetForProfile(profile); |
| SigninManagerBase* signin_manager = |
| SigninManagerFactory::GetInstance()->GetForProfile(profile); |
| account_id = signin_manager->GetAuthenticatedAccountId(); |
| service = token_service; |
| } |
| } else if (type == "device") { |
| #if defined(OS_CHROMEOS) |
| chromeos::DeviceOAuth2TokenService* token_service = |
| chromeos::DeviceOAuth2TokenServiceFactory::Get(); |
| account_id = token_service->GetRobotAccountId(); |
| service = token_service; |
| #endif |
| } |
| |
| if (!service) { |
| // Unknown type. |
| handler_->SendAccessToken(callback_id, std::string()); |
| return; |
| } |
| |
| OAuth2TokenService::ScopeSet oauth_scopes; |
| oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope); |
| requests_[type].request = |
| service->StartRequest(account_id, oauth_scopes, this); |
| requests_[type].callback_id = callback_id; |
| } |
| |
| void OnGetTokenSuccess(const OAuth2TokenService::Request* request, |
| const std::string& access_token, |
| const base::Time& expiration_time) override { |
| OnServiceResponse(request, access_token); |
| } |
| |
| void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
| const GoogleServiceAuthError& error) override { |
| OnServiceResponse(request, std::string()); |
| } |
| |
| private: |
| void OnServiceResponse(const OAuth2TokenService::Request* request, |
| const std::string& access_token) { |
| for (auto it = requests_.begin(); it != requests_.end(); ++it) { |
| auto& entry = it->second; |
| if (entry.request.get() == request) { |
| handler_->SendAccessToken(entry.callback_id, access_token); |
| requests_.erase(it); |
| return; |
| } |
| } |
| NOTREACHED(); |
| } |
| |
| struct Request { |
| std::unique_ptr<OAuth2TokenService::Request> request; |
| std::string callback_id; |
| }; |
| // Maps types to Requests. |
| base::flat_map<std::string, Request> requests_; |
| |
| PrintPreviewHandler* const handler_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AccessTokenService); |
| }; |
| |
| PrintPreviewHandler::PrintPreviewHandler() |
| : regenerate_preview_request_count_(0), |
| manage_printers_dialog_request_count_(0), |
| reported_failed_preview_(false), |
| has_logged_printers_count_(false), |
| gaia_cookie_manager_service_(nullptr), |
| weak_factory_(this) { |
| ReportUserActionHistogram(PREVIEW_STARTED); |
| } |
| |
| PrintPreviewHandler::~PrintPreviewHandler() { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters", |
| manage_printers_dialog_request_count_); |
| UnregisterForGaiaCookieChanges(); |
| } |
| |
| void PrintPreviewHandler::RegisterMessages() { |
| web_ui()->RegisterMessageCallback("getPrinters", |
| base::Bind(&PrintPreviewHandler::HandleGetPrinters, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("getPreview", |
| base::Bind(&PrintPreviewHandler::HandleGetPreview, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("print", |
| base::Bind(&PrintPreviewHandler::HandlePrint, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "getPrinterCapabilities", |
| base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "setupPrinter", base::Bind(&PrintPreviewHandler::HandlePrinterSetup, |
| base::Unretained(this))); |
| #if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG) |
| web_ui()->RegisterMessageCallback("showSystemDialog", |
| base::Bind(&PrintPreviewHandler::HandleShowSystemDialog, |
| base::Unretained(this))); |
| #endif |
| web_ui()->RegisterMessageCallback("signIn", |
| base::Bind(&PrintPreviewHandler::HandleSignin, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("getAccessToken", |
| base::Bind(&PrintPreviewHandler::HandleGetAccessToken, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "managePrinters", base::Bind(&PrintPreviewHandler::HandleManagePrinters, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("closePrintPreviewDialog", |
| base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("hidePreview", |
| base::Bind(&PrintPreviewHandler::HandleHidePreview, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("cancelPendingPrintRequest", |
| base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("saveAppState", |
| base::Bind(&PrintPreviewHandler::HandleSaveAppState, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("getInitialSettings", |
| base::Bind(&PrintPreviewHandler::HandleGetInitialSettings, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback("forceOpenNewTab", |
| base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "grantExtensionPrinterAccess", |
| base::Bind(&PrintPreviewHandler::HandleGrantExtensionPrinterAccess, |
| base::Unretained(this))); |
| } |
| |
| void PrintPreviewHandler::OnJavascriptAllowed() { |
| // Now that the UI is initialized, any future account changes will require |
| // a printer list refresh. |
| RegisterForGaiaCookieChanges(); |
| } |
| |
| void PrintPreviewHandler::OnJavascriptDisallowed() { |
| // Normally the handler and print preview will be destroyed together, but |
| // this is necessary for refresh or navigation from the chrome://print page. |
| weak_factory_.InvalidateWeakPtrs(); |
| UnregisterForGaiaCookieChanges(); |
| } |
| |
| WebContents* PrintPreviewHandler::preview_web_contents() const { |
| return web_ui()->GetWebContents(); |
| } |
| |
| PrintPreviewUI* PrintPreviewHandler::print_preview_ui() const { |
| return static_cast<PrintPreviewUI*>(web_ui()->GetController()); |
| } |
| |
| void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* args) { |
| std::string callback_id; |
| CHECK(args->GetString(0, &callback_id)); |
| CHECK(!callback_id.empty()); |
| int type; |
| CHECK(args->GetInteger(1, &type)); |
| PrinterType printer_type = static_cast<PrinterType>(type); |
| |
| PrinterHandler* handler = GetPrinterHandler(printer_type); |
| if (!handler) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value()); |
| return; |
| } |
| // Make sure all in progress requests are canceled before new printer search |
| // starts. |
| handler->Reset(); |
| handler->StartGetPrinters( |
| base::Bind(&PrintPreviewHandler::OnAddedPrinters, |
| weak_factory_.GetWeakPtr(), printer_type), |
| base::Bind(&PrintPreviewHandler::OnGetPrintersDone, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleGrantExtensionPrinterAccess( |
| const base::ListValue* args) { |
| std::string callback_id; |
| std::string printer_id; |
| bool ok = args->GetString(0, &callback_id) && |
| args->GetString(1, &printer_id) && !callback_id.empty(); |
| DCHECK(ok); |
| |
| GetPrinterHandler(PrinterType::kExtensionPrinter) |
| ->StartGrantPrinterAccess( |
| printer_id, |
| base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterInfo, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleGetPrinterCapabilities( |
| const base::ListValue* args) { |
| std::string callback_id; |
| std::string printer_name; |
| int type; |
| if (!args->GetString(0, &callback_id) || !args->GetString(1, &printer_name) || |
| !args->GetInteger(2, &type) || callback_id.empty() || |
| printer_name.empty()) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value()); |
| return; |
| } |
| PrinterType printer_type = static_cast<PrinterType>(type); |
| |
| PrinterHandler* handler = GetPrinterHandler(printer_type); |
| if (!handler) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value()); |
| return; |
| } |
| |
| handler->StartGetCapability( |
| printer_name, |
| base::BindOnce(&PrintPreviewHandler::SendPrinterCapabilities, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) { |
| DCHECK_EQ(3U, args->GetSize()); |
| std::string callback_id; |
| std::string json_str; |
| |
| // All of the conditions below should be guaranteed by the print preview |
| // javascript. |
| args->GetString(0, &callback_id); |
| CHECK(!callback_id.empty()); |
| args->GetString(1, &json_str); |
| std::unique_ptr<base::DictionaryValue> settings = |
| GetSettingsDictionary(json_str); |
| CHECK(settings); |
| int request_id = -1; |
| settings->GetInteger(printing::kPreviewRequestID, &request_id); |
| CHECK_GT(request_id, -1); |
| |
| preview_callbacks_.push(callback_id); |
| print_preview_ui()->OnPrintPreviewRequest(request_id); |
| // Add an additional key in order to identify |print_preview_ui| later on |
| // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO |
| // thread. |
| settings->SetInteger(printing::kPreviewUIID, |
| print_preview_ui()->GetIDForPrintPreviewUI()); |
| |
| // Increment request count. |
| ++regenerate_preview_request_count_; |
| |
| WebContents* initiator = GetInitiator(); |
| RenderFrameHost* rfh = |
| initiator |
| ? PrintViewManager::FromWebContents(initiator)->print_preview_rfh() |
| : nullptr; |
| if (!rfh) { |
| ReportUserActionHistogram(INITIATOR_CLOSED); |
| print_preview_ui()->OnClosePrintPreviewDialog(); |
| return; |
| } |
| |
| // Retrieve the page title and url and send it to the renderer process if |
| // headers and footers are to be displayed. |
| bool display_header_footer = false; |
| bool success = settings->GetBoolean(printing::kSettingHeaderFooterEnabled, |
| &display_header_footer); |
| DCHECK(success); |
| if (display_header_footer) { |
| settings->SetString(printing::kSettingHeaderFooterTitle, |
| initiator->GetTitle()); |
| |
| url::Replacements<char> url_sanitizer; |
| url_sanitizer.ClearUsername(); |
| url_sanitizer.ClearPassword(); |
| const GURL& initiator_url = initiator->GetLastCommittedURL(); |
| settings->SetString(printing::kSettingHeaderFooterURL, |
| initiator_url.ReplaceComponents(url_sanitizer).spec()); |
| } |
| |
| bool generate_draft_data = false; |
| success = settings->GetBoolean(printing::kSettingGenerateDraftData, |
| &generate_draft_data); |
| DCHECK(success); |
| |
| if (!generate_draft_data) { |
| int page_count = -1; |
| success = args->GetInteger(2, &page_count); |
| DCHECK(success); |
| |
| if (page_count != -1) { |
| bool preview_modifiable = false; |
| success = settings->GetBoolean(printing::kSettingPreviewModifiable, |
| &preview_modifiable); |
| DCHECK(success); |
| |
| if (preview_modifiable && |
| print_preview_ui()->GetAvailableDraftPageCount() != page_count) { |
| settings->SetBoolean(printing::kSettingGenerateDraftData, true); |
| } |
| } |
| } |
| |
| VLOG(1) << "Print preview request start"; |
| |
| rfh->Send(new PrintMsg_PrintPreview(rfh->GetRoutingID(), *settings)); |
| } |
| |
| void PrintPreviewHandler::HandlePrint(const base::ListValue* args) { |
| // Record the number of times the user requests to regenerate preview data |
| // before printing. |
| UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint", |
| regenerate_preview_request_count_); |
| std::string callback_id; |
| CHECK(args->GetString(0, &callback_id)); |
| CHECK(!callback_id.empty()); |
| std::string json_str; |
| CHECK(args->GetString(1, &json_str)); |
| |
| std::unique_ptr<base::DictionaryValue> settings = |
| GetSettingsDictionary(json_str); |
| if (!settings) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value(-1)); |
| return; |
| } |
| |
| ReportPrintSettingsStats(*settings); |
| |
| // Report whether the user printed a PDF or an HTML document. |
| ReportPrintDocumentTypeHistogram(print_preview_ui()->source_is_modifiable() ? |
| HTML_DOCUMENT : PDF_DOCUMENT); |
| |
| bool print_to_pdf = false; |
| bool is_cloud_printer = false; |
| bool print_with_privet = false; |
| bool print_with_extension = false; |
| bool show_system_dialog = false; |
| bool open_pdf_in_preview = false; |
| #if defined(OS_MACOSX) |
| open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview); |
| #endif |
| |
| if (!open_pdf_in_preview) { |
| settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf); |
| settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet); |
| settings->GetBoolean(printing::kSettingPrintWithExtension, |
| &print_with_extension); |
| settings->GetBoolean(printing::kSettingShowSystemDialog, |
| &show_system_dialog); |
| is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId); |
| } |
| |
| int page_count = 0; |
| if (!settings->GetInteger(printing::kSettingPreviewPageCount, &page_count) || |
| page_count <= 0) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value(-1)); |
| return; |
| } |
| |
| if (print_with_privet) { |
| #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count); |
| ReportUserActionHistogram(PRINT_WITH_PRIVET); |
| #endif |
| } else if (print_with_extension) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithExtension", |
| page_count); |
| ReportUserActionHistogram(PRINT_WITH_EXTENSION); |
| } else if (print_to_pdf) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count); |
| ReportUserActionHistogram(PRINT_TO_PDF); |
| } else if (show_system_dialog) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count); |
| ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG); |
| } else if (!open_pdf_in_preview) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count); |
| ReportUserActionHistogram(PRINT_TO_PRINTER); |
| } else if (is_cloud_printer) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint", |
| page_count); |
| ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT); |
| } |
| |
| scoped_refptr<base::RefCountedBytes> data; |
| print_preview_ui()->GetPrintPreviewDataForIndex( |
| printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data); |
| if (!data) { |
| // Nothing to print, no preview available. |
| RejectJavascriptCallback( |
| base::Value(callback_id), |
| print_with_privet ? base::Value(-1) : base::Value("NO_DATA")); |
| return; |
| } |
| DCHECK(data->size()); |
| DCHECK(data->front()); |
| |
| if (is_cloud_printer) { |
| // Does not send the title like the other printer handler types below, |
| // because JS already has the document title from the initial settings. |
| SendCloudPrintJob(callback_id, data.get()); |
| return; |
| } |
| |
| std::string destination_id; |
| std::string print_ticket; |
| std::string capabilities; |
| int width = 0; |
| int height = 0; |
| if ((print_with_privet || print_with_extension) && |
| (!settings->GetString(printing::kSettingDeviceName, &destination_id) || |
| !settings->GetString(printing::kSettingTicket, &print_ticket) || |
| !settings->GetString(printing::kSettingCapabilities, &capabilities) || |
| !settings->GetInteger(printing::kSettingPageWidth, &width) || |
| !settings->GetInteger(printing::kSettingPageHeight, &height) || |
| width <= 0 || height <= 0)) { |
| NOTREACHED(); |
| RejectJavascriptCallback( |
| base::Value(callback_id), |
| print_with_privet ? base::Value(-1) : base::Value("FAILED")); |
| return; |
| } |
| |
| PrinterType type = PrinterType::kLocalPrinter; |
| if (print_with_extension) |
| type = PrinterType::kExtensionPrinter; |
| else if (print_with_privet) |
| type = PrinterType::kPrivetPrinter; |
| else if (print_to_pdf) |
| type = PrinterType::kPdfPrinter; |
| PrinterHandler* handler = GetPrinterHandler(type); |
| handler->StartPrint( |
| destination_id, capabilities, print_preview_ui()->initiator_title(), |
| type == PrinterType::kLocalPrinter ? json_str : print_ticket, |
| gfx::Size(width, height), data, |
| base::BindOnce(&PrintPreviewHandler::OnPrintResult, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) { |
| print_preview_ui()->OnHidePreviewDialog(); |
| } |
| |
| void PrintPreviewHandler::HandleCancelPendingPrintRequest( |
| const base::ListValue* /*args*/) { |
| WebContents* initiator = GetInitiator(); |
| if (initiator) |
| ClearInitiatorDetails(); |
| ShowPrintErrorDialog(); |
| } |
| |
| void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) { |
| std::string data_to_save; |
| printing::StickySettings* sticky_settings = GetStickySettings(); |
| if (args->GetString(0, &data_to_save) && !data_to_save.empty()) |
| sticky_settings->StoreAppState(data_to_save); |
| sticky_settings->SaveInPrefs(Profile::FromBrowserContext( |
| preview_web_contents()->GetBrowserContext())->GetPrefs()); |
| } |
| |
| // |args| is expected to contain a string with representing the callback id |
| // followed by a list of arguments the first of which should be the printer id. |
| void PrintPreviewHandler::HandlePrinterSetup(const base::ListValue* args) { |
| std::string callback_id; |
| std::string printer_name; |
| if (!args->GetString(0, &callback_id) || !args->GetString(1, &printer_name) || |
| callback_id.empty() || printer_name.empty()) { |
| RejectJavascriptCallback(base::Value(callback_id), |
| base::Value(printer_name)); |
| return; |
| } |
| |
| GetPrinterHandler(PrinterType::kLocalPrinter) |
| ->StartGetCapability( |
| printer_name, base::BindOnce(&PrintPreviewHandler::SendPrinterSetup, |
| weak_factory_.GetWeakPtr(), callback_id, |
| printer_name)); |
| } |
| |
| void PrintPreviewHandler::OnSigninComplete(const std::string& callback_id) { |
| ResolveJavascriptCallback(base::Value(callback_id), base::Value()); |
| } |
| |
| void PrintPreviewHandler::HandleSignin(const base::ListValue* args) { |
| std::string callback_id; |
| bool add_account = false; |
| CHECK(args->GetString(0, &callback_id)); |
| CHECK(!callback_id.empty()); |
| CHECK(args->GetBoolean(1, &add_account)); |
| |
| Profile* profile = Profile::FromBrowserContext( |
| preview_web_contents()->GetBrowserContext()); |
| chrome::ScopedTabbedBrowserDisplayer displayer(profile); |
| print_dialog_cloud::CreateCloudPrintSigninTab( |
| displayer.browser(), add_account, |
| base::Bind(&PrintPreviewHandler::OnSigninComplete, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) { |
| std::string callback_id; |
| std::string type; |
| |
| bool ok = args->GetString(0, &callback_id) && args->GetString(1, &type) && |
| !callback_id.empty(); |
| DCHECK(ok); |
| |
| if (!token_service_) |
| token_service_ = std::make_unique<AccessTokenService>(this); |
| token_service_->RequestToken(type, callback_id); |
| } |
| |
| void PrintPreviewHandler::HandleManagePrinters(const base::ListValue* args) { |
| GURL local_printers_manage_url( |
| chrome::GetSettingsUrl(chrome::kPrintingSettingsSubPage)); |
| preview_web_contents()->OpenURL( |
| content::OpenURLParams(local_printers_manage_url, content::Referrer(), |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_LINK, false)); |
| } |
| |
| #if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG) |
| void PrintPreviewHandler::HandleShowSystemDialog( |
| const base::ListValue* /*args*/) { |
| manage_printers_dialog_request_count_++; |
| ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG); |
| |
| WebContents* initiator = GetInitiator(); |
| if (!initiator) |
| return; |
| |
| auto* print_view_manager = PrintViewManager::FromWebContents(initiator); |
| print_view_manager->PrintForSystemDialogNow( |
| base::Bind(&PrintPreviewHandler::ClosePreviewDialog, |
| weak_factory_.GetWeakPtr())); |
| |
| // Cancel the pending preview request if exists. |
| print_preview_ui()->OnCancelPendingPreviewRequest(); |
| } |
| #endif |
| |
| void PrintPreviewHandler::HandleClosePreviewDialog( |
| const base::ListValue* /*args*/) { |
| ReportUserActionHistogram(CANCEL); |
| |
| // Record the number of times the user requests to regenerate preview data |
| // before cancelling. |
| UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel", |
| regenerate_preview_request_count_); |
| } |
| |
| void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem( |
| base::DictionaryValue* settings) { |
| |
| // Getting the measurement system based on the locale. |
| UErrorCode errorCode = U_ZERO_ERROR; |
| const char* locale = g_browser_process->GetApplicationLocale().c_str(); |
| UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode); |
| // On error, assume the units are SI. |
| // Since the only measurement units print preview's WebUI cares about are |
| // those for measuring distance, assume anything non-US is SI. |
| if (errorCode > U_ZERO_ERROR || system != UMS_US) |
| system = UMS_SI; |
| |
| // Getting the number formatting based on the locale and writing to |
| // dictionary. |
| base::string16 number_format = base::FormatDouble(123456.78, 2); |
| settings->SetString(kDecimalDelimeter, number_format.substr(6, 1)); |
| settings->SetString(kThousandsDelimeter, number_format.substr(3, 1)); |
| settings->SetInteger(kUnitType, system); |
| } |
| |
| void PrintPreviewHandler::HandleGetInitialSettings( |
| const base::ListValue* args) { |
| std::string callback_id; |
| CHECK(args->GetString(0, &callback_id)); |
| CHECK(!callback_id.empty()); |
| |
| AllowJavascript(); |
| |
| // Send before SendInitialSettings() to allow cloud printer auto select. |
| SendCloudPrintEnabled(); |
| GetPrinterHandler(PrinterType::kLocalPrinter) |
| ->GetDefaultPrinter(base::Bind(&PrintPreviewHandler::SendInitialSettings, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) { |
| std::string url; |
| if (!args->GetString(0, &url)) |
| return; |
| Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator()); |
| if (!browser) |
| return; |
| chrome::AddSelectedTabWithURL(browser, |
| GURL(url), |
| ui::PAGE_TRANSITION_LINK); |
| } |
| |
| void PrintPreviewHandler::SendInitialSettings( |
| const std::string& callback_id, |
| const std::string& default_printer) { |
| base::DictionaryValue initial_settings; |
| initial_settings.SetString(kDocumentTitle, |
| print_preview_ui()->initiator_title()); |
| initial_settings.SetBoolean(printing::kSettingPreviewModifiable, |
| print_preview_ui()->source_is_modifiable()); |
| initial_settings.SetString(printing::kSettingPrinterName, default_printer); |
| initial_settings.SetBoolean(kDocumentHasSelection, |
| print_preview_ui()->source_has_selection()); |
| initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly, |
| print_preview_ui()->print_selection_only()); |
| PrefService* prefs = Profile::FromBrowserContext( |
| preview_web_contents()->GetBrowserContext())->GetPrefs(); |
| printing::StickySettings* sticky_settings = GetStickySettings(); |
| sticky_settings->RestoreFromPrefs(prefs); |
| if (sticky_settings->printer_app_state()) { |
| initial_settings.SetString(kAppState, |
| *sticky_settings->printer_app_state()); |
| } else { |
| initial_settings.SetKey(kAppState, base::Value()); |
| } |
| |
| base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); |
| initial_settings.SetBoolean(kIsInKioskAutoPrintMode, |
| cmdline->HasSwitch(switches::kKioskModePrinting)); |
| initial_settings.SetBoolean(kIsInAppKioskMode, |
| chrome::IsRunningInForcedAppMode()); |
| bool set_rules = false; |
| if (prefs) { |
| const std::string rules_str = |
| prefs->GetString(prefs::kPrintPreviewDefaultDestinationSelectionRules); |
| if (!rules_str.empty()) { |
| initial_settings.SetString(kDefaultDestinationSelectionRules, rules_str); |
| set_rules = true; |
| } |
| } |
| if (!set_rules) { |
| initial_settings.SetKey(kDefaultDestinationSelectionRules, base::Value()); |
| } |
| |
| GetNumberFormatAndMeasurementSystem(&initial_settings); |
| ResolveJavascriptCallback(base::Value(callback_id), initial_settings); |
| } |
| |
| void PrintPreviewHandler::ClosePreviewDialog() { |
| print_preview_ui()->OnClosePrintPreviewDialog(); |
| } |
| |
| void PrintPreviewHandler::SendAccessToken(const std::string& callback_id, |
| const std::string& access_token) { |
| VLOG(1) << "Get getAccessToken finished"; |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(access_token)); |
| } |
| |
| void PrintPreviewHandler::SendPrinterCapabilities( |
| const std::string& callback_id, |
| std::unique_ptr<base::DictionaryValue> settings_info) { |
| // Check that |settings_info| is valid. |
| if (settings_info && |
| settings_info->FindKeyOfType(printing::kSettingCapabilities, |
| base::Value::Type::DICTIONARY)) { |
| VLOG(1) << "Get printer capabilities finished"; |
| ResolveJavascriptCallback(base::Value(callback_id), *settings_info); |
| return; |
| } |
| |
| VLOG(1) << "Get printer capabilities failed"; |
| RejectJavascriptCallback(base::Value(callback_id), base::Value()); |
| } |
| |
| void PrintPreviewHandler::SendPrinterSetup( |
| const std::string& callback_id, |
| const std::string& printer_name, |
| std::unique_ptr<base::DictionaryValue> destination_info) { |
| auto response = std::make_unique<base::DictionaryValue>(); |
| bool success = true; |
| auto caps_value = std::make_unique<base::Value>(); |
| auto caps = std::make_unique<base::DictionaryValue>(); |
| if (destination_info && |
| destination_info->Remove(printing::kSettingCapabilities, &caps_value) && |
| caps_value->is_dict()) { |
| caps = base::DictionaryValue::From(std::move(caps_value)); |
| } else { |
| LOG(WARNING) << "Printer setup failed"; |
| success = false; |
| } |
| |
| response->SetString("printerId", printer_name); |
| response->SetBoolean("success", success); |
| response->Set("capabilities", std::move(caps)); |
| |
| ResolveJavascriptCallback(base::Value(callback_id), *response); |
| } |
| |
| void PrintPreviewHandler::SendCloudPrintEnabled() { |
| Profile* profile = Profile::FromBrowserContext( |
| preview_web_contents()->GetBrowserContext()); |
| PrefService* prefs = profile->GetPrefs(); |
| if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) { |
| FireWebUIListener( |
| "use-cloud-print", |
| base::Value(GURL(cloud_devices::GetCloudPrintURL()).spec()), |
| base::Value(chrome::IsRunningInForcedAppMode())); |
| } |
| } |
| |
| void PrintPreviewHandler::SendCloudPrintJob(const std::string& callback_id, |
| const base::RefCountedBytes* data) { |
| // BASE64 encode the job data. |
| const base::StringPiece raw_data(reinterpret_cast<const char*>(data->front()), |
| data->size()); |
| std::string base64_data; |
| base::Base64Encode(raw_data, &base64_data); |
| |
| if (base64_data.size() >= kMaxCloudPrintPdfDataSizeInBytes) { |
| RejectJavascriptCallback(base::Value(callback_id), |
| base::Value("OVERSIZED_PDF")); |
| return; |
| } |
| ResolveJavascriptCallback(base::Value(callback_id), base::Value(base64_data)); |
| } |
| |
| WebContents* PrintPreviewHandler::GetInitiator() const { |
| printing::PrintPreviewDialogController* dialog_controller = |
| printing::PrintPreviewDialogController::GetInstance(); |
| if (!dialog_controller) |
| return NULL; |
| return dialog_controller->GetInitiator(preview_web_contents()); |
| } |
| |
| void PrintPreviewHandler::OnAddAccountToCookieCompleted( |
| const std::string& account_id, |
| const GoogleServiceAuthError& error) { |
| FireWebUIListener("reload-printer-list"); |
| } |
| |
| void PrintPreviewHandler::OnPrintPreviewReady(int preview_uid, int request_id) { |
| if (request_id < 0 || preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| // invalid ID or extra message |
| BadMessageReceived(); |
| return; |
| } |
| |
| ResolveJavascriptCallback(base::Value(preview_callbacks_.front()), |
| base::Value(preview_uid)); |
| preview_callbacks_.pop(); |
| } |
| |
| void PrintPreviewHandler::OnPrintPreviewFailed() { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| if (!reported_failed_preview_) { |
| reported_failed_preview_ = true; |
| ReportUserActionHistogram(PREVIEW_FAILED); |
| } |
| RejectJavascriptCallback(base::Value(preview_callbacks_.front()), |
| base::Value("PREVIEW_FAILED")); |
| preview_callbacks_.pop(); |
| } |
| |
| void PrintPreviewHandler::OnInvalidPrinterSettings() { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| RejectJavascriptCallback(base::Value(preview_callbacks_.front()), |
| base::Value("SETTINGS_INVALID")); |
| preview_callbacks_.pop(); |
| } |
| |
| void PrintPreviewHandler::SendPrintPresetOptions(bool disable_scaling, |
| int copies, |
| int duplex) { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| FireWebUIListener("print-preset-options", base::Value(disable_scaling), |
| base::Value(copies), base::Value(duplex)); |
| } |
| |
| void PrintPreviewHandler::SendPageCountReady(int page_count, |
| int request_id, |
| int fit_to_page_scaling) { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| FireWebUIListener("page-count-ready", base::Value(page_count), |
| base::Value(request_id), base::Value(fit_to_page_scaling)); |
| } |
| |
| void PrintPreviewHandler::SendPageLayoutReady( |
| const base::DictionaryValue& layout, |
| bool has_custom_page_size_style) { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| FireWebUIListener("page-layout-ready", layout, |
| base::Value(has_custom_page_size_style)); |
| } |
| |
| void PrintPreviewHandler::SendPagePreviewReady(int page_index, |
| int preview_uid, |
| int preview_response_id) { |
| if (!IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| FireWebUIListener("page-preview-ready", base::Value(page_index), |
| base::Value(preview_uid), base::Value(preview_response_id)); |
| } |
| |
| void PrintPreviewHandler::OnPrintPreviewCancelled() { |
| if (preview_callbacks_.empty() || !IsJavascriptAllowed()) { |
| BadMessageReceived(); |
| return; |
| } |
| |
| RejectJavascriptCallback(base::Value(preview_callbacks_.front()), |
| base::Value("CANCELLED")); |
| preview_callbacks_.pop(); |
| } |
| |
| void PrintPreviewHandler::OnPrintRequestCancelled() { |
| HandleCancelPendingPrintRequest(nullptr); |
| } |
| |
| void PrintPreviewHandler::ClearInitiatorDetails() { |
| WebContents* initiator = GetInitiator(); |
| if (!initiator) |
| return; |
| |
| // We no longer require the initiator details. Remove those details associated |
| // with the preview dialog to allow the initiator to create another preview |
| // dialog. |
| printing::PrintPreviewDialogController* dialog_controller = |
| printing::PrintPreviewDialogController::GetInstance(); |
| if (dialog_controller) |
| dialog_controller->EraseInitiatorInfo(preview_web_contents()); |
| } |
| |
| PrinterHandler* PrintPreviewHandler::GetPrinterHandler( |
| PrinterType printer_type) { |
| if (printer_type == PrinterType::kExtensionPrinter) { |
| if (!extension_printer_handler_) { |
| extension_printer_handler_ = PrinterHandler::CreateForExtensionPrinters( |
| Profile::FromWebUI(web_ui())); |
| } |
| return extension_printer_handler_.get(); |
| } |
| #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) |
| if (printer_type == PrinterType::kPrivetPrinter) { |
| if (!privet_printer_handler_) { |
| privet_printer_handler_ = |
| PrinterHandler::CreateForPrivetPrinters(Profile::FromWebUI(web_ui())); |
| } |
| return privet_printer_handler_.get(); |
| } |
| #endif |
| if (printer_type == PrinterType::kPdfPrinter) { |
| if (!pdf_printer_handler_) { |
| pdf_printer_handler_ = PrinterHandler::CreateForPdfPrinter( |
| Profile::FromWebUI(web_ui()), preview_web_contents(), |
| GetStickySettings()); |
| } |
| return pdf_printer_handler_.get(); |
| } |
| if (printer_type == PrinterType::kLocalPrinter) { |
| if (!local_printer_handler_) { |
| local_printer_handler_ = PrinterHandler::CreateForLocalPrinters( |
| preview_web_contents(), Profile::FromWebUI(web_ui())); |
| } |
| return local_printer_handler_.get(); |
| } |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| PdfPrinterHandler* PrintPreviewHandler::GetPdfPrinterHandler() { |
| return static_cast<PdfPrinterHandler*>( |
| GetPrinterHandler(PrinterType::kPdfPrinter)); |
| } |
| |
| void PrintPreviewHandler::OnAddedPrinters(printing::PrinterType printer_type, |
| const base::ListValue& printers) { |
| DCHECK(printer_type == PrinterType::kExtensionPrinter || |
| printer_type == PrinterType::kPrivetPrinter || |
| printer_type == PrinterType::kLocalPrinter); |
| DCHECK(!printers.empty()); |
| FireWebUIListener("printers-added", base::Value(printer_type), printers); |
| |
| if (printer_type == PrinterType::kLocalPrinter && |
| !has_logged_printers_count_) { |
| UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers.GetSize()); |
| has_logged_printers_count_ = true; |
| } |
| } |
| |
| void PrintPreviewHandler::OnGetPrintersDone(const std::string& callback_id) { |
| ResolveJavascriptCallback(base::Value(callback_id), base::Value()); |
| } |
| |
| void PrintPreviewHandler::OnGotExtensionPrinterInfo( |
| const std::string& callback_id, |
| const base::DictionaryValue& printer_info) { |
| if (printer_info.empty()) { |
| RejectJavascriptCallback(base::Value(callback_id), base::Value()); |
| return; |
| } |
| ResolveJavascriptCallback(base::Value(callback_id), printer_info); |
| } |
| |
| void PrintPreviewHandler::OnPrintResult(const std::string& callback_id, |
| const base::Value& error) { |
| if (error.is_none()) |
| ResolveJavascriptCallback(base::Value(callback_id), error); |
| else |
| RejectJavascriptCallback(base::Value(callback_id), error); |
| // Remove the preview dialog from the background printing manager if it is |
| // being stored there. Since the PDF has been sent and the callback is |
| // resolved or rejected, it is no longer needed and can be destroyed. |
| printing::BackgroundPrintingManager* background_printing_manager = |
| g_browser_process->background_printing_manager(); |
| if (background_printing_manager->HasPrintPreviewDialog( |
| preview_web_contents())) { |
| background_printing_manager->OnPrintRequestCancelled( |
| preview_web_contents()); |
| } |
| } |
| |
| void PrintPreviewHandler::RegisterForGaiaCookieChanges() { |
| DCHECK(!gaia_cookie_manager_service_); |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| if (signin::IsAccountConsistencyMirrorEnabled() && |
| !profile->IsOffTheRecord()) { |
| gaia_cookie_manager_service_ = |
| GaiaCookieManagerServiceFactory::GetForProfile(profile); |
| if (gaia_cookie_manager_service_) |
| gaia_cookie_manager_service_->AddObserver(this); |
| } |
| } |
| |
| void PrintPreviewHandler::UnregisterForGaiaCookieChanges() { |
| if (gaia_cookie_manager_service_) |
| gaia_cookie_manager_service_->RemoveObserver(this); |
| } |
| |
| void PrintPreviewHandler::BadMessageReceived() { |
| bad_message::ReceivedBadMessage( |
| GetInitiator()->GetMainFrame()->GetProcess(), |
| bad_message::BadMessageReason::PPH_EXTRA_PREVIEW_MESSAGE); |
| } |
| |
| void PrintPreviewHandler::FileSelectedForTesting(const base::FilePath& path, |
| int index, |
| void* params) { |
| GetPdfPrinterHandler()->FileSelected(path, index, params); |
| } |
| |
| void PrintPreviewHandler::SetPdfSavedClosureForTesting( |
| const base::Closure& closure) { |
| GetPdfPrinterHandler()->SetPdfSavedClosureForTesting(closure); |
| } |
| |
| void PrintPreviewHandler::SendEnableManipulateSettingsForTest() { |
| FireWebUIListener("enable-manipulate-settings-for-test", base::Value()); |
| } |
| |
| void PrintPreviewHandler::SendManipulateSettingsForTest( |
| const base::DictionaryValue& settings) { |
| FireWebUIListener("manipulate-settings-for-test", settings); |
| } |