From f2ade01f4c0c33e070d89b473b4c0037aed9e7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 10 Dec 2013 10:02:51 +0100 Subject: 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 --- src/plugins/platforms/cocoa/qcocoabackingstore.mm | 2 +- src/plugins/platforms/cocoa/qcocoahelpers.h | 6 +- src/plugins/platforms/cocoa/qcocoahelpers.mm | 131 +++++---------------- .../platforms/cocoa/qcocoanativeinterface.mm | 2 +- src/plugins/platforms/cocoa/qmacmime.mm | 2 +- src/plugins/platforms/cocoa/qnsview.mm | 6 +- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 6 +- 7 files changed, 42 insertions(+), 113 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 30c15d823a..3ca611b537 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -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 diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 419bf631aa..893aa4408a 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -68,10 +68,12 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list); inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist) { return reinterpret_cast(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 T qt_mac_resolveOption(const T &fallback, const QByteArray &environment) diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index d27c134fa3..9b3198224e 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -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(info); + delete static_cast(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 dataProvider = CGDataProviderCreateWithData(image, - static_cast(image)->bits(), - image->byteCount(), - drawImageReleaseData); - - return CGImageCreate(image->width(), image->height(), 8, 32, - image->bytesPerLine(), - qt_mac_genericColorSpace(), - cgflags, dataProvider, 0, false, kCGRenderingIntentDefault); + QCFType 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 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(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), diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 85ce96a8b6..f4776342de 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -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) diff --git a/src/plugins/platforms/cocoa/qmacmime.mm b/src/plugins/platforms/cocoa/qmacmime.mm index 89d1b5f681..4274e178f7 100644 --- a/src/plugins/platforms/cocoa/qmacmime.mm +++ b/src/plugins/platforms/cocoa/qmacmime.mm @@ -565,7 +565,7 @@ QList QMacPasteboardMimeTiff::convertFromMime(const QString &mime, Q return ret; QImage img = qvariant_cast(variant); - QCFType cgimage = qt_mac_image_to_cgimage(img); + QCFType cgimage = qt_mac_toCGImage(img); QCFType data = CFDataCreateMutable(0, 0); QCFType imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 58c732de98..e246775406 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -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 diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 40d60a6a0a..61fbe3a61f 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -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 img = qt_mac_image_to_cgimage(pm.toImage()); + QCFType 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) -- cgit v1.2.3