diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2021-04-08 22:20:53 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2021-04-12 15:05:49 +0200 |
commit | 8043fe3e45c8999c8eaf475ba46d50b125e38b93 (patch) | |
tree | 2fd08de84cff532eef60eafc9552b9f8081fb0d2 /vcl | |
parent | f0ef4e6b83f5ad3b916c42682561b86ddd485f0d (diff) |
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.lunak@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/skia/utils.hxx | 38 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 6 | ||||
-rw-r--r-- | vcl/skia/salbmp.cxx | 13 |
3 files changed, 48 insertions, 9 deletions
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)); |