Enable WorkerDevToolsSanityTest.InspectSharedWorker
[chromium-blink-merge.git] / printing / printing_context_mac.mm
blob90654e20ad228a86f845b81480e1b99dfe0bede0
1 // Copyright (c) 2011 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 "printing/printing_context_mac.h"
7 #import <ApplicationServices/ApplicationServices.h>
8 #import <AppKit/AppKit.h>
10 #include "base/logging.h"
11 #include "base/mac/scoped_cftyperef.h"
12 #include "base/mac/scoped_nsautorelease_pool.h"
13 #include "base/mac/scoped_nsexception_enabler.h"
14 #include "base/sys_string_conversions.h"
15 #include "base/values.h"
16 #include "printing/print_settings_initializer_mac.h"
18 static const CFStringRef kColorModel = CFSTR("ColorModel");
19 static const CFStringRef kGrayColor = CFSTR("Gray");
21 namespace printing {
23 // static
24 PrintingContext* PrintingContext::Create(const std::string& app_locale) {
25   return static_cast<PrintingContext*>(new PrintingContextMac(app_locale));
28 PrintingContextMac::PrintingContextMac(const std::string& app_locale)
29     : PrintingContext(app_locale),
30       print_info_([[NSPrintInfo sharedPrintInfo] copy]),
31       context_(NULL) {
34 PrintingContextMac::~PrintingContextMac() {
35   ReleaseContext();
38 void PrintingContextMac::AskUserForSettings(gfx::NativeView parent_view,
39                                             int max_pages,
40                                             bool has_selection,
41                                             PrintSettingsCallback* callback) {
42   // Third-party print drivers seem to be an area prone to raising exceptions.
43   // This will allow exceptions to be raised, but does not handle them.  The
44   // NSPrintPanel appears to have appropriate NSException handlers.
45   base::mac::ScopedNSExceptionEnabler enabler;
47   // Exceptions can also happen when the NSPrintPanel is being
48   // deallocated, so it must be autoreleased within this scope.
49   base::mac::ScopedNSAutoreleasePool pool;
51   DCHECK([NSThread isMainThread]);
53   // We deliberately don't feed max_pages into the dialog, because setting
54   // NSPrintLastPage makes the print dialog pre-select the option to only print
55   // a range.
57   // TODO(stuartmorgan): implement 'print selection only' (probably requires
58   // adding a new custom view to the panel on 10.5; 10.6 has
59   // NSPrintPanelShowsPrintSelection).
60   NSPrintPanel* panel = [NSPrintPanel printPanel];
61   NSPrintInfo* printInfo = print_info_.get();
63   NSPrintPanelOptions options = [panel options];
64   options |= NSPrintPanelShowsPaperSize;
65   options |= NSPrintPanelShowsOrientation;
66   options |= NSPrintPanelShowsScaling;
67   [panel setOptions:options];
69   // Set the print job title text.
70   if (parent_view) {
71     NSString* job_title = [[parent_view window] title];
72     if (job_title) {
73       PMPrintSettings printSettings =
74           (PMPrintSettings)[printInfo PMPrintSettings];
75       PMPrintSettingsSetJobName(printSettings, (CFStringRef)job_title);
76       [printInfo updateFromPMPrintSettings];
77     }
78   }
80   // TODO(stuartmorgan): We really want a tab sheet here, not a modal window.
81   // Will require restructuring the PrintingContext API to use a callback.
82   NSInteger selection = [panel runModalWithPrintInfo:printInfo];
83   if (selection == NSOKButton) {
84     print_info_.reset([[panel printInfo] retain]);
85     InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo());
86     callback->Run(OK);
87   } else {
88     callback->Run(CANCEL);
89   }
92 PrintingContext::Result PrintingContextMac::UseDefaultSettings() {
93   DCHECK(!in_print_job_);
95   print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
96   InitPrintSettingsFromPrintInfo(GetPageRangesFromPrintInfo());
98   return OK;
101 PrintingContext::Result PrintingContextMac::UpdatePrintSettings(
102     const DictionaryValue& job_settings, const PageRanges& ranges) {
103   DCHECK(!in_print_job_);
105   // NOTE: Reset |print_info_| with a copy of |sharedPrintInfo| so as to start
106   // with a clean slate.
107   print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
109   bool collate;
110   bool color;
111   bool landscape;
112   bool print_to_pdf;
113   int copies;
114   int duplex_mode;
115   std::string device_name;
117   if (!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
118       !job_settings.GetBoolean(kSettingCollate, &collate) ||
119       !job_settings.GetBoolean(kSettingColor, &color) ||
120       !job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf) ||
121       !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
122       !job_settings.GetInteger(kSettingCopies, &copies) ||
123       !job_settings.GetString(kSettingDeviceName, &device_name)) {
124     return OnError();
125   }
127   bool print_to_cloud = job_settings.HasKey(printing::kSettingCloudPrintId);
129   if (!print_to_pdf && !print_to_cloud) {
130     if (!SetPrinter(device_name))
131       return OnError();
133     if (!SetCopiesInPrintSettings(copies))
134       return OnError();
136     if (!SetCollateInPrintSettings(collate))
137       return OnError();
139     if (!SetDuplexModeInPrintSettings(
140             static_cast<DuplexMode>(duplex_mode))) {
141       return OnError();
142     }
144     if (!SetOutputIsColor(color))
145       return OnError();
146   }
148   if (!SetOrientationIsLandscape(landscape))
149     return OnError();
151   [print_info_.get() updateFromPMPrintSettings];
153   InitPrintSettingsFromPrintInfo(ranges);
154   return OK;
157 void PrintingContextMac::InitPrintSettingsFromPrintInfo(
158     const PageRanges& ranges) {
159   PMPrintSession print_session =
160       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
161   PMPageFormat page_format =
162       static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
163   PMPrinter printer;
164   PMSessionGetCurrentPrinter(print_session, &printer);
165   PrintSettingsInitializerMac::InitPrintSettings(
166       printer, page_format, ranges, false, &settings_);
169 bool PrintingContextMac::SetPrinter(const std::string& device_name) {
170   DCHECK(print_info_.get());
171   PMPrintSession print_session =
172       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
174   PMPrinter current_printer;
175   if (PMSessionGetCurrentPrinter(print_session, &current_printer) != noErr)
176     return false;
178   CFStringRef current_printer_id = PMPrinterGetID(current_printer);
179   if (!current_printer_id)
180     return false;
182   base::mac::ScopedCFTypeRef<CFStringRef> new_printer_id(
183       base::SysUTF8ToCFStringRef(device_name));
184   if (!new_printer_id.get())
185     return false;
187   if (CFStringCompare(new_printer_id.get(), current_printer_id, 0) ==
188           kCFCompareEqualTo) {
189     return true;
190   }
192   PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
193   if (new_printer == NULL)
194     return false;
196   OSStatus status = PMSessionSetCurrentPMPrinter(print_session, new_printer);
197   PMRelease(new_printer);
198   return status == noErr;
201 bool PrintingContextMac::SetCopiesInPrintSettings(int copies) {
202   if (copies < 1)
203     return false;
205   PMPrintSettings pmPrintSettings =
206       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
207   return PMSetCopies(pmPrintSettings, copies, false) == noErr;
210 bool PrintingContextMac::SetCollateInPrintSettings(bool collate) {
211   PMPrintSettings pmPrintSettings =
212       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
213   return PMSetCollate(pmPrintSettings, collate) == noErr;
216 bool PrintingContextMac::SetOrientationIsLandscape(bool landscape) {
217   PMPageFormat page_format =
218       static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
220   PMOrientation orientation = landscape ? kPMLandscape : kPMPortrait;
222   if (PMSetOrientation(page_format, orientation, false) != noErr)
223     return false;
225   [print_info_.get() updateFromPMPageFormat];
226   return true;
229 bool PrintingContextMac::SetDuplexModeInPrintSettings(DuplexMode mode) {
230   PMDuplexMode duplexSetting;
231   switch (mode) {
232     case LONG_EDGE:
233       duplexSetting = kPMDuplexNoTumble;
234       break;
235     case SHORT_EDGE:
236       duplexSetting = kPMDuplexTumble;
237       break;
238     default:
239       duplexSetting = kPMDuplexNone;
240       break;
241   }
243   PMPrintSettings pmPrintSettings =
244       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
245   return PMSetDuplex(pmPrintSettings, duplexSetting) == noErr;
248 bool PrintingContextMac::SetOutputIsColor(bool color) {
249   PMPrintSettings pmPrintSettings =
250       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
251   CFStringRef output_color = color ? NULL : kGrayColor;
253   return PMPrintSettingsSetValue(pmPrintSettings,
254                                  kColorModel,
255                                  output_color,
256                                  false) == noErr;
259 PageRanges PrintingContextMac::GetPageRangesFromPrintInfo() {
260   PageRanges page_ranges;
261   NSDictionary* print_info_dict = [print_info_.get() dictionary];
262   if (![[print_info_dict objectForKey:NSPrintAllPages] boolValue]) {
263     PageRange range;
264     range.from = [[print_info_dict objectForKey:NSPrintFirstPage] intValue] - 1;
265     range.to = [[print_info_dict objectForKey:NSPrintLastPage] intValue] - 1;
266     page_ranges.push_back(range);
267   }
268   return page_ranges;
271 PrintingContext::Result PrintingContextMac::InitWithSettings(
272     const PrintSettings& settings) {
273   DCHECK(!in_print_job_);
275   settings_ = settings;
277   NOTIMPLEMENTED();
279   return FAILED;
282 PrintingContext::Result PrintingContextMac::NewDocument(
283     const string16& document_name) {
284   DCHECK(!in_print_job_);
286   in_print_job_ = true;
288   PMPrintSession print_session =
289       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
290   PMPrintSettings print_settings =
291       static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
292   PMPageFormat page_format =
293       static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
295   base::mac::ScopedCFTypeRef<CFStringRef> job_title(
296       base::SysUTF16ToCFStringRef(document_name));
297   PMPrintSettingsSetJobName(print_settings, job_title.get());
299   OSStatus status = PMSessionBeginCGDocumentNoDialog(print_session,
300                                                      print_settings,
301                                                      page_format);
302   if (status != noErr)
303     return OnError();
305   return OK;
308 PrintingContext::Result PrintingContextMac::NewPage() {
309   if (abort_printing_)
310     return CANCEL;
311   DCHECK(in_print_job_);
312   DCHECK(!context_);
314   PMPrintSession print_session =
315       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
316   PMPageFormat page_format =
317       static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
318   OSStatus status;
319   status = PMSessionBeginPageNoDialog(print_session, page_format, NULL);
320   if (status != noErr)
321     return OnError();
322   status = PMSessionGetCGGraphicsContext(print_session, &context_);
323   if (status != noErr)
324     return OnError();
326   return OK;
329 PrintingContext::Result PrintingContextMac::PageDone() {
330   if (abort_printing_)
331     return CANCEL;
332   DCHECK(in_print_job_);
333   DCHECK(context_);
335   PMPrintSession print_session =
336       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
337   OSStatus status = PMSessionEndPageNoDialog(print_session);
338   if (status != noErr)
339     OnError();
340   context_ = NULL;
342   return OK;
345 PrintingContext::Result PrintingContextMac::DocumentDone() {
346   if (abort_printing_)
347     return CANCEL;
348   DCHECK(in_print_job_);
350   PMPrintSession print_session =
351       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
352   OSStatus status = PMSessionEndDocumentNoDialog(print_session);
353   if (status != noErr)
354     OnError();
356   ResetSettings();
357   return OK;
360 void PrintingContextMac::Cancel() {
361   abort_printing_ = true;
362   in_print_job_ = false;
363   context_ = NULL;
365   PMPrintSession print_session =
366       static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
367   PMSessionEndPageNoDialog(print_session);
370 void PrintingContextMac::ReleaseContext() {
371   print_info_.reset();
372   context_ = NULL;
375 gfx::NativeDrawingContext PrintingContextMac::context() const {
376   return context_;
379 }  // namespace printing