Skip to content

Commit

Permalink
macOS: Fix CGImage memory access violation on Monterey
Browse files Browse the repository at this point in the history
  • Loading branch information
tpoole committed Dec 14, 2021
1 parent 08283c9 commit 05796be
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 36 deletions.
60 changes: 26 additions & 34 deletions modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
Expand Up @@ -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)) };
}

Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -98,46 +98,35 @@ static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef col
auto cgim = dynamic_cast<CoreGraphicsPixelData*> (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));

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<CoreGraphicsPixelData*> (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<CFDataRef> 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<CoreGraphicsPixelData*> (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,
Expand All @@ -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<HeapBlockContainer>;
ImageDataContainer() = default;

using Ptr = ReferenceCountedObjectPtr<ImageDataContainer>;
HeapBlock<uint8> data;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageDataContainer)
};

HeapBlockContainer::Ptr imageDataHolder = new HeapBlockContainer();
ImageDataContainer::Ptr imageData = new ImageDataContainer();
int pixelStride, lineStride;

private:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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];
Expand Down
Expand Up @@ -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
Expand Down
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp
Expand Up @@ -112,6 +112,11 @@ struct ButtonBasedStatusItem : public StatusItemContainer
#endif
}

~ButtonBasedStatusItem() override
{
[statusItem.get() button].image = nullptr;
}

void configureIcon() override
{
[statusIcon.get() setTemplate: true];
Expand Down

0 comments on commit 05796be

Please sign in to comment.