42 Q_ASSERT(dev && dev->devType() == QInternal::Printer);
43 if (!
static_cast<QPrinter *>(dev)->isValid())
46 if (d->state == QPrinter::Idle && !d->isPrintSessionInitialized())
49 d->paintEngine->state = state;
50 d->paintEngine->begin(dev);
51 Q_ASSERT_X(d->state == QPrinter::Idle,
"QMacPrintEngine",
"printer already active");
53 if (PMSessionValidatePrintSettings(d->session(), d->settings(), kPMDontWantBoolean) != noErr
54 || PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean) != noErr) {
55 d->state = QPrinter::Error;
59 if (!d->outputFilename.isEmpty()) {
60 QCFType<CFURLRef> outFile = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault,
61 QCFString(d->outputFilename),
64 if (PMSessionSetDestination(d->session(), d->settings(), kPMDestinationFile,
65 kPMDocumentFormatPDF, outFile) != noErr) {
66 qWarning(
"QMacPrintEngine::begin: Problem setting file [%s]", d->outputFilename.toUtf8().constData());
71 OSStatus status = PMSessionBeginCGDocumentNoDialog(d->session(), d->settings(), d->format());
72 if (status != noErr) {
73 d->state = QPrinter::Error;
77 d->state = QPrinter::Active;
154 Q_D(
const QMacPrintEngine);
157 case QPaintDevice::PdmWidth:
158 val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).width();
160 case QPaintDevice::PdmHeight:
161 val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).height();
163 case QPaintDevice::PdmWidthMM:
164 val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).width());
166 case QPaintDevice::PdmHeightMM:
167 val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).height());
169 case QPaintDevice::PdmPhysicalDpiX:
170 case QPaintDevice::PdmPhysicalDpiY: {
172 if (PMSessionGetCurrentPrinter(d->session(), &printer) == noErr) {
173 PMResolution resolution;
174 PMPrinterGetOutputResolution(printer, d->settings(), &resolution);
175 val = (
int)resolution.vRes;
180 case QPaintDevice::PdmDpiY:
181 val = (
int)d->resolution.vRes;
183 case QPaintDevice::PdmDpiX:
184 val = (
int)d->resolution.hRes;
186 case QPaintDevice::PdmNumColors:
187 val = (1 << metric(QPaintDevice::PdmDepth));
189 case QPaintDevice::PdmDepth:
192 case QPaintDevice::PdmDevicePixelRatio:
195 case QPaintDevice::PdmDevicePixelRatioScaled:
196 val = 1 * QPaintDevice::devicePixelRatioFScale();
200 qWarning(
"QPrinter::metric: Invalid metric command");
207 Q_Q(QMacPrintEngine);
209 Q_ASSERT(!printInfo);
212 paintEngine =
new QCoreGraphicsPaintEngine();
214 q->gccaps = paintEngine->gccaps;
216 QMacAutoReleasePool pool;
217 printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]];
219 QList<
int> resolutions = m_printDevice->supportedResolutions();
220 if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) {
221 std::sort(resolutions.begin(), resolutions.end());
222 if (resolutions.count() > 1 && mode == QPrinter::HighResolution)
223 resolution.hRes = resolution.vRes = resolutions.constLast();
225 resolution.hRes = resolution.vRes = resolutions.constFirst();
226 if (resolution.hRes == 0)
227 resolution.hRes = resolution.vRes = 600;
229 resolution.hRes = resolution.vRes = qt_defaultDpi();
232 setPageSize(m_pageLayout.pageSize());
234 QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant>::const_iterator propC;
235 for (propC = valueCache.constBegin(); propC != valueCache.constEnd(); ++propC) {
236 q->setProperty(propC.key(), propC.value());
250 Q_Q(QMacPrintEngine);
251 Q_ASSERT(state == QPrinter::Active);
253 if (PMSessionError(session()) != noErr) {
262 while (cgEngine->d_func()->stackCount > 0)
263 cgEngine->d_func()->restoreGraphicsState();
265 OSStatus status = PMSessionBeginPageNoDialog(session(), format(),
nullptr);
266 if (status != noErr) {
267 state = QPrinter::Error;
271 QRect page = m_pageLayout.paintRectPixels(resolution.hRes);
272 QRect paper = m_pageLayout.fullRectPixels(resolution.hRes);
275 OSStatus err = noErr;
276 err = PMSessionGetCGGraphicsContext(session(), &cgContext);
278 qWarning(
"QMacPrintEngine::newPage: Cannot retrieve CoreGraphics context: %ld",
long(err));
279 state = QPrinter::Error;
282 cgEngine->d_func()->hd = cgContext;
285 CGContextScaleCTM(cgContext, 72 / resolution.hRes, 72 / resolution.vRes);
287 CGContextScaleCTM(cgContext, 1, -1);
288 CGContextTranslateCTM(cgContext, 0, -paper.height());
289 if (m_pageLayout.mode() != QPageLayout::FullPageMode)
290 CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y());
291 cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext);
292 cgEngine->d_func()->setClip(
nullptr);
293 cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlags(QPaintEngine::AllDirty)
294 & ~(QPaintEngine::DirtyClipEnabled
295 | QPaintEngine::DirtyClipRegion
296 | QPaintEngine::DirtyClipPath);
297 if (cgEngine->painter()->hasClipping())
298 cgEngine->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
299 cgEngine->syncState();
413 Q_D(QMacPrintEngine);
415 d->valueCache.insert(key, value);
426 case PPK_PaperSources:
428 case PPK_SupportsMultipleCopies:
430 case PPK_SupportedResolutions:
441 case PPK_PaperSource:
444 case PPK_PrinterProgram:
446 case PPK_SelectionOption:
450 case PPK_FontEmbedding:
451 d->embedFonts = value.toBool();
453 case PPK_Resolution: {
454 int bestResolution = 0;
455 int dpi = value.toInt();
456 int bestDistance = INT_MAX;
457 for (
int resolution : d->m_printDevice->supportedResolutions()) {
458 if (dpi == resolution) {
459 bestResolution = resolution;
462 int distance = qAbs(dpi - resolution);
463 if (distance < bestDistance) {
464 bestDistance = distance;
465 bestResolution = resolution;
469 PMResolution resolution;
470 resolution.hRes = resolution.vRes = bestResolution;
471 if (PMPrinterSetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &resolution) == noErr) {
474 if (PMPrinterGetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &d->resolution) != noErr) {
477 d->resolution = resolution;
482 case PPK_CollateCopies:
483 PMSetCollate(d->settings(), value.toBool());
486 d->m_creator = value.toString();
488 case PPK_DocumentName:
489 PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString()));
492 QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt());
493 if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice->supportedDuplexModes().contains(mode))
496 case QPrint::DuplexNone:
497 PMSetDuplex(d->settings(), kPMDuplexNone);
499 case QPrint::DuplexAuto:
500 PMSetDuplex(d->settings(), d->m_pageLayout.orientation() == QPageLayout::Landscape ? kPMDuplexTumble : kPMDuplexNoTumble);
502 case QPrint::DuplexLongSide:
503 PMSetDuplex(d->settings(), kPMDuplexNoTumble);
505 case QPrint::DuplexShortSide:
506 PMSetDuplex(d->settings(), kPMDuplexTumble);
516 d->m_pageLayout.setMode(QPageLayout::FullPageMode);
518 d->m_pageLayout.setMode(QPageLayout::StandardMode);
521 case PPK_NumberOfCopies:
522 PMSetCopies(d->settings(), value.toInt(),
false);
524 case PPK_Orientation: {
526 QPageLayout::Orientation newOrientation = QPageLayout::Orientation(value.toInt());
527 PMOrientation macOrientation = (newOrientation == QPageLayout::Landscape) ? kPMLandscape : kPMPortrait;
528 PMSetOrientation(d->format(), macOrientation, kPMUnlocked);
529 PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean);
530 PMGetOrientation(d->format(), &macOrientation);
531 d->m_pageLayout.setOrientation(macOrientation == kPMLandscape ? QPageLayout::Landscape : QPageLayout::Portrait);
534 case PPK_OutputFileName:
535 d->outputFilename = value.toString();
538 d->setPageSize(QPageSize(QPageSize::PageSizeId(value.toInt())));
542 d->setPageSize(d->m_printDevice->supportedPageSize(value.toString()));
544 case PPK_WindowsPageSize:
545 d->setPageSize(QPageSize(QPageSize::id(value.toInt())));
547 case PPK_PrinterName: {
548 QVariant pageSize = QVariant::fromValue(d->m_pageLayout.pageSize());
549 const bool isFullPage = d->m_pageLayout.mode() == QPageLayout::FullPageMode;
550 QVariant orientation = QVariant::fromValue(d->m_pageLayout.orientation());
551 QVariant margins = QVariant::fromValue(QPair<QMarginsF, QPageLayout::Unit>(d->m_pageLayout.margins(),
552 d->m_pageLayout.units()));
553 QString id = value.toString();
555 id = QCocoaPrinterSupport().defaultPrintDeviceId();
556 else if (!QCocoaPrinterSupport().availablePrintDeviceIds().contains(id))
558 d->m_printDevice.reset(
new QCocoaPrintDevice(id));
559 PMPrinter printer = d->m_printDevice->macPrinter();
561 PMSessionSetCurrentPMPrinter(d->session(), printer);
563 if (d->m_printDevice->supportedPageSize(pageSize.value<QPageSize>()).isValid())
564 setProperty(PPK_QPageSize, pageSize);
566 setProperty(PPK_CustomPaperSize, pageSize.value<QPageSize>().size(QPageSize::Point));
567 setProperty(PPK_FullPage, QVariant(isFullPage));
568 setProperty(PPK_Orientation, orientation);
569 setProperty(PPK_QPageMargins, margins);
572 case PPK_CustomPaperSize:
573 d->setPageSize(QPageSize(value.toSizeF(), QPageSize::Point));
575 case PPK_PageMargins:
577 QList<QVariant> margins(value.toList());
578 Q_ASSERT(margins.size() == 4);
579 d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
580 margins.at(2).toReal(), margins.at(3).toReal()),
581 QPageLayout::OutOfBoundsPolicy::Clamp);
585 d->setPageSize(value.value<QPageSize>());
587 case PPK_QPageMargins: {
588 QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
589 d->m_pageLayout.setUnits(pair.second);
590 d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
593 case PPK_QPageLayout: {
594 QPageLayout pageLayout = value.value<QPageLayout>();
595 if (pageLayout.isValid() && d->m_printDevice->isValidPageLayout(pageLayout, d->resolution.hRes)) {
596 setProperty(PPK_QPageSize, QVariant::fromValue(pageLayout.pageSize()));
597 setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
598 setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
599 d->m_pageLayout.setUnits(pageLayout.units());
600 d->m_pageLayout.setMargins(pageLayout.margins(), QPageLayout::OutOfBoundsPolicy::Clamp);
610 Q_D(
const QMacPrintEngine);
613 if (!d->printInfo && d->valueCache.contains(key))
614 return *d->valueCache.find(key);
621 ret = QPrinter::Color;
628 ret = QPrinter::FirstPageFirst;
630 case PPK_PaperSource:
632 ret = QPrinter::Auto;
634 case PPK_PaperSources: {
637 out <<
int(QPrinter::Auto);
641 case PPK_PrinterProgram:
644 case PPK_SelectionOption:
649 case PPK_FontEmbedding:
652 case PPK_CollateCopies: {
654 PMGetCollate(d->settings(), &status);
661 case PPK_DocumentName: {
663 PMPrintSettingsGetJobName(d->settings(), &name);
664 ret = QString::fromCFString(name);
668 PMDuplexMode mode = kPMDuplexNone;
669 PMGetDuplex(d->settings(), &mode);
671 case kPMDuplexNoTumble:
672 ret = QPrinter::DuplexLongSide;
674 case kPMDuplexTumble:
675 ret = QPrinter::DuplexShortSide;
679 ret = QPrinter::DuplexNone;
685 ret = d->m_pageLayout.mode() == QPageLayout::FullPageMode;
687 case PPK_NumberOfCopies:
690 case PPK_CopyCount: {
692 PMGetCopies(d->settings(), &copies);
696 case PPK_SupportsMultipleCopies:
699 case PPK_Orientation:
700 ret = d->m_pageLayout.orientation();
702 case PPK_OutputFileName:
703 ret = d->outputFilename;
707 ret = d->m_pageLayout.paintRectPixels(d->resolution.hRes);
710 ret = d->m_pageLayout.pageSize().id();
713 ret = d->m_pageLayout.pageSize().name();
715 case PPK_WindowsPageSize:
716 ret = d->m_pageLayout.pageSize().windowsId();
720 ret = d->m_pageLayout.fullRectPixels(d->resolution.hRes);
722 case PPK_PrinterName:
723 return d->m_printDevice->id();
725 case PPK_Resolution: {
726 ret = d->resolution.hRes;
729 case PPK_SupportedResolutions: {
730 QList<QVariant> list;
731 for (
int resolution : d->m_printDevice->supportedResolutions())
736 case PPK_CustomPaperSize:
737 ret = d->m_pageLayout.fullRectPoints().size();
739 case PPK_PageMargins: {
740 QList<QVariant> list;
741 QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Point);
742 list << margins.left() << margins.top() << margins.right() << margins.bottom();
747 ret.setValue(d->m_pageLayout.pageSize());
749 case PPK_QPageMargins: {
750 QPair<QMarginsF, QPageLayout::Unit> pair = qMakePair(d->m_pageLayout.margins(), d->m_pageLayout.units());
754 case PPK_QPageLayout:
755 ret.setValue(d->m_pageLayout);
QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)