From 05796beffddebbc789e0a29dcd4708fdd54fb1c4 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Tue, 14 Dec 2021 14:36:52 +0000 Subject: [PATCH] macOS: Fix CGImage memory access violation on Monterey --- .../native/juce_mac_CoreGraphicsContext.mm | 60 ++++++++----------- .../native/juce_mac_CoreGraphicsHelpers.h | 2 +- .../native/juce_mac_NSViewComponentPeer.mm | 2 +- .../native/juce_mac_SystemTrayIcon.cpp | 5 ++ 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm index c81701be9e3b..86bfd9a6b701 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm @@ -48,12 +48,12 @@ Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). numComponents += (size_t) lineStride; #endif - imageDataHolder->data.allocate (numComponents, clearImage); + imageData->data.allocate (numComponents, clearImage); auto colourSpace = detail::ColorSpacePtr { CGColorSpaceCreateWithName ((format == Image::SingleChannel) ? kCGColorSpaceGenericGrayGamma2_2 : kCGColorSpaceSRGB) }; - context = detail::ContextPtr { CGBitmapContextCreate (imageDataHolder->data, (size_t) width, (size_t) height, 8, (size_t) lineStride, + context = detail::ContextPtr { CGBitmapContextCreate (imageData->data, (size_t) width, (size_t) height, 8, (size_t) lineStride, colourSpace.get(), getCGImageFlags (format)) }; } @@ -71,7 +71,7 @@ Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override { - bitmap.data = imageDataHolder->data + x * pixelStride + y * lineStride; + bitmap.data = imageData->data + x * pixelStride + y * lineStride; bitmap.pixelFormat = pixelFormat; bitmap.lineStride = lineStride; bitmap.pixelStride = pixelStride; @@ -86,7 +86,7 @@ void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::Bitma ImagePixelData::Ptr clone() override { auto im = new CoreGraphicsPixelData (pixelFormat, width, height, false); - memcpy (im->imageDataHolder->data, imageDataHolder->data, (size_t) (lineStride * height)); + memcpy (im->imageData->data, imageData->data, (size_t) (lineStride * height)); return *im; } @@ -98,12 +98,9 @@ static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef col auto cgim = dynamic_cast (juceImage.getPixelData()); if (cgim != nullptr && cgim->cachedImageRef != nullptr) - { - CGImageRetain (cgim->cachedImageRef.get()); - return cgim->cachedImageRef.get(); - } + return CGImageRetain (cgim->cachedImageRef.get()); - CGImageRef ref = createImage (juceImage, colourSpace, false); + CGImageRef ref = createImage (juceImage, colourSpace); if (cgim != nullptr) cgim->cachedImageRef.reset (CGImageRetain (ref)); @@ -111,33 +108,25 @@ static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef col return ref; } - static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, bool mustOutliveSource) + static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace) { const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly); detail::DataProviderPtr provider; - if (mustOutliveSource) + if (auto* cgim = dynamic_cast (juceImage.getPixelData())) + { + provider = detail::DataProviderPtr { CGDataProviderCreateWithData (new ImageDataContainer::Ptr (cgim->imageData), + srcData.data, + (size_t) srcData.lineStride * (size_t) srcData.height, + [] (void * __nullable info, const void*, size_t) { delete (ImageDataContainer::Ptr*) info; }) }; + } + else { CFUniquePtr data (CFDataCreate (nullptr, (const UInt8*) srcData.data, (CFIndex) ((size_t) srcData.lineStride * (size_t) srcData.height))); provider = detail::DataProviderPtr { CGDataProviderCreateWithCFData (data.get()) }; } - else - { - auto* imageDataContainer = [] (const Image& img) -> HeapBlockContainer::Ptr* - { - if (auto* cgim = dynamic_cast (img.getPixelData())) - return new HeapBlockContainer::Ptr (cgim->imageDataHolder); - - return nullptr; - } (juceImage); - - provider = detail::DataProviderPtr { CGDataProviderCreateWithData (imageDataContainer, - srcData.data, - (size_t) srcData.lineStride * (size_t) srcData.height, - [] (void * __nullable info, const void*, size_t) { delete (HeapBlockContainer::Ptr*) info; }) }; - } CGImageRef imageRef = CGImageCreate ((size_t) srcData.width, (size_t) srcData.height, @@ -154,13 +143,17 @@ static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpa detail::ContextPtr context; detail::ImagePtr cachedImageRef; - struct HeapBlockContainer : public ReferenceCountedObject + struct ImageDataContainer : public ReferenceCountedObject { - using Ptr = ReferenceCountedObjectPtr; + ImageDataContainer() = default; + + using Ptr = ReferenceCountedObjectPtr; HeapBlock data; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageDataContainer) }; - HeapBlockContainer::Ptr imageDataHolder = new HeapBlockContainer(); + ImageDataContainer::Ptr imageData = new ImageDataContainer(); int pixelStride, lineStride; private: @@ -329,7 +322,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) if (sourceImage.getFormat() != Image::SingleChannel) singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel); - auto image = detail::ImagePtr { CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace.get(), true) }; + auto image = detail::ImagePtr { CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace.get()) }; flip(); auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform); @@ -899,10 +892,9 @@ Image juce_createImageFromCIImage (CIImage* im, int w, int h) return Image (*cgImage); } -CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace, - const bool mustOutliveSource) +CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace) { - return CoreGraphicsPixelData::createImage (juceImage, colourSpace, mustOutliveSource); + return CoreGraphicsPixelData::createImage (juceImage, colourSpace); } CGContextRef juce_getImageContext (const Image& image) @@ -941,7 +933,7 @@ Image juce_createImageFromUIImage (UIImage* img) [im setSize: requiredSize]; detail::ColorSpacePtr colourSpace { CGColorSpaceCreateWithName (kCGColorSpaceSRGB) }; - detail::ImagePtr imageRef { juce_createCoreGraphicsImage (image, colourSpace.get(), true) }; + detail::ImagePtr imageRef { juce_createCoreGraphicsImage (image, colourSpace.get()) }; NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: imageRef.get()]; [imageRep setSize: requiredSize]; diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h b/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h index 89c9cf99fea4..424a608b4adf 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h @@ -94,7 +94,7 @@ namespace #endif } -CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource); +CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef); CGContextRef juce_getImageContext (const Image&); #if JUCE_IOS diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 6598f1a6dcb2..205ac732a376 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -925,7 +925,7 @@ Image temp (component.isOpaque() ? Image::RGB : Image::ARGB, } detail::ColorSpacePtr colourSpace { CGColorSpaceCreateWithName (kCGColorSpaceSRGB) }; - CGImageRef image = juce_createCoreGraphicsImage (temp, colourSpace.get(), false); + CGImageRef image = juce_createCoreGraphicsImage (temp, colourSpace.get()); CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, r.origin.x, r.origin.y + clipH)); CGContextDrawImage (cg, CGRectMake (0.0f, 0.0f, clipW, clipH), image); CGImageRelease (image); diff --git a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp index af34082a573b..dc33b0c0cf91 100644 --- a/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp +++ b/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp @@ -112,6 +112,11 @@ struct ButtonBasedStatusItem : public StatusItemContainer #endif } + ~ButtonBasedStatusItem() override + { + [statusItem.get() button].image = nullptr; + } + void configureIcon() override { [statusIcon.get() setTemplate: true];