1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

CoreGraphics: Use generic colour spaces, instead of device colour spaces

This commit is contained in:
reuk 2020-06-08 10:13:13 +01:00
parent ae35ebd5bc
commit cbfbd8cf12
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
4 changed files with 168 additions and 157 deletions

View file

@ -19,6 +19,41 @@
namespace juce
{
namespace detail
{
struct ColorSpaceDelete
{
void operator() (CGColorSpaceRef ptr) const noexcept { CGColorSpaceRelease (ptr); }
};
struct ContextDelete
{
void operator() (CGContextRef ptr) const noexcept { CGContextRelease (ptr); }
};
struct DataProviderDelete
{
void operator() (CGDataProviderRef ptr) const noexcept { CGDataProviderRelease (ptr); }
};
struct ImageDelete
{
void operator() (CGImageRef ptr) const noexcept { CGImageRelease (ptr); }
};
struct GradientDelete
{
void operator() (CGGradientRef ptr) const noexcept { CGGradientRelease (ptr); }
};
//==============================================================================
using ColorSpacePtr = std::unique_ptr<CGColorSpace, ColorSpaceDelete>;
using ContextPtr = std::unique_ptr<CGContext, ContextDelete>;
using DataProviderPtr = std::unique_ptr<CGDataProvider, DataProviderDelete>;
using ImagePtr = std::unique_ptr<CGImage, ImageDelete>;
using GradientPtr = std::unique_ptr<CGGradient, GradientDelete>;
}
//==============================================================================
class CoreGraphicsContext : public LowLevelGraphicsContext
{
@ -67,9 +102,10 @@ public:
bool drawTextLayout (const AttributedString&, const Rectangle<float>&) override;
private:
CGContextRef context;
//==============================================================================
detail::ContextPtr context;
const CGFloat flipHeight;
CGColorSpaceRef rgbColourSpace, greyColourSpace;
detail::ColorSpacePtr rgbColourSpace, greyColourSpace;
mutable Rectangle<int> lastClipRect;
mutable bool lastClipRectIsValid = false;
@ -86,7 +122,7 @@ private:
CGFontRef fontRef = {};
CGAffineTransform textMatrix = CGAffineTransformIdentity,
inverseTextMatrix = CGAffineTransformIdentity;
CGGradientRef gradient = {};
detail::GradientPtr gradient = {};
};
std::unique_ptr<SavedState> state;

View file

@ -43,26 +43,23 @@ public:
imageDataHolder->data.allocate (numComponents, clearImage);
CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray()
: CGColorSpaceCreateDeviceRGB();
auto colourSpace = detail::ColorSpacePtr { CGColorSpaceCreateWithName ((format == Image::SingleChannel) ? kCGColorSpaceGenericGrayGamma2_2
: kCGColorSpaceSRGB) };
context = CGBitmapContextCreate (imageDataHolder->data, (size_t) width, (size_t) height, 8, (size_t) lineStride,
colourSpace, getCGImageFlags (format));
CGColorSpaceRelease (colourSpace);
context = detail::ContextPtr { CGBitmapContextCreate (imageDataHolder->data, (size_t) width, (size_t) height, 8, (size_t) lineStride,
colourSpace.get(), getCGImageFlags (format)) };
}
~CoreGraphicsPixelData() override
{
freeCachedImageRef();
CGContextRelease (context);
}
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
{
freeCachedImageRef();
sendDataChangeMessage();
return std::make_unique<CoreGraphicsContext> (context, height);
return std::make_unique<CoreGraphicsContext> (context.get(), height);
}
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
@ -95,14 +92,14 @@ public:
if (cgim != nullptr && cgim->cachedImageRef != nullptr)
{
CGImageRetain (cgim->cachedImageRef);
return cgim->cachedImageRef;
CGImageRetain (cgim->cachedImageRef.get());
return cgim->cachedImageRef.get();
}
CGImageRef ref = createImage (juceImage, colourSpace, false);
if (cgim != nullptr)
cgim->cachedImageRef = CGImageRetain (ref);
cgim->cachedImageRef.reset (CGImageRetain (ref));
return ref;
}
@ -110,12 +107,12 @@ public:
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, bool mustOutliveSource)
{
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
CGDataProviderRef provider;
detail::DataProviderPtr provider;
if (mustOutliveSource)
{
CFDataRef data = CFDataCreate (nullptr, (const UInt8*) srcData.data, (CFIndex) ((size_t) srcData.lineStride * (size_t) srcData.height));
provider = CGDataProviderCreateWithCFData (data);
provider = detail::DataProviderPtr { CGDataProviderCreateWithCFData (data) };
CFRelease (data);
}
else
@ -128,10 +125,10 @@ public:
return nullptr;
} (juceImage);
provider = CGDataProviderCreateWithData (imageDataContainer,
srcData.data,
(size_t) srcData.lineStride * (size_t) srcData.height,
[] (void * __nullable info, const void*, size_t) { delete (HeapBlockContainer::Ptr*) info; });
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,
@ -139,16 +136,15 @@ public:
8,
(size_t) srcData.pixelStride * 8,
(size_t) srcData.lineStride,
colourSpace, getCGImageFlags (juceImage.getFormat()), provider,
colourSpace, getCGImageFlags (juceImage.getFormat()), provider.get(),
nullptr, true, kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
return imageRef;
}
//==============================================================================
CGContextRef context;
CGImageRef cachedImageRef = {};
detail::ContextPtr context;
detail::ImagePtr cachedImageRef;
struct HeapBlockContainer : public ReferenceCountedObject
{
@ -162,11 +158,7 @@ public:
private:
void freeCachedImageRef()
{
if (cachedImageRef != CGImageRef())
{
CGImageRelease (cachedImageRef);
cachedImageRef = {};
}
cachedImageRef.reset();
}
static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format)
@ -192,8 +184,8 @@ CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, float h)
flipHeight (h),
state (new SavedState())
{
CGContextRetain (context);
CGContextSaveGState (context);
CGContextRetain (context.get());
CGContextSaveGState (context.get());
bool enableFontSmoothing
#if JUCE_DISABLE_COREGRAPHICS_FONT_SMOOTHING
@ -202,27 +194,24 @@ CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, float h)
= true;
#endif
CGContextSetShouldSmoothFonts (context, enableFontSmoothing);
CGContextSetAllowsFontSmoothing (context, enableFontSmoothing);
CGContextSetShouldAntialias (context, true);
CGContextSetBlendMode (context, kCGBlendModeNormal);
rgbColourSpace = CGColorSpaceCreateDeviceRGB();
greyColourSpace = CGColorSpaceCreateDeviceGray();
CGContextSetShouldSmoothFonts (context.get(), enableFontSmoothing);
CGContextSetAllowsFontSmoothing (context.get(), enableFontSmoothing);
CGContextSetShouldAntialias (context.get(), true);
CGContextSetBlendMode (context.get(), kCGBlendModeNormal);
rgbColourSpace.reset (CGColorSpaceCreateWithName (kCGColorSpaceSRGB));
greyColourSpace.reset (CGColorSpaceCreateWithName (kCGColorSpaceGenericGrayGamma2_2));
setFont (Font());
}
CoreGraphicsContext::~CoreGraphicsContext()
{
CGContextRestoreGState (context);
CGContextRelease (context);
CGColorSpaceRelease (rgbColourSpace);
CGColorSpaceRelease (greyColourSpace);
CGContextRestoreGState (context.get());
}
//==============================================================================
void CoreGraphicsContext::setOrigin (Point<int> o)
{
CGContextTranslateCTM (context, o.x, -o.y);
CGContextTranslateCTM (context.get(), o.x, -o.y);
if (lastClipRectIsValid)
lastClipRect.translate (-o.x, -o.y);
@ -241,7 +230,7 @@ void CoreGraphicsContext::addTransform (const AffineTransform& transform)
float CoreGraphicsContext::getPhysicalPixelScaleFactor()
{
auto t = CGContextGetUserSpaceToDeviceSpaceTransform (context);
auto t = CGContextGetUserSpaceToDeviceSpaceTransform (context.get());
auto determinant = (t.a * t.d) - (t.c * t.b);
return (float) std::sqrt (std::abs (determinant));
@ -249,8 +238,8 @@ float CoreGraphicsContext::getPhysicalPixelScaleFactor()
bool CoreGraphicsContext::clipToRectangle (const Rectangle<int>& r)
{
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(),
r.getWidth(), r.getHeight()));
CGContextClipToRect (context.get(), CGRectMake (r.getX(), flipHeight - r.getBottom(),
r.getWidth(), r.getHeight()));
if (lastClipRectIsValid)
{
@ -269,7 +258,7 @@ bool CoreGraphicsContext::clipToRectangleListWithoutTest (const RectangleList<in
{
if (clipRegion.isEmpty())
{
CGContextClipToRect (context, CGRectZero);
CGContextClipToRect (context.get(), CGRectZero);
lastClipRectIsValid = true;
lastClipRect = Rectangle<int>();
return false;
@ -282,7 +271,7 @@ bool CoreGraphicsContext::clipToRectangleListWithoutTest (const RectangleList<in
for (auto& r : clipRegion)
rects[i++] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight());
CGContextClipToRects (context, rects, numRects);
CGContextClipToRects (context.get(), rects, numRects);
lastClipRectIsValid = false;
return true;
}
@ -304,9 +293,9 @@ void CoreGraphicsContext::clipToPath (const Path& path, const AffineTransform& t
createPath (path, transform);
if (path.isUsingNonZeroWinding())
CGContextClip (context);
CGContextClip (context.get());
else
CGContextEOClip (context);
CGContextEOClip (context.get());
lastClipRectIsValid = false;
}
@ -320,19 +309,18 @@ void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const Affi
if (sourceImage.getFormat() != Image::SingleChannel)
singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel);
CGImageRef image = CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace, true);
auto image = detail::ImagePtr { CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace.get(), true) };
flip();
auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform);
applyTransform (t);
auto r = convertToCGRect (sourceImage.getBounds());
CGContextClipToMask (context, r, image);
CGContextClipToMask (context.get(), r, image.get());
applyTransform (t.inverted());
flip();
CGImageRelease (image);
lastClipRectIsValid = false;
}
}
@ -346,7 +334,7 @@ Rectangle<int> CoreGraphicsContext::getClipBounds() const
{
if (! lastClipRectIsValid)
{
auto bounds = CGRectIntegral (CGContextGetClipBoundingBox (context));
auto bounds = CGRectIntegral (CGContextGetClipBoundingBox (context.get()));
lastClipRectIsValid = true;
lastClipRect.setBounds (roundToInt (bounds.origin.x),
@ -366,18 +354,18 @@ bool CoreGraphicsContext::isClipEmpty() const
//==============================================================================
void CoreGraphicsContext::saveState()
{
CGContextSaveGState (context);
CGContextSaveGState (context.get());
stateStack.add (new SavedState (*state));
}
void CoreGraphicsContext::restoreState()
{
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
if (auto* top = stateStack.getLast())
{
state.reset (top);
CGContextSetTextMatrix (context, state->textMatrix);
CGContextSetTextMatrix (context.get(), state->textMatrix);
stateStack.removeLast (1, false);
lastClipRectIsValid = false;
@ -391,13 +379,13 @@ void CoreGraphicsContext::restoreState()
void CoreGraphicsContext::beginTransparencyLayer (float opacity)
{
saveState();
CGContextSetAlpha (context, opacity);
CGContextBeginTransparencyLayer (context, nullptr);
CGContextSetAlpha (context.get(), opacity);
CGContextBeginTransparencyLayer (context.get(), nullptr);
}
void CoreGraphicsContext::endTransparencyLayer()
{
CGContextEndTransparencyLayer (context);
CGContextEndTransparencyLayer (context.get());
restoreState();
}
@ -408,9 +396,9 @@ void CoreGraphicsContext::setFill (const FillType& fillType)
if (fillType.isColour())
{
CGContextSetRGBFillColor (context, fillType.colour.getFloatRed(), fillType.colour.getFloatGreen(),
CGContextSetRGBFillColor (context.get(), fillType.colour.getFloatRed(), fillType.colour.getFloatGreen(),
fillType.colour.getFloatBlue(), fillType.colour.getFloatAlpha());
CGContextSetAlpha (context, 1.0f);
CGContextSetAlpha (context.get(), 1.0f);
}
}
@ -424,9 +412,9 @@ void CoreGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality q
{
switch (quality)
{
case Graphics::lowResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationNone); return;
case Graphics::mediumResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationMedium); return;
case Graphics::highResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationHigh); return;
case Graphics::lowResamplingQuality: CGContextSetInterpolationQuality (context.get(), kCGInterpolationNone); return;
case Graphics::mediumResamplingQuality: CGContextSetInterpolationQuality (context.get(), kCGInterpolationMedium); return;
case Graphics::highResamplingQuality: CGContextSetInterpolationQuality (context.get(), kCGInterpolationHigh); return;
default: return;
}
}
@ -446,36 +434,36 @@ void CoreGraphicsContext::fillCGRect (const CGRect& cgRect, bool replaceExisting
{
if (replaceExistingContents)
{
CGContextSetBlendMode (context, kCGBlendModeCopy);
CGContextSetBlendMode (context.get(), kCGBlendModeCopy);
fillCGRect (cgRect, false);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextSetBlendMode (context.get(), kCGBlendModeNormal);
}
else
{
if (state->fillType.isColour())
{
CGContextFillRect (context, cgRect);
CGContextFillRect (context.get(), cgRect);
}
else if (state->fillType.isGradient())
{
CGContextSaveGState (context);
CGContextClipToRect (context, cgRect);
CGContextSaveGState (context.get());
CGContextClipToRect (context.get(), cgRect);
drawGradient();
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
else
{
CGContextSaveGState (context);
CGContextClipToRect (context, cgRect);
CGContextSaveGState (context.get());
CGContextClipToRect (context.get(), cgRect);
drawImage (state->fillType.image, state->fillType.transform, true);
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
}
}
void CoreGraphicsContext::fillPath (const Path& path, const AffineTransform& transform)
{
CGContextSaveGState (context);
CGContextSaveGState (context.get());
if (state->fillType.isColour())
{
@ -484,18 +472,18 @@ void CoreGraphicsContext::fillPath (const Path& path, const AffineTransform& tra
createPath (path);
if (path.isUsingNonZeroWinding())
CGContextFillPath (context);
CGContextFillPath (context.get());
else
CGContextEOFillPath (context);
CGContextEOFillPath (context.get());
}
else
{
createPath (path, transform);
if (path.isUsingNonZeroWinding())
CGContextClip (context);
CGContextClip (context.get());
else
CGContextEOClip (context);
CGContextEOClip (context.get());
if (state->fillType.isGradient())
drawGradient();
@ -503,7 +491,7 @@ void CoreGraphicsContext::fillPath (const Path& path, const AffineTransform& tra
drawImage (state->fillType.image, state->fillType.transform, true);
}
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform)
@ -516,12 +504,12 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
auto iw = sourceImage.getWidth();
auto ih = sourceImage.getHeight();
auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace
: rgbColourSpace;
CGImageRef image = CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace);
auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace.get()
: rgbColourSpace.get();
auto image = detail::ImagePtr { CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace) };
CGContextSaveGState (context);
CGContextSetAlpha (context, state->fillType.getOpacity());
CGContextSaveGState (context.get());
CGContextSetAlpha (context.get(), state->fillType.getOpacity());
flip();
applyTransform (AffineTransform::verticalFlip (ih).followedBy (transform));
@ -530,18 +518,18 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
if (fillEntireClipAsTiles)
{
#if JUCE_IOS
CGContextDrawTiledImage (context, imageRect, image);
CGContextDrawTiledImage (context.get(), imageRect, image.get());
#else
// There's a bug in CGContextDrawTiledImage that makes it incredibly slow
// if it's doing a transformation - it's quicker to just draw lots of images manually
if (&CGContextDrawTiledImage != nullptr && transform.isOnlyTranslation())
{
CGContextDrawTiledImage (context, imageRect, image);
CGContextDrawTiledImage (context.get(), imageRect, image.get());
}
else
{
// Fallback to manually doing a tiled fill
auto clip = CGRectIntegral (CGContextGetClipBoundingBox (context));
auto clip = CGRectIntegral (CGContextGetClipBoundingBox (context.get()));
int x = 0, y = 0;
while (x > clip.origin.x) x -= iw;
@ -553,7 +541,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
while (y < bottom)
{
for (int x2 = x; x2 < right; x2 += iw)
CGContextDrawImage (context, CGRectMake (x2, y, iw, ih), image);
CGContextDrawImage (context.get(), CGRectMake (x2, y, iw, ih), image.get());
y += ih;
}
@ -562,11 +550,10 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
}
else
{
CGContextDrawImage (context, imageRect, image);
CGContextDrawImage (context.get(), imageRect, image.get());
}
CGImageRelease (image); // (This causes a memory bug in iOS sim 3.0 - try upgrading to a later version if you hit this)
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
//==============================================================================
@ -588,21 +575,21 @@ void CoreGraphicsContext::fillRectList (const RectangleList<float>& list)
if (state->fillType.isColour())
{
CGContextFillRects (context, rects, num);
CGContextFillRects (context.get(), rects, num);
}
else if (state->fillType.isGradient())
{
CGContextSaveGState (context);
CGContextClipToRects (context, rects, num);
CGContextSaveGState (context.get());
CGContextClipToRects (context.get(), rects, num);
drawGradient();
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
else
{
CGContextSaveGState (context);
CGContextClipToRects (context, rects, num);
CGContextSaveGState (context.get());
CGContextClipToRects (context.get(), rects, num);
drawImage (state->fillType.image, state->fillType.transform, true);
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
}
@ -616,12 +603,12 @@ void CoreGraphicsContext::setFont (const Font& newFont)
if (auto osxTypeface = dynamic_cast<OSXTypeface*> (state->font.getTypeface()))
{
state->fontRef = osxTypeface->fontRef;
CGContextSetFont (context, state->fontRef);
CGContextSetFontSize (context, state->font.getHeight() * osxTypeface->fontHeightToPointsFactor);
CGContextSetFont (context.get(), state->fontRef);
CGContextSetFontSize (context.get(), state->font.getHeight() * osxTypeface->fontHeightToPointsFactor);
state->textMatrix = osxTypeface->renderingTransform;
state->textMatrix.a *= state->font.getHorizontalScale();
CGContextSetTextMatrix (context, state->textMatrix);
CGContextSetTextMatrix (context.get(), state->textMatrix);
state->inverseTextMatrix = CGAffineTransformInvert (state->textMatrix);
}
}
@ -648,24 +635,24 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };
CGPoint positions[1] = { { x, flipHeight - roundToInt (y) } };
CGContextShowGlyphsAtPositions (context, glyphs, positions, 1);
CGContextShowGlyphsAtPositions (context.get(), glyphs, positions, 1);
}
else
{
CGContextSaveGState (context);
CGContextSaveGState (context.get());
flip();
applyTransform (transform);
CGContextConcatCTM (context, state->inverseTextMatrix);
CGContextConcatCTM (context.get(), state->inverseTextMatrix);
auto cgTransform = state->textMatrix;
cgTransform.d = -cgTransform.d;
CGContextConcatCTM (context, cgTransform);
CGContextConcatCTM (context.get(), cgTransform);
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };
CGPoint positions[1] = { { 0.0f, 0.0f } };
CGContextShowGlyphsAtPositions (context, glyphs, positions, 1);
CGContextShowGlyphsAtPositions (context.get(), glyphs, positions, 1);
CGContextRestoreGState (context);
CGContextRestoreGState (context.get());
}
}
else
@ -681,7 +668,7 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
bool CoreGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle<float>& area)
{
CoreTextTypeLayout::drawToCGContext (text, area, context, (float) flipHeight);
CoreTextTypeLayout::drawToCGContext (text, area, context.get(), (float) flipHeight);
return true;
}
@ -693,27 +680,18 @@ CoreGraphicsContext::SavedState::SavedState()
CoreGraphicsContext::SavedState::SavedState (const SavedState& other)
: fillType (other.fillType), font (other.font), fontRef (other.fontRef),
textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix),
gradient (other.gradient)
gradient (other.gradient.get())
{
if (gradient != nullptr)
CGGradientRetain (gradient);
CGGradientRetain (gradient.get());
}
CoreGraphicsContext::SavedState::~SavedState()
{
if (gradient != nullptr)
CGGradientRelease (gradient);
}
CoreGraphicsContext::SavedState::~SavedState() = default;
void CoreGraphicsContext::SavedState::setFill (const FillType& newFill)
{
fillType = newFill;
if (gradient != nullptr)
{
CGGradientRelease (gradient);
gradient = nullptr;
}
gradient = nullptr;
}
static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace)
@ -745,37 +723,37 @@ void CoreGraphicsContext::drawGradient()
{
flip();
applyTransform (state->fillType.transform);
CGContextSetAlpha (context, state->fillType.getOpacity());
CGContextSetAlpha (context.get(), state->fillType.getOpacity());
auto& g = *state->fillType.gradient;
if (state->gradient == nullptr)
state->gradient = createGradient (g, rgbColourSpace);
state->gradient.reset (createGradient (g, rgbColourSpace.get()));
auto p1 = convertToCGPoint (g.point1);
auto p2 = convertToCGPoint (g.point2);
if (g.isRadial)
CGContextDrawRadialGradient (context, state->gradient, p1, 0, p1, g.point1.getDistanceFrom (g.point2),
CGContextDrawRadialGradient (context.get(), state->gradient.get(), p1, 0, p1, g.point1.getDistanceFrom (g.point2),
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
else
CGContextDrawLinearGradient (context, state->gradient, p1, p2,
CGContextDrawLinearGradient (context.get(), state->gradient.get(), p1, p2,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
}
void CoreGraphicsContext::createPath (const Path& path) const
{
CGContextBeginPath (context);
CGContextBeginPath (context.get());
for (Path::Iterator i (path); i.next();)
{
switch (i.elementType)
{
case Path::Iterator::startNewSubPath: CGContextMoveToPoint (context, i.x1, i.y1); break;
case Path::Iterator::lineTo: CGContextAddLineToPoint (context, i.x1, i.y1); break;
case Path::Iterator::quadraticTo: CGContextAddQuadCurveToPoint (context, i.x1, i.y1, i.x2, i.y2); break;
case Path::Iterator::cubicTo: CGContextAddCurveToPoint (context, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break;
case Path::Iterator::closePath: CGContextClosePath (context); break;
case Path::Iterator::startNewSubPath: CGContextMoveToPoint (context.get(), i.x1, i.y1); break;
case Path::Iterator::lineTo: CGContextAddLineToPoint (context.get(), i.x1, i.y1); break;
case Path::Iterator::quadraticTo: CGContextAddQuadCurveToPoint (context.get(), i.x1, i.y1, i.x2, i.y2); break;
case Path::Iterator::cubicTo: CGContextAddCurveToPoint (context.get(), i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break;
case Path::Iterator::closePath: CGContextClosePath (context.get()); break;
default: jassertfalse; break;
}
}
@ -783,7 +761,7 @@ void CoreGraphicsContext::createPath (const Path& path) const
void CoreGraphicsContext::createPath (const Path& path, const AffineTransform& transform) const
{
CGContextBeginPath (context);
CGContextBeginPath (context.get());
for (Path::Iterator i (path); i.next();)
{
@ -791,22 +769,22 @@ void CoreGraphicsContext::createPath (const Path& path, const AffineTransform& t
{
case Path::Iterator::startNewSubPath:
transform.transformPoint (i.x1, i.y1);
CGContextMoveToPoint (context, i.x1, flipHeight - i.y1);
CGContextMoveToPoint (context.get(), i.x1, flipHeight - i.y1);
break;
case Path::Iterator::lineTo:
transform.transformPoint (i.x1, i.y1);
CGContextAddLineToPoint (context, i.x1, flipHeight - i.y1);
CGContextAddLineToPoint (context.get(), i.x1, flipHeight - i.y1);
break;
case Path::Iterator::quadraticTo:
transform.transformPoints (i.x1, i.y1, i.x2, i.y2);
CGContextAddQuadCurveToPoint (context, i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2);
CGContextAddQuadCurveToPoint (context.get(), i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2);
break;
case Path::Iterator::cubicTo:
transform.transformPoints (i.x1, i.y1, i.x2, i.y2, i.x3, i.y3);
CGContextAddCurveToPoint (context, i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2, i.x3, flipHeight - i.y3);
CGContextAddCurveToPoint (context.get(), i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2, i.x3, flipHeight - i.y3);
break;
case Path::Iterator::closePath:
CGContextClosePath (context); break;
CGContextClosePath (context.get()); break;
default:
jassertfalse;
break;
@ -816,7 +794,7 @@ void CoreGraphicsContext::createPath (const Path& path, const AffineTransform& t
void CoreGraphicsContext::flip() const
{
CGContextConcatCTM (context, CGAffineTransformMake (1, 0, 0, -1, 0, flipHeight));
CGContextConcatCTM (context.get(), CGAffineTransformMake (1, 0, 0, -1, 0, flipHeight));
}
void CoreGraphicsContext::applyTransform (const AffineTransform& transform) const
@ -828,7 +806,7 @@ void CoreGraphicsContext::applyTransform (const AffineTransform& transform) cons
t.d = transform.mat11;
t.tx = transform.mat02;
t.ty = transform.mat12;
CGContextConcatCTM (context, t);
CGContextConcatCTM (context.get(), t);
}
//==============================================================================
@ -856,12 +834,11 @@ Image juce_loadWithCoreImage (InputStream& input)
CGImageRef loadedImage = uiImage.CGImage;
#else
auto provider = CGDataProviderCreateWithData (new MemoryBlockHolder::Ptr (memBlockHolder),
memBlockHolder->block.getData(),
memBlockHolder->block.getSize(),
[] (void * __nullable info, const void*, size_t) { delete (MemoryBlockHolder::Ptr*) info; });
auto imageSource = CGImageSourceCreateWithDataProvider (provider, nullptr);
CGDataProviderRelease (provider);
auto provider = detail::DataProviderPtr { CGDataProviderCreateWithData (new MemoryBlockHolder::Ptr (memBlockHolder),
memBlockHolder->block.getData(),
memBlockHolder->block.getSize(),
[] (void * __nullable info, const void*, size_t) { delete (MemoryBlockHolder::Ptr*) info; }) };
auto imageSource = CGImageSourceCreateWithDataProvider (provider.get(), nullptr);
if (imageSource != nullptr)
{
@ -884,8 +861,8 @@ Image juce_loadWithCoreImage (InputStream& input)
auto cgImage = dynamic_cast<CoreGraphicsPixelData*> (image.getPixelData());
jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsPixelData class should have been used.
CGContextDrawImage (cgImage->context, convertToCGRect (image.getBounds()), loadedImage);
CGContextFlush (cgImage->context);
CGContextDrawImage (cgImage->context.get(), convertToCGRect (image.getBounds()), loadedImage);
CGContextFlush (cgImage->context.get());
#if ! JUCE_IOS
CFRelease (loadedImage);
@ -908,9 +885,9 @@ Image juce_createImageFromCIImage (CIImage* im, int w, int h)
{
auto cgImage = new CoreGraphicsPixelData (Image::ARGB, w, h, false);
CIContext* cic = [CIContext contextWithCGContext: cgImage->context options: nil];
CIContext* cic = [CIContext contextWithCGContext: cgImage->context.get() options: nil];
[cic drawImage: im inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)];
CGContextFlush (cgImage->context);
CGContextFlush (cgImage->context.get());
return Image (*cgImage);
}
@ -924,7 +901,7 @@ CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef
CGContextRef juce_getImageContext (const Image& image)
{
if (auto cgi = dynamic_cast<CoreGraphicsPixelData*> (image.getPixelData()))
return cgi->context;
return cgi->context.get();
jassertfalse;
return {};
@ -953,15 +930,13 @@ CGContextRef juce_getImageContext (const Image& image)
auto requiredSize = NSMakeSize (image.getWidth() / scaleFactor, image.getHeight() / scaleFactor);
[im setSize: requiredSize];
auto colourSpace = CGColorSpaceCreateDeviceRGB();
auto imageRef = juce_createCoreGraphicsImage (image, colourSpace, true);
CGColorSpaceRelease (colourSpace);
auto colourSpace = detail::ColorSpacePtr { CGColorSpaceCreateWithName (kCGColorSpaceSRGB) };
auto imageRef = detail::ImagePtr { juce_createCoreGraphicsImage (image, colourSpace.get(), true) };
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: imageRef];
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: imageRef.get()];
[imageRep setSize: requiredSize];
[im addRepresentation: imageRep];
[imageRep release];
CGImageRelease (imageRef);
return im;
}
}

View file

@ -201,7 +201,7 @@ namespace CoreTextTypeLayout
static CFAttributedStringRef createCFAttributedString (const AttributedString& text)
{
#if JUCE_IOS
auto rgbColourSpace = CGColorSpaceCreateDeviceRGB();
auto rgbColourSpace = CGColorSpaceCreateWithName (kCGColorSpaceSRGB);
#endif
auto attribString = CFAttributedStringCreateMutable (kCFAllocatorDefault, 0);

View file

@ -909,7 +909,7 @@ public:
invokePaint (*context);
}
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGColorSpaceRef colourSpace = CGColorSpaceCreateWithName (kCGColorSpaceSRGB);
CGImageRef image = juce_createCoreGraphicsImage (temp, colourSpace, false);
CGColorSpaceRelease (colourSpace);
CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, clipW, clipH), image);