FillType gradient affine transform broken with CoreGraphics renderer

It appears that applying affine transforms that include translations are not rendered correctly with the macOS CoreGraphics context in JUCE 5.4.1.

Consider the following example code:

paint(Graphics& g)
{
const auto bounds = getLocalBounds();
ColourGradient gradient(Colours::black, Point(0,0), Colours::white, Point(10,10), true );
FillType fill(gradient);
g.setFillType(fill.transformed(AffineTransform().translated(bounds.getCentreX(), bounds.getCentreY())));
g.fillAll();
}

This code should render a small circular gradient blob at the centre of the canvas. However, it does render the blob at the bottom right corner of the canvas.

The problem appears to be located in juce_mac_CoreGraphicsContext.mm where CoreGraphicsContext::drawGradient() transforms the gradient twice. First in line 793 the filltype affine transform is applied to the entire canvas, then in line 801 the gradient defining points are transformed again. This results in the gradient being shifted twice, ending up at the wrong location.

Apart from that, transforming the gradient-defining points is not the proper way to transform a gradient, as it will mess up all affine transforms that are not angle-preserving.

Removing line juce_mac_CoreGraphicsContext.mm:801 restores the proper and expected behaviour.

I have not checked the implementation in other renderers. So when you’re fixing this, please make sure to check there, too.

Thanks for reporting, it’s hard to believe that this has been around since 2013! I’ve pushed a fix to the develop branch in a5e5831. It seems like this was only an issue in the CoreGraphics renderer and the software and OpenGL renderers are unaffected.