using NSImage as first-class native representation

If given an NSImage this will be used, unless raw bitmap data access is needed, lazily converting to a CGBitmapContext at that moment
This commit is contained in:
Stefan Csomor
2018-09-20 21:05:17 +02:00
committed by Vadim Zeitlin
parent 3e6d927eab
commit ee8132fea9

View File

@@ -37,12 +37,9 @@ CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffe
// Implementation Notes // Implementation Notes
// -------------------- // --------------------
// //
// we are always working with a 32 bit deep pixel buffer // A bitmap can be represented using an NSImage or a CGBitmapContextRef
// under QuickDraw its alpha parts are going to be ignored in the GWorld, // If raw bitmap data needs to be accessed, then even the NSImage has to be
// therefore we have a separate GWorld there for blitting the mask in // rendered into a CGBitmapContextRef
// under Quartz then content is transformed into a CGImageRef representing the same data
// which can be transferred to the GPU by the OS for fast rendering
class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData
{ {
@@ -52,31 +49,23 @@ public:
wxBitmapRefData(int width , int height , int depth, double logicalscale = 1.0); wxBitmapRefData(int width , int height , int depth, double logicalscale = 1.0);
wxBitmapRefData(CGContextRef context); wxBitmapRefData(CGContextRef context);
wxBitmapRefData(CGImageRef image, double scale); wxBitmapRefData(CGImageRef image, double scale);
wxBitmapRefData(WX_NSImage image);
wxBitmapRefData(); wxBitmapRefData();
wxBitmapRefData(const wxBitmapRefData &tocopy); wxBitmapRefData(const wxBitmapRefData &tocopy);
virtual ~wxBitmapRefData(); virtual ~wxBitmapRefData();
virtual bool IsOk() const wxOVERRIDE { return m_ok; } bool IsOk() const;
void Free(); void Free();
#if wxOSX_BITMAP_NATIVE_ACCESS #if wxOSX_BITMAP_NATIVE_ACCESS
int GetWidth() const int GetWidth() const;
{ return CGBitmapContextGetWidth(m_hBitmap); } int GetHeight() const;
int GetHeight() const int GetDepth() const;
{ return CGBitmapContextGetHeight(m_hBitmap); } int GetBytesPerRow() const;
int GetDepth() const bool HasAlpha() const;
{ return CGBitmapContextGetBitsPerPixel(m_hBitmap); } WX_NSImage GetNSImage() const;
int GetBytesPerRow() const
{ return CGBitmapContextGetBytesPerRow(m_hBitmap); }
bool HasAlpha() const
{
CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(m_hBitmap);
return !(alpha == kCGImageAlphaNone ||
alpha == kCGImageAlphaNoneSkipFirst ||
alpha == kCGImageAlphaNoneSkipLast);
}
#else #else
void SetWidth( int width ) { m_width = width; } void SetWidth( int width ) { m_width = width; }
void SetHeight( int height ) { m_height = height; } void SetHeight( int height ) { m_height = height; }
@@ -130,7 +119,11 @@ private :
bool Create(int width , int height , int depth, double logicalscale); bool Create(int width , int height , int depth, double logicalscale);
bool Create( CGImageRef image, double scale ); bool Create( CGImageRef image, double scale );
bool Create( CGContextRef bitmapcontext); bool Create( CGContextRef bitmapcontext);
bool Create( WX_NSImage image);
void Init(); void Init();
void EnsureBitmapExists() const;
void FreeDerivedRepresentations(); void FreeDerivedRepresentations();
#if !wxOSX_BITMAP_NATIVE_ACCESS #if !wxOSX_BITMAP_NATIVE_ACCESS
@@ -140,9 +133,11 @@ private :
int m_depth; int m_depth;
bool m_hasAlpha; bool m_hasAlpha;
wxMemoryBuffer m_memBuf; wxMemoryBuffer m_memBuf;
bool m_ok;
#else
WX_NSImage m_nsImage;
#endif #endif
int m_rawAccessCount; int m_rawAccessCount;
bool m_ok;
mutable CGImageRef m_cgImageRef; mutable CGImageRef m_cgImageRef;
bool m_isTemplate; bool m_isTemplate;
@@ -187,8 +182,9 @@ void wxBitmapRefData::Init()
m_depth = 0 ; m_depth = 0 ;
m_bytesPerRow = 0; m_bytesPerRow = 0;
m_hasAlpha = false; m_hasAlpha = false;
#else
m_nsImage = NULL;
#endif #endif
m_ok = false ;
m_bitmapMask = NULL ; m_bitmapMask = NULL ;
m_cgImageRef = NULL ; m_cgImageRef = NULL ;
m_isTemplate = false; m_isTemplate = false;
@@ -241,6 +237,32 @@ wxBitmapRefData::wxBitmapRefData(CGImageRef image, double scale)
Init(); Init();
Create( image, scale ); Create( image, scale );
} }
wxBitmapRefData::wxBitmapRefData(WX_NSImage image)
{
Init();
Create( image );
}
void wxBitmapRefData::EnsureBitmapExists() const
{
if ( ! m_hBitmap && m_nsImage)
{
wxBitmapRefData* t = const_cast<wxBitmapRefData*>(this);
t->m_hBitmap = wxOSXCreateBitmapContextFromNSImage(m_nsImage, &t->m_isTemplate);
}
}
bool wxBitmapRefData::Create( WX_NSImage image )
{
m_nsImage = image;
wxMacCocoaRetain(image);
return true;
}
// code from Technical Q&A QA1509 // code from Technical Q&A QA1509
bool wxBitmapRefData::Create(CGImageRef image, double scale) bool wxBitmapRefData::Create(CGImageRef image, double scale)
@@ -289,10 +311,7 @@ bool wxBitmapRefData::Create(CGImageRef image, double scale)
} /* data != NULL */ } /* data != NULL */
#endif #endif
} }
m_ok = ( m_hBitmap != NULL ) ; return IsOk() ;
return m_ok ;
} }
bool wxBitmapRefData::Create(CGContextRef context) bool wxBitmapRefData::Create(CGContextRef context)
@@ -336,9 +355,7 @@ bool wxBitmapRefData::Create(CGContextRef context)
#endif #endif
} }
} }
m_ok = ( m_hBitmap != NULL ) ; return IsOk() ;
return m_ok ;
} }
bool wxBitmapRefData::Create( int w , int h , int d, double logicalscale ) bool wxBitmapRefData::Create( int w , int h , int d, double logicalscale )
@@ -370,13 +387,94 @@ bool wxBitmapRefData::Create( int w , int h , int d, double logicalscale )
#if !wxOSX_BITMAP_NATIVE_ACCESS #if !wxOSX_BITMAP_NATIVE_ACCESS
} /* data != NULL */ } /* data != NULL */
#endif #endif
m_ok = ( m_hBitmap != NULL ) ; return IsOk() ;
return m_ok ;
} }
bool wxBitmapRefData::IsOk() const
{
return ( m_hBitmap.get() != NULL
#if wxOSX_BITMAP_NATIVE_ACCESS
|| m_nsImage != NULL
#endif
);
}
#if wxOSX_BITMAP_NATIVE_ACCESS
int wxBitmapRefData::GetWidth() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return CGBitmapContextGetWidth(m_hBitmap);
else
return (int) wxOSXGetImageSize(m_nsImage).width;
}
int wxBitmapRefData::GetHeight() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return CGBitmapContextGetHeight(m_hBitmap);
else
return (int) wxOSXGetImageSize(m_nsImage).height;
}
int wxBitmapRefData::GetDepth() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return CGBitmapContextGetBitsPerPixel(m_hBitmap);
else
return 32; // a bitmap converted from an nsimage would have this depth
}
int wxBitmapRefData::GetBytesPerRow() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return CGBitmapContextGetBytesPerRow(m_hBitmap);
else
return GetBestBytesPerRow( GetWidth() * 4);
}
bool wxBitmapRefData::HasAlpha() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
{
CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(m_hBitmap);
return !(alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast);
}
else
{
return true; // a bitmap converted from an nsimage would have alpha
}
}
WX_NSImage wxBitmapRefData::GetNSImage() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( !m_nsImage )
{
wxCFRef< CGImageRef > cgimage(CreateCGImage());
return wxOSXGetNSImageFromCGImage( cgimage, GetScaleFactor(), IsTemplate() );
}
return m_nsImage;
}
#endif
void wxBitmapRefData::UseAlpha( bool use ) void wxBitmapRefData::UseAlpha( bool use )
{ {
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
if ( HasAlpha() == use ) if ( HasAlpha() == use )
return ; return ;
@@ -400,6 +498,9 @@ void wxBitmapRefData::UseAlpha( bool use )
const void *wxBitmapRefData::GetRawAccess() const const void *wxBitmapRefData::GetRawAccess() const
{ {
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ; wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
EnsureBitmapExists();
#if !wxOSX_BITMAP_NATIVE_ACCESS #if !wxOSX_BITMAP_NATIVE_ACCESS
return m_memBuf.GetData() ; return m_memBuf.GetData() ;
#else #else
@@ -665,10 +766,16 @@ IconRef wxBitmapRefData::GetIconRef()
CGImageRef wxBitmapRefData::CreateCGImage() const CGImageRef wxBitmapRefData::CreateCGImage() const
{ {
wxASSERT( m_ok ) ; wxASSERT( IsOk() ) ;
wxASSERT( m_rawAccessCount >= 0 ) ; wxASSERT( m_rawAccessCount >= 0 ) ;
CGImageRef image ; CGImageRef image ;
if ( m_rawAccessCount > 0 || m_cgImageRef == NULL ) if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
{
if (m_nsImage)
{
image = wxOSXCreateCGImageFromNSImage(m_nsImage);
}
else
{ {
if (GetDepth() != 1 && m_bitmapMask == NULL) if (GetDepth() != 1 && m_bitmapMask == NULL)
{ {
@@ -749,8 +856,7 @@ CGImageRef wxBitmapRefData::CreateCGImage() const
} }
maskBuf.UngetWriteBuf(GetWidth() * GetHeight()); maskBuf.UngetWriteBuf(GetWidth() * GetHeight());
dataProvider = dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer(maskBuf);
wxMacCGDataProviderCreateWithMemoryBuffer( maskBuf );
image = ::CGImageMaskCreate(w, h, 8, 8, GetWidth(), dataProvider, NULL, false); image = ::CGImageMaskCreate(w, h, 8, 8, GetWidth(), dataProvider, NULL, false);
} }
@@ -758,14 +864,14 @@ CGImageRef wxBitmapRefData::CreateCGImage() const
{ {
CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace(); CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer(membuf); dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer(membuf);
image = image = ::CGImageCreate(
::CGImageCreate(
w, h, 8, 32, GetBytesPerRow(), colorSpace, alphaInfo, w, h, 8, 32, GetBytesPerRow(), colorSpace, alphaInfo,
dataProvider, NULL, false, kCGRenderingIntentDefault); dataProvider, NULL, false, kCGRenderingIntentDefault);
} }
CGDataProviderRelease(dataProvider); CGDataProviderRelease(dataProvider);
} }
} }
}
else else
{ {
image = m_cgImageRef ; image = m_cgImageRef ;
@@ -832,6 +938,8 @@ void wxBitmapRefData::Free()
FreeDerivedRepresentations(); FreeDerivedRepresentations();
wxMacCocoaRelease(m_nsImage);
m_hBitmap.reset(); m_hBitmap.reset();
wxDELETE(m_bitmapMask); wxDELETE(m_bitmapMask);
} }
@@ -849,6 +957,9 @@ wxBitmapRefData::~wxBitmapRefData()
bool wxBitmap::CopyFromIcon(const wxIcon& icon) bool wxBitmap::CopyFromIcon(const wxIcon& icon)
{ {
#if wxOSX_BITMAP_NATIVE_ACCESS
return Create( icon.GetNSImage() );
#else
int w = icon.GetWidth() ; int w = icon.GetWidth() ;
int h = icon.GetHeight() ; int h = icon.GetHeight() ;
@@ -866,6 +977,7 @@ bool wxBitmap::CopyFromIcon(const wxIcon& icon)
} }
return false; return false;
#endif
} }
wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits) wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
@@ -1006,11 +1118,11 @@ wxBitmap::wxBitmap(WX_NSImage image)
bool wxBitmap::Create(WX_NSImage image) bool wxBitmap::Create(WX_NSImage image)
{ {
bool isTemplate; UnRef();
if (!Create(wxOSXCreateBitmapContextFromNSImage(image, &isTemplate)))
return false; m_refData = new wxBitmapRefData( image );
GetBitmapData()->SetTemplate(isTemplate);
return true; return GetBitmapData()->IsOk() ;
} }
wxBitmap::wxBitmap(CGContextRef bitmapcontext) wxBitmap::wxBitmap(CGContextRef bitmapcontext)
@@ -1029,8 +1141,7 @@ bool wxBitmap::Create(CGContextRef bitmapcontext)
WX_NSImage wxBitmap::GetNSImage() const WX_NSImage wxBitmap::GetNSImage() const
{ {
wxCFRef< CGImageRef > cgimage(CreateCGImage()); return GetBitmapData()->GetNSImage();
return wxOSXGetNSImageFromCGImage( cgimage, GetScaleFactor(), GetBitmapData()->IsTemplate() );
} }
#endif #endif