summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-04-08 22:20:53 +0200
committerLuboš Luňák <l.lunak@collabora.com>2021-04-12 15:05:49 +0200
commit8043fe3e45c8999c8eaf475ba46d50b125e38b93 (patch)
tree2fd08de84cff532eef60eafc9552b9f8081fb0d2 /vcl
parentf0ef4e6b83f5ad3b916c42682561b86ddd485f0d (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.hxx38
-rw-r--r--vcl/skia/gdiimpl.cxx6
-rw-r--r--vcl/skia/salbmp.cxx13
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));