macOS: Clean up and deduplicate QMacCGContext

We now use QCFType to track the CGContextRef, instead of manually
maintaining the lifetime of the context. A bunch of unused methods
were removed, including completely broken ones like isNull().

Change-Id: Ib5a05aadbf8f228192e74c9a4c8919580b831497
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Tor Arne Vestbø 2019-03-22 15:13:25 +01:00
parent b556890a9f
commit 585150e3d9
2 changed files with 95 additions and 103 deletions

View File

@ -366,40 +366,35 @@ void qt_mac_scale_region(QRegion *region, qreal scaleFactor)
// ---------------------- QMacCGContext ----------------------
QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0)
QMacCGContext::QMacCGContext(QPaintDevice *paintDevice)
{
// In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood.
QImage *image = 0;
if (paintDevice->devType() == QInternal::Image) {
image = static_cast<QImage *>(paintDevice);
} else if (paintDevice->devType() == QInternal::Pixmap) {
const QPixmap *pm = static_cast<const QPixmap*>(paintDevice);
QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data();
if (data && data->classId() == QPlatformPixmap::RasterClass) {
image = data->buffer();
} else {
qDebug("QMacCGContext: Unsupported pixmap class");
}
} else if (paintDevice->devType() == QInternal::Widget) {
// TODO test: image = static_cast<QImage *>(static_cast<const QWidget *>(paintDevice)->backingStore()->paintDevice());
qDebug("QMacCGContext: not implemented: Widget class");
}
if (!image)
return; // Context type not supported.
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
CGContextTranslateCTM(context, 0, image->height());
const qreal devicePixelRatio = paintDevice->devicePixelRatioF();
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGContextScaleCTM(context, 1, -1);
initialize(paintDevice);
}
QMacCGContext::QMacCGContext(QPainter *painter) : context(0)
void QMacCGContext::initialize(QPaintDevice *paintDevice)
{
// Find the underlying QImage of the paint device
switch (int deviceType = paintDevice->devType()) {
case QInternal::Pixmap: {
auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle();
if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass)
initialize(platformPixmap->buffer());
else
qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
break;
}
case QInternal::Image:
initialize(static_cast<const QImage *>(paintDevice));
break;
case QInternal::Widget:
qWarning() << "QMacCGContext: not implemented: Widget class";
break;
default:
qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType;
}
}
QMacCGContext::QMacCGContext(QPainter *painter)
{
QPaintEngine *paintEngine = painter->paintEngine();
@ -414,51 +409,68 @@ QMacCGContext::QMacCGContext(QPainter *painter) : context(0)
return;
}
int devType = painter->device()->devType();
if (paintEngine->type() == QPaintEngine::Raster
&& (devType == QInternal::Widget ||
devType == QInternal::Pixmap ||
devType == QInternal::Image)) {
const QImage *image = static_cast<const QImage *>(paintEngine->paintDevice());
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
// Invert y axis
CGContextTranslateCTM(context, 0, image->height());
CGContextScaleCTM(context, 1, -1);
const qreal devicePixelRatio = image->devicePixelRatio();
if (devType == QInternal::Widget) {
// Set the clip rect which is an intersection of the system clip
// and the painter clip. To make matters more interesting these
// are in device pixels and device-independent pixels, respectively.
QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels
QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels
if (painter->hasClipping()) {
QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels
qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels
r.translate(native.dx(), native.dy());
if (clip.isEmpty())
clip = r;
else
clip &= r;
}
qt_mac_clip_cg(context, clip, 0); // clip in device pixels
// Scale the context so that painting happens in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio);
} else {
// Scale to paint in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
}
} else {
qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType;
if (paintEngine->type() != QPaintEngine::Raster) {
qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type();
return;
}
// The raster paint engine always operates on a QImage
Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image);
// On behalf of one of these supported painter devices
switch (int painterDeviceType = painter->device()->devType()) {
case QInternal::Pixmap:
case QInternal::Image:
case QInternal::Widget:
break;
default:
qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType;
return;
}
// Applying the clip is so entangled with the rest of the context setup
// that for simplicity we just pass in the painter.
initialize(static_cast<const QImage *>(paintEngine->paintDevice()), painter);
}
void QMacCGContext::initialize(const QImage *image, QPainter *painter)
{
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
// Invert y axis
CGContextTranslateCTM(context, 0, image->height());
CGContextScaleCTM(context, 1, -1);
const qreal devicePixelRatio = image->devicePixelRatio();
if (painter && painter->device()->devType() == QInternal::Widget) {
// Set the clip rect which is an intersection of the system clip and the painter clip
QRegion clip = painter->paintEngine()->systemClip();
QTransform deviceTransform = painter->deviceTransform();
if (painter->hasClipping()) {
// To make matters more interesting the painter clip is in device-independent pixels,
// so we need to scale it to match the device-pixels of the system clip.
QRegion painterClip = painter->clipRegion();
qt_mac_scale_region(&painterClip, devicePixelRatio);
painterClip.translate(deviceTransform.dx(), deviceTransform.dy());
if (clip.isEmpty())
clip = painterClip;
else
clip &= painterClip;
}
qt_mac_clip_cg(context, clip, 0);
CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy());
}
// Scale the context so that painting happens in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
}
QT_END_NAMESPACE

View File

@ -51,6 +51,8 @@
// We mean it.
//
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/qregion.h>
#include <QtGui/qpalette.h>
@ -89,38 +91,16 @@ Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color);
class Q_GUI_EXPORT QMacCGContext
{
public:
inline QMacCGContext() { context = 0; }
QMacCGContext() = default;
QMacCGContext(QPaintDevice *pdev);
QMacCGContext(QPainter *p);
inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) {
context = cg;
if (!takeOwnership)
CGContextRetain(context);
}
inline QMacCGContext(const QMacCGContext &copy) : context(0) { *this = copy; }
inline ~QMacCGContext() {
if (context)
CGContextRelease(context);
}
inline bool isNull() const { return context; }
inline operator CGContextRef() { return context; }
inline QMacCGContext &operator=(const QMacCGContext &copy) {
if (context)
CGContextRelease(context);
context = copy.context;
CGContextRetain(context);
return *this;
}
inline QMacCGContext &operator=(CGContextRef cg) {
if (context)
CGContextRelease(context);
context = cg;
CGContextRetain(context); //we do not take ownership
return *this;
}
operator CGContextRef() { return context; }
private:
CGContextRef context;
void initialize(QPaintDevice *paintDevice);
void initialize(const QImage *, QPainter *painter = nullptr);
QCFType<CGContextRef> context;
};
QT_END_NAMESPACE