Don't manually flip cgimages

CGImage is flipped vertically relative to what we expect (for our texture coordinates). Previously we manually flipped the image (by drawing into a software canvas and extracting a new image). This is ok, but forces a particular colorspace and pixelformat -- rather than leaving it as the coregraphics decoder chose.

This PR removes the manual flipping, and just appends an additional transform to the CTM when we reference the image. For some tests (e.g. hero_editor) this shows a speed-up as well (not sure, but likely the colorspace of the original image is closer to what CG wanted for drawing.)

Diffs=
1f9ff75d9 Don't manually flip images
diff --git a/.rive_head b/.rive_head
index 285d534..dd757ab 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-4802c650a88b7120ab5ce13cfc2c45e9584f590b
+1f9ff75d9c216c4418ab0e282b3501b2592e1e45
diff --git a/skia/renderer/src/cg_factory.cpp b/skia/renderer/src/cg_factory.cpp
index 5a8450e..9e5aaf7 100644
--- a/skia/renderer/src/cg_factory.cpp
+++ b/skia/renderer/src/cg_factory.cpp
@@ -19,6 +19,7 @@
 
 #include "utils/factory_utils.hpp"
 #include "rive/math/vec2d.hpp"
+#include "rive/core/type_conversions.hpp"
 #include "rive/shapes/paint/color.hpp"
 
 using namespace rive;
@@ -273,15 +274,21 @@
 public:
     AutoCF<CGImageRef> m_image;
 
-    CGRenderImage(const Span<const uint8_t> span) : m_image(FlipCGImageInY(DecodeToCGImage(span))) {
+    CGRenderImage(const Span<const uint8_t> span) : m_image(DecodeToCGImage(span)) {
         if (m_image) {
-            m_Width = CGImageGetWidth(m_image.get());
-            m_Height = CGImageGetHeight(m_image.get());
+            m_Width = rive::castTo<uint32_t>(CGImageGetWidth(m_image.get()));
+            m_Height = rive::castTo<uint32_t>(CGImageGetHeight(m_image.get()));
         }
     }
 
-    static CGImageRef Cast(const RenderImage* image) {
-        return reinterpret_cast<const CGRenderImage*>(image)->m_image.get();
+    Mat2D localM2D() const { return Mat2D(1, 0, 0, -1, 0, (float)m_Height); }
+
+    void applyLocalMatrix(CGContextRef ctx) const {
+        CGContextConcatCTM(ctx, CGAffineTransformMake(1, 0, 0, -1, 0, (float)m_Height));
+    }
+
+    static const CGRenderImage* Cast(const RenderImage* image) {
+        return reinterpret_cast<const CGRenderImage*>(image);
     }
 };
 
@@ -291,6 +298,8 @@
     CGContextSaveGState(ctx);
     Mat2D m(1, 0, 0, -1, 0, height);
     CGContextConcatCTM(ctx, convert(m));
+
+    CGContextSetInterpolationQuality(ctx, kCGInterpolationMedium);
 }
 
 CGRenderer::~CGRenderer() { CGContextRestoreGState(m_ctx); }
@@ -342,7 +351,9 @@
     CGContextSaveGState(m_ctx);
     CGContextSetAlpha(m_ctx, opacity);
     CGContextSetBlendMode(m_ctx, convert(blendMode));
-    CGContextDrawImage(m_ctx, bounds, CGRenderImage::Cast(image));
+    auto cgimg = CGRenderImage::Cast(image);
+    cgimg->applyLocalMatrix(m_ctx);
+    CGContextDrawImage(m_ctx, bounds, cgimg->m_image);
     CGContextRestoreGState(m_ctx);
 }
 
@@ -358,6 +369,9 @@
                                rcp<RenderBuffer> indices,
                                BlendMode blendMode,
                                float opacity) {
+    auto cgimage = CGRenderImage::Cast(image);
+    auto const localMatrix = cgimage->localM2D();
+
     const float sx = image->width();
     const float sy = image->height();
     auto const bounds = CGRectMake(0, 0, sx, sy);
@@ -397,9 +411,10 @@
         const auto v0 = scale(uvs[index0]);
         const auto v1 = scale(uvs[index1]);
         const auto v2 = scale(uvs[index2]);
-        auto mx = basis_matrix(p0, p1, p2) * basis_matrix(v0, v1, v2).invertOrIdentity();
+        auto mx =
+            basis_matrix(p0, p1, p2) * basis_matrix(v0, v1, v2).invertOrIdentity() * localMatrix;
         CGContextConcatCTM(m_ctx, convert(mx));
-        CGContextDrawImage(m_ctx, bounds, CGRenderImage::Cast(image));
+        CGContextDrawImage(m_ctx, bounds, cgimage->m_image);
 
         CGContextRestoreGState(m_ctx);
     }