Port QMacPrintEngine and QCoreGraphicsPaintEngine from Qt 4 to Qt 5

Copy qprintengine_mac_p.h, qprintengine_mac.mm, qpaintengine_mac_p.h,
and qpaintengine_mac.cpp (as qpaintengine_mac.mm) from src/gui/painting/
in the 4.8 branch of http://git.gitorious.org/qt/qt.git at commit
e6bd33d4aef0e4538d7918e7ab130624c911b553.

The following changes are necessary to port these files to the Qt 5 API:

- The copyright notice on these files has been updated to match the
  header.LGPL template.

- Fix #includes for qprintengine_mac* and qpaintengine_mac*, as some
  headers have moved in Qt 5.

- Remove extern forward declarations for functions that no longer exist.

- Remove friend declarations for classes/functions that are not part of
  the Cocoa platform plugin.

- Remove QT_MAC_USE_COCOA blocks. Qt is always using Cocoa now, there
  is no need to keep the non-Cocoa code paths anymore. The
  QMacPrintEngine::shouldSuppressStatus() method was also removed,
  since it is no longer used.

- Do not use Qt::UniteClip, it was removed in commit
  01b72952c3

- Use QCocoaAutoReleasePool in qprintengine_mac.mm

- Use QPlatformPrintSupport::convert*() functions in QMacPrintEngine,
  since we cannot use non-exported functions from QtPrintSupport in the
  Cocoa plugin.

- Use qt_mac_image_to_cg_image() to convert QPixmap to CGImageRef. First
  convert QPixmap to QImage (cheap, since the Cocoa platform plugin
  uses QRasterPlatformPixmap), and then convert the QImage to CFImageRef
  using the existing helper function.

- Copy qt_mac_cg_context() to the Cocoa platform plugin from
  qmacstyle_mac.mm, adding a note at each location about the
  duplication.

- Add qt_mac_QRegionToHIMutableShape() helper. Adapt the Qt 4.x code for
  QRegion::toHIMutableShape(), and use this in QCoreGraphicsPaintEngine.

- Add qt_mac_drawCGImage() and qt_mac_get_scalefactor() helper. These
  functions are copied directly from the 4.8 branch of
  http://git.gitorious.org/qt/qt.git at the same revision shown above.

- Add qt_mac_create_imagemask() helper in qpaintengine_mac.cpp.  This
  helper is based on the function with the same name from the 4.8
  branch of http://git.gitorious.org/qt/qt.git at the same revision
  shown above. The correctness of the implementation has not yet been
  verified.

Since these files use the QPrinter API from QtPrintSupport, the Cocoa
plugin now needs to link to that library as well.

Change-Id: I90b9bbe201327489ef9e1b3294e68e91ddda27bd
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
This commit is contained in:
Bradley T. Hughes 2012-03-02 12:17:24 +01:00 committed by Qt by Nokia
parent cad51669d8
commit 7e3c632e96
9 changed files with 3079 additions and 2 deletions

View File

@ -32,6 +32,8 @@ OBJECTIVE_SOURCES += main.mm \
qmacmime.mm \
qcocoasystemsettings.mm \
qcocoainputcontext.mm \
qpaintengine_mac.mm \
qprintengine_mac.mm \
HEADERS += qcocoaintegration.h \
qcocoatheme.h \
@ -61,13 +63,15 @@ HEADERS += qcocoaintegration.h \
qmacmime.h \
qcocoasystemsettings.h \
qcocoainputcontext.h \
qpaintengine_mac_p.h \
qprintengine_mac_p.h \
FORMS += $$PWD/../../../widgets/dialogs/qfiledialog.ui
RESOURCES += qcocoaresources.qrc
LIBS += -framework Cocoa
QT += core-private gui-private widgets-private platformsupport-private
QT += core-private gui-private widgets-private platformsupport-private printsupport
OTHER_FILES += cocoa.json
target.path += $$[QT_INSTALL_PLUGINS]/platforms

View File

@ -76,6 +76,13 @@ NSSize qt_mac_toNSSize(const QSize &qtSize);
QColor qt_mac_toQColor(const NSColor *color);
// Creates a mutable shape, it's the caller's responsibility to release.
HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion &region);
OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage);
CGFloat qt_mac_get_scalefactor();
QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);

View File

@ -132,6 +132,22 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm)
return qt_mac_cgimage_to_nsimage(qt_mac_image_to_cgimage(image));
}
HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion &region)
{
HIMutableShapeRef shape = HIShapeCreateMutable();
QVector<QRect> rects = region.rects();
if (!rects.isEmpty()) {
int n = rects.count();
const QRect *qt_r = rects.constData();
while (n--) {
CGRect cgRect = CGRectMake(qt_r->x(), qt_r->y(), qt_r->width(), qt_r->height());
HIShapeUnionWithRect(shape, &cgRect);
++qt_r;
}
}
return shape;
}
NSSize qt_mac_toNSSize(const QSize &qtSize)
{
return NSMakeSize(qtSize.width(), qtSize.height());
@ -538,4 +554,31 @@ NSRect qt_mac_flipRect(const QRect &rect, QWindow *window)
return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
}
OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
{
// Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
OSStatus err = noErr;
require_action(inContext != NULL, InvalidContext, err = paramErr);
require_action(inBounds != NULL, InvalidBounds, err = paramErr);
require_action(inImage != NULL, InvalidImage, err = paramErr);
CGContextSaveGState( inContext );
CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
CGContextScaleCTM(inContext, 1, -1);
CGContextDrawImage(inContext, *inBounds, inImage);
CGContextRestoreGState(inContext);
InvalidImage:
InvalidBounds:
InvalidContext:
return err;
}
CGFloat qt_mac_get_scalefactor()
{
return [[NSScreen mainScreen] userSpaceScaleFactor];
}
QT_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,254 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QPAINTENGINE_MAC_P_H
#define QPAINTENGINE_MAC_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "QtGui/qpaintengine.h"
#include "private/qpaintengine_p.h"
#include "private/qpolygonclipper_p.h"
#include "private/qfont_p.h"
#include "QtCore/qhash.h"
#include "qt_mac_p.h"
typedef struct CGColorSpace *CGColorSpaceRef;
QT_BEGIN_NAMESPACE
class QCoreGraphicsPaintEnginePrivate;
class QCoreGraphicsPaintEngine : public QPaintEngine
{
Q_DECLARE_PRIVATE(QCoreGraphicsPaintEngine)
public:
QCoreGraphicsPaintEngine();
~QCoreGraphicsPaintEngine();
bool begin(QPaintDevice *pdev);
bool end();
static CGColorSpaceRef macGenericColorSpace();
static CGColorSpaceRef macDisplayColorSpace(const QWidget *widget = 0);
void updateState(const QPaintEngineState &state);
void updatePen(const QPen &pen);
void updateBrush(const QBrush &brush, const QPointF &pt);
void updateFont(const QFont &font);
void updateOpacity(qreal opacity);
void updateMatrix(const QTransform &matrix);
void updateTransform(const QTransform &matrix);
void updateClipRegion(const QRegion &region, Qt::ClipOperation op);
void updateClipPath(const QPainterPath &path, Qt::ClipOperation op);
void updateCompositionMode(QPainter::CompositionMode mode);
void updateRenderHints(QPainter::RenderHints hints);
void drawLines(const QLineF *lines, int lineCount);
void drawRects(const QRectF *rects, int rectCount);
void drawPoints(const QPointF *p, int pointCount);
void drawEllipse(const QRectF &r);
void drawPath(const QPainterPath &path);
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
void drawTextItem(const QPointF &pos, const QTextItem &item);
void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
Type type() const { return QPaintEngine::CoreGraphics; }
CGContextRef handle() const;
static void initialize();
static void cleanup();
QPainter::RenderHints supportedRenderHints() const;
//avoid partial shadowed overload warnings...
void drawLines(const QLine *lines, int lineCount) { QPaintEngine::drawLines(lines, lineCount); }
void drawRects(const QRect *rects, int rectCount) { QPaintEngine::drawRects(rects, rectCount); }
void drawPoints(const QPoint *p, int pointCount) { QPaintEngine::drawPoints(p, pointCount); }
void drawEllipse(const QRect &r) { QPaintEngine::drawEllipse(r); }
void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
bool supportsTransformations(qreal, const QTransform &) const { return true; };
protected:
friend class QMacPrintEngine;
friend class QMacPrintEnginePrivate;
QCoreGraphicsPaintEngine(QPaintEnginePrivate &dptr);
private:
static bool m_postRoutineRegistered;
static CGColorSpaceRef m_genericColorSpace;
static QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
static void cleanUpMacColorSpaces();
Q_DISABLE_COPY(QCoreGraphicsPaintEngine)
};
/*****************************************************************************
Private data
*****************************************************************************/
class QCoreGraphicsPaintEnginePrivate : public QPaintEnginePrivate
{
Q_DECLARE_PUBLIC(QCoreGraphicsPaintEngine)
public:
QCoreGraphicsPaintEnginePrivate()
: hd(0), shading(0), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
{
}
struct {
QPen pen;
QBrush brush;
uint clipEnabled : 1;
QRegion clip;
QTransform transform;
} current;
//state info (shared with QD)
CGAffineTransform orig_xform;
//cg structures
CGContextRef hd;
CGShadingRef shading;
int stackCount;
bool complexXForm;
bool disabledSmoothFonts;
enum { CosmeticNone, CosmeticTransformPath, CosmeticSetPenWidth } cosmeticPen;
// pixel and cosmetic pen size in user coordinates.
QPointF pixelSize;
float cosmeticPenSize;
//internal functions
enum { CGStroke=0x01, CGEOFill=0x02, CGFill=0x04 };
void drawPath(uchar ops, CGMutablePathRef path = 0);
void setClip(const QRegion *rgn=0);
void resetClip();
void setFillBrush(const QPointF &origin=QPoint());
void setStrokePen(const QPen &pen);
inline void saveGraphicsState();
inline void restoreGraphicsState();
float penOffset();
QPointF devicePixelSize(CGContextRef context);
float adjustPenWidth(float penWidth);
inline void setTransform(const QTransform *matrix=0)
{
CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
CGAffineTransform xform = orig_xform;
if (matrix) {
extern CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &);
xform = CGAffineTransformConcat(qt_mac_convert_transform_to_cg(*matrix), xform);
}
CGContextConcatCTM(hd, xform);
CGContextSetTextMatrix(hd, xform);
}
};
inline void QCoreGraphicsPaintEnginePrivate::saveGraphicsState()
{
++stackCount;
CGContextSaveGState(hd);
}
inline void QCoreGraphicsPaintEnginePrivate::restoreGraphicsState()
{
--stackCount;
Q_ASSERT(stackCount >= 0);
CGContextRestoreGState(hd);
}
class QMacQuartzPaintDevice : public QPaintDevice
{
public:
QMacQuartzPaintDevice(CGContextRef cg, int width, int height, int bytesPerLine)
: mCG(cg), mWidth(width), mHeight(height), mBytesPerLine(bytesPerLine)
{ }
int devType() const { return QInternal::MacQuartz; }
CGContextRef cgContext() const { return mCG; }
int metric(PaintDeviceMetric metric) const {
switch (metric) {
case PdmWidth:
return mWidth;
case PdmHeight:
return mHeight;
case PdmWidthMM:
return (qt_defaultDpiX() * mWidth) / 2.54;
case PdmHeightMM:
return (qt_defaultDpiY() * mHeight) / 2.54;
case PdmNumColors:
return 0;
case PdmDepth:
return 32;
case PdmDpiX:
case PdmPhysicalDpiX:
return qt_defaultDpiX();
case PdmDpiY:
case PdmPhysicalDpiY:
return qt_defaultDpiY();
}
return 0;
}
QPaintEngine *paintEngine() const { qWarning("This function should never be called."); return 0; }
private:
CGContextRef mCG;
int mWidth;
int mHeight;
int mBytesPerLine;
};
QT_END_NAMESPACE
#endif // QPAINTENGINE_MAC_P_H

View File

@ -0,0 +1,823 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qprintengine_mac_p.h"
#include <qdebug.h>
#include <qthread.h>
#include <QtCore/qcoreapplication.h>
#include <QtPrintSupport/QPlatformPrinterSupport>
#include "qcocoaautoreleasepool.h"
#ifndef QT_NO_PRINTER
QT_BEGIN_NAMESPACE
QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode) : QPaintEngine(*(new QMacPrintEnginePrivate))
{
Q_D(QMacPrintEngine);
d->mode = mode;
d->initialize();
}
bool QMacPrintEngine::begin(QPaintDevice *dev)
{
Q_D(QMacPrintEngine);
Q_ASSERT(dev && dev->devType() == QInternal::Printer);
if (!static_cast<QPrinter *>(dev)->isValid())
return false;
if (d->state == QPrinter::Idle && !d->isPrintSessionInitialized()) // Need to reinitialize
d->initialize();
d->paintEngine->state = state;
d->paintEngine->begin(dev);
Q_ASSERT_X(d->state == QPrinter::Idle, "QMacPrintEngine", "printer already active");
if (PMSessionValidatePrintSettings(d->session, d->settings, kPMDontWantBoolean) != noErr
|| PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean) != noErr) {
d->state = QPrinter::Error;
return false;
}
if (!d->outputFilename.isEmpty()) {
QCFType<CFURLRef> outFile = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault,
QCFString(d->outputFilename),
kCFURLPOSIXPathStyle,
false);
if (PMSessionSetDestination(d->session, d->settings, kPMDestinationFile,
kPMDocumentFormatPDF, outFile) != noErr) {
qWarning("QMacPrintEngine::begin: Problem setting file [%s]", d->outputFilename.toUtf8().constData());
return false;
}
}
OSStatus status = PMSessionBeginCGDocumentNoDialog(d->session, d->settings, d->format);
if (status != noErr) {
d->state = QPrinter::Error;
return false;
}
d->state = QPrinter::Active;
setActive(true);
d->newPage_helper();
return true;
}
bool QMacPrintEngine::end()
{
Q_D(QMacPrintEngine);
if (d->state == QPrinter::Aborted)
return true; // I was just here a function call ago :)
if (d->paintEngine->type() == QPaintEngine::CoreGraphics) {
// We dont need the paint engine to call restoreGraphicsState()
static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->stackCount = 0;
static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = 0;
}
d->paintEngine->end();
if (d->state != QPrinter::Idle)
d->releaseSession();
d->state = QPrinter::Idle;
return true;
}
QPaintEngine *
QMacPrintEngine::paintEngine() const
{
return d_func()->paintEngine;
}
Qt::HANDLE QMacPrintEngine::handle() const
{
QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine());
return cgEngine->d_func()->hd;
}
QMacPrintEnginePrivate::~QMacPrintEnginePrivate()
{
[printInfo release];
delete paintEngine;
}
void QMacPrintEnginePrivate::setPaperSize(QPrinter::PaperSize ps)
{
Q_Q(QMacPrintEngine);
QSizeF newSize = QPlatformPrinterSupport::convertPaperSizeToQSizeF(ps);
QCFType<CFArrayRef> formats;
PMPrinter printer;
if (PMSessionGetCurrentPrinter(session, &printer) == noErr
&& PMSessionCreatePageFormatList(session, printer, &formats) == noErr) {
CFIndex total = CFArrayGetCount(formats);
PMPageFormat tmp;
PMRect paper;
for (CFIndex idx = 0; idx < total; ++idx) {
tmp = static_cast<PMPageFormat>(
const_cast<void *>(CFArrayGetValueAtIndex(formats, idx)));
PMGetUnadjustedPaperRect(tmp, &paper);
int wMM = int((paper.right - paper.left) / 72 * 25.4 + 0.5);
int hMM = int((paper.bottom - paper.top) / 72 * 25.4 + 0.5);
if (newSize.width() == wMM && newSize.height() == hMM) {
PMCopyPageFormat(tmp, format);
// reset the orientation and resolution as they are lost in the copy.
q->setProperty(QPrintEngine::PPK_Orientation, orient);
if (PMSessionValidatePageFormat(session, format, kPMDontWantBoolean) != noErr) {
// Don't know, warn for the moment.
qWarning("QMacPrintEngine, problem setting format and resolution for this page size");
}
break;
}
}
}
}
QPrinter::PaperSize QMacPrintEnginePrivate::paperSize() const
{
if (hasCustomPaperSize)
return QPrinter::Custom;
PMRect paper;
PMGetUnadjustedPaperRect(format, &paper);
QSizeF sizef((paper.right - paper.left) / 72.0 * 25.4, (paper.bottom - paper.top) / 72.0 * 25.4);
return QPlatformPrinterSupport::convertQSizeFToPaperSize(sizef);
}
QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const
{
Q_ASSERT_X(session, "QMacPrinterEngine::supportedResolutions",
"must have a valid printer session");
UInt32 resCount;
QList<QVariant> resolutions;
PMPrinter printer;
if (PMSessionGetCurrentPrinter(session, &printer) == noErr) {
PMResolution res;
OSStatus status = PMPrinterGetPrinterResolutionCount(printer, &resCount);
if (status == kPMNotImplemented) {
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
// *Sigh* we have to use the non-indexed version.
if (PMPrinterGetPrinterResolution(printer, kPMMinSquareResolution, &res) == noErr)
resolutions.append(int(res.hRes));
if (PMPrinterGetPrinterResolution(printer, kPMMaxSquareResolution, &res) == noErr) {
QVariant var(int(res.hRes));
if (!resolutions.contains(var))
resolutions.append(var);
}
if (PMPrinterGetPrinterResolution(printer, kPMDefaultResolution, &res) == noErr) {
QVariant var(int(res.hRes));
if (!resolutions.contains(var))
resolutions.append(var);
}
#endif
} else if (status == noErr) {
// According to the docs, index start at 1.
for (UInt32 i = 1; i <= resCount; ++i) {
if (PMPrinterGetIndexedPrinterResolution(printer, i, &res) == noErr)
resolutions.append(QVariant(int(res.hRes)));
}
} else {
qWarning("QMacPrintEngine::supportedResolutions: Unexpected error: %ld", long(status));
}
}
return resolutions;
}
QPrinter::PrinterState QMacPrintEngine::printerState() const
{
return d_func()->state;
}
bool QMacPrintEngine::newPage()
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
OSStatus err =
PMSessionEndPageNoDialog(d->session);
if (err != noErr) {
if (err == kPMCancel) {
// User canceled, we need to abort!
abort();
} else {
// Not sure what the problem is...
qWarning("QMacPrintEngine::newPage: Cannot end current page. %ld", long(err));
d->state = QPrinter::Error;
}
return false;
}
return d->newPage_helper();
}
bool QMacPrintEngine::abort()
{
Q_D(QMacPrintEngine);
if (d->state != QPrinter::Active)
return false;
bool ret = end();
d->state = QPrinter::Aborted;
return ret;
}
static inline int qt_get_PDMWidth(PMPageFormat pformat, bool fullPage,
const PMResolution &resolution)
{
int val = 0;
PMRect r;
qreal hRatio = resolution.hRes / 72;
if (fullPage) {
if (PMGetAdjustedPaperRect(pformat, &r) == noErr)
val = qRound((r.right - r.left) * hRatio);
} else {
if (PMGetAdjustedPageRect(pformat, &r) == noErr)
val = qRound((r.right - r.left) * hRatio);
}
return val;
}
static inline int qt_get_PDMHeight(PMPageFormat pformat, bool fullPage,
const PMResolution &resolution)
{
int val = 0;
PMRect r;
qreal vRatio = resolution.vRes / 72;
if (fullPage) {
if (PMGetAdjustedPaperRect(pformat, &r) == noErr)
val = qRound((r.bottom - r.top) * vRatio);
} else {
if (PMGetAdjustedPageRect(pformat, &r) == noErr)
val = qRound((r.bottom - r.top) * vRatio);
}
return val;
}
int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const
{
Q_D(const QMacPrintEngine);
int val = 1;
switch (m) {
case QPaintDevice::PdmWidth:
if (d->hasCustomPaperSize) {
val = qRound(d->customSize.width());
if (d->hasCustomPageMargins) {
val -= qRound(d->leftMargin + d->rightMargin);
} else {
QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList();
val -= qRound(margins.at(0).toDouble() + margins.at(2).toDouble());
}
} else {
val = qt_get_PDMWidth(d->format, property(PPK_FullPage).toBool(), d->resolution);
}
break;
case QPaintDevice::PdmHeight:
if (d->hasCustomPaperSize) {
val = qRound(d->customSize.height());
if (d->hasCustomPageMargins) {
val -= qRound(d->topMargin + d->bottomMargin);
} else {
QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList();
val -= qRound(margins.at(1).toDouble() + margins.at(3).toDouble());
}
} else {
val = qt_get_PDMHeight(d->format, property(PPK_FullPage).toBool(), d->resolution);
}
break;
case QPaintDevice::PdmWidthMM:
val = metric(QPaintDevice::PdmWidth);
val = int((val * 254 + 5 * d->resolution.hRes) / (10 * d->resolution.hRes));
break;
case QPaintDevice::PdmHeightMM:
val = metric(QPaintDevice::PdmHeight);
val = int((val * 254 + 5 * d->resolution.vRes) / (10 * d->resolution.vRes));
break;
case QPaintDevice::PdmPhysicalDpiX:
case QPaintDevice::PdmPhysicalDpiY: {
PMPrinter printer;
if (PMSessionGetCurrentPrinter(d->session, &printer) == noErr) {
PMResolution resolution;
PMPrinterGetOutputResolution(printer, d->settings, &resolution);
val = (int)resolution.vRes;
break;
}
//otherwise fall through
}
case QPaintDevice::PdmDpiY:
val = (int)d->resolution.vRes;
break;
case QPaintDevice::PdmDpiX:
val = (int)d->resolution.hRes;
break;
case QPaintDevice::PdmNumColors:
val = (1 << metric(QPaintDevice::PdmDepth));
break;
case QPaintDevice::PdmDepth:
val = 24;
break;
default:
val = 0;
qWarning("QPrinter::metric: Invalid metric command");
}
return val;
}
void QMacPrintEnginePrivate::initialize()
{
Q_Q(QMacPrintEngine);
Q_ASSERT(!printInfo);
if (!paintEngine)
paintEngine = new QCoreGraphicsPaintEngine();
q->gccaps = paintEngine->gccaps;
fullPage = false;
QCocoaAutoReleasePool pool;
printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]];
session = static_cast<PMPrintSession>([printInfo PMPrintSession]);
PMPrinter printer;
if (session && PMSessionGetCurrentPrinter(session, &printer) == noErr) {
QList<QVariant> resolutions = supportedResolutions();
if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) {
if (resolutions.count() > 1 && mode == QPrinter::HighResolution) {
int max = 0;
for (int i = 0; i < resolutions.count(); ++i) {
int value = resolutions.at(i).toInt();
if (value > max)
max = value;
}
resolution.hRes = resolution.vRes = max;
} else {
resolution.hRes = resolution.vRes = resolutions.at(0).toInt();
}
if (resolution.hRes == 0)
resolution.hRes = resolution.vRes = 600;
} else {
resolution.hRes = resolution.vRes = qt_defaultDpi();
}
}
settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
format = static_cast<PMPageFormat>([printInfo PMPageFormat]);
QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant>::const_iterator propC;
for (propC = valueCache.constBegin(); propC != valueCache.constEnd(); propC++) {
q->setProperty(propC.key(), propC.value());
}
}
void QMacPrintEnginePrivate::releaseSession()
{
PMSessionEndPageNoDialog(session);
PMSessionEndDocumentNoDialog(session);
[printInfo release];
printInfo = 0;
session = 0;
}
bool QMacPrintEnginePrivate::newPage_helper()
{
Q_Q(QMacPrintEngine);
Q_ASSERT(state == QPrinter::Active);
if (PMSessionError(session) != noErr) {
q->abort();
return false;
}
// pop the stack of saved graphic states, in case we get the same
// context back - either way, the stack count should be 0 when we
// get the new one
QCoreGraphicsPaintEngine *cgEngine = static_cast<QCoreGraphicsPaintEngine*>(paintEngine);
while (cgEngine->d_func()->stackCount > 0)
cgEngine->d_func()->restoreGraphicsState();
OSStatus status = PMSessionBeginPageNoDialog(session, format, 0);
if (status != noErr) {
state = QPrinter::Error;
return false;
}
QRect page = q->property(QPrintEngine::PPK_PageRect).toRect();
QRect paper = q->property(QPrintEngine::PPK_PaperRect).toRect();
CGContextRef cgContext;
OSStatus err = noErr;
err = PMSessionGetCGGraphicsContext(session, &cgContext);
if (err != noErr) {
qWarning("QMacPrintEngine::newPage: Cannot retrieve CoreGraphics context: %ld", long(err));
state = QPrinter::Error;
return false;
}
cgEngine->d_func()->hd = cgContext;
// Set the resolution as a scaling ration of 72 (the default).
CGContextScaleCTM(cgContext, 72 / resolution.hRes, 72 / resolution.vRes);
CGContextScaleCTM(cgContext, 1, -1);
CGContextTranslateCTM(cgContext, 0, -paper.height());
if (!fullPage)
CGContextTranslateCTM(cgContext, page.x() - paper.x(), page.y() - paper.y());
cgEngine->d_func()->orig_xform = CGContextGetCTM(cgContext);
cgEngine->d_func()->setClip(0);
cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty
& ~(QPaintEngine::DirtyClipEnabled
| QPaintEngine::DirtyClipRegion
| QPaintEngine::DirtyClipPath));
if (cgEngine->painter()->hasClipping())
cgEngine->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
cgEngine->syncState();
return true;
}
void QMacPrintEngine::updateState(const QPaintEngineState &state)
{
d_func()->paintEngine->updateState(state);
}
void QMacPrintEngine::drawRects(const QRectF *r, int num)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawRects(r, num);
}
void QMacPrintEngine::drawPoints(const QPointF *points, int pointCount)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawPoints(points, pointCount);
}
void QMacPrintEngine::drawEllipse(const QRectF &r)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawEllipse(r);
}
void QMacPrintEngine::drawLines(const QLineF *lines, int lineCount)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawLines(lines, lineCount);
}
void QMacPrintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawPolygon(points, pointCount, mode);
}
void QMacPrintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawPixmap(r, pm, sr);
}
void QMacPrintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawImage(r, pm, sr, flags);
}
void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawTextItem(p, ti);
}
void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawTiledPixmap(dr, pixmap, sr);
}
void QMacPrintEngine::drawPath(const QPainterPath &path)
{
Q_D(QMacPrintEngine);
Q_ASSERT(d->state == QPrinter::Active);
d->paintEngine->drawPath(path);
}
void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &value)
{
Q_D(QMacPrintEngine);
d->valueCache.insert(key, value);
if (!d->session)
return;
switch (key) {
case PPK_CollateCopies:
break;
case PPK_ColorMode:
break;
case PPK_Creator:
break;
case PPK_DocumentName:
break;
case PPK_PageOrder:
break;
case PPK_PaperSource:
break;
case PPK_SelectionOption:
break;
case PPK_Resolution: {
PMPrinter printer;
UInt32 count;
if (PMSessionGetCurrentPrinter(d->session, &printer) != noErr)
break;
if (PMPrinterGetPrinterResolutionCount(printer, &count) != noErr)
break;
PMResolution resolution = { 0.0, 0.0 };
PMResolution bestResolution = { 0.0, 0.0 };
int dpi = value.toInt();
int bestDistance = INT_MAX;
for (UInt32 i = 1; i <= count; ++i) { // Yes, it starts at 1
if (PMPrinterGetIndexedPrinterResolution(printer, i, &resolution) == noErr) {
if (dpi == int(resolution.hRes)) {
bestResolution = resolution;
break;
} else {
int distance = qAbs(dpi - int(resolution.hRes));
if (distance < bestDistance) {
bestDistance = distance;
bestResolution = resolution;
}
}
}
}
PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean);
break;
}
case PPK_FullPage:
d->fullPage = value.toBool();
break;
case PPK_CopyCount: // fallthrough
case PPK_NumberOfCopies:
PMSetCopies(d->settings, value.toInt(), false);
break;
case PPK_Orientation: {
if (d->state == QPrinter::Active) {
qWarning("QMacPrintEngine::setOrientation: Orientation cannot be changed during a print job, ignoring change");
} else {
QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt());
if (d->hasCustomPaperSize && (d->orient != newOrientation))
d->customSize = QSizeF(d->customSize.height(), d->customSize.width());
d->orient = newOrientation;
PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape;
PMSetOrientation(d->format, o, false);
PMSessionValidatePageFormat(d->session, d->format, kPMDontWantBoolean);
}
break; }
case PPK_OutputFileName:
d->outputFilename = value.toString();
break;
case PPK_PaperSize:
d->setPaperSize(QPrinter::PaperSize(value.toInt()));
break;
case PPK_PrinterName: {
bool printerNameSet = false;
OSStatus status = noErr;
QCFType<CFArrayRef> printerList;
status = PMServerCreatePrinterList(kPMServerLocal, &printerList);
if (status == noErr) {
CFIndex count = CFArrayGetCount(printerList);
for (CFIndex i=0; i<count; ++i) {
PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(printerList, i)));
QString name = QCFString::toQString(PMPrinterGetName(printer));
if (name == value.toString()) {
status = PMSessionSetCurrentPMPrinter(d->session, printer);
printerNameSet = true;
break;
}
}
}
if (status != noErr)
qWarning("QMacPrintEngine::setPrinterName: Error setting printer: %ld", long(status));
if (!printerNameSet) {
qWarning("QMacPrintEngine::setPrinterName: Failed to set printer named '%s'.", qPrintable(value.toString()));
d->releaseSession();
d->state = QPrinter::Idle;
}
break; }
case PPK_SuppressSystemPrintStatus:
break;
case PPK_CustomPaperSize:
{
PMOrientation orientation;
PMGetOrientation(d->format, &orientation);
d->hasCustomPaperSize = true;
d->customSize = value.toSizeF();
if (orientation != kPMPortrait)
d->customSize = QSizeF(d->customSize.height(), d->customSize.width());
break;
}
case PPK_PageMargins:
{
QList<QVariant> margins(value.toList());
Q_ASSERT(margins.size() == 4);
d->leftMargin = margins.at(0).toDouble();
d->topMargin = margins.at(1).toDouble();
d->rightMargin = margins.at(2).toDouble();
d->bottomMargin = margins.at(3).toDouble();
d->hasCustomPageMargins = true;
break;
}
default:
break;
}
}
QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
{
Q_D(const QMacPrintEngine);
QVariant ret;
if (!d->session && d->valueCache.contains(key))
return *d->valueCache.find(key);
switch (key) {
case PPK_CollateCopies:
ret = false;
break;
case PPK_ColorMode:
ret = QPrinter::Color;
break;
case PPK_Creator:
break;
case PPK_DocumentName:
break;
case PPK_FullPage:
ret = d->fullPage;
break;
case PPK_NumberOfCopies:
ret = 1;
break;
case PPK_CopyCount: {
UInt32 copies = 1;
PMGetCopies(d->settings, &copies);
ret = (uint) copies;
break;
}
case PPK_SupportsMultipleCopies:
ret = true;
break;
case PPK_Orientation:
PMOrientation orientation;
PMGetOrientation(d->format, &orientation);
ret = orientation == kPMPortrait ? QPrinter::Portrait : QPrinter::Landscape;
break;
case PPK_OutputFileName:
ret = d->outputFilename;
break;
case PPK_PageOrder:
break;
case PPK_PaperSource:
break;
case PPK_PageRect: {
// PageRect is returned in device pixels
QRect r;
PMRect macrect, macpaper;
qreal hRatio = d->resolution.hRes / 72;
qreal vRatio = d->resolution.vRes / 72;
if (d->hasCustomPaperSize) {
r = QRect(0, 0, qRound(d->customSize.width() * hRatio), qRound(d->customSize.height() * vRatio));
if (d->hasCustomPageMargins) {
r.adjust(qRound(d->leftMargin * hRatio), qRound(d->topMargin * vRatio),
-qRound(d->rightMargin * hRatio), -qRound(d->bottomMargin * vRatio));
} else {
QList<QVariant> margins = property(QPrintEngine::PPK_PageMargins).toList();
r.adjust(qRound(margins.at(0).toDouble() * hRatio),
qRound(margins.at(1).toDouble() * vRatio),
-qRound(margins.at(2).toDouble() * hRatio),
-qRound(margins.at(3).toDouble()) * vRatio);
}
} else if (PMGetAdjustedPageRect(d->format, &macrect) == noErr
&& PMGetAdjustedPaperRect(d->format, &macpaper) == noErr)
{
if (d->fullPage || d->hasCustomPageMargins) {
r.setCoords(int(macpaper.left * hRatio), int(macpaper.top * vRatio),
int(macpaper.right * hRatio), int(macpaper.bottom * vRatio));
r.translate(-r.x(), -r.y());
if (d->hasCustomPageMargins) {
r.adjust(qRound(d->leftMargin * hRatio), qRound(d->topMargin * vRatio),
-qRound(d->rightMargin * hRatio), -qRound(d->bottomMargin * vRatio));
}
} else {
r.setCoords(int(macrect.left * hRatio), int(macrect.top * vRatio),
int(macrect.right * hRatio), int(macrect.bottom * vRatio));
r.translate(int(-macpaper.left * hRatio), int(-macpaper.top * vRatio));
}
}
ret = r;
break; }
case PPK_PaperSize:
ret = d->paperSize();
break;
case PPK_PaperRect: {
QRect r;
PMRect macrect;
qreal hRatio = d->resolution.hRes / 72;
qreal vRatio = d->resolution.vRes / 72;
if (d->hasCustomPaperSize) {
r = QRect(0, 0, qRound(d->customSize.width() * hRatio), qRound(d->customSize.height() * vRatio));
} else if (PMGetAdjustedPaperRect(d->format, &macrect) == noErr) {
r.setCoords(int(macrect.left * hRatio), int(macrect.top * vRatio),
int(macrect.right * hRatio), int(macrect.bottom * vRatio));
r.translate(-r.x(), -r.y());
}
ret = r;
break; }
case PPK_PrinterName: {
PMPrinter printer;
OSStatus status = PMSessionGetCurrentPrinter(d->session, &printer);
if (status != noErr)
qWarning("QMacPrintEngine::printerName: Failed getting current PMPrinter: %ld", long(status));
if (printer)
ret = QCFString::toQString(PMPrinterGetName(printer));
break; }
case PPK_Resolution: {
ret = d->resolution.hRes;
break;
}
case PPK_SupportedResolutions:
ret = d->supportedResolutions();
break;
case PPK_CustomPaperSize:
ret = d->customSize;
break;
case PPK_PageMargins:
{
QList<QVariant> margins;
if (d->hasCustomPageMargins) {
margins << d->leftMargin << d->topMargin
<< d->rightMargin << d->bottomMargin;
} else {
PMPaperMargins paperMargins;
PMPaper paper;
PMGetPageFormatPaper(d->format, &paper);
PMPaperGetMargins(paper, &paperMargins);
margins << paperMargins.left << paperMargins.top
<< paperMargins.right << paperMargins.bottom;
}
ret = margins;
break;
}
default:
break;
}
return ret;
}
QT_END_NAMESPACE
#endif // QT_NO_PRINTER

View File

@ -0,0 +1,157 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QPRINTENGINE_MAC_P_H
#define QPRINTENGINE_MAC_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/qprinter.h>
#include <QtPrintSupport/qprintengine.h>
#include <QtGui/private/qpainter_p.h>
#include "qpaintengine_mac_p.h"
#ifdef __OBJC__
@class NSPrintInfo;
#else
typedef void NSPrintInfo;
#endif
QT_BEGIN_NAMESPACE
class QPrinterPrivate;
class QMacPrintEnginePrivate;
class QMacPrintEngine : public QPaintEngine, public QPrintEngine
{
Q_DECLARE_PRIVATE(QMacPrintEngine)
public:
QMacPrintEngine(QPrinter::PrinterMode mode);
Qt::HANDLE handle() const;
bool begin(QPaintDevice *dev);
bool end();
virtual QPaintEngine::Type type() const { return QPaintEngine::MacPrinter; }
QPaintEngine *paintEngine() const;
void setProperty(PrintEnginePropertyKey key, const QVariant &value);
QVariant property(PrintEnginePropertyKey key) const;
QPrinter::PrinterState printerState() const;
bool newPage();
bool abort();
int metric(QPaintDevice::PaintDeviceMetric) const;
//forwarded functions
void updateState(const QPaintEngineState &state);
virtual void drawLines(const QLineF *lines, int lineCount);
virtual void drawRects(const QRectF *r, int num);
virtual void drawPoints(const QPointF *p, int pointCount);
virtual void drawEllipse(const QRectF &r);
virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags);
virtual void drawTextItem(const QPointF &p, const QTextItem &ti);
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawPath(const QPainterPath &);
};
class QMacPrintEnginePrivate : public QPaintEnginePrivate
{
Q_DECLARE_PUBLIC(QMacPrintEngine)
public:
QPrinter::PrinterMode mode;
QPrinter::PrinterState state;
QPrinter::Orientation orient;
NSPrintInfo *printInfo;
PMPageFormat format;
PMPrintSettings settings;
PMPrintSession session;
PMResolution resolution;
QString outputFilename;
bool fullPage;
QPaintEngine *paintEngine;
bool hasCustomPaperSize;
QSizeF customSize;
bool hasCustomPageMargins;
qreal leftMargin;
qreal topMargin;
qreal rightMargin;
qreal bottomMargin;
QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant> valueCache;
QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle),
orient(QPrinter::Portrait), printInfo(0), format(0), settings(0),
session(0), paintEngine(0),
hasCustomPaperSize(false), hasCustomPageMargins(false) {}
~QMacPrintEnginePrivate();
void initialize();
void releaseSession();
bool newPage_helper();
void setPaperSize(QPrinter::PaperSize ps);
QPrinter::PaperSize paperSize() const;
QList<QVariant> supportedResolutions() const;
inline bool isPrintSessionInitialized() const
{
return printInfo != 0;
}
};
QT_END_NAMESPACE
#endif // QT_NO_PRINTER
#endif // QPRINTENGINE_WIN_P_H

View File

@ -159,7 +159,7 @@ class QMacCGContext
{
CGContextRef context;
public:
QMacCGContext(QPainter *p); //qpaintengine_mac.cpp
QMacCGContext(QPainter *p); //qpaintengine_mac.mm
inline QMacCGContext() { context = 0; }
inline QMacCGContext(const QPaintDevice *pdev) {
extern CGContextRef qt_mac_cg_context(const QPaintDevice *);

View File

@ -6390,6 +6390,7 @@ CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice)
CGContextRelease the context when finished using it.
\warning This function is only available on Mac OS X.
\warning This function is duplicated in the Cocoa platform plugin.
*/
CGContextRef qt_mac_cg_context(const QPaintDevice *pdev)