From 6d5bd15d12c5462cf5db7fb80bdd74e0bbc2f60d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 2 Jun 2022 01:34:25 +0100 Subject: [PATCH] Use non-integer scale that is exact multiple of an available one Always rounding non-integer scale when upscaling is wrong, as we could be able to upscale an existing x1.5 image to e.g. 300% DPI scaling with relatively good results, so only do it if there is no available scale that exactly divides the requested one. Add a previously failing unit test which passes now. --- src/common/bmpbndl.cpp | 39 +++++++++++++++++++++++++++++++++--- tests/graphics/bmpbundle.cpp | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/common/bmpbndl.cpp b/src/common/bmpbndl.cpp index e73cff491a..0f83b4da24 100644 --- a/src/common/bmpbndl.cpp +++ b/src/common/bmpbndl.cpp @@ -711,9 +711,42 @@ wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget) const // bitmaps of standard size are scaled when 2x DPI scaling is used. if ( scaleTarget > 1.5*scaleLast ) { - // However scaling by non-integer scales doesn't work well at all, so - // round it to the closest integer in this case. - scaleBest = wxRound(scaleTarget); + // However scaling by non-integer scales doesn't work well at + // all, so try to find a bitmap that we may rescale by an + // integer factor. + // + // Note that this is similar to GetIndexToUpscale(), but we + // don't want to fall back on the largest bitmap here, so we + // can't reuse it. + // + // Also, while we reenter GetNextAvailableScale() here, it + // doesn't matter because we're not going to continue using it + // in the outer loop any more. + for ( i = 0;; ) + { + const double scale = GetNextAvailableScale(i); + if ( scale == 0.0 ) + break; + + const double factor = scaleTarget / scale; + if ( wxRound(factor) == factor ) + { + scaleBest = scaleTarget; + + // We don't need to keep going: if there is a bigger + // bitmap which can be scaled using an integer factor + // to the target scale, our GetIndexToUpscale() will + // find it, we don't need to do it here. + break; + } + } + + // If none of the bitmaps can be upscaled by an integer factor, + // round the target scale itself, as we can be sure to be able + // to scale at least the base bitmap to it using an integer + // factor then. + if ( scaleBest == 0.0 ) + scaleBest = wxRound(scaleTarget); } else // Target scale is not much greater than the biggest one we have. { diff --git a/tests/graphics/bmpbundle.cpp b/tests/graphics/bmpbundle.cpp index 174c9085ab..c40e50124a 100644 --- a/tests/graphics/bmpbundle.cpp +++ b/tests/graphics/bmpbundle.cpp @@ -301,6 +301,7 @@ TEST_CASE("BitmapBundle::GetPreferredSize", "[bmpbundle]") CHECK_THAT( BitmapAtScale(b, 3.33), SameAs(3.0, 1.5) ); CHECK_THAT( BitmapAtScale(b, 4.25), SameAs(4.0, 2.0) ); + CHECK_THAT( BitmapAtScale(b, 4.50), SameAs(4.5, 1.5) ); CHECK_THAT( BitmapAtScale(b, 5 ), SameAs(5.0, 1.0) ); }