Choose the best bitmap to rescale to the target size

It's not necessarily the largest bitmap, but one which may be scaled
using an integer factor.

Fix the tests to expect the correct results, now that they actually
pass.
This commit is contained in:
Vadim Zeitlin 2022-06-01 23:09:10 +01:00
parent 3414e6a1d4
commit 2d782443a4
3 changed files with 55 additions and 19 deletions

View file

@ -292,18 +292,35 @@ wxBitmap wxBitmapBundleImplSet::GetBitmap(const wxSize& size)
// We only get here if the requested size is larger than the size of all
// the bitmaps we have, in which case we have no choice but to upscale one
// of the bitmaps, so find the largest available non-generated bitmap.
for ( size_t i = n; n > 0; --i )
// of the bitmaps, so find the largest available non-generated bitmap which
// can be scaled using an integer factor or, failing that, just the largest
// non-generated bitmap.
const Entry* entryToRescale = NULL;
const Entry* entryLastNotGen = NULL;
for ( size_t i = 0; i < n; ++i )
{
const Entry& entry = m_entries[i - 1];
if ( !entry.generated )
{
const Entry entryNew(entry, size);
const Entry& entry = m_entries[i];
if ( entry.generated )
continue;
m_entries.push_back(entryNew);
entryLastNotGen = &entry;
return entryNew.bitmap;
}
const double
scale = static_cast<double>(size.y) / entry.bitmap.GetSize().y;
if ( scale == wxRound(scale) )
entryToRescale = &entry;
}
if ( !entryToRescale )
entryToRescale = entryLastNotGen;
if ( entryToRescale )
{
const Entry entryNew(*entryToRescale, size);
m_entries.push_back(entryNew);
return entryNew.bitmap;
}
// We should have at least one non-generated bitmap.

View file

@ -269,17 +269,28 @@ wxBitmap wxBitmapBundleImplRC::GetBitmap(const wxSize& size)
const wxSize sizeThis = sizeDef*info.scale;
// Use this bitmap if it's the first one bigger than the requested size
// or if it's the last item as in this case we're not going to find any
// bitmap bigger than the given one anyhow and we don't have any choice
// but to upscale the largest one we have.
if ( sizeThis.y >= size.y || i + 1 == m_resourceInfos.size() )
// Use this bitmap if it's the first one bigger than the requested size.
if ( sizeThis.y >= size.y )
return AddBitmap(info, sizeThis, size);
}
wxFAIL_MSG( wxS("unreachable") );
// We have to upscale some bitmap because we don't have any bitmaps larger
// than the requested size. Try to find one which can be upscaled using an
// integer factor.
const ResourceInfo* infoToRescale = NULL;
for ( size_t i = 0; i < m_resourceInfos.size(); ++i )
{
const ResourceInfo& info = m_resourceInfos[i];
return wxBitmap();
const double scale = size.y / sizeDef.y*info.scale;
if ( scale == wxRound(scale) )
infoToRescale = &info;
}
if ( !infoToRescale )
infoToRescale = &m_resourceInfos.back();
return AddBitmap(*infoToRescale, sizeDef*infoToRescale->scale, size);
}
// ============================================================================

View file

@ -272,10 +272,14 @@ TEST_CASE("BitmapBundle::GetPreferredSize", "[bmpbundle]")
CHECK_THAT( BitmapAtScale(b, 3 ), SameAs(2) );
// This scale is too big to use any of the existing bitmaps, so they will
// be scaled, but use integer factors.
CHECK_THAT( BitmapAtScale(b, 3.33), SameAs(3, 2) );
// be scaled, but use integer factors and, importantly, scale the correct
// bitmap using them: we need to scale the small bitmap by a factor of 3,
// rather than scaling the larger bitmap by a factor of 1.5 here, but we
// must also scale the larger one by a factor of 2 rather than scaling the
// small one by a factor of 4.
CHECK_THAT( BitmapAtScale(b, 3.33), SameAs(3, 1) );
CHECK_THAT( BitmapAtScale(b, 4 ), SameAs(4, 2) );
CHECK_THAT( BitmapAtScale(b, 5 ), SameAs(5, 2) );
CHECK_THAT( BitmapAtScale(b, 5 ), SameAs(5, 1) );
// Finally check that things work as expected when we have 3 versions.
@ -294,6 +298,10 @@ TEST_CASE("BitmapBundle::GetPreferredSize", "[bmpbundle]")
CHECK_THAT( BitmapAtScale(b, 2 ), SameAs(2.0) );
CHECK_THAT( BitmapAtScale(b, 2.5 ), SameAs(2.0) );
CHECK_THAT( BitmapAtScale(b, 3 ), SameAs(2.0) );
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, 5 ), SameAs(5.0, 1.0) );
}
#ifdef wxHAS_DPI_INDEPENDENT_PIXELS