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 }