Add wxBitmapBundleImpl::GetIndexToUpscale()

Ensure that wxBitmapBundleImplSet and wxBitmapBundleImplRC use the same
logic for actually selecting the bitmap to upscale, and not just for
deciding the size that it must have, too.

No real changes, but this should make impossible for these functions to
diverge once again -- and also make it simpler to reuse the same logic
in any other wxBitmapBundleImpl-derived classes in the future.
This commit is contained in:
Vadim Zeitlin 2022-06-02 01:08:21 +01:00
parent 36abfe973a
commit d86c1a8c46
4 changed files with 85 additions and 51 deletions

View file

@ -230,10 +230,16 @@ protected:
// If this function is used, GetNextAvailableScale() must be overridden!
wxSize DoGetPreferredSize(double scale) const;
// Override this function if DoGetPreferredSize() is used: it can use the
// provided parameter as an internal index, it's guaranteed to be 0 when
// calling this function for the first time. When there are no more scales,
// return 0.
// Helper for implementing GetBitmap(): if we need to upscale a bitmap,
// uses GetNextAvailableScale() to find the index of the best bitmap to
// use, where "best" is defined as "using scale which is a divisor of the
// given one", as upscaling by an integer factor is strongly preferable.
size_t GetIndexToUpscale(const wxSize& size) const;
// Override this function if DoGetPreferredSize() or GetIndexToUpscale() is
// used: it can use the provided parameter as an internal index, it's
// guaranteed to be 0 when calling this function for the first time. When
// there are no more scales, return 0.
//
// This function is not pure virtual because it doesn't need to be
// implemented if DoGetPreferredSize() is never used, but it will assert if

View file

@ -505,16 +505,42 @@ protected:
used.
Typically this function is used in the derived classes implementation
to forward GetPreferredBitmapSizeAtScale() to it, e.g.
to forward GetPreferredBitmapSizeAtScale() to it and when this is done,
GetBitmap() may also use GetIndexToUpscale() to choose the bitmap to
upscale if necessary:
@code
class MyCustomBitmapBundleImpl : public wxBitmapBundleImpl
{
public:
wxSize GetDefaultSize() const
{
return wxSize(32, 32);
}
wxSize GetPreferredBitmapSizeAtScale(double scale) const wxOVERRIDE
{
return DoGetPreferredSize(scale);
}
wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE
{
// For consistency with GetNextAvailableScale(), we must have
// bitmap variants for 32, 48 and 64px sizes.
const wxSize availableSizes[] = { 32, 48, 64 };
if ( size.y <= 64 )
{
... get the bitmap from somewhere ...
}
else
{
size_t n = GetIndexToUpscale(size);
bitmap = ... get bitmap for availableSizes[n] ...;
wxBitmap::Rescale(bitmap, size);
}
return bitmap;
}
protected:
double GetNextAvailableScale(size_t& i) const wxOVERRIDE
{
@ -535,12 +561,26 @@ protected:
*/
wxSize DoGetPreferredSize(double scale) const;
/**
Return the index of the available scale most suitable to be upscaled to
the given size.
See DoGetPreferredSize() for an example of using this function.
@param size The required size, typically the same one as passed to
GetBitmap()
@since 3.1.7
*/
size_t GetIndexToUpscale(const wxSize& size) const;
/**
Return information about the available bitmaps.
Overriding this function is optional and only needs to be done if
DoGetPreferredSize() is called. If you do override it, this function
must return the next available scale or 0.0 if there are no more.
either DoGetPreferredSize() or GetIndexToUpscale() are called. If you
do override it, this function must return the next available scale or
0.0 if there are no more.
The returned scales must be in ascending order and the first returned
scale, for the initial @a i value of 0, should be 1. The function must

View file

@ -298,41 +298,14 @@ 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 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];
if ( entry.generated )
continue;
// of the bitmaps, so find the most appropriate one for doing it.
const size_t i = GetIndexToUpscale(size);
entryLastNotGen = &entry;
const Entry entryNew(m_entries[i], size);
const double
scale = static_cast<double>(size.y) / entry.bitmap.GetSize().y;
if ( scale == wxRound(scale) )
entryToRescale = &entry;
}
m_entries.push_back(entryNew);
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.
wxFAIL_MSG( wxS("unreachable") );
return wxBitmap();
return entryNew.bitmap;
}
#ifdef __WXOSX__
@ -787,6 +760,30 @@ wxBitmapBundleImpl::DoGetPreferredSize(double scaleTarget) const
return GetDefaultSize()*scaleBest;
}
size_t wxBitmapBundleImpl::GetIndexToUpscale(const wxSize& size) const
{
// Our best hope is to find a scale dividing the given one evenly.
size_t indexBest = (size_t)-1;
// In the worst case, we will use the largest index, as it should hopefully
// result in the least bad results.
size_t indexLast = 0;
const wxSize sizeDef = GetDefaultSize();
for ( size_t i = 0;; indexLast = i)
{
const double scaleThis = GetNextAvailableScale(i);
if ( scaleThis == 0.0 )
break;
const double scale = size.y / (sizeDef.y*scaleThis);
if (wxRound(scale) == scale)
indexBest = indexLast;
}
return indexBest != (size_t)-1 ? indexBest : indexLast;
}
wxBitmapBundleImpl::~wxBitmapBundleImpl()
{
#ifdef __WXOSX__

View file

@ -285,20 +285,11 @@ wxBitmap wxBitmapBundleImplRC::GetBitmap(const wxSize& size)
// 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];
const size_t i = GetIndexToUpscale(size);
const double scale = size.y / sizeDef.y*info.scale;
if ( scale == wxRound(scale) )
infoToRescale = &info;
}
const ResourceInfo& info = m_resourceInfos[i];
if ( !infoToRescale )
infoToRescale = &m_resourceInfos.back();
return AddBitmap(*infoToRescale, sizeDef*infoToRescale->scale, size);
return AddBitmap(info, sizeDef*info.scale, size);
}
// ============================================================================