Cocoa: QImage -> CGImage conversion cleanup
Move to one qt_mac_toCGImage function that has simple semantics and properly retains a copy of the QImage for the lifetime of the CGImage. Remove the old qt_mac_toCGImage function which had two problems: 1) It would not retain the QImage data (this was probably ok for its original use case: creating short-lived CGImages for the paint engine) 2) It had acquired a somewhat odd **datacopy out parameter for the cases where you _do_ want to retain the image data. This makes the exported image conversion function from QtMacExtras work: The CGImages it creates will no longer reference free'd memory once the QImage is deleted. Change-Id: I583040d16aefb17fc3d801d6b047a0b2a76c7f74 Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
This commit is contained in:
parent
51572d3d8f
commit
f2ade01f4c
@ -122,7 +122,7 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy)
|
||||
CGImageRef QCocoaBackingStore::getBackingStoreCGImage()
|
||||
{
|
||||
if (!m_cgImage)
|
||||
m_cgImage = qt_mac_toCGImage(m_qImage, false, 0);
|
||||
m_cgImage = qt_mac_toCGImage(m_qImage);
|
||||
|
||||
// Warning: do not retain/release/cache the returned image from
|
||||
// outside the backingstore since it shares data with a QImage and
|
||||
|
@ -68,10 +68,12 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list);
|
||||
inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist)
|
||||
{ return reinterpret_cast<NSMutableArray *>(qt_mac_QStringListToNSMutableArrayVoid(qstrlist)); }
|
||||
|
||||
CGImageRef qt_mac_image_to_cgimage(const QImage &image);
|
||||
NSImage *qt_mac_cgimage_to_nsimage(CGImageRef iamge);
|
||||
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
|
||||
NSImage *qt_mac_create_nsimage(const QIcon &icon);
|
||||
CGImageRef qt_mac_toCGImage(const QImage &qImage);
|
||||
CGImageRef qt_mac_toCGImageMask(const QImage &qImage);
|
||||
QImage qt_mac_toQImage(CGImageRef image);
|
||||
|
||||
NSSize qt_mac_toNSSize(const QSize &qtSize);
|
||||
NSRect qt_mac_toNSRect(const QRect &rect);
|
||||
@ -159,8 +161,6 @@ public:
|
||||
};
|
||||
|
||||
CGContextRef qt_mac_cg_context(QPaintDevice *pdev);
|
||||
CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy);
|
||||
QImage qt_mac_toQImage(CGImageRef image);
|
||||
|
||||
template<typename T>
|
||||
T qt_mac_resolveOption(const T &fallback, const QByteArray &environment)
|
||||
|
@ -79,24 +79,28 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void drawImageReleaseData (void *info, const void *, size_t)
|
||||
static void qt_mac_deleteImage(void *image, const void *, size_t)
|
||||
{
|
||||
delete static_cast<QImage *>(info);
|
||||
delete static_cast<QImage *>(image);
|
||||
}
|
||||
|
||||
CGImageRef qt_mac_image_to_cgimage(const QImage &img)
|
||||
// Creates a CGDataProvider with the data from the given image.
|
||||
// The data provider retains a copy of the image.
|
||||
CGDataProviderRef qt_mac_CGDataProvider(const QImage &image)
|
||||
{
|
||||
if (img.isNull())
|
||||
return CGDataProviderCreateWithData(new QImage(image), image.bits(),
|
||||
image.byteCount(), qt_mac_deleteImage);
|
||||
}
|
||||
|
||||
CGImageRef qt_mac_toCGImage(const QImage &inImage)
|
||||
{
|
||||
if (inImage.isNull())
|
||||
return 0;
|
||||
|
||||
QImage *image;
|
||||
if (img.depth() != 32)
|
||||
image = new QImage(img.convertToFormat(QImage::Format_ARGB32_Premultiplied));
|
||||
else
|
||||
image = new QImage(img);
|
||||
QImage image = (inImage.depth() == 32) ? inImage : inImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
uint cgflags = kCGImageAlphaNone;
|
||||
switch (image->format()) {
|
||||
switch (image.format()) {
|
||||
case QImage::Format_ARGB32_Premultiplied:
|
||||
cgflags = kCGImageAlphaPremultipliedFirst;
|
||||
break;
|
||||
@ -105,20 +109,26 @@ CGImageRef qt_mac_image_to_cgimage(const QImage &img)
|
||||
break;
|
||||
case QImage::Format_RGB32:
|
||||
cgflags = kCGImageAlphaNoneSkipFirst;
|
||||
break;
|
||||
case QImage::Format_RGB888:
|
||||
cgflags |= kCGImageAlphaNone;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cgflags |= kCGBitmapByteOrder32Host;
|
||||
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(image,
|
||||
static_cast<const QImage *>(image)->bits(),
|
||||
image->byteCount(),
|
||||
drawImageReleaseData);
|
||||
|
||||
return CGImageCreate(image->width(), image->height(), 8, 32,
|
||||
image->bytesPerLine(),
|
||||
qt_mac_genericColorSpace(),
|
||||
cgflags, dataProvider, 0, false, kCGRenderingIntentDefault);
|
||||
QCFType<CGDataProviderRef> dataProvider = qt_mac_CGDataProvider(image);
|
||||
return CGImageCreate(image.width(), image.height(), 8, 32,
|
||||
image.bytesPerLine(),
|
||||
qt_mac_genericColorSpace(),
|
||||
cgflags, dataProvider, 0, false, kCGRenderingIntentDefault);
|
||||
}
|
||||
|
||||
CGImageRef qt_mac_toCGImageMask(const QImage &image)
|
||||
{
|
||||
QCFType<CGDataProviderRef> dataProvider = qt_mac_CGDataProvider(image);
|
||||
return CGImageMaskCreate(image.width(), image.height(), 8, image.depth(),
|
||||
image.bytesPerLine(), dataProvider, NULL, false);
|
||||
}
|
||||
|
||||
NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image)
|
||||
@ -132,7 +142,7 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm)
|
||||
if (pm.isNull())
|
||||
return 0;
|
||||
QImage image = pm.toImage();
|
||||
CGImageRef cgImage = qt_mac_image_to_cgimage(image);
|
||||
CGImageRef cgImage = qt_mac_toCGImage(image);
|
||||
NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage);
|
||||
CGImageRelease(cgImage);
|
||||
return nsImage;
|
||||
@ -147,7 +157,7 @@ NSImage *qt_mac_create_nsimage(const QIcon &icon)
|
||||
foreach (QSize size, icon.availableSizes()) {
|
||||
QPixmap pm = icon.pixmap(size);
|
||||
QImage image = pm.toImage();
|
||||
CGImageRef cgImage = qt_mac_image_to_cgimage(image);
|
||||
CGImageRef cgImage = qt_mac_toCGImage(image);
|
||||
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
|
||||
[nsImage addRepresentation:imageRep];
|
||||
[imageRep release];
|
||||
@ -780,85 +790,6 @@ CGContextRef qt_mac_cg_context(QPaintDevice *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// qpaintengine_mac.mm
|
||||
extern void qt_mac_cgimage_data_free(void *, const void *memoryToFree, size_t);
|
||||
|
||||
CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy)
|
||||
{
|
||||
int width = qImage.width();
|
||||
int height = qImage.height();
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
qWarning() << Q_FUNC_INFO <<
|
||||
"setting invalid size" << width << "x" << height << "for qnsview image";
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uchar *imageData = qImage.bits();
|
||||
if (dataCopy) {
|
||||
*dataCopy = static_cast<uchar *>(malloc(qImage.byteCount()));
|
||||
memcpy(*dataCopy, imageData, qImage.byteCount());
|
||||
}
|
||||
int bitDepth = qImage.depth();
|
||||
int colorBufferSize = 8;
|
||||
int bytesPrLine = qImage.bytesPerLine();
|
||||
|
||||
CGDataProviderRef cgDataProviderRef = CGDataProviderCreateWithData(
|
||||
NULL,
|
||||
dataCopy ? *dataCopy : imageData,
|
||||
qImage.byteCount(),
|
||||
dataCopy ? qt_mac_cgimage_data_free : NULL);
|
||||
|
||||
CGImageRef cgImage = 0;
|
||||
if (isMask) {
|
||||
cgImage = CGImageMaskCreate(width,
|
||||
height,
|
||||
colorBufferSize,
|
||||
bitDepth,
|
||||
bytesPrLine,
|
||||
cgDataProviderRef,
|
||||
NULL,
|
||||
false);
|
||||
} else {
|
||||
CGColorSpaceRef cgColourSpaceRef = qt_mac_displayColorSpace(0);
|
||||
|
||||
// Create a CGBitmapInfo contiaining the image format.
|
||||
// Support the 8-bit per component (A)RGB formats.
|
||||
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little;
|
||||
switch (qImage.format()) {
|
||||
case QImage::Format_ARGB32_Premultiplied :
|
||||
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
|
||||
break;
|
||||
case QImage::Format_ARGB32 :
|
||||
bitmapInfo |= kCGImageAlphaFirst;
|
||||
break;
|
||||
case QImage::Format_RGB32 :
|
||||
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
|
||||
break;
|
||||
case QImage::Format_RGB888 :
|
||||
bitmapInfo |= kCGImageAlphaNone;
|
||||
break;
|
||||
default:
|
||||
qWarning() << "qt_mac_toCGImage: Unsupported image format" << qImage.format();
|
||||
break;
|
||||
}
|
||||
|
||||
cgImage = CGImageCreate(width,
|
||||
height,
|
||||
colorBufferSize,
|
||||
bitDepth,
|
||||
bytesPrLine,
|
||||
cgColourSpaceRef,
|
||||
bitmapInfo,
|
||||
cgDataProviderRef,
|
||||
NULL,
|
||||
false,
|
||||
kCGRenderingIntentDefault);
|
||||
}
|
||||
CGDataProviderRelease(cgDataProviderRef);
|
||||
return cgImage;
|
||||
}
|
||||
|
||||
QImage qt_mac_toQImage(CGImageRef image)
|
||||
{
|
||||
const size_t w = CGImageGetWidth(image),
|
||||
|
@ -248,7 +248,7 @@ void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar)
|
||||
|
||||
CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image)
|
||||
{
|
||||
return qt_mac_toCGImage(image, false, 0);
|
||||
return qt_mac_toCGImage(image);
|
||||
}
|
||||
|
||||
QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image)
|
||||
|
@ -565,7 +565,7 @@ QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, Q
|
||||
return ret;
|
||||
|
||||
QImage img = qvariant_cast<QImage>(variant);
|
||||
QCFType<CGImageRef> cgimage = qt_mac_image_to_cgimage(img);
|
||||
QCFType<CGImageRef> cgimage = qt_mac_toCGImage(img);
|
||||
|
||||
QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
|
||||
QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0);
|
||||
|
@ -80,7 +80,6 @@ static QTouchDevice *touchDevice = 0;
|
||||
if (self) {
|
||||
m_backingStore = 0;
|
||||
m_maskImage = 0;
|
||||
m_maskData = 0;
|
||||
m_shouldInvalidateWindowShadow = false;
|
||||
m_window = 0;
|
||||
m_buttons = Qt::NoButton;
|
||||
@ -106,7 +105,6 @@ static QTouchDevice *touchDevice = 0;
|
||||
{
|
||||
CGImageRelease(m_maskImage);
|
||||
m_maskImage = 0;
|
||||
m_maskData = 0;
|
||||
m_window = 0;
|
||||
m_subscribesForGlobalFrameNotifications = false;
|
||||
[m_inputSource release];
|
||||
@ -372,7 +370,7 @@ static QTouchDevice *touchDevice = 0;
|
||||
|
||||
- (BOOL) hasMask
|
||||
{
|
||||
return m_maskData != 0;
|
||||
return m_maskImage != 0;
|
||||
}
|
||||
|
||||
- (BOOL) isOpaque
|
||||
@ -405,7 +403,7 @@ static QTouchDevice *touchDevice = 0;
|
||||
dst[x] = src[x] & 0xff;
|
||||
}
|
||||
}
|
||||
m_maskImage = qt_mac_toCGImage(maskImage, true, &m_maskData);
|
||||
m_maskImage = qt_mac_toCGImageMask(maskImage);
|
||||
}
|
||||
|
||||
- (void)invalidateWindowShadowIfNeeded
|
||||
|
@ -488,7 +488,7 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c)
|
||||
if (isBitmap)
|
||||
pat->image = qt_mac_create_imagemask(pat->data.pixmap, pat->data.pixmap.rect());
|
||||
else
|
||||
pat->image = qt_mac_image_to_cgimage(pat->data.pixmap.toImage());
|
||||
pat->image = qt_mac_toCGImage(pat->data.pixmap.toImage());
|
||||
}
|
||||
} else {
|
||||
w = CGImageGetWidth(pat->image);
|
||||
@ -963,11 +963,11 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co
|
||||
CGContextSetFillColorWithColor(d->hd, cgColorForQColor(col, d->pdev));
|
||||
image = qt_mac_create_imagemask(pm, sr);
|
||||
} else if (differentSize) {
|
||||
QCFType<CGImageRef> img = qt_mac_image_to_cgimage(pm.toImage());
|
||||
QCFType<CGImageRef> img = qt_mac_toCGImage(pm.toImage());
|
||||
if (img)
|
||||
image = CGImageCreateWithImageInRect(img, CGRectMake(qRound(sr.x()), qRound(sr.y()), qRound(sr.width()), qRound(sr.height())));
|
||||
} else {
|
||||
image = qt_mac_image_to_cgimage(pm.toImage());
|
||||
image = qt_mac_toCGImage(pm.toImage());
|
||||
}
|
||||
qt_mac_drawCGImage(d->hd, &rect, image);
|
||||
if (doRestore)
|
||||
|
Loading…
Reference in New Issue
Block a user