|
|
|
@@ -178,9 +178,6 @@ CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, const float h, const f |
|
|
|
CGContextSetBlendMode (context, kCGBlendModeNormal);
|
|
|
|
rgbColourSpace = CGColorSpaceCreateDeviceRGB();
|
|
|
|
greyColourSpace = CGColorSpaceCreateDeviceGray();
|
|
|
|
gradientCallbacks.version = 0;
|
|
|
|
gradientCallbacks.evaluate = SavedState::gradientCallback;
|
|
|
|
gradientCallbacks.releaseInfo = 0;
|
|
|
|
setFont (Font());
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -251,7 +248,7 @@ bool CoreGraphicsContext::clipToRectangleListWithoutTest (const RectangleList<in |
|
|
|
else
|
|
|
|
{
|
|
|
|
const size_t numRects = (size_t) clipRegion.getNumRectangles();
|
|
|
|
HeapBlock <CGRect> rects (numRects);
|
|
|
|
HeapBlock<CGRect> rects (numRects);
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (const Rectangle<int>* r = clipRegion.begin(), * const e = clipRegion.end(); r != e; ++r)
|
|
|
|
@@ -519,7 +516,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans |
|
|
|
while (x > clip.origin.x) x -= iw;
|
|
|
|
while (y > clip.origin.y) y -= ih;
|
|
|
|
|
|
|
|
const int right = (int) (clip.origin.x + clip.size.width);
|
|
|
|
const int right = (int) (clip.origin.x + clip.size.width);
|
|
|
|
const int bottom = (int) (clip.origin.y + clip.size.height);
|
|
|
|
|
|
|
|
while (y < bottom)
|
|
|
|
@@ -600,7 +597,7 @@ void CoreGraphicsContext::setFont (const Font& newFont) |
|
|
|
state->fontRef = 0;
|
|
|
|
state->font = newFont;
|
|
|
|
|
|
|
|
if (OSXTypeface* osxTypeface = dynamic_cast <OSXTypeface*> (state->font.getTypeface()))
|
|
|
|
if (OSXTypeface* osxTypeface = dynamic_cast<OSXTypeface*> (state->font.getTypeface()))
|
|
|
|
{
|
|
|
|
state->fontRef = osxTypeface->fontRef;
|
|
|
|
CGContextSetFont (context, state->fontRef);
|
|
|
|
@@ -678,89 +675,78 @@ bool CoreGraphicsContext::drawTextLayout (const AttributedString& text, const Re |
|
|
|
}
|
|
|
|
|
|
|
|
CoreGraphicsContext::SavedState::SavedState()
|
|
|
|
: font (1.0f), fontRef (0), fontTransform (CGAffineTransformIdentity),
|
|
|
|
shading (0), numGradientLookupEntries (0)
|
|
|
|
: font (1.0f), fontRef (0), fontTransform (CGAffineTransformIdentity), gradient (0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CoreGraphicsContext::SavedState::SavedState (const SavedState& other)
|
|
|
|
: fillType (other.fillType), font (other.font), fontRef (other.fontRef),
|
|
|
|
fontTransform (other.fontTransform), shading (0),
|
|
|
|
gradientLookupTable ((size_t) other.numGradientLookupEntries),
|
|
|
|
numGradientLookupEntries (other.numGradientLookupEntries)
|
|
|
|
fontTransform (other.fontTransform), gradient (other.gradient)
|
|
|
|
{
|
|
|
|
memcpy (gradientLookupTable, other.gradientLookupTable, sizeof (PixelARGB) * (size_t) numGradientLookupEntries);
|
|
|
|
if (gradient != 0)
|
|
|
|
CGGradientRetain (gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
CoreGraphicsContext::SavedState::~SavedState()
|
|
|
|
{
|
|
|
|
if (shading != 0)
|
|
|
|
CGShadingRelease (shading);
|
|
|
|
if (gradient != 0)
|
|
|
|
CGGradientRelease (gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreGraphicsContext::SavedState::setFill (const FillType& newFill)
|
|
|
|
{
|
|
|
|
fillType = newFill;
|
|
|
|
|
|
|
|
if (fillType.isGradient() && shading != 0)
|
|
|
|
if (gradient != 0)
|
|
|
|
{
|
|
|
|
CGShadingRelease (shading);
|
|
|
|
shading = 0;
|
|
|
|
CGGradientRelease (gradient);
|
|
|
|
gradient = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CGShadingRef CoreGraphicsContext::SavedState::getShading (CoreGraphicsContext& owner)
|
|
|
|
static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace)
|
|
|
|
{
|
|
|
|
if (shading == 0)
|
|
|
|
{
|
|
|
|
ColourGradient& g = *(fillType.gradient);
|
|
|
|
numGradientLookupEntries = g.createLookupTable (fillType.transform, gradientLookupTable) - 1;
|
|
|
|
|
|
|
|
CGFunctionRef function = CGFunctionCreate (this, 1, 0, 4, 0, &(owner.gradientCallbacks));
|
|
|
|
CGPoint p1 (convertToCGPoint (g.point1));
|
|
|
|
const int numColours = g.getNumColours();
|
|
|
|
CGFloat* const data = (CGFloat*) alloca (numColours * 5 * sizeof (CGFloat));
|
|
|
|
CGFloat* const locations = data;
|
|
|
|
CGFloat* const components = data + numColours;
|
|
|
|
CGFloat* comps = components;
|
|
|
|
|
|
|
|
if (g.isRadial)
|
|
|
|
{
|
|
|
|
shading = CGShadingCreateRadial (owner.rgbColourSpace, p1, 0,
|
|
|
|
p1, g.point1.getDistanceFrom (g.point2),
|
|
|
|
function, true, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
shading = CGShadingCreateAxial (owner.rgbColourSpace, p1,
|
|
|
|
convertToCGPoint (g.point2),
|
|
|
|
function, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
CGFunctionRelease (function);
|
|
|
|
for (int i = 0; i < numColours; ++i)
|
|
|
|
{
|
|
|
|
const Colour colour (g.getColour (i));
|
|
|
|
*comps++ = colour.getFloatRed();
|
|
|
|
*comps++ = colour.getFloatGreen();
|
|
|
|
*comps++ = colour.getFloatBlue();
|
|
|
|
*comps++ = colour.getFloatAlpha();
|
|
|
|
locations[i] = g.getColourPosition (i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return shading;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreGraphicsContext::SavedState::gradientCallback (void* info, const CGFloat* inData, CGFloat* outData)
|
|
|
|
{
|
|
|
|
const SavedState* const s = static_cast <const SavedState*> (info);
|
|
|
|
|
|
|
|
const int index = roundToInt (s->numGradientLookupEntries * inData[0]);
|
|
|
|
PixelARGB colour (s->gradientLookupTable [jlimit (0, s->numGradientLookupEntries, index)]);
|
|
|
|
colour.unpremultiply();
|
|
|
|
|
|
|
|
outData[0] = colour.getRed() / 255.0f;
|
|
|
|
outData[1] = colour.getGreen() / 255.0f;
|
|
|
|
outData[2] = colour.getBlue() / 255.0f;
|
|
|
|
outData[3] = colour.getAlpha() / 255.0f;
|
|
|
|
return CGGradientCreateWithColorComponents (colourSpace, components, locations, numColours);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreGraphicsContext::drawGradient()
|
|
|
|
{
|
|
|
|
flip();
|
|
|
|
applyTransform (state->fillType.transform);
|
|
|
|
|
|
|
|
CGContextSetInterpolationQuality (context, kCGInterpolationDefault); // (This is required for 10.4, where there's a crash if
|
|
|
|
// you draw a gradient with high quality interp enabled).
|
|
|
|
CGContextSetAlpha (context, state->fillType.getOpacity());
|
|
|
|
CGContextDrawShading (context, state->getShading (*this));
|
|
|
|
|
|
|
|
const ColourGradient& g = *state->fillType.gradient;
|
|
|
|
|
|
|
|
CGPoint p1 (convertToCGPoint (g.point1));
|
|
|
|
CGPoint p2 (convertToCGPoint (g.point2));
|
|
|
|
|
|
|
|
state->fillType.transform.transformPoints (p1.x, p1.y, p2.x, p2.y);
|
|
|
|
|
|
|
|
if (state->gradient == 0)
|
|
|
|
state->gradient = createGradient (g, rgbColourSpace);
|
|
|
|
|
|
|
|
if (g.isRadial)
|
|
|
|
CGContextDrawRadialGradient (context, state->gradient, p1, 0, p1, g.point1.getDistanceFrom (g.point2),
|
|
|
|
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
|
|
|
else
|
|
|
|
CGContextDrawLinearGradient (context, state->gradient, p1, p2,
|
|
|
|
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreGraphicsContext::createPath (const Path& path) const
|
|
|
|
@@ -917,7 +903,7 @@ CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef |
|
|
|
|
|
|
|
CGContextRef juce_getImageContext (const Image& image)
|
|
|
|
{
|
|
|
|
if (CoreGraphicsImage* const cgi = dynamic_cast <CoreGraphicsImage*> (image.getPixelData()))
|
|
|
|
if (CoreGraphicsImage* const cgi = dynamic_cast<CoreGraphicsImage*> (image.getPixelData()))
|
|
|
|
return cgi->context;
|
|
|
|
|
|
|
|
jassertfalse;
|
|
|
|
|