Merge branch 'bundle-scaled-bitmaps'

Make wxBitmapBundle compatible with bitmap scale factor > 1, both when
converting the latter to the former and when retrieving bitmaps from the
bundle.

See https://github.com/wxWidgets/wxWidgets/pull/2564
This commit is contained in:
Vadim Zeitlin
2021-10-25 13:18:47 +02:00
14 changed files with 273 additions and 51 deletions

View File

@@ -167,6 +167,9 @@ Currently the following symbols exist:
have an efficient (CPU-specific) implementation. Notice that the functions
themselves are always available but can be prohibitively slow to use when
implemented in a generic way, using a critical section.}
@itemdef{wxHAS_BITMAP_SCALE_FACTOR, Defined in @c wx/bitmap.h if bitmaps
actually use scale factor under the current platform, see
wxBitmap::SetScaleFactor().}
@itemdef{wxHAS_BITMAPTOGGLEBUTTON, Defined in @c wx/tglbtn.h if
wxBitmapToggleButton class is available in addition to wxToggleButton.}
@itemdef{wxHAS_CONFIG_TEMPLATE_RW, Defined if the currently used compiler

View File

@@ -177,8 +177,7 @@ public:
virtual bool Create(int width, int height, int depth = wxBITMAP_SCREEN_DEPTH) = 0;
virtual bool Create(const wxSize& sz, int depth = wxBITMAP_SCREEN_DEPTH) = 0;
virtual bool CreateScaled(int w, int h, int d, double logicalScale)
{ return Create(wxRound(w*logicalScale), wxRound(h*logicalScale), d); }
virtual bool CreateScaled(int w, int h, int d, double logicalScale);
virtual int GetHeight() const = 0;
virtual int GetWidth() const = 0;
@@ -188,11 +187,11 @@ public:
{ return wxSize(GetWidth(), GetHeight()); }
// support for scaled bitmaps
virtual double GetScaleFactor() const { return 1.0; }
virtual double GetScaledWidth() const { return GetWidth() / GetScaleFactor(); }
virtual double GetScaledHeight() const { return GetHeight() / GetScaleFactor(); }
virtual wxSize GetScaledSize() const
{ return wxSize(wxRound(GetScaledWidth()), wxRound(GetScaledHeight())); }
virtual void SetScaleFactor(double scale);
virtual double GetScaleFactor() const;
virtual double GetScaledWidth() const;
virtual double GetScaledHeight() const;
virtual wxSize GetScaledSize() const;
#if wxUSE_IMAGE
virtual wxImage ConvertToImage() const = 0;

View File

@@ -149,12 +149,7 @@ wxBitmapBundle wxBitmapBundle::FromBitmaps(const wxBitmap& bitmap1,
/* static */ inline
wxBitmapBundle wxBitmapBundle::FromBitmap(const wxBitmap& bitmap)
{
if ( !bitmap.IsOk() )
return wxBitmapBundle();
wxVector<wxBitmap> bitmaps;
bitmaps.push_back(bitmap);
return FromBitmaps(bitmaps);
return wxBitmapBundle(bitmap);
}
/* static */ inline

View File

@@ -17,6 +17,10 @@ typedef struct _GdkPixbuf GdkPixbuf;
class WXDLLIMPEXP_FWD_CORE wxPixelDataBase;
class WXDLLIMPEXP_FWD_CORE wxCursor;
#ifdef __WXGTK3__
#define wxHAS_BITMAP_SCALE_FACTOR
#endif
//-----------------------------------------------------------------------------
// wxMask
//-----------------------------------------------------------------------------
@@ -85,8 +89,9 @@ public:
{ return Create(sz.GetWidth(), sz.GetHeight(), depth); }
bool Create(int width, int height, const wxDC& WXUNUSED(dc))
{ return Create(width,height); }
#ifdef __WXGTK3__
#ifdef wxHAS_BITMAP_SCALE_FACTOR
virtual bool CreateScaled(int w, int h, int depth, double scale) wxOVERRIDE;
virtual void SetScaleFactor(double scale) wxOVERRIDE;
virtual double GetScaleFactor() const wxOVERRIDE;
#endif

View File

@@ -158,8 +158,7 @@ public:
virtual bool Create(int width, int height, const wxDC& dc);
virtual bool Create(const void* data, wxBitmapType type, int width, int height, int depth = 1);
virtual bool CreateScaled(int w, int h, int d, double logicalScale)
{ return Create(wxRound(w*logicalScale), wxRound(h*logicalScale), d); }
virtual bool CreateScaled(int w, int h, int d, double logicalScale);
virtual bool LoadFile(const wxString& name, wxBitmapType type = wxBITMAP_DEFAULT_TYPE);
virtual bool SaveFile(const wxString& name, wxBitmapType type, const wxPalette *cmap = NULL) const;
@@ -185,12 +184,12 @@ public:
void UseAlpha(bool use = true);
void ResetAlpha() { UseAlpha(false); }
// support for scaled bitmaps
virtual double GetScaleFactor() const { return 1.0; }
virtual double GetScaledWidth() const { return GetWidth() / GetScaleFactor(); }
virtual double GetScaledHeight() const { return GetHeight() / GetScaleFactor(); }
virtual wxSize GetScaledSize() const
{ return wxSize(wxRound(GetScaledWidth()), wxRound(GetScaledHeight())); }
// provide stabs of scaled bitmaps functions, they are trivial here
virtual void SetScaleFactor(double scale);
virtual double GetScaleFactor() const;
virtual double GetScaledWidth() const;
virtual double GetScaledHeight() const;
virtual wxSize GetScaledSize() const;
// implementation only from now on
// -------------------------------

View File

@@ -13,6 +13,8 @@
#include "wx/palette.h"
#define wxHAS_BITMAP_SCALE_FACTOR
// Bitmap
class WXDLLIMPEXP_FWD_CORE wxBitmap;
class wxBitmapRefData ;
@@ -239,6 +241,7 @@ public:
void EndRawAccess();
#endif
void SetScaleFactor(double scale) wxOVERRIDE;
double GetScaleFactor() const wxOVERRIDE;
void SetSelectedInto(wxDC *dc);

View File

@@ -402,6 +402,15 @@ public:
*/
static void CleanUpHandlers();
/**
Returns disabled (dimmed) version of the bitmap.
This method is not available when <code>wxUSE_IMAGE == 0</code>.
@since 2.9.0
*/
wxBitmap ConvertToDisabled(unsigned char brightness = 255) const;
/**
Creates an image from a platform-dependent bitmap. This preserves
mask information so that bitmaps and images can be converted back
@@ -460,7 +469,7 @@ public:
@param depth
The number of bits used to represent each bitmap pixel.
@param logicalScale
Scale factor used by the bitmap
Scale factor used by the bitmap, see SetScaleFactor().
@return @true if the creation was successful.
@@ -542,7 +551,7 @@ public:
/**
Gets the height of the bitmap in pixels.
@see GetWidth(), GetSize()
@see GetWidth(), GetSize(), GetScaledHeight()
*/
virtual int GetHeight() const;
@@ -568,28 +577,75 @@ public:
*/
virtual wxBitmap GetSubBitmap(const wxRect& rect) const;
/**
Returns the scale factor of this bitmap.
Scale factor is 1 by default, but can be greater to indicate that the
size of bitmap in logical, DPI-independent pixels is smaller than its
actual size in physical pixels. Bitmaps with scale factor greater than
1 must be used in high DPI to appear sharp on the screen.
Note that the scale factor is only used in the ports where logical
pixels are not the same as physical ones, such as wxOSX or wxGTK3, and
this function always returns 1 under the other platforms.
@see SetScaleFactor(), GetScaledWidth(), GetScaledHeight(), GetScaledSize()
@since 2.9.5
*/
virtual double GetScaleFactor() const;
/**
Returns the scaled height of the bitmap.
See GetScaledSize() for more information.
@see GetScaledWidth(), GetHeight()
@since 2.9.5
*/
virtual double GetScaledHeight() const;
/**
Returns the scaled size of the bitmap.
The scaled size of the bitmap is its size in pixels, as returned by
GetSize(), divided by its scale factor, as returned by
GetScaleFactor(), and so is the same as the normal size for bitmaps
with the default scale factor of 1 and always less than the physical
size for the higher resolution bitmaps supposed to be used on high DPI
screens.
@see GetScaledWidth(), GetScaledHeight(), GetSize()
@since 2.9.5
*/
virtual wxSize GetScaledSize() const;
/**
Returns the scaled width of the bitmap.
See GetScaledSize() for more information.
@see GetScaledHeight(), GetWidth()
@since 2.9.5
*/
virtual double GetScaledWidth() const;
/**
Returns the size of the bitmap in pixels.
@since 2.9.0
@see GetHeight(), GetWidth()
@see GetHeight(), GetWidth(), GetScaledSize()
*/
wxSize GetSize() const;
/**
Returns disabled (dimmed) version of the bitmap.
This method is not available when <code>wxUSE_IMAGE == 0</code>.
@since 2.9.0
*/
wxBitmap ConvertToDisabled(unsigned char brightness = 255) const;
/**
Gets the width of the bitmap in pixels.
@see GetHeight(), GetSize()
@see GetHeight(), GetSize(), GetScaledWidth()
*/
virtual int GetWidth() const;
@@ -741,6 +797,38 @@ public:
*/
virtual void SetHeight(int height);
/**
Sets the bitmap scale factor.
This doesn't change the bitmap actual size or its contents, but changes
its scale factor, so that it appears in a smaller size when it is drawn
on screen: e.g. setting @a scale to 2 means that the bitmap will be
twice smaller (in each direction) when drawn on screen in the ports in
which logical and physical pixels differ (i.e. wxOSX and wxGTK3, but
not wxMSW).
When creating a new bitmap, CreateScaled() can be used to specify the
correct scale factor from the beginning.
Note that this method exists in all ports, but simply does nothing in
those of them that don't use logical pixel scaling. The preprocessor
symbol @c wxHAS_BITMAP_SCALE_FACTOR can be tested to determine whether
the scale factor is really supported, e.g.
@code
bitmap.SetScaleFactor(2);
// In the other ports scale factor is always 1, so the assert would
// fail there.
#ifdef wxHAS_BITMAP_SCALE_FACTOR
wxASSERT( bitmap.GetScaleFactor() == 2 );
#endif
@endcode
@since 3.1.6
*/
virtual void SetScaleFactor(double scale);
/**
Sets the mask for this bitmap.

View File

@@ -196,6 +196,39 @@ public:
wxIMPLEMENT_DYNAMIC_CLASS(wxBitmapBaseModule, wxModule);
// ----------------------------------------------------------------------------
// Trivial implementations of scale-factor related functions
// ----------------------------------------------------------------------------
bool wxBitmapBase::CreateScaled(int w, int h, int d, double logicalScale)
{
return Create(wxRound(w*logicalScale), wxRound(h*logicalScale), d);
}
void wxBitmapBase::SetScaleFactor(double WXUNUSED(scale))
{
}
double wxBitmapBase::GetScaleFactor() const
{
return 1.0;
}
double wxBitmapBase::GetScaledWidth() const
{
return GetWidth() / GetScaleFactor();
}
double wxBitmapBase::GetScaledHeight() const
{
return GetHeight() / GetScaleFactor();
}
wxSize wxBitmapBase::GetScaledSize() const
{
return wxSize(wxRound(GetScaledWidth()), wxRound(GetScaledHeight()));
}
#endif // wxUSE_BITMAP_BASE
// ----------------------------------------------------------------------------

View File

@@ -110,6 +110,11 @@ private:
// Note that this vector is never empty.
Entries m_entries;
// The size of the bitmap at the default size.
//
// Note that it may be different from the size of the first entry if we
// only have high resolution bitmap and no bitmap for 100% DPI.
wxSize m_sizeDefault;
// Common implementation of all ctors.
void Init(const wxBitmap* bitmaps, size_t n);
@@ -141,6 +146,13 @@ void wxBitmapBundleImplSet::Init(const wxBitmap* bitmaps, size_t n)
std::sort(m_entries.begin(), m_entries.end(), BitmapSizeComparator());
// This is not normally the case, but it could happen that even the
// smallest bitmap has scale factor > 1, so use its scaled size (this can
// notably be the case when there is only a single high resolution bitmap
// provided, e.g. in the code predating wxBitmapBundle introduction but now
// using it due to implicit conversion to it from wxBitmap).
m_sizeDefault = m_entries[0].bitmap.GetScaledSize();
// Should we check that all bitmaps really have unique sizes here? For now,
// don't bother with this, but we might want to do it later if it really
// turns out to be a problem in practice.
@@ -152,8 +164,7 @@ void wxBitmapBundleImplSet::Init(const wxBitmap* bitmaps, size_t n)
wxSize wxBitmapBundleImplSet::GetDefaultSize() const
{
// Default size is the size of the smallest bitmap in the bundle.
return m_entries[0].bitmap.GetSize();
return m_sizeDefault;
}
wxSize wxBitmapBundleImplSet::GetPreferredSizeAtScale(double scale) const
@@ -384,7 +395,16 @@ wxBitmap wxBitmapBundle::GetBitmap(const wxSize& size) const
if ( !m_impl )
return wxBitmap();
return m_impl->GetBitmap(size == wxDefaultSize ? GetDefaultSize() : size);
const wxSize sizeDef = GetDefaultSize();
wxBitmap bmp = m_impl->GetBitmap(size == wxDefaultSize ? sizeDef : size);
// Ensure that the returned bitmap uses the scale factor such that it takes
// the same space, in logical pixels, as the bitmap in the default size.
if ( size != wxDefaultSize )
bmp.SetScaleFactor(static_cast<double>(size.y)/sizeDef.y);
return bmp;
}
// ============================================================================

View File

@@ -1002,6 +1002,13 @@ bool wxBitmap::CreateScaled(int w, int h, int depth, double scale)
return true;
}
void wxBitmap::SetScaleFactor(double scale)
{
wxCHECK_RET(m_refData, "invalid bitmap");
M_BMPDATA->m_scaleFactor = scale;
}
double wxBitmap::GetScaleFactor() const
{
wxCHECK_MSG(m_refData, -1, "invalid bitmap");

View File

@@ -155,24 +155,13 @@ static gboolean wxGtkImageDraw(GtkWidget* widget, GdkEventExpose* event)
#endif
}
const double scaleFactor = image->m_provider->GetScale();
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);
int x = (alloc.width - int(bitmap.GetWidth() /scaleFactor)) / 2;
int y = (alloc.height - int(bitmap.GetHeight()/scaleFactor)) / 2;
int x = (alloc.width - int(bitmap.GetScaledWidth() )) / 2;
int y = (alloc.height - int(bitmap.GetScaledHeight())) / 2;
#ifdef __WXGTK3__
gtk_render_background(gtk_widget_get_style_context(widget),
cr, 0, 0, alloc.width, alloc.height);
if (!wxIsSameDouble(scaleFactor, 1))
{
cairo_translate(cr, x, y);
const double scale = 1 / scaleFactor;
cairo_scale(cr, scale, scale);
x = 0;
y = 0;
}
bitmap.Draw(cr, x, y);
#else
x += alloc.x;

View File

@@ -745,6 +745,11 @@ bool wxBitmap::Create(int width, int height, const wxDC& dc)
return false;
}
bool wxBitmap::CreateScaled(int w, int h, int d, double logicalScale)
{
return Create(wxRound(w*logicalScale), wxRound(h*logicalScale), d);
}
bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc)
{
UnRef();
@@ -1357,6 +1362,39 @@ bool wxBitmap::InitFromHBITMAP(WXHBITMAP bmp, int width, int height, int depth)
return IsOk();
}
// ----------------------------------------------------------------------------
// scale factor-related functions
// ----------------------------------------------------------------------------
// Note: currently we don't use scale factor at all and don't even store it
// because this seems useless, but we define these functions out of line here
// and not inline in the header to make it possible to change this later
// without breaking ABI if necessary.
void wxBitmap::SetScaleFactor(double WXUNUSED(scale))
{
}
double wxBitmap::GetScaleFactor() const
{
return 1.0;
}
double wxBitmap::GetScaledWidth() const
{
return GetWidth();
}
double wxBitmap::GetScaledHeight() const
{
return GetHeight();
}
wxSize wxBitmap::GetScaledSize() const
{
return GetSize();
}
// ----------------------------------------------------------------------------
// raw bitmap access support
// ----------------------------------------------------------------------------

View File

@@ -75,6 +75,8 @@ public:
int GetBytesPerRow() const;
bool HasAlpha() const;
WXImage GetImage() const;
void SetScaleFactor(double scale) { m_scaleFactor = scale; }
double GetScaleFactor() const { return m_scaleFactor; }
const void *GetRawAccess() const;
@@ -1389,6 +1391,13 @@ int wxBitmap::GetWidth() const
return GetBitmapData()->GetWidth() ;
}
void wxBitmap::SetScaleFactor(double scale)
{
wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
return GetBitmapData()->SetScaleFactor(scale) ;
}
double wxBitmap::GetScaleFactor() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );

View File

@@ -68,6 +68,40 @@ TEST_CASE("BitmapBundle::GetPreferredSize", "[bmpbundle]")
CHECK( b.GetPreferredSizeAtScale(3 ) == bigger );
}
#ifdef wxHAS_BITMAP_SCALE_FACTOR
TEST_CASE("BitmapBundle::Scaled", "[bmpbundle]")
{
// Adding a bitmap with scale factor > 1 should create the bundle using the
// scaled size as default size.
wxBitmap scaled2x(64, 64);
scaled2x.SetScaleFactor(2);
CHECK( scaled2x.GetScaledSize() == wxSize(32, 32) );
wxBitmapBundle b(scaled2x);
CHECK( b.GetDefaultSize() == wxSize(32, 32) );
// Retrieving this bitmap back from the bundle should preserve its scale.
scaled2x = b.GetBitmap(wxSize(64, 64));
CHECK( scaled2x.GetSize() == wxSize(64, 64) );
CHECK( scaled2x.GetScaleFactor() == 2 );
// And retrieving the bitmap from the bundle should set scale factor for it
// even if it hadn't originally been added with it.
b = wxBitmapBundle::FromBitmaps(wxBitmap(32, 32), wxBitmap(64, 64));
scaled2x = b.GetBitmap(wxSize(64, 64));
CHECK( scaled2x.GetSize() == wxSize(64, 64) );
CHECK( scaled2x.GetScaleFactor() == 2 );
// Using scaled bitmaps when there is more than one of them is a bad idea
// in general, as only physical size matters, but the default size should
// still be the scaled size of the smallest one.
b = wxBitmapBundle::FromBitmaps(scaled2x, wxBitmap(64, 64));
CHECK( b.GetDefaultSize() == wxSize(32, 32) );
}
#endif // wxHAS_BITMAP_SCALE_FACTOR
#ifdef wxHAS_SVG
TEST_CASE("BitmapBundle::FromSVG", "[bmpbundle][svg]")