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:
parent
ae35ebd5bc
commit
cbfbd8cf12
4 changed files with 168 additions and 157 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue