printing_context_mac.mm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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.
  4. #include "printing/printing_context_mac.h"
  5. #import <AppKit/AppKit.h>
  6. #import <QuartzCore/QuartzCore.h>
  7. #include <cups/cups.h>
  8. #import <iomanip>
  9. #import <numeric>
  10. #include "base/check.h"
  11. #include "base/mac/scoped_cftyperef.h"
  12. #include "base/strings/string_piece.h"
  13. #include "base/strings/sys_string_conversions.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "base/values.h"
  16. #include "build/build_config.h"
  17. #include "printing/buildflags/buildflags.h"
  18. #include "printing/metafile.h"
  19. #include "printing/mojom/print.mojom.h"
  20. #include "printing/print_settings_initializer_mac.h"
  21. #include "printing/printing_features.h"
  22. #include "printing/units.h"
  23. namespace printing {
  24. namespace {
  25. const int kMaxPaperSizeDiffereceInPoints = 2;
  26. // Return true if PPD name of paper is equal.
  27. bool IsPaperNameEqual(CFStringRef name1, const PMPaper& paper2) {
  28. CFStringRef name2 = nullptr;
  29. return (name1 && PMPaperGetPPDPaperName(paper2, &name2) == noErr) &&
  30. (CFStringCompare(name1, name2, kCFCompareCaseInsensitive) ==
  31. kCFCompareEqualTo);
  32. }
  33. PMPaper MatchPaper(CFArrayRef paper_list,
  34. CFStringRef name,
  35. double width,
  36. double height) {
  37. double best_match = std::numeric_limits<double>::max();
  38. PMPaper best_matching_paper = nullptr;
  39. int num_papers = CFArrayGetCount(paper_list);
  40. for (int i = 0; i < num_papers; ++i) {
  41. PMPaper paper = (PMPaper)((NSArray*)paper_list)[i];
  42. double paper_width = 0.0;
  43. double paper_height = 0.0;
  44. PMPaperGetWidth(paper, &paper_width);
  45. PMPaperGetHeight(paper, &paper_height);
  46. double difference =
  47. std::max(fabs(width - paper_width), fabs(height - paper_height));
  48. // Ignore papers with size too different from expected.
  49. if (difference > kMaxPaperSizeDiffereceInPoints)
  50. continue;
  51. if (name && IsPaperNameEqual(name, paper))
  52. return paper;
  53. if (difference < best_match) {
  54. best_matching_paper = paper;
  55. best_match = difference;
  56. }
  57. }
  58. return best_matching_paper;
  59. }
  60. } // namespace
  61. // static
  62. std::unique_ptr<PrintingContext> PrintingContext::CreateImpl(
  63. Delegate* delegate,
  64. bool skip_system_calls) {
  65. auto context = std::make_unique<PrintingContextMac>(delegate);
  66. #if BUILDFLAG(ENABLE_OOP_PRINTING)
  67. if (skip_system_calls)
  68. context->set_skip_system_calls();
  69. #endif
  70. return context;
  71. }
  72. PrintingContextMac::PrintingContextMac(Delegate* delegate)
  73. : PrintingContext(delegate),
  74. print_info_([[NSPrintInfo sharedPrintInfo] copy]),
  75. context_(nullptr) {}
  76. PrintingContextMac::~PrintingContextMac() {
  77. ReleaseContext();
  78. }
  79. void PrintingContextMac::AskUserForSettings(int max_pages,
  80. bool has_selection,
  81. bool is_scripted,
  82. PrintSettingsCallback callback) {
  83. // Exceptions can also happen when the NSPrintPanel is being
  84. // deallocated, so it must be autoreleased within this scope.
  85. @autoreleasepool {
  86. DCHECK([NSThread isMainThread]);
  87. // We deliberately don't feed max_pages into the dialog, because setting
  88. // NSPrintLastPage makes the print dialog pre-select the option to only
  89. // print a range.
  90. // TODO(stuartmorgan): implement 'print selection only' (probably requires
  91. // adding a new custom view to the panel on 10.5; 10.6 has
  92. // NSPrintPanelShowsPrintSelection).
  93. NSPrintPanel* panel = [NSPrintPanel printPanel];
  94. NSPrintInfo* print_info = print_info_.get();
  95. NSPrintPanelOptions options = [panel options];
  96. options |= NSPrintPanelShowsPaperSize;
  97. options |= NSPrintPanelShowsOrientation;
  98. options |= NSPrintPanelShowsScaling;
  99. [panel setOptions:options];
  100. // Set the print job title text.
  101. gfx::NativeView parent_view = delegate_->GetParentView();
  102. if (parent_view) {
  103. NSString* job_title = [[parent_view.GetNativeNSView() window] title];
  104. if (job_title) {
  105. PMPrintSettings print_settings =
  106. (PMPrintSettings)[print_info PMPrintSettings];
  107. PMPrintSettingsSetJobName(print_settings, (CFStringRef)job_title);
  108. [print_info updateFromPMPrintSettings];
  109. }
  110. }
  111. // TODO(stuartmorgan): We really want a tab sheet here, not a modal window.
  112. // Will require restructuring the PrintingContext API to use a callback.
  113. // This function may be called in the middle of a CATransaction, where
  114. // running a modal panel is forbidden. That situation isn't ideal, but from
  115. // this code's POV the right answer is to defer running the panel until
  116. // after the current transaction. See https://crbug.com/849538.
  117. __block auto block_callback = std::move(callback);
  118. [CATransaction setCompletionBlock:^{
  119. NSInteger selection = [panel runModalWithPrintInfo:print_info];
  120. if (selection == NSModalResponseOK) {
  121. print_info_.reset([[panel printInfo] retain]);
  122. settings_->set_ranges(GetPageRangesFromPrintInfo());
  123. InitPrintSettingsFromPrintInfo();
  124. std::move(block_callback).Run(mojom::ResultCode::kSuccess);
  125. } else {
  126. std::move(block_callback).Run(mojom::ResultCode::kCanceled);
  127. }
  128. }];
  129. }
  130. }
  131. gfx::Size PrintingContextMac::GetPdfPaperSizeDeviceUnits() {
  132. // NOTE: Reset |print_info_| with a copy of |sharedPrintInfo| so as to start
  133. // with a clean slate.
  134. print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
  135. UpdatePageFormatWithPaperInfo();
  136. PMPageFormat page_format =
  137. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  138. PMRect paper_rect;
  139. PMGetAdjustedPaperRect(page_format, &paper_rect);
  140. // Device units are in points. Units per inch is 72.
  141. gfx::Size physical_size_device_units((paper_rect.right - paper_rect.left),
  142. (paper_rect.bottom - paper_rect.top));
  143. DCHECK(settings_->device_units_per_inch() == kPointsPerInch);
  144. return physical_size_device_units;
  145. }
  146. mojom::ResultCode PrintingContextMac::UseDefaultSettings() {
  147. DCHECK(!in_print_job_);
  148. print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
  149. settings_->set_ranges(GetPageRangesFromPrintInfo());
  150. InitPrintSettingsFromPrintInfo();
  151. return mojom::ResultCode::kSuccess;
  152. }
  153. mojom::ResultCode PrintingContextMac::UpdatePrinterSettings(
  154. const PrinterSettings& printer_settings) {
  155. DCHECK(!printer_settings.show_system_dialog);
  156. DCHECK(!in_print_job_);
  157. // NOTE: Reset |print_info_| with a copy of |sharedPrintInfo| so as to start
  158. // with a clean slate.
  159. print_info_.reset([[NSPrintInfo sharedPrintInfo] copy]);
  160. if (printer_settings.external_preview) {
  161. if (!SetPrintPreviewJob())
  162. return OnError();
  163. } else {
  164. // Don't need this for preview.
  165. if (!SetPrinter(base::UTF16ToUTF8(settings_->device_name())) ||
  166. !SetCopiesInPrintSettings(settings_->copies()) ||
  167. !SetCollateInPrintSettings(settings_->collate()) ||
  168. !SetDuplexModeInPrintSettings(settings_->duplex_mode()) ||
  169. !SetOutputColor(static_cast<int>(settings_->color())) ||
  170. !SetResolution(settings_->dpi_size())) {
  171. return OnError();
  172. }
  173. }
  174. if (!UpdatePageFormatWithPaperInfo() ||
  175. !SetOrientationIsLandscape(settings_->landscape())) {
  176. return OnError();
  177. }
  178. [print_info_.get() updateFromPMPrintSettings];
  179. InitPrintSettingsFromPrintInfo();
  180. return mojom::ResultCode::kSuccess;
  181. }
  182. bool PrintingContextMac::SetPrintPreviewJob() {
  183. PMPrintSession print_session =
  184. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  185. PMPrintSettings print_settings =
  186. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  187. return PMSessionSetDestination(print_session, print_settings,
  188. kPMDestinationPreview, nullptr,
  189. nullptr) == noErr;
  190. }
  191. void PrintingContextMac::InitPrintSettingsFromPrintInfo() {
  192. PMPrintSession print_session =
  193. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  194. PMPageFormat page_format =
  195. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  196. PMPrinter printer;
  197. PMSessionGetCurrentPrinter(print_session, &printer);
  198. PrintSettingsInitializerMac::InitPrintSettings(printer, page_format,
  199. settings_.get());
  200. }
  201. bool PrintingContextMac::SetPrinter(const std::string& device_name) {
  202. DCHECK(print_info_.get());
  203. PMPrintSession print_session =
  204. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  205. PMPrinter current_printer;
  206. if (PMSessionGetCurrentPrinter(print_session, &current_printer) != noErr)
  207. return false;
  208. CFStringRef current_printer_id = PMPrinterGetID(current_printer);
  209. if (!current_printer_id)
  210. return false;
  211. base::ScopedCFTypeRef<CFStringRef> new_printer_id(
  212. base::SysUTF8ToCFStringRef(device_name));
  213. if (!new_printer_id.get())
  214. return false;
  215. if (CFStringCompare(new_printer_id.get(), current_printer_id, 0) ==
  216. kCFCompareEqualTo) {
  217. return true;
  218. }
  219. PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
  220. if (!new_printer)
  221. return false;
  222. OSStatus status = PMSessionSetCurrentPMPrinter(print_session, new_printer);
  223. PMRelease(new_printer);
  224. return status == noErr;
  225. }
  226. bool PrintingContextMac::UpdatePageFormatWithPaperInfo() {
  227. PMPrintSession print_session =
  228. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  229. PMPageFormat default_page_format =
  230. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  231. PMPrinter current_printer = nullptr;
  232. if (PMSessionGetCurrentPrinter(print_session, &current_printer) != noErr)
  233. return false;
  234. double page_width = 0.0;
  235. double page_height = 0.0;
  236. base::ScopedCFTypeRef<CFStringRef> paper_name;
  237. PMPaperMargins margins = {0};
  238. const PrintSettings::RequestedMedia& media = settings_->requested_media();
  239. if (media.IsDefault()) {
  240. PMPaper default_paper;
  241. if (PMGetPageFormatPaper(default_page_format, &default_paper) != noErr ||
  242. PMPaperGetWidth(default_paper, &page_width) != noErr ||
  243. PMPaperGetHeight(default_paper, &page_height) != noErr) {
  244. return false;
  245. }
  246. // Ignore result, because we can continue without following.
  247. CFStringRef tmp_paper_name = nullptr;
  248. PMPaperGetPPDPaperName(default_paper, &tmp_paper_name);
  249. PMPaperGetMargins(default_paper, &margins);
  250. paper_name.reset(tmp_paper_name, base::scoped_policy::RETAIN);
  251. } else {
  252. const double kMutiplier =
  253. kPointsPerInch / static_cast<float>(kMicronsPerInch);
  254. page_width = media.size_microns.width() * kMutiplier;
  255. page_height = media.size_microns.height() * kMutiplier;
  256. paper_name.reset(base::SysUTF8ToCFStringRef(media.vendor_id));
  257. }
  258. CFArrayRef paper_list = nullptr;
  259. if (PMPrinterGetPaperList(current_printer, &paper_list) != noErr)
  260. return false;
  261. PMPaper best_matching_paper =
  262. MatchPaper(paper_list, paper_name, page_width, page_height);
  263. if (best_matching_paper)
  264. return UpdatePageFormatWithPaper(best_matching_paper, default_page_format);
  265. // Do nothing if unmatched paper was default system paper.
  266. if (media.IsDefault())
  267. return true;
  268. PMPaper paper = nullptr;
  269. if (PMPaperCreateCustom(current_printer, CFSTR("Custom paper ID"),
  270. CFSTR("Custom paper"), page_width, page_height,
  271. &margins, &paper) != noErr) {
  272. return false;
  273. }
  274. bool result = UpdatePageFormatWithPaper(paper, default_page_format);
  275. PMRelease(paper);
  276. return result;
  277. }
  278. bool PrintingContextMac::UpdatePageFormatWithPaper(PMPaper paper,
  279. PMPageFormat page_format) {
  280. PMPageFormat new_format = nullptr;
  281. if (PMCreatePageFormatWithPMPaper(&new_format, paper) != noErr)
  282. return false;
  283. // Copy over the original format with the new page format.
  284. bool result = (PMCopyPageFormat(new_format, page_format) == noErr);
  285. [print_info_.get() updateFromPMPageFormat];
  286. PMRelease(new_format);
  287. return result;
  288. }
  289. bool PrintingContextMac::SetCopiesInPrintSettings(int copies) {
  290. if (copies < 1)
  291. return false;
  292. PMPrintSettings print_settings =
  293. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  294. return PMSetCopies(print_settings, copies, false) == noErr;
  295. }
  296. bool PrintingContextMac::SetCollateInPrintSettings(bool collate) {
  297. PMPrintSettings print_settings =
  298. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  299. return PMSetCollate(print_settings, collate) == noErr;
  300. }
  301. bool PrintingContextMac::SetOrientationIsLandscape(bool landscape) {
  302. PMPageFormat page_format =
  303. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  304. PMOrientation orientation = landscape ? kPMLandscape : kPMPortrait;
  305. if (PMSetOrientation(page_format, orientation, false) != noErr)
  306. return false;
  307. PMPrintSession print_session =
  308. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  309. PMSessionValidatePageFormat(print_session, page_format, kPMDontWantBoolean);
  310. [print_info_.get() updateFromPMPageFormat];
  311. return true;
  312. }
  313. bool PrintingContextMac::SetDuplexModeInPrintSettings(mojom::DuplexMode mode) {
  314. PMDuplexMode duplexSetting;
  315. switch (mode) {
  316. case mojom::DuplexMode::kLongEdge:
  317. duplexSetting = kPMDuplexNoTumble;
  318. break;
  319. case mojom::DuplexMode::kShortEdge:
  320. duplexSetting = kPMDuplexTumble;
  321. break;
  322. case mojom::DuplexMode::kSimplex:
  323. duplexSetting = kPMDuplexNone;
  324. break;
  325. default: // kUnknownDuplexMode
  326. return true;
  327. }
  328. PMPrintSettings print_settings =
  329. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  330. return PMSetDuplex(print_settings, duplexSetting) == noErr;
  331. }
  332. bool PrintingContextMac::SetOutputColor(int color_mode) {
  333. const mojom::ColorModel color_model = ColorModeToColorModel(color_mode);
  334. if (!base::FeatureList::IsEnabled(features::kCupsIppPrintingBackend)) {
  335. std::string color_setting_name;
  336. std::string color_value;
  337. GetColorModelForModel(color_model, &color_setting_name, &color_value);
  338. return SetKeyValue(color_setting_name, color_value);
  339. }
  340. // First, set the default CUPS IPP output color.
  341. if (!SetKeyValue(CUPS_PRINT_COLOR_MODE,
  342. GetIppColorModelForModel(color_model))) {
  343. return false;
  344. }
  345. struct PpdColorSetting {
  346. constexpr PpdColorSetting(base::StringPiece name,
  347. base::StringPiece bw,
  348. base::StringPiece color)
  349. : name(name), bw(bw), color(color) {}
  350. base::StringPiece name;
  351. base::StringPiece bw;
  352. base::StringPiece color;
  353. };
  354. // TODO(crbug.com/1210992): Move `kKnownPpdColorSettings` elsewhere so it can
  355. // be used for general CUPS printing code (e.g., for parsing PPDs).
  356. static constexpr PpdColorSetting kKnownPpdColorSettings[] = {
  357. {"ARCMode", "CMBW", "CMColor"}, // Sharp
  358. {"BLW", "TrueM", "FalseM"}, // Lexmark
  359. {"BRMonoColor", "Mono", "FullColor"}, // Brother
  360. {"BRPrintQuality", "Black", "Color"}, // Brother
  361. {"CNIJGrayScale", "1", "0"}, // Canon
  362. {"ColorMode", "Monochrome", "Color"}, // Samsung
  363. {"ColorModel", "Gray", "Color"}, // Generic
  364. {"HPColorMode", "GrayscalePrint", "ColorPrint"}, // HP
  365. {"Ink", "MONO", "COLOR"}, // Epson
  366. {"OKControl", "Gray", "Auto"}, // Oki
  367. {"PrintoutMode", "Normal.Gray", "Normal"}, // Foomatic
  368. {"SelectColor", "Grayscale", "Color"}, // Konica Minolta
  369. {"XRXColor", "BW", "Automatic"}, // Xerox
  370. {"XROutputColor", "PrintAsGrayscale", "PrintAsColor"}, // Xerox
  371. };
  372. // Even when interfacing with printer settings using CUPS IPP, the print job
  373. // may still expect PPD color values if the printer was added to the system
  374. // with a PPD. To avoid parsing PPDs (which is the point of using CUPS IPP),
  375. // set every single known PPD color setting and hope that one of them sticks.
  376. const bool is_color = IsColorModelSelected(color_model).value_or(false);
  377. for (const auto& setting : kKnownPpdColorSettings) {
  378. const base::StringPiece& color_setting_name = setting.name;
  379. const base::StringPiece& color_value =
  380. is_color ? setting.color : setting.bw;
  381. if (!SetKeyValue(color_setting_name, color_value))
  382. return false;
  383. }
  384. return true;
  385. }
  386. bool PrintingContextMac::SetResolution(const gfx::Size& dpi_size) {
  387. if (dpi_size.IsEmpty())
  388. return true;
  389. PMPrintSession print_session =
  390. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  391. PMPrinter current_printer;
  392. if (PMSessionGetCurrentPrinter(print_session, &current_printer) != noErr)
  393. return false;
  394. PMResolution resolution;
  395. resolution.hRes = dpi_size.width();
  396. resolution.vRes = dpi_size.height();
  397. PMPrintSettings print_settings =
  398. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  399. return PMPrinterSetOutputResolution(current_printer, print_settings,
  400. &resolution) == noErr;
  401. }
  402. bool PrintingContextMac::SetKeyValue(base::StringPiece key,
  403. base::StringPiece value) {
  404. PMPrintSettings print_settings =
  405. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  406. base::ScopedCFTypeRef<CFStringRef> cf_key(base::SysUTF8ToCFStringRef(key));
  407. base::ScopedCFTypeRef<CFStringRef> cf_value(
  408. base::SysUTF8ToCFStringRef(value));
  409. return PMPrintSettingsSetValue(print_settings, cf_key.get(), cf_value.get(),
  410. /*locked=*/false) == noErr;
  411. }
  412. PageRanges PrintingContextMac::GetPageRangesFromPrintInfo() {
  413. PageRanges page_ranges;
  414. NSDictionary* print_info_dict = [print_info_.get() dictionary];
  415. if (![print_info_dict[NSPrintAllPages] boolValue]) {
  416. PageRange range;
  417. range.from = [print_info_dict[NSPrintFirstPage] intValue] - 1;
  418. range.to = [print_info_dict[NSPrintLastPage] intValue] - 1;
  419. page_ranges.push_back(range);
  420. }
  421. return page_ranges;
  422. }
  423. mojom::ResultCode PrintingContextMac::NewDocument(
  424. const std::u16string& document_name) {
  425. DCHECK(!in_print_job_);
  426. in_print_job_ = true;
  427. if (skip_system_calls())
  428. return mojom::ResultCode::kSuccess;
  429. PMPrintSession print_session =
  430. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  431. PMPrintSettings print_settings =
  432. static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
  433. PMPageFormat page_format =
  434. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  435. base::ScopedCFTypeRef<CFStringRef> job_title(
  436. base::SysUTF16ToCFStringRef(document_name));
  437. PMPrintSettingsSetJobName(print_settings, job_title.get());
  438. OSStatus status = PMSessionBeginCGDocumentNoDialog(
  439. print_session, print_settings, page_format);
  440. if (status != noErr)
  441. return OnError();
  442. return mojom::ResultCode::kSuccess;
  443. }
  444. mojom::ResultCode PrintingContextMac::NewPage() {
  445. if (abort_printing_)
  446. return mojom::ResultCode::kCanceled;
  447. DCHECK(in_print_job_);
  448. DCHECK(!context_);
  449. PMPrintSession print_session =
  450. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  451. PMPageFormat page_format =
  452. static_cast<PMPageFormat>([print_info_.get() PMPageFormat]);
  453. OSStatus status;
  454. status = PMSessionBeginPageNoDialog(print_session, page_format, nullptr);
  455. if (status != noErr)
  456. return OnError();
  457. status = PMSessionGetCGGraphicsContext(print_session, &context_);
  458. if (status != noErr)
  459. return OnError();
  460. return mojom::ResultCode::kSuccess;
  461. }
  462. mojom::ResultCode PrintingContextMac::PageDone() {
  463. if (abort_printing_)
  464. return mojom::ResultCode::kCanceled;
  465. DCHECK(in_print_job_);
  466. DCHECK(context_);
  467. PMPrintSession print_session =
  468. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  469. OSStatus status = PMSessionEndPageNoDialog(print_session);
  470. if (status != noErr)
  471. OnError();
  472. context_ = nullptr;
  473. return mojom::ResultCode::kSuccess;
  474. }
  475. mojom::ResultCode PrintingContextMac::PrintDocument(
  476. const MetafilePlayer& metafile,
  477. const PrintSettings& settings,
  478. uint32_t num_pages) {
  479. const PageSetup& page_setup = settings.page_setup_device_units();
  480. const CGRect paper_rect = gfx::Rect(page_setup.physical_size()).ToCGRect();
  481. for (size_t metafile_page_number = 1; metafile_page_number <= num_pages;
  482. metafile_page_number++) {
  483. mojom::ResultCode result = NewPage();
  484. if (result != mojom::ResultCode::kSuccess)
  485. return result;
  486. if (!metafile.RenderPage(metafile_page_number, context_, paper_rect,
  487. /*autorotate=*/true, /*fit_to_page=*/false)) {
  488. return mojom::ResultCode::kFailed;
  489. }
  490. result = PageDone();
  491. if (result != mojom::ResultCode::kSuccess)
  492. return result;
  493. }
  494. return mojom::ResultCode::kSuccess;
  495. }
  496. mojom::ResultCode PrintingContextMac::DocumentDone() {
  497. if (abort_printing_)
  498. return mojom::ResultCode::kCanceled;
  499. DCHECK(in_print_job_);
  500. PMPrintSession print_session =
  501. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  502. OSStatus status = PMSessionEndDocumentNoDialog(print_session);
  503. if (status != noErr)
  504. OnError();
  505. ResetSettings();
  506. return mojom::ResultCode::kSuccess;
  507. }
  508. void PrintingContextMac::Cancel() {
  509. abort_printing_ = true;
  510. in_print_job_ = false;
  511. context_ = nullptr;
  512. PMPrintSession print_session =
  513. static_cast<PMPrintSession>([print_info_.get() PMPrintSession]);
  514. PMSessionEndPageNoDialog(print_session);
  515. }
  516. void PrintingContextMac::ReleaseContext() {
  517. print_info_.reset();
  518. context_ = nullptr;
  519. }
  520. printing::NativeDrawingContext PrintingContextMac::context() const {
  521. return context_;
  522. }
  523. } // namespace printing