Fix wxBitmapBundle compatibility for template NSImages

Fix backward compatibility regression where native NSImage bitmaps, such
as those loaded via wxArtProvider on macOS, would loose their isTemplate
property when implicitly converted to wxBitmap and back. This resulted
in broken rendering of templates.

This is a common situation in pre-wxBitmapBundle code. wxArtProvider
returns wxBitmapBundle, which is then implicitly converted to a single
wxBitmap in wxArtProvider::GetBitmap() and when its later passed to a
function that takes wxBitmapBundle, it is converted back using the
wxBitmapBundleImplSet implementation.

wxBitmapBundleImplSet serves dual role: it is used both for manually
assembling bitmap bundles and to implicitly faciliate the backward
compatiblity mechanism described above. To make the latter truly
transparent, we need to special-case it and preserve NSImage as is, and
this commit does exactly that.

See #22623.
This commit is contained in:
Václav Slavík 2022-07-12 19:27:42 +02:00 committed by Vadim Zeitlin
parent f8fb90c1bd
commit e9d299d92c

View file

@ -312,19 +312,41 @@ wxBitmap wxBitmapBundleImplSet::GetBitmap(const wxSize& size)
void wxBitmapBundleImplSet::OSXCreateNSImage()
{
WXImage image = NULL;
#if wxOSX_USE_COCOA
image = wxOSXImageFromBitmap(m_entries[0].bitmap);
const size_t n = m_entries.size();
for ( size_t i = 1; i < n; ++i )
if ( n == 1 )
{
const Entry& entry = m_entries[i];
wxOSXAddBitmapToImage(image, entry.bitmap);
// The special case of only a single bitmap in the bundle is common and
// occurs in older code using wxBitmap instead of wxBitmapBundle. We want
// to avoid creating a new NSImage as is done below in this case for two
// reasons:
//
// - performance - returning existing NSImage is much cheaper
// - backward compatibility - using existing NSImage preserves existing
// metadata such as image name or, importantly, its isTemplate property
//
// The OSXGetImage() method will either return NSImage representation
// if it already exists, which takes care of the two above points.
// Otherwise, it will create NSImage using wxOSXGetImageFromCGImage,
// which is essentially identical to wxOSXImageFromBitmap below.
image = m_entries[0].bitmap.OSXGetImage();
}
else
{
// Generate NSImage with multiple scale factors from individual bitmaps
#if wxOSX_USE_COCOA
image = wxOSXImageFromBitmap(m_entries[0].bitmap);
for ( size_t i = 1; i < n; ++i )
{
const Entry& entry = m_entries[i];
wxOSXAddBitmapToImage(image, entry.bitmap);
}
#else
image = wxOSXImageFromBitmap(m_entries[0].bitmap);
// TODO determine best bitmap for device scale factor, and use that
// with wxOSXImageFromBitmap as on iOS there is only one bitmap in a UIImage
image = wxOSXImageFromBitmap(m_entries[0].bitmap);
// TODO determine best bitmap for device scale factor, and use that
// with wxOSXImageFromBitmap as on iOS there is only one bitmap in a UIImage
#endif
}
if ( image )
wxOSXSetImageForBundleImpl(this, image);
}