vcl/inc/skia/gdiimpl.hxx |    9 +++++++--
 vcl/inc/skia/utils.hxx   |   24 ++++++++++++++++++++++--
 2 files changed, 29 insertions(+), 4 deletions(-)

New commits:
commit 7ef881c76e656ece71cf6d1d472757edf5c1ff44
Author:     Patrick Luby <guibmac...@gmail.com>
AuthorDate: Mon Jan 6 19:58:14 2025 -0500
Commit:     Patrick Luby <guibomac...@gmail.com>
CommitDate: Tue Jan 7 13:29:43 2025 +0100

    tdf#161480 use BmpScaleFlag::NearestNeighbor when upscaling on macOS
    
    On macOS, due to Retina window scaling, it is very common to
    have Skia surfaces that are 2 times the size of their respective
    output device sizes so upscaling is often the default state.
    
    But when upscaling bitmaps on macOS with either Skia/Metal or
    Skia/Raster, some distortion to color and/or alpha values is
    introduced and only BmpScaleFlag::NearestNeighbor will upscale
    the bitmap correctly.
    
    Change-Id: I9cf02d3acace82751fa6e114aaecf23cbbb85c65
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179848
    Tested-by: Jenkins
    Reviewed-by: Patrick Luby <guibomac...@gmail.com>

diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index c261e4af97c1..9ed245e7c696 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -292,7 +292,10 @@ protected:
     void performDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double 
transparency,
                                 bool useAA);
 
-    BmpScaleFlag goodScalingQuality() const { return 
SkiaHelper::goodScalingQuality(isGPU()); }
+    BmpScaleFlag goodScalingQuality(bool isUpscale = false) const
+    {
+        return SkiaHelper::goodScalingQuality(isGPU(), isUpscale);
+    }
     SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int 
scalingFactor,
                                           int srcScalingFactor = 1)
     {
@@ -300,7 +303,9 @@ protected:
     }
     SkSamplingOptions makeSamplingOptions(const SkMatrix& matrix, int 
scalingFactor)
     {
-        return SkiaHelper::makeSamplingOptions(goodScalingQuality(), matrix, 
scalingFactor);
+        bool isUpscale = (matrix.getScaleX() > 1.0 || matrix.getScaleY() > 
1.0);
+        return SkiaHelper::makeSamplingOptions(goodScalingQuality(isUpscale), 
matrix,
+                                               scalingFactor);
     }
 
     // Create SkPaint to use when drawing to the surface. It is not to be used
diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx
index 37aedfb2165a..08d3ad4da44e 100644
--- a/vcl/inc/skia/utils.hxx
+++ b/vcl/inc/skia/utils.hxx
@@ -159,8 +159,23 @@ inline bool isUnitTestRunning(const char* name = nullptr)
 // In that case use only BmpScaleFlag::Default, which is bilinear+mipmap,
 // which should be good enough (and that's what the "super" bitmap scaling
 // algorithm done by VCL does as well).
-inline BmpScaleFlag goodScalingQuality(bool isGPU)
+inline BmpScaleFlag goodScalingQuality(bool isGPU, bool isUpscale = false)
 {
+#ifdef MACOSX
+    // tdf#161480 use BmpScaleFlag::NearestNeighbor when upscaling on macOS
+    // On macOS, due to Retina window scaling, it is very common to
+    // have Skia surfaces that are 2 times the size of their respective
+    // output device sizes so upscaling is often the default state.
+    // But when upscaling bitmaps on macOS with either Skia/Metal or
+    // Skia/Raster, some distortion to color and/or alpha values is
+    // introduced and only BmpScaleFlag::NearestNeighbor will upscale
+    // the bitmap correctly.
+    if (isUpscale)
+        return BmpScaleFlag::NearestNeighbor;
+#else
+    (void)isUpscale;
+#endif
+
     return isGPU ? BmpScaleFlag::BestQuality : BmpScaleFlag::Default;
 }
 
@@ -235,7 +250,12 @@ inline SkSamplingOptions makeSamplingOptions(const 
SalTwoRect& rPosAry, int scal
     if (srcScalingFactor != 1)
         srcSize *= srcScalingFactor;
     if (srcSize != destSize)
-        return makeSamplingOptions(goodScalingQuality(isGPU), srcSize, 
destSize, 1);
+    {
+        bool isUpscale
+            = (srcSize.Width() < destSize.Width() || srcSize.Height() < 
destSize.Height());
+        BmpScaleFlag scalingType = goodScalingQuality(isGPU, isUpscale);
+        return makeSamplingOptions(scalingType, srcSize, destSize, 1);
+    }
     return SkSamplingOptions(); // none
 }
 

Reply via email to