vcl/inc/skia/utils.hxx |   38 +++++++++++++++++++++++++++++++++++++-
 vcl/skia/gdiimpl.cxx   |    6 +++---
 vcl/skia/salbmp.cxx    |   13 ++++++++-----
 3 files changed, 48 insertions(+), 9 deletions(-)

New commits:
commit 8043fe3e45c8999c8eaf475ba46d50b125e38b93
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 8 22:20:53 2021 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Apr 12 15:05:49 2021 +0200

    use Skia linear+mipmap for quality large downscaling (tdf#140129)
    
    This is what https://bugs.chromium.org/p/skia/issues/detail?id=11810#c1
    suggests (although I consider it to be an annoyance having to do this
    explicitly).
    
    Change-Id: I3df80374492c7b208ebaf819c0b4794ba535aa53
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113979
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx
index 716bd3e2471c..e53a17c7d934 100644
--- a/vcl/inc/skia/utils.hxx
+++ b/vcl/inc/skia/utils.hxx
@@ -85,11 +85,42 @@ VCL_DLLPUBLIC const SkSurfaceProps* surfaceProps();
 // Set pixel geometry to be used by SkSurfaceProps.
 VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry);
 
-inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scaling)
+// Normal scaling algorithms have a poor quality when downscaling a lot.
+// https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use 
mipmaps
+// in such a case, which is annoying to do explicitly instead of Skia deciding 
which
+// algorithm would be the best, but now with Skia removing SkFilterQuality and 
requiring
+// explicitly being told what algorithm to use this appears to be the best we 
can do.
+// Anything scaled down at least this ratio will use linear+mipmaps.
+constexpr int downscaleRatioThreshold = 4;
+
+inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scaling, const 
SkMatrix& matrix)
 {
     switch (scaling)
     {
         case BmpScaleFlag::BestQuality:
+            if (matrix.getScaleX() <= 1.0 / downscaleRatioThreshold
+                || matrix.getScaleY() <= 1.0 / downscaleRatioThreshold)
+                return SkSamplingOptions(SkFilterMode::kLinear, 
SkMipmapMode::kLinear);
+            return SkSamplingOptions(SkCubicResampler::Mitchell());
+        case BmpScaleFlag::Default:
+            return SkSamplingOptions(SkFilterMode::kLinear, 
SkMipmapMode::kNone);
+        case BmpScaleFlag::Fast:
+            return SkSamplingOptions(SkFilterMode::kNearest, 
SkMipmapMode::kNone);
+        default:
+            assert(false);
+            return SkSamplingOptions();
+    }
+}
+
+inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scaling, const Size& 
srcSize,
+                                             const Size& destSize)
+{
+    switch (scaling)
+    {
+        case BmpScaleFlag::BestQuality:
+            if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold
+                || srcSize.Height() / destSize.Height() >= 
downscaleRatioThreshold)
+                return SkSamplingOptions(SkFilterMode::kLinear, 
SkMipmapMode::kLinear);
             return SkSamplingOptions(SkCubicResampler::Mitchell());
         case BmpScaleFlag::Default:
             return SkSamplingOptions(SkFilterMode::kLinear, 
SkMipmapMode::kNone);
@@ -104,7 +135,12 @@ inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag 
scaling)
 inline SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry)
 {
     if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != 
rPosAry.mnDestHeight)
+    {
+        if (rPosAry.mnSrcWidth / rPosAry.mnDestWidth >= downscaleRatioThreshold
+            || rPosAry.mnSrcHeight / rPosAry.mnDestHeight >= 
downscaleRatioThreshold)
+            return SkSamplingOptions(SkFilterMode::kLinear, 
SkMipmapMode::kLinear);
         return SkSamplingOptions(SkCubicResampler::Mitchell()); // best
+    }
     return SkSamplingOptions(); // none
 }
 
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 828b7959244b..fd4f64e930cf 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1652,7 +1652,7 @@ sk_sp<SkImage> 
SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
         matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / 
bitmap.GetSize().Width());
         matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / 
bitmap.GetSize().Height());
         canvas->concat(matrix);
-        samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality);
+        samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality, 
matrix);
     }
     if (alphaBitmap != nullptr)
     {
@@ -1884,7 +1884,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const 
basegfx::B2DPoint& rNull,
         canvas->concat(matrix);
         SkSamplingOptions samplingOptions;
         if (matrixNeedsHighQuality(matrix))
-            samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality);
+            samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality, 
matrix);
         if (fAlpha == 1.0)
             canvas->drawImage(imageToDraw, 0, 0, samplingOptions);
         else
@@ -1911,7 +1911,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const 
basegfx::B2DPoint& rNull,
         canvas->concat(matrix);
         SkSamplingOptions samplingOptions;
         if (matrixNeedsHighQuality(matrix))
-            samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality);
+            samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality, 
matrix);
         if (pSkiaAlphaBitmap)
         {
             SkPaint paint;
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index 1302a3532afb..bb19f9118637 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -779,9 +779,9 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetSkImage() const
             assert(surface);
             SkPaint paint;
             paint.setBlendMode(SkBlendMode::kSrc); // set as is, including 
alpha
-            surface->getCanvas()->drawImageRect(mImage,
-                                                SkRect::MakeWH(mSize.Width(), 
mSize.Height()),
-                                                
makeSamplingOptions(mScaleQuality), &paint);
+            surface->getCanvas()->drawImageRect(
+                mImage, SkRect::MakeWH(mSize.Width(), mSize.Height()),
+                makeSamplingOptions(mScaleQuality, imageSize(mImage), mSize), 
&paint);
             SAL_INFO("vcl.skia.trace", "getskimage(" << this << "): image 
scaled "
                                                      << Size(mImage->width(), 
mImage->height())
                                                      << "->" << mSize << ":"
@@ -893,7 +893,9 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
         paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
         surface->getCanvas()->drawImageRect(
             mImage, SkRect::MakeWH(mSize.Width(), mSize.Height()),
-            scaling ? makeSamplingOptions(mScaleQuality) : 
SkSamplingOptions(), &paint);
+            scaling ? makeSamplingOptions(mScaleQuality, imageSize(mImage), 
mSize)
+                    : SkSamplingOptions(),
+            &paint);
         if (scaling)
             SAL_INFO("vcl.skia.trace", "getalphaskimage(" << this << "): image 
scaled "
                                                           << 
Size(mImage->width(), mImage->height())
@@ -1147,7 +1149,8 @@ void SkiaSalBitmap::EnsureBitmapData()
         if (imageSize(mImage) != mSize) // pending scaling?
         {
             canvas.drawImageRect(mImage, SkRect::MakeWH(mSize.getWidth(), 
mSize.getHeight()),
-                                 makeSamplingOptions(mScaleQuality), &paint);
+                                 makeSamplingOptions(mScaleQuality, 
imageSize(mImage), mSize),
+                                 &paint);
             SAL_INFO("vcl.skia.trace",
                      "ensurebitmapdata(" << this << "): image scaled " << 
imageSize(mImage) << "->"
                                          << mSize << ":" << 
static_cast<int>(mScaleQuality));
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to