1/**************************************************************************** 2** 3** Copyright (C) 2016 The Qt Company Ltd. 4** Contact: https://www.qt.io/licensing/ 5** 6** This file is part of the plugins of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see https://www.qt.io/terms-conditions. For further 15** information use the contact form at https://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 3 as published by the Free Software 20** Foundation and appearing in the file LICENSE.LGPL3 included in the 21** packaging of this file. Please review the following information to 22** ensure the GNU Lesser General Public License version 3 requirements 23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24** 25** GNU General Public License Usage 26** Alternatively, this file may be used under the terms of the GNU 27** General Public License version 2.0 or (at your option) the GNU General 28** Public license version 3 or any later version approved by the KDE Free 29** Qt Foundation. The licenses are as published by the Free Software 30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31** included in the packaging of this file. Please review the following 32** information to ensure the GNU General Public License requirements will 33** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34** https://www.gnu.org/licenses/gpl-3.0.html. 35** 36** $QT_END_LICENSE$ 37** 38****************************************************************************/ 39 40#include <AppKit/AppKit.h> 41#include <ApplicationServices/ApplicationServices.h> 42 43#include "qprintengine_mac_p.h" 44#include "qcocoaprintersupport.h" 45#include <quuid.h> 46#include <QtGui/qpagelayout.h> 47#include <QtCore/qcoreapplication.h> 48#include <QtCore/qdebug.h> 49 50#include <QtCore/private/qcore_mac_p.h> 51 52#ifndef QT_NO_PRINTER 53 54QT_BEGIN_NAMESPACE 55 56extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits); 57 58QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode, const QString &deviceId) 59 : QPaintEngine(*(new QMacPrintEnginePrivate)) 60{ 61 Q_D(QMacPrintEngine); 62 d->mode = mode; 63 QString id = deviceId; 64 if (id.isEmpty()) 65 id = QCocoaPrinterSupport().defaultPrintDeviceId(); 66 else 67 setProperty(QPrintEngine::PPK_PrinterName, deviceId); 68 d->m_printDevice.reset(new QCocoaPrintDevice(id)); 69 d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize()); 70 d->initialize(); 71} 72 73bool QMacPrintEngine::begin(QPaintDevice *dev) 74{ 75 Q_D(QMacPrintEngine); 76 77 Q_ASSERT(dev && dev->devType() == QInternal::Printer); 78 if (!static_cast<QPrinter *>(dev)->isValid()) 79 return false; 80 81 if (d->state == QPrinter::Idle && !d->isPrintSessionInitialized()) // Need to reinitialize 82 d->initialize(); 83 84 d->paintEngine->state = state; 85 d->paintEngine->begin(dev); 86 Q_ASSERT_X(d->state == QPrinter::Idle, "QMacPrintEngine", "printer already active"); 87 88 if (PMSessionValidatePrintSettings(d->session(), d->settings(), kPMDontWantBoolean) != noErr 89 || PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean) != noErr) { 90 d->state = QPrinter::Error; 91 return false; 92 } 93 94 if (!d->outputFilename.isEmpty()) { 95 QCFType<CFURLRef> outFile = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, 96 QCFString(d->outputFilename), 97 kCFURLPOSIXPathStyle, 98 false); 99 if (PMSessionSetDestination(d->session(), d->settings(), kPMDestinationFile, 100 kPMDocumentFormatPDF, outFile) != noErr) { 101 qWarning("QMacPrintEngine::begin: Problem setting file [%s]", d->outputFilename.toUtf8().constData()); 102 return false; 103 } 104 } 105 106 OSStatus status = PMSessionBeginCGDocumentNoDialog(d->session(), d->settings(), d->format()); 107 if (status != noErr) { 108 d->state = QPrinter::Error; 109 return false; 110 } 111 112 d->state = QPrinter::Active; 113 setActive(true); 114 d->newPage_helper(); 115 return true; 116} 117 118bool QMacPrintEngine::end() 119{ 120 Q_D(QMacPrintEngine); 121 if (d->state == QPrinter::Aborted) 122 return true; // I was just here a function call ago :) 123 if (d->paintEngine->type() == QPaintEngine::CoreGraphics) { 124 // We don't need the paint engine to call restoreGraphicsState() 125 static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->stackCount = 0; 126 static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = nullptr; 127 } 128 d->paintEngine->end(); 129 if (d->state != QPrinter::Idle) 130 d->releaseSession(); 131 d->state = QPrinter::Idle; 132 return true; 133} 134 135QPaintEngine * 136QMacPrintEngine::paintEngine() const 137{ 138 return d_func()->paintEngine; 139} 140 141Qt::HANDLE QMacPrintEngine::handle() const 142{ 143 QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine()); 144 return cgEngine->d_func()->hd; 145} 146 147QMacPrintEnginePrivate::~QMacPrintEnginePrivate() 148{ 149 [printInfo release]; 150 delete paintEngine; 151} 152 153QPrinter::PrinterState QMacPrintEngine::printerState() const 154{ 155 return d_func()->state; 156} 157 158bool QMacPrintEngine::newPage() 159{ 160 Q_D(QMacPrintEngine); 161 Q_ASSERT(d->state == QPrinter::Active); 162 OSStatus err = PMSessionEndPageNoDialog(d->session()); 163 if (err != noErr) { 164 if (err == kPMCancel) { 165 // User canceled, we need to abort! 166 abort(); 167 } else { 168 // Not sure what the problem is... 169 qWarning("QMacPrintEngine::newPage: Cannot end current page. %ld", long(err)); 170 d->state = QPrinter::Error; 171 } 172 return false; 173 } 174 return d->newPage_helper(); 175} 176 177bool QMacPrintEngine::abort() 178{ 179 Q_D(QMacPrintEngine); 180 if (d->state != QPrinter::Active) 181 return false; 182 bool ret = end(); 183 d->state = QPrinter::Aborted; 184 return ret; 185} 186 187int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const 188{ 189 Q_D(const QMacPrintEngine); 190 int val = 1; 191 switch (m) { 192 case QPaintDevice::PdmWidth: 193 val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).width(); 194 break; 195 case QPaintDevice::PdmHeight: 196 val = d->m_pageLayout.paintRectPixels(d->resolution.hRes).height(); 197 break; 198 case QPaintDevice::PdmWidthMM: 199 val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).width()); 200 break; 201 case QPaintDevice::PdmHeightMM: 202 val = qRound(d->m_pageLayout.paintRect(QPageLayout::Millimeter).height()); 203 break; 204 case QPaintDevice::PdmPhysicalDpiX: 205 case QPaintDevice::PdmPhysicalDpiY: { 206 PMPrinter printer; 207 if (PMSessionGetCurrentPrinter(d->session(), &printer) == noErr) { 208 PMResolution resolution; 209 PMPrinterGetOutputResolution(printer, d->settings(), &resolution); 210 val = (int)resolution.vRes; 211 break; 212 } 213 Q_FALLTHROUGH(); 214 } 215 case QPaintDevice::PdmDpiY: 216 val = (int)d->resolution.vRes; 217 break; 218 case QPaintDevice::PdmDpiX: 219 val = (int)d->resolution.hRes; 220 break; 221 case QPaintDevice::PdmNumColors: 222 val = (1 << metric(QPaintDevice::PdmDepth)); 223 break; 224 case QPaintDevice::PdmDepth: 225 val = 24; 226 break; 227 case QPaintDevice::PdmDevicePixelRatio: 228 val = 1; 229 break; 230 case QPaintDevice::PdmDevicePixelRatioScaled: 231 val = 1 * QPaintDevice::devicePixelRatioFScale(); 232 break; 233 default: 234 val = 0; 235 qWarning("QPrinter::metric: Invalid metric command"); 236 } 237 return val; 238} 239 240void QMacPrintEnginePrivate::initialize() 241{ 242 Q_Q(QMacPrintEngine); 243 244 Q_ASSERT(!printInfo); 245 246 if (!paintEngine) 247 paintEngine = new QCoreGraphicsPaintEngine(); 248 249 q->gccaps = paintEngine->gccaps; 250 251 QMacAutoReleasePool pool; 252 printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]]; 253 254 QList<int> resolutions = m_printDevice->supportedResolutions(); 255 if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) { 256 std::sort(resolutions.begin(), resolutions.end()); 257 if (resolutions.count() > 1 && mode == QPrinter::HighResolution) 258 resolution.hRes = resolution.vRes = resolutions.last(); 259 else 260 resolution.hRes = resolution.vRes = resolutions.first(); 261 if (resolution.hRes == 0) 262 resolution.hRes = resolution.vRes = 600; 263 } else { 264 resolution.hRes = resolution.vRes = qt_defaultDpi(); 265 } 266 267 setPageSize(m_pageLayout.pageSize()); 268 269 QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant>::const_iterator propC; 270 for (propC = valueCache.constBegin(); propC != valueCache.constEnd(); ++propC) { 271 q->setProperty(propC.key(), propC.value()); 272 } 273} 274 275void QMacPrintEnginePrivate::releaseSession() 276{ 277 PMSessionEndPageNoDialog(session()); 278 PMSessionEndDocumentNoDialog(session()); 279 [printInfo release]; 280 printInfo = nil; 281} 282 283bool QMacPrintEnginePrivate::newPage_helper() 284{ 285 Q_Q(QMacPrintEngine); 286 Q_ASSERT(state == QPrinter::Active); 287 288 if (PMSessionError(session()) != noErr) { 289 q->abort(); 290 return false; 291 } 292 293 // pop the stack of saved graphic states, in case we get the same 294 // context back - either way, the stack count should be 0 when we 295 // get the new one 296 QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine); 297 while (cgEngine->d_func()->stackCount > 0) 298 cgEngine->d_func()->restoreGraphicsState(); 299 300 OSStatus status = PMSessionBeginPageNoDialog(session(), format(), nullptr); 301 if (status != noErr) { 302 state = QPrinter::Error; 303 return false; 304 } 305 306 QRect page = m_pageLayout.paintRectPixels(resolution.hRes); 307 QRect paper = m_pageLayout.fullRectPixels(resolution.hRes); 308 309 CGContextRef cgContext; 310 OSStatus err = noErr; 311 err = PMSessionGetCGGraphicsContext(session(), &cgContext); 312 if (err != noErr) { 313 qWarning("QMacPrintEngine::newPage: Cannot retrieve CoreGraphics context: %ld", long(err)); 314 state = QPrinter::Error; 315 return false; 316 } 317 cgEngine->d_func()->hd = cgContext; 318 319 // Set the resolution as a scaling ration of 72 (the default). 320 CGContextScaleCTM(cgContext, 72 / resolution.hRes, 72 / resolution.vRes); 321 322 CGContextScaleCTM(cgContext, 1, -1); 323 CGContextTranslateCTM(cgContext, 0, -paper.height()); 324 if (m_pageLayout.mode() != QPageLayout::FullPageMode) 325 CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y()); 326 cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext); 327 cgEngine->d_func()->setClip(nullptr); 328 cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty 329 & ~(QPaintEngine::DirtyClipEnabled 330 | QPaintEngine::DirtyClipRegion 331 | QPaintEngine::DirtyClipPath)); 332 if (cgEngine->painter()->hasClipping()) 333 cgEngine->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled; 334 cgEngine->syncState(); 335 return true; 336} 337 338void QMacPrintEnginePrivate::setPageSize(const QPageSize &pageSize) 339{ 340 if (!pageSize.isValid()) 341 return; 342 343 // Get the matching printer paper 344 QPageSize printerPageSize = m_printDevice->supportedPageSize(pageSize); 345 QPageSize usePageSize = printerPageSize.isValid() ? printerPageSize : pageSize; 346 347 // Get the PMPaper and check it is valid 348 PMPaper macPaper = m_printDevice->macPaper(usePageSize); 349 if (!macPaper) { 350 qWarning() << "QMacPrintEngine: Invalid PMPaper returned for " << pageSize; 351 return; 352 } 353 354 QMarginsF printable = m_printDevice->printableMargins(usePageSize, m_pageLayout.orientation(), resolution.hRes); 355 m_pageLayout.setPageSize(usePageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units())); 356 357 // You cannot set the page size on a PMPageFormat, you must create a new PMPageFormat 358 PMPageFormat pageFormat; 359 PMCreatePageFormatWithPMPaper(&pageFormat, macPaper); 360 PMSetOrientation(pageFormat, m_pageLayout.orientation() == QPageLayout::Landscape ? kPMLandscape : kPMPortrait, kPMUnlocked); 361 PMCopyPageFormat(pageFormat, format()); 362 if (PMSessionValidatePageFormat(session(), format(), kPMDontWantBoolean) != noErr) 363 qWarning("QMacPrintEngine: Invalid page format"); 364 PMRelease(pageFormat); 365} 366 367void QMacPrintEngine::updateState(const QPaintEngineState &state) 368{ 369 d_func()->paintEngine->updateState(state); 370} 371 372void QMacPrintEngine::drawRects(const QRectF *r, int num) 373{ 374 Q_D(QMacPrintEngine); 375 Q_ASSERT(d->state == QPrinter::Active); 376 d->paintEngine->drawRects(r, num); 377} 378 379void QMacPrintEngine::drawPoints(const QPointF *points, int pointCount) 380{ 381 Q_D(QMacPrintEngine); 382 Q_ASSERT(d->state == QPrinter::Active); 383 d->paintEngine->drawPoints(points, pointCount); 384} 385 386void QMacPrintEngine::drawEllipse(const QRectF &r) 387{ 388 Q_D(QMacPrintEngine); 389 Q_ASSERT(d->state == QPrinter::Active); 390 d->paintEngine->drawEllipse(r); 391} 392 393void QMacPrintEngine::drawLines(const QLineF *lines, int lineCount) 394{ 395 Q_D(QMacPrintEngine); 396 Q_ASSERT(d->state == QPrinter::Active); 397 d->paintEngine->drawLines(lines, lineCount); 398} 399 400void QMacPrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) 401{ 402 Q_D(QMacPrintEngine); 403 Q_ASSERT(d->state == QPrinter::Active); 404 d->paintEngine->drawPolygon(points, pointCount, mode); 405} 406 407void QMacPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) 408{ 409 Q_D(QMacPrintEngine); 410 Q_ASSERT(d->state == QPrinter::Active); 411 d->paintEngine->drawPixmap(r, pm, sr); 412} 413 414void QMacPrintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags) 415{ 416 Q_D(QMacPrintEngine); 417 Q_ASSERT(d->state == QPrinter::Active); 418 d->paintEngine->drawImage(r, pm, sr, flags); 419} 420 421void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti) 422{ 423 Q_D(QMacPrintEngine); 424 Q_ASSERT(d->state == QPrinter::Active); 425 if (!d->embedFonts) 426 QPaintEngine::drawTextItem(p, ti); 427 else 428 d->paintEngine->drawTextItem(p, ti); 429} 430 431void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr) 432{ 433 Q_D(QMacPrintEngine); 434 Q_ASSERT(d->state == QPrinter::Active); 435 d->paintEngine->drawTiledPixmap(dr, pixmap, sr); 436} 437 438void QMacPrintEngine::drawPath(const QPainterPath &path) 439{ 440 Q_D(QMacPrintEngine); 441 Q_ASSERT(d->state == QPrinter::Active); 442 d->paintEngine->drawPath(path); 443} 444 445 446void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value) 447{ 448 Q_D(QMacPrintEngine); 449 450 d->valueCache.insert(key, value); 451 if (!d->printInfo) 452 return; 453 454 switch (key) { 455 456 // The following keys are properties or derived values and so cannot be set 457 case PPK_PageRect: 458 break; 459 case PPK_PaperRect: 460 break; 461 case PPK_PaperSources: 462 break; 463 case PPK_SupportsMultipleCopies: 464 break; 465 case PPK_SupportedResolutions: 466 break; 467 468 // The following keys are settings that are unsupported by the Mac PrintEngine 469 case PPK_ColorMode: 470 break; 471 case PPK_CustomBase: 472 break; 473 case PPK_PageOrder: 474 // TODO Check if can be supported via Cups Options 475 break; 476 case PPK_PaperSource: 477 // TODO Check if can be supported via Cups Options 478 break; 479 case PPK_PrinterProgram: 480 break; 481 case PPK_SelectionOption: 482 break; 483 484 // The following keys are properties and settings that are supported by the Mac PrintEngine 485 case PPK_FontEmbedding: 486 d->embedFonts = value.toBool(); 487 break; 488 case PPK_Resolution: { 489 int bestResolution = 0; 490 int dpi = value.toInt(); 491 int bestDistance = INT_MAX; 492 for (int resolution : d->m_printDevice->supportedResolutions()) { 493 if (dpi == resolution) { 494 bestResolution = resolution; 495 break; 496 } else { 497 int distance = qAbs(dpi - resolution); 498 if (distance < bestDistance) { 499 bestDistance = distance; 500 bestResolution = resolution; 501 } 502 } 503 } 504 PMResolution resolution; 505 resolution.hRes = resolution.vRes = bestResolution; 506 if (PMPrinterSetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &resolution) == noErr) { 507 // Setting the resolution succeeded. 508 // Now try to read the actual resolution selected by the OS. 509 if (PMPrinterGetOutputResolution(d->m_printDevice->macPrinter(), d->settings(), &d->resolution) != noErr) { 510 // Reading the resolution somehow failed; d->resolution is in undefined state. 511 // So use the value which was acceptable to PMPrinterSetOutputResolution. 512 d->resolution = resolution; 513 } 514 } 515 break; 516 } 517 case PPK_CollateCopies: 518 PMSetCollate(d->settings(), value.toBool()); 519 break; 520 case PPK_Creator: 521 d->m_creator = value.toString(); 522 break; 523 case PPK_DocumentName: 524 PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString())); 525 break; 526 case PPK_Duplex: { 527 QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt()); 528 if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice->supportedDuplexModes().contains(mode)) 529 break; 530 switch (mode) { 531 case QPrint::DuplexNone: 532 PMSetDuplex(d->settings(), kPMDuplexNone); 533 break; 534 case QPrint::DuplexAuto: 535 PMSetDuplex(d->settings(), d->m_pageLayout.orientation() == QPageLayout::Landscape ? kPMDuplexTumble : kPMDuplexNoTumble); 536 break; 537 case QPrint::DuplexLongSide: 538 PMSetDuplex(d->settings(), kPMDuplexNoTumble); 539 break; 540 case QPrint::DuplexShortSide: 541 PMSetDuplex(d->settings(), kPMDuplexTumble); 542 break; 543 default: 544 // Don't change 545 break; 546 } 547 break; 548 } 549 case PPK_FullPage: 550 if (value.toBool()) 551 d->m_pageLayout.setMode(QPageLayout::FullPageMode); 552 else 553 d->m_pageLayout.setMode(QPageLayout::StandardMode); 554 break; 555 case PPK_CopyCount: // fallthrough 556 case PPK_NumberOfCopies: 557 PMSetCopies(d->settings(), value.toInt(), false); 558 break; 559 case PPK_Orientation: { 560 // First try set the Mac format orientation, then set our orientation to match result 561 QPageLayout::Orientation newOrientation = QPageLayout::Orientation(value.toInt()); 562 PMOrientation macOrientation = (newOrientation == QPageLayout::Landscape) ? kPMLandscape : kPMPortrait; 563 PMSetOrientation(d->format(), macOrientation, kPMUnlocked); 564 PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean); 565 PMGetOrientation(d->format(), &macOrientation); 566 d->m_pageLayout.setOrientation(macOrientation == kPMLandscape ? QPageLayout::Landscape : QPageLayout::Portrait); 567 break; 568 } 569 case PPK_OutputFileName: 570 d->outputFilename = value.toString(); 571 break; 572 case PPK_PageSize: 573 d->setPageSize(QPageSize(QPageSize::PageSizeId(value.toInt()))); 574 break; 575 case PPK_PaperName: 576 // Get the named page size from the printer if supported 577 d->setPageSize(d->m_printDevice->supportedPageSize(value.toString())); 578 break; 579 case PPK_WindowsPageSize: 580 d->setPageSize(QPageSize(QPageSize::id(value.toInt()))); 581 break; 582 case PPK_PrinterName: { 583 QVariant pageSize = QVariant::fromValue(d->m_pageLayout.pageSize()); 584 const bool isFullPage = d->m_pageLayout.mode() == QPageLayout::FullPageMode; 585 QVariant orientation = QVariant::fromValue(d->m_pageLayout.orientation()); 586 QVariant margins = QVariant::fromValue(QPair<QMarginsF, QPageLayout::Unit>(d->m_pageLayout.margins(), 587 d->m_pageLayout.units())); 588 QString id = value.toString(); 589 if (id.isEmpty()) 590 id = QCocoaPrinterSupport().defaultPrintDeviceId(); 591 else if (!QCocoaPrinterSupport().availablePrintDeviceIds().contains(id)) 592 break; 593 d->m_printDevice.reset(new QCocoaPrintDevice(id)); 594 PMPrinter printer = d->m_printDevice->macPrinter(); 595 PMRetain(printer); 596 PMSessionSetCurrentPMPrinter(d->session(), printer); 597 // Ensure the settings are up to date and valid 598 if (d->m_printDevice->supportedPageSize(pageSize.value<QPageSize>()).isValid()) 599 setProperty(PPK_QPageSize, pageSize); 600 else 601 setProperty(PPK_CustomPaperSize, pageSize.value<QPageSize>().size(QPageSize::Point)); 602 setProperty(PPK_FullPage, QVariant(isFullPage)); 603 setProperty(PPK_Orientation, orientation); 604 setProperty(PPK_QPageMargins, margins); 605 break; 606 } 607 case PPK_CustomPaperSize: 608 d->setPageSize(QPageSize(value.toSizeF(), QPageSize::Point)); 609 break; 610 case PPK_PageMargins: 611 { 612 QList<QVariant> margins(value.toList()); 613 Q_ASSERT(margins.size() == 4); 614 d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(), 615 margins.at(2).toReal(), margins.at(3).toReal())); 616 break; 617 } 618 case PPK_QPageSize: 619 d->setPageSize(value.value<QPageSize>()); 620 break; 621 case PPK_QPageMargins: { 622 QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >(); 623 d->m_pageLayout.setUnits(pair.second); 624 d->m_pageLayout.setMargins(pair.first); 625 break; 626 } 627 case PPK_QPageLayout: { 628 QPageLayout pageLayout = value.value<QPageLayout>(); 629 if (pageLayout.isValid() && d->m_printDevice->isValidPageLayout(pageLayout, d->resolution.hRes)) { 630 setProperty(PPK_QPageSize, QVariant::fromValue(pageLayout.pageSize())); 631 setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode); 632 setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation())); 633 d->m_pageLayout.setUnits(pageLayout.units()); 634 d->m_pageLayout.setMargins(pageLayout.margins()); 635 } 636 break; 637 } 638 // No default so that compiler will complain if new keys added and not handled in this engine 639 } 640} 641 642QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const 643{ 644 Q_D(const QMacPrintEngine); 645 QVariant ret; 646 647 if (!d->printInfo && d->valueCache.contains(key)) 648 return *d->valueCache.find(key); 649 650 switch (key) { 651 652 // The following keys are settings that are unsupported by the Mac PrintEngine 653 // Return sensible default values to ensure consistent behavior across platforms 654 case PPK_ColorMode: 655 ret = QPrinter::Color; 656 break; 657 case PPK_CustomBase: 658 // Special case, leave null 659 break; 660 case PPK_PageOrder: 661 // TODO Check if can be supported via Cups Options 662 ret = QPrinter::FirstPageFirst; 663 break; 664 case PPK_PaperSource: 665 // TODO Check if can be supported via Cups Options 666 ret = QPrinter::Auto; 667 break; 668 case PPK_PaperSources: { 669 // TODO Check if can be supported via Cups Options 670 QList<QVariant> out; 671 out << int(QPrinter::Auto); 672 ret = out; 673 break; 674 } 675 case PPK_PrinterProgram: 676 ret = QString(); 677 break; 678 case PPK_SelectionOption: 679 ret = QString(); 680 break; 681 682 // The following keys are properties and settings that are supported by the Mac PrintEngine 683 case PPK_FontEmbedding: 684 ret = d->embedFonts; 685 break; 686 case PPK_CollateCopies: { 687 Boolean status; 688 PMGetCollate(d->settings(), &status); 689 ret = bool(status); 690 break; 691 } 692 case PPK_Creator: 693 ret = d->m_creator; 694 break; 695 case PPK_DocumentName: { 696 CFStringRef name; 697 PMPrintSettingsGetJobName(d->settings(), &name); 698 ret = QString::fromCFString(name); 699 break; 700 } 701 case PPK_Duplex: { 702 PMDuplexMode mode = kPMDuplexNone; 703 PMGetDuplex(d->settings(), &mode); 704 switch (mode) { 705 case kPMDuplexNoTumble: 706 ret = QPrinter::DuplexLongSide; 707 break; 708 case kPMDuplexTumble: 709 ret = QPrinter::DuplexShortSide; 710 break; 711 case kPMDuplexNone: 712 default: 713 ret = QPrinter::DuplexNone; 714 break; 715 } 716 break; 717 } 718 case PPK_FullPage: 719 ret = d->m_pageLayout.mode() == QPageLayout::FullPageMode; 720 break; 721 case PPK_NumberOfCopies: 722 ret = 1; 723 break; 724 case PPK_CopyCount: { 725 UInt32 copies = 1; 726 PMGetCopies(d->settings(), &copies); 727 ret = (uint) copies; 728 break; 729 } 730 case PPK_SupportsMultipleCopies: 731 ret = true; 732 break; 733 case PPK_Orientation: 734 ret = d->m_pageLayout.orientation(); 735 break; 736 case PPK_OutputFileName: 737 ret = d->outputFilename; 738 break; 739 case PPK_PageRect: 740 // PageRect is returned in device pixels 741 ret = d->m_pageLayout.paintRectPixels(d->resolution.hRes); 742 break; 743 case PPK_PageSize: 744 ret = d->m_pageLayout.pageSize().id(); 745 break; 746 case PPK_PaperName: 747 ret = d->m_pageLayout.pageSize().name(); 748 break; 749 case PPK_WindowsPageSize: 750 ret = d->m_pageLayout.pageSize().windowsId(); 751 break; 752 case PPK_PaperRect: 753 // PaperRect is returned in device pixels 754 ret = d->m_pageLayout.fullRectPixels(d->resolution.hRes); 755 break; 756 case PPK_PrinterName: 757 return d->m_printDevice->id(); 758 break; 759 case PPK_Resolution: { 760 ret = d->resolution.hRes; 761 break; 762 } 763 case PPK_SupportedResolutions: { 764 QList<QVariant> list; 765 for (int resolution : d->m_printDevice->supportedResolutions()) 766 list << resolution; 767 ret = list; 768 break; 769 } 770 case PPK_CustomPaperSize: 771 ret = d->m_pageLayout.fullRectPoints().size(); 772 break; 773 case PPK_PageMargins: { 774 QList<QVariant> list; 775 QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Point); 776 list << margins.left() << margins.top() << margins.right() << margins.bottom(); 777 ret = list; 778 break; 779 } 780 case PPK_QPageSize: 781 ret.setValue(d->m_pageLayout.pageSize()); 782 break; 783 case PPK_QPageMargins: { 784 QPair<QMarginsF, QPageLayout::Unit> pair = qMakePair(d->m_pageLayout.margins(), d->m_pageLayout.units()); 785 ret.setValue(pair); 786 break; 787 } 788 case PPK_QPageLayout: 789 ret.setValue(d->m_pageLayout); 790 // No default so that compiler will complain if new keys added and not handled in this engine 791 } 792 return ret; 793} 794 795QT_END_NAMESPACE 796 797#endif // QT_NO_PRINTER 798