diff options
author | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
---|---|---|
committer | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
commit | 679147eead574d186ebf3069647b4c23e8ccace6 (patch) | |
tree | fc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/printing/printing_context_mac.mm | |
download | qtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz |
Initial import.
Diffstat (limited to 'chromium/printing/printing_context_mac.mm')
-rw-r--r-- | chromium/printing/printing_context_mac.mm | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/chromium/printing/printing_context_mac.mm b/chromium/printing/printing_context_mac.mm new file mode 100644 index 00000000000..4d83c130718 --- /dev/null +++ b/chromium/printing/printing_context_mac.mm @@ -0,0 +1,519 @@ +// Copyright (c) 2011 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 "printing/printing_context_mac.h" + +#import <ApplicationServices/ApplicationServices.h> +#import <AppKit/AppKit.h> + +#import <iomanip> +#import <numeric> + +#include "base/logging.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/mac/scoped_nsexception_enabler.h" +#include "base/strings/sys_string_conversions.h" +#include "base/values.h" +#include "printing/print_settings_initializer_mac.h" + +namespace printing { + +namespace { + +// Return true if PPD name of paper is equal. +bool IsPaperNameEqual(const PMPaper& paper1, const PMPaper& paper2) { + CFStringRef name1 = NULL; + CFStringRef name2 = NULL; + return (PMPaperGetPPDPaperName(paper1, &name1) == noErr) && + (PMPaperGetPPDPaperName(paper2, &name2) == noErr) && + (CFStringCompare(name1, name2, + kCFCompareCaseInsensitive) == kCFCompareEqualTo); +} + +} // namespace + +// static +PrintingContext* PrintingContext::Create(const std::string& app_locale) { + return static_cast<PrintingContext*>(new PrintingContextMac(app_locale)); +} + +PrintingContextMac::PrintingContextMac(const std::string& app_locale) + : PrintingContext(app_locale), + print_info_([[NSPrintInfo sharedPrintInfo] copy]), + context_(NULL) { +} + +PrintingContextMac::~PrintingContextMac() { + ReleaseContext(); +} + +void PrintingContextMac::AskUserForSettings( + gfx::NativeView parent_view, + int max_pages, + bool has_selection, + const PrintSettingsCallback& callback) { + // Third-party print drivers seem to be an area prone to raising exceptions. + // This will allow exceptions to be raised, but does not handle them. The + // NSPrintPanel appears to have appropriate NSException handlers. + base::mac::ScopedNSExceptionEnabler enabler; + + // Exceptions can also happen when the NSPrintPanel is being + // deallocated, so it must be autoreleased within this scope. + base::mac::ScopedNSAutoreleasePool pool; + + DCHECK([NSThread isMainThread]); + + // We deliberately don't feed max_pages into the dialog, because setting + // NSPrintLastPage makes the print dialog pre-select the option to only print + // a range. + + // TODO(stuartmorgan): implement 'print selection only' (probably requires + // adding a new custom view to the panel on 10.5; 10.6 has + // NSPrintPanelShowsPrintSelection). + NSPrintPanel* panel = [NSPrintPanel printPanel]; + NSPrintInfo* printInfo = print_info_.get(); + + NSPrintPanelOptions options = [panel options]; + options |= NSPrintPanelShowsPaperSize; + options |= NSPrintPanelShowsOrientation; + options |= NSPrintPanelShowsScaling; + [panel setOptions:options]; + + // Set the print job title text. + if (parent_view) { + NSString* job_title = [[parent_view window] title]; + if (job_title) { + PMPrintSettings printSettings = + (PMPrintSettings)[printInfo PMPrintSettings]; + PMPrintSettingsSetJobName(printSettings, (CFStringRef)job_title); + [printInfo updateFromPMPrintSettings]; + } + } + + // TODO(stuartmorgan): We really want a tab sheet here, not a modal window. + // Will require restructuring the PrintingContext API to use a callback. + NSInteger selection = [panel runModalWithPrintInfo:printInfo]; + if (selection == NSOKButton) { + print_info_.reset([[panel printInfo] retain]); + InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo()); + callback.Run(OK); + } else { + callback.Run(CANCEL); + } +} + +PrintingContext::Result PrintingContextMac::UseDefaultSettings() { + DCHECK(!in_print_job_); + + print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]); + InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo()); + + return OK; +} + +PrintingContext::Result PrintingContextMac::UpdatePrinterSettings( + const DictionaryValue& job_settings, const PageRanges& ranges) { + DCHECK(!in_print_job_); + + // NOTE: Reset |print_info_| with a copy of |sharedPrintInfo| so as to start + // with a clean slate. + print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]); + + bool collate; + int color; + bool landscape; + bool print_to_pdf; + bool is_cloud_dialog; + int copies; + int duplex_mode; + std::string device_name; + + if (!job_settings.GetBoolean(kSettingLandscape, &landscape) || + !job_settings.GetBoolean(kSettingCollate, &collate) || + !job_settings.GetInteger(kSettingColor, &color) || + !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) || + !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) || + !job_settings.GetInteger(kSettingCopies, &copies) || + !job_settings.GetString(kSettingDeviceName, &device_name) || + !job_settings.GetBoolean(kSettingCloudPrintDialog, &is_cloud_dialog)) { + return OnError(); + } + + bool print_to_cloud = job_settings.HasKey(kSettingCloudPrintId); + bool open_pdf_in_preview = job_settings.HasKey(kSettingOpenPDFInPreview); + + if (!print_to_pdf && !print_to_cloud && !is_cloud_dialog) { + if (!SetPrinter(device_name)) + return OnError(); + + if (!SetCopiesInPrintSettings(copies)) + return OnError(); + + if (!SetCollateInPrintSettings(collate)) + return OnError(); + + if (!SetDuplexModeInPrintSettings( + static_cast<DuplexMode>(duplex_mode))) { + return OnError(); + } + + if (!SetOutputColor(color)) + return OnError(); + } + if (open_pdf_in_preview) { + if (!SetPrintPreviewJob()) + return OnError(); + } + + if (!UpdatePageFormatWithPaperInfo()) + return OnError(); + + if (!SetOrientationIsLandscape(landscape)) + return OnError(); + + [print_info_.get() updateFromPMPrintSettings]; + + InitPrintSettingsFromPrintInfo(ranges); + return OK; +} + +bool PrintingContextMac::SetPrintPreviewJob() { + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + PMPrintSettings print_settings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + return PMSessionSetDestination( + print_session, print_settings, kPMDestinationPreview, + NULL, NULL) == noErr; +} + +void PrintingContextMac::InitPrintSettingsFromPrintInfo( + const PageRanges& ranges) { + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + PMPageFormat page_format = + static_cast<PMPageFormat>([print_info_.get() PMPageFormat]); + PMPrinter printer; + PMSessionGetCurrentPrinter(print_session, &printer); + PrintSettingsInitializerMac::InitPrintSettings( + printer, page_format, ranges, false, &settings_); +} + +bool PrintingContextMac::SetPrinter(const std::string& device_name) { + DCHECK(print_info_.get()); + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + + PMPrinter current_printer; + if (PMSessionGetCurrentPrinter(print_session, ¤t_printer) != noErr) + return false; + + CFStringRef current_printer_id = PMPrinterGetID(current_printer); + if (!current_printer_id) + return false; + + base::ScopedCFTypeRef<CFStringRef> new_printer_id( + base::SysUTF8ToCFStringRef(device_name)); + if (!new_printer_id.get()) + return false; + + if (CFStringCompare(new_printer_id.get(), current_printer_id, 0) == + kCFCompareEqualTo) { + return true; + } + + PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get()); + if (new_printer == NULL) + return false; + + OSStatus status = PMSessionSetCurrentPMPrinter(print_session, new_printer); + PMRelease(new_printer); + return status == noErr; +} + +bool PrintingContextMac::UpdatePageFormatWithPaperInfo() { + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + + PMPageFormat default_page_format = + static_cast<PMPageFormat>([print_info_.get() PMPageFormat]); + + PMPaper default_paper; + if (PMGetPageFormatPaper(default_page_format, &default_paper) != noErr) + return false; + + double default_page_width = 0.0; + double default_page_height = 0.0; + if (PMPaperGetWidth(default_paper, &default_page_width) != noErr) + return false; + + if (PMPaperGetHeight(default_paper, &default_page_height) != noErr) + return false; + + PMPrinter current_printer = NULL; + if (PMSessionGetCurrentPrinter(print_session, ¤t_printer) != noErr) + return false; + + if (current_printer == nil) + return false; + + CFArrayRef paper_list = NULL; + if (PMPrinterGetPaperList(current_printer, &paper_list) != noErr) + return false; + + double best_match = std::numeric_limits<double>::max(); + PMPaper best_matching_paper = kPMNoData; + int num_papers = CFArrayGetCount(paper_list); + for (int i = 0; i < num_papers; ++i) { + PMPaper paper = (PMPaper)[(NSArray*)paper_list objectAtIndex: i]; + double paper_width = 0.0; + double paper_height = 0.0; + PMPaperGetWidth(paper, &paper_width); + PMPaperGetHeight(paper, &paper_height); + double current_match = std::max(fabs(default_page_width - paper_width), + fabs(default_page_height - paper_height)); + // Ignore paper sizes that are very different. + if (current_match > 2) + continue; + current_match += IsPaperNameEqual(paper, default_paper) ? 0 : 1; + if (current_match < best_match) { + best_matching_paper = paper; + best_match = current_match; + } + } + + if (best_matching_paper == kPMNoData) { + PMPaper paper = kPMNoData; + // Create a custom paper for the specified default page size. + PMPaperMargins default_margins; + if (PMPaperGetMargins(default_paper, &default_margins) != noErr) + return false; + + const PMPaperMargins margins = + {default_margins.top, default_margins.left, default_margins.bottom, + default_margins.right}; + CFStringRef paper_id = CFSTR("Custom paper ID"); + CFStringRef paper_name = CFSTR("Custom paper"); + if (PMPaperCreateCustom(current_printer, paper_id, paper_name, + default_page_width, default_page_height, &margins, &paper) != + noErr) { + return false; + } + [print_info_.get() updateFromPMPageFormat]; + PMRelease(paper); + } else { + PMPageFormat chosen_page_format = NULL; + if (PMCreatePageFormat((PMPageFormat*) &chosen_page_format) != noErr) + return false; + + // Create page format from that paper. + if (PMCreatePageFormatWithPMPaper(&chosen_page_format, + best_matching_paper) != noErr) { + PMRelease(chosen_page_format); + return false; + } + // Copy over the original format with the new page format. + if (PMCopyPageFormat(chosen_page_format, default_page_format) != noErr) { + PMRelease(chosen_page_format); + return false; + } + [print_info_.get() updateFromPMPageFormat]; + PMRelease(chosen_page_format); + } + return true; +} + +bool PrintingContextMac::SetCopiesInPrintSettings(int copies) { + if (copies < 1) + return false; + + PMPrintSettings pmPrintSettings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + return PMSetCopies(pmPrintSettings, copies, false) == noErr; +} + +bool PrintingContextMac::SetCollateInPrintSettings(bool collate) { + PMPrintSettings pmPrintSettings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + return PMSetCollate(pmPrintSettings, collate) == noErr; +} + +bool PrintingContextMac::SetOrientationIsLandscape(bool landscape) { + PMPageFormat page_format = + static_cast<PMPageFormat>([print_info_.get() PMPageFormat]); + + PMOrientation orientation = landscape ? kPMLandscape : kPMPortrait; + + if (PMSetOrientation(page_format, orientation, false) != noErr) + return false; + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + + PMSessionValidatePageFormat(print_session, page_format, kPMDontWantBoolean); + + [print_info_.get() updateFromPMPageFormat]; + return true; +} + +bool PrintingContextMac::SetDuplexModeInPrintSettings(DuplexMode mode) { + PMDuplexMode duplexSetting; + switch (mode) { + case LONG_EDGE: + duplexSetting = kPMDuplexNoTumble; + break; + case SHORT_EDGE: + duplexSetting = kPMDuplexTumble; + break; + case SIMPLEX: + duplexSetting = kPMDuplexNone; + break; + default: // UNKNOWN_DUPLEX_MODE + return true; + } + + PMPrintSettings pmPrintSettings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + return PMSetDuplex(pmPrintSettings, duplexSetting) == noErr; +} + +bool PrintingContextMac::SetOutputColor(int color_mode) { + PMPrintSettings pmPrintSettings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + std::string color_setting_name; + std::string color_value; + GetColorModelForMode(color_mode, &color_setting_name, &color_value); + base::ScopedCFTypeRef<CFStringRef> color_setting( + base::SysUTF8ToCFStringRef(color_setting_name)); + base::ScopedCFTypeRef<CFStringRef> output_color( + base::SysUTF8ToCFStringRef(color_value)); + + return PMPrintSettingsSetValue(pmPrintSettings, + color_setting.get(), + output_color.get(), + false) == noErr; +} + +PageRanges PrintingContextMac::GetPageRangesFromPrintInfo() { + PageRanges page_ranges; + NSDictionary* print_info_dict = [print_info_.get() dictionary]; + if (![[print_info_dict objectForKey:NSPrintAllPages] boolValue]) { + PageRange range; + range.from = [[print_info_dict objectForKey:NSPrintFirstPage] intValue] - 1; + range.to = [[print_info_dict objectForKey:NSPrintLastPage] intValue] - 1; + page_ranges.push_back(range); + } + return page_ranges; +} + +PrintingContext::Result PrintingContextMac::InitWithSettings( + const PrintSettings& settings) { + DCHECK(!in_print_job_); + + settings_ = settings; + + NOTIMPLEMENTED(); + + return FAILED; +} + +PrintingContext::Result PrintingContextMac::NewDocument( + const string16& document_name) { + DCHECK(!in_print_job_); + + in_print_job_ = true; + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + PMPrintSettings print_settings = + static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]); + PMPageFormat page_format = + static_cast<PMPageFormat>([print_info_.get() PMPageFormat]); + + base::ScopedCFTypeRef<CFStringRef> job_title( + base::SysUTF16ToCFStringRef(document_name)); + PMPrintSettingsSetJobName(print_settings, job_title.get()); + + OSStatus status = PMSessionBeginCGDocumentNoDialog(print_session, + print_settings, + page_format); + if (status != noErr) + return OnError(); + + return OK; +} + +PrintingContext::Result PrintingContextMac::NewPage() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + DCHECK(!context_); + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + PMPageFormat page_format = + static_cast<PMPageFormat>([print_info_.get() PMPageFormat]); + OSStatus status; + status = PMSessionBeginPageNoDialog(print_session, page_format, NULL); + if (status != noErr) + return OnError(); + status = PMSessionGetCGGraphicsContext(print_session, &context_); + if (status != noErr) + return OnError(); + + return OK; +} + +PrintingContext::Result PrintingContextMac::PageDone() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + DCHECK(context_); + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + OSStatus status = PMSessionEndPageNoDialog(print_session); + if (status != noErr) + OnError(); + context_ = NULL; + + return OK; +} + +PrintingContext::Result PrintingContextMac::DocumentDone() { + if (abort_printing_) + return CANCEL; + DCHECK(in_print_job_); + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + OSStatus status = PMSessionEndDocumentNoDialog(print_session); + if (status != noErr) + OnError(); + + ResetSettings(); + return OK; +} + +void PrintingContextMac::Cancel() { + abort_printing_ = true; + in_print_job_ = false; + context_ = NULL; + + PMPrintSession print_session = + static_cast<PMPrintSession>([print_info_.get() PMPrintSession]); + PMSessionEndPageNoDialog(print_session); +} + +void PrintingContextMac::ReleaseContext() { + print_info_.reset(); + context_ = NULL; +} + +gfx::NativeDrawingContext PrintingContextMac::context() const { + return context_; +} + +} // namespace printing |