1/**************************************************************************** 2** 3** Copyright (C) 2015 The Qt Company Ltd. 4** Contact: http://www.qt.io/licensing/ 5** 6** This file is part of the QtGui module 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 http://www.qt.io/terms-conditions. For further 15** information use the contact form at http://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 2.1 or version 3 as published by the Free 20** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22** following information to ensure the GNU Lesser General Public License 23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25** 26** As a special exception, The Qt Company gives you certain additional 27** rights. These rights are described in The Qt Company LGPL Exception 28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29** 30** GNU General Public License Usage 31** Alternatively, this file may be used under the terms of the GNU 32** General Public License version 3.0 as published by the Free Software 33** Foundation and appearing in the file LICENSE.GPL included in the 34** packaging of this file. Please review the following information to 35** ensure the GNU General Public License version 3.0 requirements will be 36** met: http://www.gnu.org/copyleft/gpl.html. 37** 38** $QT_END_LICENSE$ 39** 40****************************************************************************/ 41 42#include <private/qprintengine_mac_p.h> 43#include <qthread.h> 44#include <quuid.h> 45#include <QtCore/qcoreapplication.h> 46 47#ifndef QT_NO_PRINTER 48 49QT_BEGIN_NAMESPACE 50 51extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); 52 53QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode) : QPaintEngine(*(new QMacPrintEnginePrivate)) 54{ 55 Q_D(QMacPrintEngine); 56 d->mode = mode; 57 d->initialize(); 58} 59 60bool QMacPrintEngine::begin(QPaintDevice *dev) 61{ 62 Q_D(QMacPrintEngine); 63 64 Q_ASSERT(dev && dev->devType() == QInternal::Printer); 65 if (!static_cast<QPrinter *>(dev)->isValid()) 66 return false; 67 68 if (d->state == QPrinter::Idle && !d->isPrintSessionInitialized()) // Need to reinitialize 69 d->initialize(); 70 71 d->paintEngine->state = state; 72 d->paintEngine->begin(dev); 73 Q_ASSERT_X(d->state == QPrinter::Idle, "QMacPrintEngine", "printer already active"); 74 75 if (PMSessionValidatePrintSettings(d->session, d->settings, kPMDontWantBoolean) != noErr 76 || PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean) != noErr) { 77 d->state = QPrinter::Error; 78 return false; 79 } 80 81 if (!d->outputFilename.isEmpty()) { 82 QCFType<CFURLRef> outFile = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, 83 QCFString(d->outputFilename), 84 kCFURLPOSIXPathStyle, 85 false); 86 if (PMSessionSetDestination(d->session, d->settings, kPMDestinationFile, 87 kPMDocumentFormatPDF, outFile) != noErr) { 88 qWarning("QMacPrintEngine::begin: Problem setting file [%s]", d->outputFilename.toUtf8().constData()); 89 return false; 90 } 91 } 92 OSStatus status = noErr; 93#ifndef QT_MAC_USE_COCOA 94 status = d->shouldSuppressStatus() ? PMSessionBeginCGDocumentNoDialog(d->session, d->settings, d->format) 95 : PMSessionBeginCGDocument(d->session, d->settings, d->format); 96#else 97 status = PMSessionBeginCGDocumentNoDialog(d->session, d->settings, d->format); 98#endif 99 100 if (status != noErr) { 101 d->state = QPrinter::Error; 102 return false; 103 } 104 105 d->state = QPrinter::Active; 106 setActive(true); 107 d->newPage_helper(); 108 return true; 109} 110 111bool QMacPrintEngine::end() 112{ 113 Q_D(QMacPrintEngine); 114 if (d->state == QPrinter::Aborted) 115 return true; // I was just here a function call ago :) 116 if(d->paintEngine->type() == QPaintEngine::CoreGraphics) { 117 // We dont need the paint engine to call restoreGraphicsState() 118 static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->stackCount = 0; 119 static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = 0; 120 } 121 d->paintEngine->end(); 122 if (d->state != QPrinter::Idle) 123 d->releaseSession(); 124 d->state = QPrinter::Idle; 125 return true; 126} 127 128QPaintEngine * 129QMacPrintEngine::paintEngine() const 130{ 131 return d_func()->paintEngine; 132} 133 134Qt::HANDLE QMacPrintEngine::handle() const 135{ 136 QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine()); 137 return cgEngine->d_func()->hd; 138} 139 140QMacPrintEnginePrivate::~QMacPrintEnginePrivate() 141{ 142#ifdef QT_MAC_USE_COCOA 143 [printInfo release]; 144#endif 145 delete paintEngine; 146} 147 148void QMacPrintEnginePrivate::setPaperSize(QPrinter::PaperSize ps) 149{ 150 Q_Q(QMacPrintEngine); 151 if (hasCustomPaperSize) { 152 PMRelease(customPaper); 153 customPaper = 0; 154 } 155 hasCustomPaperSize = (ps == QPrinter::Custom); 156 PMPrinter printer; 157 158 if (PMSessionGetCurrentPrinter(session, &printer) == noErr) { 159 if (ps != QPrinter::Custom) { 160 QSize newSize = qt_paperSizeToQSizeF(ps).toSize(); 161 QCFType<CFArrayRef> formats; 162 if (PMSessionCreatePageFormatList(session, printer, &formats) == noErr) { 163 CFIndex total = CFArrayGetCount(formats); 164 PMPageFormat tmp; 165 PMRect paper; 166 for (CFIndex idx = 0; idx < total; ++idx) { 167 tmp = static_cast<PMPageFormat>(const_cast<void *>(CFArrayGetValueAtIndex(formats, idx))); 168 PMGetUnadjustedPaperRect(tmp, &paper); 169 int wMM = int((paper.right - paper.left) / 72 * 25.4 + 0.5); 170 int hMM = int((paper.bottom - paper.top) / 72 * 25.4 + 0.5); 171 if (newSize.width() == wMM && newSize.height() == hMM) { 172 PMCopyPageFormat(tmp, format); 173 // reset the orientation and resolution as they are lost in the copy. 174 q->setProperty(QPrintEngine::PPK_Orientation, orient); 175 if (PMSessionValidatePageFormat(session, format, kPMDontWantBoolean) != noErr) { 176 // Don't know, warn for the moment. 177 qWarning("QMacPrintEngine, problem setting format and resolution for this page size"); 178 } 179 break; 180 } 181 } 182 } 183 } else { 184 QCFString paperId = QCFString::toCFStringRef(QUuid::createUuid().toString()); 185 PMPaperMargins paperMargins; 186 paperMargins.left = leftMargin; 187 paperMargins.top = topMargin; 188 paperMargins.right = rightMargin; 189 paperMargins.bottom = bottomMargin; 190 PMPaperCreateCustom(printer, paperId, QCFString("Custom size"), customSize.width(), customSize.height(), &paperMargins, &customPaper); 191 PMPageFormat tmp; 192 PMCreatePageFormatWithPMPaper(&tmp, customPaper); 193 PMCopyPageFormat(tmp, format); 194 if (PMSessionValidatePageFormat(session, format, kPMDontWantBoolean) != noErr) { 195 // Don't know, warn for the moment. 196 qWarning("QMacPrintEngine, problem setting paper name"); 197 } 198 } 199 } 200} 201 202QPrinter::PaperSize QMacPrintEnginePrivate::paperSize() const 203{ 204 if (hasCustomPaperSize) 205 return QPrinter::Custom; 206 PMRect paper; 207 PMGetUnadjustedPaperRect(format, &paper); 208 int wMM = int((paper.right - paper.left) / 72 * 25.4 + 0.5); 209 int hMM = int((paper.bottom - paper.top) / 72 * 25.4 + 0.5); 210 for (int i = QPrinter::A4; i < QPrinter::NPaperSize; ++i) { 211 QSize s = qt_paperSizeToQSizeF(QPrinter::PaperSize(i)).toSize(); 212 if (s.width() == wMM && s.height() == hMM) 213 return (QPrinter::PaperSize)i; 214 } 215 return QPrinter::Custom; 216} 217 218QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const 219{ 220 Q_ASSERT_X(session, "QMacPrinterEngine::supportedResolutions", 221 "must have a valid printer session"); 222 UInt32 resCount; 223 QList<QVariant> resolutions; 224 PMPrinter printer; 225 if (PMSessionGetCurrentPrinter(session, &printer) == noErr) { 226 PMResolution res; 227 OSStatus status = PMPrinterGetPrinterResolutionCount(printer, &resCount); 228 if (status == kPMNotImplemented) { 229#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) 230 // *Sigh* we have to use the non-indexed version. 231 if (PMPrinterGetPrinterResolution(printer, kPMMinSquareResolution, &res) == noErr) 232 resolutions.append(int(res.hRes)); 233 if (PMPrinterGetPrinterResolution(printer, kPMMaxSquareResolution, &res) == noErr) { 234 QVariant var(int(res.hRes)); 235 if (!resolutions.contains(var)) 236 resolutions.append(var); 237 } 238 if (PMPrinterGetPrinterResolution(printer, kPMDefaultResolution, &res) == noErr) { 239 QVariant var(int(res.hRes)); 240 if (!resolutions.contains(var)) 241 resolutions.append(var); 242 } 243#endif 244 } else if (status == noErr) { 245 // According to the docs, index start at 1. 246 for (UInt32 i = 1; i <= resCount; ++i) { 247 if (PMPrinterGetIndexedPrinterResolution(printer, i, &res) == noErr) 248 resolutions.append(QVariant(int(res.hRes))); 249 } 250 } else { 251 qWarning("QMacPrintEngine::supportedResolutions: Unexpected error: %ld", long(status)); 252 } 253 } 254 return resolutions; 255} 256 257bool QMacPrintEnginePrivate::shouldSuppressStatus() const 258{ 259 if (suppressStatus == true) 260 return true; 261 262 // Supress displaying the automatic progress dialog if we are printing 263 // from a non-gui thread. 264 return (qApp->thread() != QThread::currentThread()); 265} 266 267QPrinter::PrinterState QMacPrintEngine::printerState() const 268{ 269 return d_func()->state; 270} 271 272bool QMacPrintEngine::newPage() 273{ 274 Q_D(QMacPrintEngine); 275 Q_ASSERT(d->state == QPrinter::Active); 276 OSStatus err = 277#ifndef QT_MAC_USE_COCOA 278 d->shouldSuppressStatus() ? PMSessionEndPageNoDialog(d->session) 279 : PMSessionEndPage(d->session); 280#else 281 PMSessionEndPageNoDialog(d->session); 282#endif 283 if (err != noErr) { 284 if (err == kPMCancel) { 285 // User canceled, we need to abort! 286 abort(); 287 } else { 288 // Not sure what the problem is... 289 qWarning("QMacPrintEngine::newPage: Cannot end current page. %ld", long(err)); 290 d->state = QPrinter::Error; 291 } 292 return false; 293 } 294 return d->newPage_helper(); 295} 296 297bool QMacPrintEngine::abort() 298{ 299 Q_D(QMacPrintEngine); 300 if (d->state != QPrinter::Active) 301 return false; 302 bool ret = end(); 303 d->state = QPrinter::Aborted; 304 return ret; 305} 306 307static inline int qt_get_PDMWidth(PMPageFormat pformat, bool fullPage, 308 const PMResolution &resolution) 309{ 310 int val = 0; 311 PMRect r; 312 qreal hRatio = resolution.hRes / 72; 313 if (fullPage) { 314 if (PMGetAdjustedPaperRect(pformat, &r) == noErr) 315 val = qRound((r.right - r.left) * hRatio); 316 } else { 317 if (PMGetAdjustedPageRect(pformat, &r) == noErr) 318 val = qRound((r.right - r.left) * hRatio); 319 } 320 return val; 321} 322 323static inline int qt_get_PDMHeight(PMPageFormat pformat, bool fullPage, 324 const PMResolution &resolution) 325{ 326 int val = 0; 327 PMRect r; 328 qreal vRatio = resolution.vRes / 72; 329 if (fullPage) { 330 if (PMGetAdjustedPaperRect(pformat, &r) == noErr) 331 val = qRound((r.bottom - r.top) * vRatio); 332 } else { 333 if (PMGetAdjustedPageRect(pformat, &r) == noErr) 334 val = qRound((r.bottom - r.top) * vRatio); 335 } 336 return val; 337} 338 339 340int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const 341{ 342 Q_D(const QMacPrintEngine); 343 int val = 1; 344 switch (m) { 345 case QPaintDevice::PdmWidth: 346 if (d->hasCustomPaperSize) { 347 val = qRound(d->customSize.width()); 348 if (d->hasCustomPageMargins) { 349 val -= qRound(d->leftMargin + d->rightMargin); 350 } else { 351 QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList(); 352 val -= qRound(margins.at(0).toDouble() + margins.at(2).toDouble()); 353 } 354 } else { 355 val = qt_get_PDMWidth(d->format, property(PPK_FullPage).toBool(), d->resolution); 356 } 357 break; 358 case QPaintDevice::PdmHeight: 359 if (d->hasCustomPaperSize) { 360 val = qRound(d->customSize.height()); 361 if (d->hasCustomPageMargins) { 362 val -= qRound(d->topMargin + d->bottomMargin); 363 } else { 364 QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList(); 365 val -= qRound(margins.at(1).toDouble() + margins.at(3).toDouble()); 366 } 367 } else { 368 val = qt_get_PDMHeight(d->format, property(PPK_FullPage).toBool(), d->resolution); 369 } 370 break; 371 case QPaintDevice::PdmWidthMM: 372 val = metric(QPaintDevice::PdmWidth); 373 val = int((val * 254 + 5 * d->resolution.hRes) / (10 * d->resolution.hRes)); 374 break; 375 case QPaintDevice::PdmHeightMM: 376 val = metric(QPaintDevice::PdmHeight); 377 val = int((val * 254 + 5 * d->resolution.vRes) / (10 * d->resolution.vRes)); 378 break; 379 case QPaintDevice::PdmPhysicalDpiX: 380 case QPaintDevice::PdmPhysicalDpiY: { 381 PMPrinter printer; 382 if(PMSessionGetCurrentPrinter(d->session, &printer) == noErr) { 383 PMResolution resolution; 384#ifndef QT_MAC_USE_COCOA 385# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 386 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) { 387 PMPrinterGetOutputResolution(printer, d->settings, &resolution); 388 } else 389# endif 390 { 391 PMPrinterGetPrinterResolution(printer, kPMCurrentValue, &resolution); 392 } 393#else 394 PMPrinterGetOutputResolution(printer, d->settings, &resolution); 395#endif 396 val = (int)resolution.vRes; 397 break; 398 } 399 //otherwise fall through 400 } 401 case QPaintDevice::PdmDpiY: 402 val = (int)d->resolution.vRes; 403 break; 404 case QPaintDevice::PdmDpiX: 405 val = (int)d->resolution.hRes; 406 break; 407 case QPaintDevice::PdmNumColors: 408 val = (1 << metric(QPaintDevice::PdmDepth)); 409 break; 410 case QPaintDevice::PdmDepth: 411 val = 24; 412 break; 413 default: 414 val = 0; 415 qWarning("QPrinter::metric: Invalid metric command"); 416 } 417 return val; 418} 419 420void QMacPrintEnginePrivate::initialize() 421{ 422 Q_Q(QMacPrintEngine); 423 424#ifndef QT_MAC_USE_COCOA 425 Q_ASSERT(!session); 426#else 427 Q_ASSERT(!printInfo); 428#endif 429 430 if (!paintEngine) 431 paintEngine = new QCoreGraphicsPaintEngine(); 432 433 q->gccaps = paintEngine->gccaps; 434 435 fullPage = false; 436 437#ifndef QT_MAC_USE_COCOA 438 if (PMCreateSession(&session) != 0) 439 session = 0; 440#else 441 QMacCocoaAutoReleasePool pool; 442 printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]]; 443 session = static_cast<PMPrintSession>([printInfo PMPrintSession]); 444#endif 445 446 PMPrinter printer; 447 if (session && PMSessionGetCurrentPrinter(session, &printer) == noErr) { 448 QList<QVariant> resolutions = supportedResolutions(); 449 if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) { 450 if (resolutions.count() > 1 && mode == QPrinter::HighResolution) { 451 int max = 0; 452 for (int i = 0; i < resolutions.count(); ++i) { 453 int value = resolutions.at(i).toInt(); 454 if (value > max) 455 max = value; 456 } 457 resolution.hRes = resolution.vRes = max; 458 } else { 459 resolution.hRes = resolution.vRes = resolutions.at(0).toInt(); 460 } 461 if(resolution.hRes == 0) 462 resolution.hRes = resolution.vRes = 600; 463 } else { 464 resolution.hRes = resolution.vRes = qt_defaultDpi(); 465 } 466 } 467 468#ifndef QT_MAC_USE_COCOA 469 bool settingsInitialized = (settings != 0); 470 bool settingsOK = !settingsInitialized ? PMCreatePrintSettings(&settings) == noErr : true; 471 if (settingsOK && !settingsInitialized) 472 settingsOK = PMSessionDefaultPrintSettings(session, settings) == noErr; 473 474 475 bool formatInitialized = (format != 0); 476 bool formatOK = !formatInitialized ? PMCreatePageFormat(&format) == noErr : true; 477 if (formatOK) { 478 if (!formatInitialized) { 479 formatOK = PMSessionDefaultPageFormat(session, format) == noErr; 480 } 481 formatOK = PMSessionValidatePageFormat(session, format, kPMDontWantBoolean) == noErr; 482 } 483#else 484 settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]); 485 format = static_cast<PMPageFormat>([printInfo PMPageFormat]); 486#endif 487 488#ifndef QT_MAC_USE_COCOA 489 if (!settingsOK || !formatOK) { 490 qWarning("QMacPrintEngine::initialize: Unable to initialize QPainter"); 491 state = QPrinter::Error; 492 } 493#endif 494 495 QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant>::const_iterator propC; 496 for (propC = valueCache.constBegin(); propC != valueCache.constEnd(); propC++) { 497 q->setProperty(propC.key(), propC.value()); 498 } 499} 500 501void QMacPrintEnginePrivate::releaseSession() 502{ 503#ifndef QT_MAC_USE_COCOA 504 if (shouldSuppressStatus()) { 505 PMSessionEndPageNoDialog(session); 506 PMSessionEndDocumentNoDialog(session); 507 } else { 508 PMSessionEndPage(session); 509 PMSessionEndDocument(session); 510 } 511 PMRelease(session); 512#else 513 PMSessionEndPageNoDialog(session); 514 PMSessionEndDocumentNoDialog(session); 515 [printInfo release]; 516#endif 517 if (hasCustomPaperSize) 518 PMRelease(customPaper); 519 printInfo = 0; 520 session = 0; 521} 522 523bool QMacPrintEnginePrivate::newPage_helper() 524{ 525 Q_Q(QMacPrintEngine); 526 Q_ASSERT(state == QPrinter::Active); 527 528 if (PMSessionError(session) != noErr) { 529 q->abort(); 530 return false; 531 } 532 533 // pop the stack of saved graphic states, in case we get the same 534 // context back - either way, the stack count should be 0 when we 535 // get the new one 536 QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine); 537 while (cgEngine->d_func()->stackCount > 0) 538 cgEngine->d_func()->restoreGraphicsState(); 539 540 OSStatus status = 541#ifndef QT_MAC_USE_COCOA 542 shouldSuppressStatus() ? PMSessionBeginPageNoDialog(session, format, 0) 543 : PMSessionBeginPage(session, format, 0); 544#else 545 PMSessionBeginPageNoDialog(session, format, 0); 546#endif 547 if(status != noErr) { 548 state = QPrinter::Error; 549 return false; 550 } 551 552 QRect page = q->property(QPrintEngine::PPK_PageRect).toRect(); 553 QRect paper = q->property(QPrintEngine::PPK_PaperRect).toRect(); 554 555 CGContextRef cgContext; 556 OSStatus err = noErr; 557 err = PMSessionGetCGGraphicsContext(session, &cgContext); 558 if(err != noErr) { 559 qWarning("QMacPrintEngine::newPage: Cannot retrieve CoreGraphics context: %ld", long(err)); 560 state = QPrinter::Error; 561 return false; 562 } 563 cgEngine->d_func()->hd = cgContext; 564 565 // Set the resolution as a scaling ration of 72 (the default). 566 CGContextScaleCTM(cgContext, 72 / resolution.hRes, 72 / resolution.vRes); 567 568 CGContextScaleCTM(cgContext, 1, -1); 569 CGContextTranslateCTM(cgContext, 0, -paper.height()); 570 if (!fullPage) 571 CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y()); 572 cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext); 573 cgEngine->d_func()->setClip(0); 574 cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty 575 & ~(QPaintEngine::DirtyClipEnabled 576 | QPaintEngine::DirtyClipRegion 577 | QPaintEngine::DirtyClipPath)); 578 if (cgEngine->painter()->hasClipping()) 579 cgEngine->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled; 580 cgEngine->syncState(); 581 return true; 582} 583 584 585void QMacPrintEngine::updateState(const QPaintEngineState &state) 586{ 587 d_func()->paintEngine->updateState(state); 588} 589 590void QMacPrintEngine::drawRects(const QRectF *r, int num) 591{ 592 Q_D(QMacPrintEngine); 593 Q_ASSERT(d->state == QPrinter::Active); 594 d->paintEngine->drawRects(r, num); 595} 596 597void QMacPrintEngine::drawPoints(const QPointF *points, int pointCount) 598{ 599 Q_D(QMacPrintEngine); 600 Q_ASSERT(d->state == QPrinter::Active); 601 d->paintEngine->drawPoints(points, pointCount); 602} 603 604void QMacPrintEngine::drawEllipse(const QRectF &r) 605{ 606 Q_D(QMacPrintEngine); 607 Q_ASSERT(d->state == QPrinter::Active); 608 d->paintEngine->drawEllipse(r); 609} 610 611void QMacPrintEngine::drawLines(const QLineF *lines, int lineCount) 612{ 613 Q_D(QMacPrintEngine); 614 Q_ASSERT(d->state == QPrinter::Active); 615 d->paintEngine->drawLines(lines, lineCount); 616} 617 618void QMacPrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) 619{ 620 Q_D(QMacPrintEngine); 621 Q_ASSERT(d->state == QPrinter::Active); 622 d->paintEngine->drawPolygon(points, pointCount, mode); 623} 624 625void QMacPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) 626{ 627 Q_D(QMacPrintEngine); 628 Q_ASSERT(d->state == QPrinter::Active); 629 d->paintEngine->drawPixmap(r, pm, sr); 630} 631 632void QMacPrintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags) 633{ 634 Q_D(QMacPrintEngine); 635 Q_ASSERT(d->state == QPrinter::Active); 636 d->paintEngine->drawImage(r, pm, sr, flags); 637} 638 639void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti) 640{ 641 Q_D(QMacPrintEngine); 642 Q_ASSERT(d->state == QPrinter::Active); 643 d->paintEngine->drawTextItem(p, ti); 644} 645 646void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr) 647{ 648 Q_D(QMacPrintEngine); 649 Q_ASSERT(d->state == QPrinter::Active); 650 d->paintEngine->drawTiledPixmap(dr, pixmap, sr); 651} 652 653void QMacPrintEngine::drawPath(const QPainterPath &path) 654{ 655 Q_D(QMacPrintEngine); 656 Q_ASSERT(d->state == QPrinter::Active); 657 d->paintEngine->drawPath(path); 658} 659 660 661void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value) 662{ 663 Q_D(QMacPrintEngine); 664 665 d->valueCache.insert(key, value); 666 if (!d->session) 667 return; 668 669 switch (key) { 670 case PPK_CollateCopies: 671 break; 672 case PPK_ColorMode: 673 break; 674 case PPK_Creator: 675 break; 676 case PPK_DocumentName: 677 break; 678 case PPK_PageOrder: 679 break; 680 case PPK_PaperSource: 681 break; 682 case PPK_SelectionOption: 683 break; 684 case PPK_Resolution: { 685 PMPrinter printer; 686 UInt32 count; 687 if (PMSessionGetCurrentPrinter(d->session, &printer) != noErr) 688 break; 689 if (PMPrinterGetPrinterResolutionCount(printer, &count) != noErr) 690 break; 691 PMResolution resolution = { 0.0, 0.0 }; 692 PMResolution bestResolution = { 0.0, 0.0 }; 693 int dpi = value.toInt(); 694 int bestDistance = INT_MAX; 695 for (UInt32 i = 1; i <= count; ++i) { // Yes, it starts at 1 696 if (PMPrinterGetIndexedPrinterResolution(printer, i, &resolution) == noErr) { 697 if (dpi == int(resolution.hRes)) { 698 bestResolution = resolution; 699 break; 700 } else { 701 int distance = qAbs(dpi - int(resolution.hRes)); 702 if (distance < bestDistance) { 703 bestDistance = distance; 704 bestResolution = resolution; 705 } 706 } 707 } 708 } 709 PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean); 710 break; 711 } 712 713 case PPK_FullPage: 714 d->fullPage = value.toBool(); 715 break; 716 case PPK_CopyCount: // fallthrough 717 case PPK_NumberOfCopies: 718 PMSetCopies(d->settings, value.toInt(), false); 719 break; 720 case PPK_Orientation: { 721 if (d->state == QPrinter::Active) { 722 qWarning("QMacPrintEngine::setOrientation: Orientation cannot be changed during a print job, ignoring change"); 723 } else { 724 QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt()); 725 if (d->hasCustomPaperSize && (d->orient != newOrientation)) 726 d->customSize = QSizeF(d->customSize.height(), d->customSize.width()); 727 d->orient = newOrientation; 728 PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape; 729 PMSetOrientation(d->format, o, false); 730 PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean); 731 } 732 break; } 733 case PPK_OutputFileName: 734 d->outputFilename = value.toString(); 735 break; 736 case PPK_PaperSize: 737 d->setPaperSize(QPrinter::PaperSize(value.toInt())); 738 break; 739 case PPK_PrinterName: { 740 bool printerNameSet = false; 741 OSStatus status = noErr; 742 QCFType<CFArrayRef> printerList; 743 status = PMServerCreatePrinterList(kPMServerLocal, &printerList); 744 if (status == noErr) { 745 CFIndex count = CFArrayGetCount(printerList); 746 for (CFIndex i=0; i<count; ++i) { 747 PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(printerList, i))); 748 QString name = QCFString::toQString(PMPrinterGetName(printer)); 749 if (name == value.toString()) { 750 status = PMSessionSetCurrentPMPrinter(d->session, printer); 751 printerNameSet = true; 752 break; 753 } 754 } 755 } 756 if (status != noErr) 757 qWarning("QMacPrintEngine::setPrinterName: Error setting printer: %ld", long(status)); 758 if (!printerNameSet) { 759 qWarning("QMacPrintEngine::setPrinterName: Failed to set printer named '%s'.", qPrintable(value.toString())); 760 d->releaseSession(); 761 d->state = QPrinter::Idle; 762 } 763 break; } 764 case PPK_SuppressSystemPrintStatus: 765 d->suppressStatus = value.toBool(); 766 break; 767 case PPK_CustomPaperSize: 768 { 769 PMOrientation orientation; 770 PMGetOrientation(d->format, &orientation); 771 d->customSize = value.toSizeF(); 772 if (orientation != kPMPortrait) 773 d->customSize = QSizeF(d->customSize.height(), d->customSize.width()); 774 d->setPaperSize(QPrinter::Custom); 775 break; 776 } 777 case PPK_PageMargins: 778 { 779 QList<QVariant> margins(value.toList()); 780 Q_ASSERT(margins.size() == 4); 781 d->leftMargin = margins.at(0).toDouble(); 782 d->topMargin = margins.at(1).toDouble(); 783 d->rightMargin = margins.at(2).toDouble(); 784 d->bottomMargin = margins.at(3).toDouble(); 785 d->hasCustomPageMargins = true; 786 break; 787 } 788 789 default: 790 break; 791 } 792} 793 794QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const 795{ 796 Q_D(const QMacPrintEngine); 797 QVariant ret; 798 799 if (!d->session && d->valueCache.contains(key)) 800 return *d->valueCache.find(key); 801 802 switch (key) { 803 case PPK_CollateCopies: 804 ret = false; 805 break; 806 case PPK_ColorMode: 807 ret = QPrinter::Color; 808 break; 809 case PPK_Creator: 810 break; 811 case PPK_DocumentName: 812 break; 813 case PPK_FullPage: 814 ret = d->fullPage; 815 break; 816 case PPK_NumberOfCopies: 817 ret = 1; 818 break; 819 case PPK_CopyCount: { 820 UInt32 copies = 1; 821 PMGetCopies(d->settings, &copies); 822 ret = (uint) copies; 823 break; 824 } 825 case PPK_SupportsMultipleCopies: 826 ret = true; 827 break; 828 case PPK_Orientation: 829 PMOrientation orientation; 830 PMGetOrientation(d->format, &orientation); 831 ret = orientation == kPMPortrait ? QPrinter::Portrait : QPrinter::Landscape; 832 break; 833 case PPK_OutputFileName: 834 ret = d->outputFilename; 835 break; 836 case PPK_PageOrder: 837 break; 838 case PPK_PaperSource: 839 break; 840 case PPK_PageRect: { 841 // PageRect is returned in device pixels 842 QRect r; 843 PMRect macrect, macpaper; 844 qreal hRatio = d->resolution.hRes / 72; 845 qreal vRatio = d->resolution.vRes / 72; 846 if (d->hasCustomPaperSize) { 847 r = QRect(0, 0, qRound(d->customSize.width() * hRatio), qRound(d->customSize.height() * vRatio)); 848 if (d->hasCustomPageMargins) { 849 r.adjust(qRound(d->leftMargin * hRatio), qRound(d->topMargin * vRatio), 850 -qRound(d->rightMargin * hRatio), -qRound(d->bottomMargin * vRatio)); 851 } else { 852 QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList(); 853 r.adjust(qRound(margins.at(0).toDouble() * hRatio), 854 qRound(margins.at(1).toDouble() * vRatio), 855 -qRound(margins.at(2).toDouble() * hRatio), 856 -qRound(margins.at(3).toDouble()) * vRatio); 857 } 858 } else if (PMGetAdjustedPageRect(d->format, ¯ect) == noErr 859 && PMGetAdjustedPaperRect(d->format, &macpaper) == noErr) 860 { 861 if (d->fullPage || d->hasCustomPageMargins) { 862 r.setCoords(int(macpaper.left * hRatio), int(macpaper.top * vRatio), 863 int(macpaper.right * hRatio), int(macpaper.bottom * vRatio)); 864 r.translate(-r.x(), -r.y()); 865 if (d->hasCustomPageMargins) { 866 r.adjust(qRound(d->leftMargin * hRatio), qRound(d->topMargin * vRatio), 867 -qRound(d->rightMargin * hRatio), -qRound(d->bottomMargin * vRatio)); 868 } 869 } else { 870 r.setCoords(int(macrect.left * hRatio), int(macrect.top * vRatio), 871 int(macrect.right * hRatio), int(macrect.bottom * vRatio)); 872 r.translate(int(-macpaper.left * hRatio), int(-macpaper.top * vRatio)); 873 } 874 } 875 ret = r; 876 break; } 877 case PPK_PaperSize: 878 ret = d->paperSize(); 879 break; 880 case PPK_PaperRect: { 881 QRect r; 882 PMRect macrect; 883 qreal hRatio = d->resolution.hRes / 72; 884 qreal vRatio = d->resolution.vRes / 72; 885 if (d->hasCustomPaperSize) { 886 r = QRect(0, 0, qRound(d->customSize.width() * hRatio), qRound(d->customSize.height() * vRatio)); 887 } else if (PMGetAdjustedPaperRect(d->format, ¯ect) == noErr) { 888 r.setCoords(int(macrect.left * hRatio), int(macrect.top * vRatio), 889 int(macrect.right * hRatio), int(macrect.bottom * vRatio)); 890 r.translate(-r.x(), -r.y()); 891 } 892 ret = r; 893 break; } 894 case PPK_PrinterName: { 895 PMPrinter printer; 896 OSStatus status = PMSessionGetCurrentPrinter(d->session, &printer); 897 if (status != noErr) 898 qWarning("QMacPrintEngine::printerName: Failed getting current PMPrinter: %ld", long(status)); 899 if (printer) 900 ret = QCFString::toQString(PMPrinterGetName(printer)); 901 break; } 902 case PPK_Resolution: { 903 ret = d->resolution.hRes; 904 break; 905 } 906 case PPK_SupportedResolutions: 907 ret = d->supportedResolutions(); 908 break; 909 case PPK_CustomPaperSize: 910 ret = d->customSize; 911 break; 912 case PPK_PageMargins: 913 { 914 QList<QVariant> margins; 915 if (d->hasCustomPageMargins) { 916 margins << d->leftMargin << d->topMargin 917 << d->rightMargin << d->bottomMargin; 918 } else { 919 PMPaperMargins paperMargins; 920 PMPaper paper; 921 PMGetPageFormatPaper(d->format, &paper); 922 PMPaperGetMargins(paper, &paperMargins); 923 margins << paperMargins.left << paperMargins.top 924 << paperMargins.right << paperMargins.bottom; 925 } 926 ret = margins; 927 break; 928 } 929 default: 930 break; 931 } 932 return ret; 933} 934 935QT_END_NAMESPACE 936 937#endif // QT_NO_PRINTER 938