+ m_hasAlpha = use ;
+ if ( m_hasAlpha )
+ {
+ wxASSERT( m_hMaskBitmap == NULL ) ;
+
+ int width = GetWidth() ;
+ int height = GetHeight() ;
+ m_maskBytesPerRow = ( width * 4 + 3 ) & 0xFFFFFFC ;
+ size_t size = height * m_maskBytesPerRow ;
+ unsigned char * data = (unsigned char * ) m_maskMemBuf.GetWriteBuf( size ) ;
+ wxASSERT( data != NULL ) ;
+
+ memset( data , 0 , size ) ;
+ Rect rect = { 0 , 0 , height , width } ;
+ verify_noerr( NewGWorldFromPtr( (GWorldPtr*) &m_hMaskBitmap , k32ARGBPixelFormat , &rect , NULL , NULL , 0 ,
+ (char*) data , m_maskBytesPerRow ) ) ;
+ wxASSERT_MSG( m_hMaskBitmap , wxT("Unable to create GWorld context for alpha mask") ) ;
+ m_maskMemBuf.UngetWriteBuf(size) ;
+
+#if !wxMAC_USE_CORE_GRAPHICS
+ UpdateAlphaMask() ;
+#endif
+ }
+ else
+ {
+ DisposeGWorld( m_hMaskBitmap ) ;
+ m_hMaskBitmap = NULL ;
+ m_maskBytesPerRow = 0 ;
+ }
+}
+
+void *wxBitmapRefData::GetRawAccess() const
+{
+ wxCHECK_MSG( Ok(), NULL , wxT("invalid bitmap") ) ;
+ return m_memBuf.GetData() ;
+}
+
+void *wxBitmapRefData::BeginRawAccess()
+{
+ wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ) ;
+ wxASSERT( m_rawAccessCount == 0 ) ;
+ wxASSERT_MSG( m_pictHandle == NULL && m_iconRef == NULL ,
+ wxT("Currently, modifing bitmaps that are used in controls already is not supported") ) ;
+
+ ++m_rawAccessCount ;
+
+#ifdef __WXMAC_OSX__
+ // we must destroy an existing cached image, as
+ // the bitmap data may change now
+ if ( m_cgImageRef )
+ {
+ CGImageRelease( m_cgImageRef ) ;
+ m_cgImageRef = NULL ;
+ }
+#endif
+
+ return m_memBuf.GetData() ;
+}
+
+void wxBitmapRefData::EndRawAccess()
+{
+ wxCHECK_RET( Ok() , wxT("invalid bitmap") ) ;
+ wxASSERT( m_rawAccessCount == 1 ) ;
+
+ --m_rawAccessCount ;
+
+#if !wxMAC_USE_CORE_GRAPHICS
+ UpdateAlphaMask() ;
+#endif
+}
+
+bool wxBitmapRefData::HasNativeSize()
+{
+ int w = GetWidth() ;
+ int h = GetHeight() ;
+ int sz = wxMax( w , h ) ;
+
+ return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );
+}
+
+IconRef wxBitmapRefData::GetIconRef()
+{
+ if ( m_iconRef == NULL )
+ {
+ // Create Icon Family Handle
+
+ IconFamilyHandle iconFamily = NULL ;
+
+#ifdef WORDS_BIGENDIAN
+ iconFamily = (IconFamilyHandle) NewHandle( 8 ) ;
+ (**iconFamily).resourceType = kIconFamilyType ;
+ (**iconFamily).resourceSize = sizeof(OSType) + sizeof(Size);
+#else
+ // test this solution on big endian as well
+ iconFamily = (IconFamilyHandle) NewHandle( 0 ) ;
+#endif
+
+ int w = GetWidth() ;
+ int h = GetHeight() ;
+ int sz = wxMax( w , h ) ;
+
+ OSType dataType = 0 ;
+ OSType maskType = 0 ;
+
+ switch (sz)
+ {
+ case 128:
+ dataType = kThumbnail32BitData ;
+ maskType = kThumbnail8BitMask ;
+ break;
+
+ case 48:
+ dataType = kHuge32BitData ;
+ maskType = kHuge8BitMask ;
+ break;
+
+ case 32:
+ dataType = kLarge32BitData ;
+ maskType = kLarge8BitMask ;
+ break;
+
+ case 16:
+ dataType = kSmall32BitData ;
+ maskType = kSmall8BitMask ;
+ break;
+
+ default:
+ break;
+ }
+
+ if ( dataType != 0 )
+ {
+ // setup the header properly
+
+ Handle data = NULL ;
+ Handle maskdata = NULL ;
+ unsigned char * maskptr = NULL ;
+ unsigned char * ptr = NULL ;
+ size_t datasize, masksize ;
+
+ datasize = sz * sz * 4 ;
+ data = NewHandle( datasize ) ;
+ HLock( data ) ;
+ ptr = (unsigned char*) *data ;
+ memset( ptr , 0, datasize ) ;
+
+ masksize = sz * sz ;
+ maskdata = NewHandle( masksize ) ;
+ HLock( maskdata ) ;
+ maskptr = (unsigned char*) *maskdata ;
+ memset( maskptr , 0 , masksize ) ;
+
+ bool hasAlpha = HasAlpha() ;
+ wxMask *mask = m_bitmapMask ;
+ unsigned char * source = (unsigned char*) GetRawAccess() ;
+ unsigned char * masksource = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
+
+ for ( int y = 0 ; y < h ; ++y )
+ {
+ unsigned char * dest = ptr + y * sz * 4 ;
+ unsigned char * maskdest = maskptr + y * sz ;
+ unsigned char a, r, g, b;
+
+ for ( int x = 0 ; x < w ; ++x )
+ {
+ a = *source ++ ;
+ r = *source ++ ;
+ g = *source ++ ;
+ b = *source ++ ;
+
+ *dest++ = 0 ;
+ *dest++ = r ;
+ *dest++ = g ;
+ *dest++ = b ;
+
+ if ( mask )
+ {
+ *maskdest++ = 0xFF - *masksource++ ;
+ masksource++ ;
+ masksource++ ;
+ masksource++ ;
+ }
+ else if ( hasAlpha )
+ *maskdest++ = a ;
+ else
+ *maskdest++ = 0xFF ;
+ }
+ }
+
+ OSStatus err = SetIconFamilyData( iconFamily, dataType , data ) ;
+ wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ;
+
+ err = SetIconFamilyData( iconFamily, maskType , maskdata ) ;
+ wxASSERT_MSG( err == noErr , wxT("Error when adding mask") ) ;
+
+ HUnlock( data ) ;
+ HUnlock( maskdata ) ;
+ DisposeHandle( data ) ;
+ DisposeHandle( maskdata ) ;
+ }
+ else
+ {
+ PicHandle pic = GetPictHandle() ;
+ SetIconFamilyData( iconFamily, 'PICT' , (Handle) pic ) ;
+ }
+
+ // transform into IconRef
+
+ static int iconCounter = 2 ;
+
+ OSStatus err = RegisterIconRefFromIconFamily( 'WXNG' , (OSType) iconCounter, iconFamily, &m_iconRef ) ;
+ wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ;
+
+ // we have to retain a reference, as Unregister will decrement it
+ AcquireIconRef( m_iconRef ) ;
+ UnregisterIconRef( 'WXNG' , (OSType) iconCounter ) ;
+ DisposeHandle( (Handle) iconFamily ) ;
+ ++iconCounter ;
+ }
+
+ return m_iconRef ;
+}
+
+PicHandle wxBitmapRefData::GetPictHandle()
+{
+ if ( m_pictHandle == NULL )
+ {
+ CGrafPtr origPort = NULL ;
+ GDHandle origDev = NULL ;
+ GWorldPtr wp = NULL ;
+ GWorldPtr mask = NULL ;
+ int height = GetHeight() ;
+ int width = GetWidth() ;
+
+ Rect rect = { 0 , 0 , height , width } ;
+ RgnHandle clipRgn = NULL ;
+
+ GetGWorld( &origPort , &origDev ) ;
+ wp = GetHBITMAP( &mask ) ;
+
+ if ( mask )
+ {
+ GWorldPtr monoworld ;
+ clipRgn = NewRgn() ;
+ OSStatus err = NewGWorld( &monoworld , 1 , &rect , NULL , NULL , 0 ) ;
+ verify_noerr(err) ;
+ LockPixels( GetGWorldPixMap( monoworld ) ) ;
+ LockPixels( GetGWorldPixMap( mask ) ) ;
+ SetGWorld( monoworld , NULL ) ;
+
+ RGBColor white = { 0xffff , 0xffff , 0xffff } ;
+ RGBColor black = { 0x0000 , 0x0000 , 0x0000 } ;
+ RGBForeColor( &black ) ;
+ RGBBackColor( &white ) ;
+
+ CopyBits(GetPortBitMapForCopyBits(mask),
+ GetPortBitMapForCopyBits(monoworld),
+ &rect,
+ &rect,
+ srcCopy, NULL);
+ BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( monoworld ) ) ;
+
+ UnlockPixels( GetGWorldPixMap( monoworld ) ) ;
+ UnlockPixels( GetGWorldPixMap( mask ) ) ;
+ DisposeGWorld( monoworld ) ;
+ }
+
+ SetGWorld( wp , NULL ) ;
+ Rect portRect ;
+ GetPortBounds( wp , &portRect ) ;
+ m_pictHandle = OpenPicture(&portRect);
+
+ if (m_pictHandle)
+ {
+ RGBColor white = { 0xffff , 0xffff , 0xffff } ;
+ RGBColor black = { 0x0000 , 0x0000 , 0x0000 } ;
+
+ RGBForeColor( &black ) ;
+ RGBBackColor( &white ) ;
+
+ if ( clipRgn )
+ SetClip( clipRgn ) ;
+
+ LockPixels( GetGWorldPixMap( wp ) ) ;
+ CopyBits(GetPortBitMapForCopyBits(wp),
+ GetPortBitMapForCopyBits(wp),
+ &portRect,
+ &portRect,
+ srcCopy,clipRgn);
+ UnlockPixels( GetGWorldPixMap( wp ) ) ;
+ ClosePicture();
+ }
+
+ SetGWorld( origPort , origDev ) ;
+ if ( clipRgn )
+ DisposeRgn( clipRgn ) ;
+ }
+
+ return m_pictHandle ;
+}
+
+#ifdef __WXMAC_OSX__
+void wxMacMemoryBufferReleaseProc(void *info, const void *data, size_t size)
+{
+ wxMemoryBuffer* membuf = (wxMemoryBuffer*) info ;
+
+ wxASSERT( data == membuf->GetData() ) ;
+
+ delete membuf ;
+}
+
+CGImageRef wxBitmapRefData::CGImageCreate() const
+{
+ wxASSERT( m_ok ) ;
+ wxASSERT( m_rawAccessCount >= 0 ) ;
+ CGImageRef image ;
+ if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
+ {
+ size_t imageSize = m_width * m_height * 4 ;
+ void * dataBuffer = m_memBuf.GetData() ;
+ int w = m_width ;
+ int h = m_height ;
+ CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst ;
+ wxMemoryBuffer* membuf = NULL ;
+
+ if ( m_bitmapMask )
+ {
+ alphaInfo = kCGImageAlphaFirst ;
+ membuf = new wxMemoryBuffer( imageSize ) ;
+ memcpy( membuf->GetData() , dataBuffer , imageSize ) ;
+ unsigned char *sourcemaskstart = (unsigned char *) m_bitmapMask->GetRawAccess() ;
+ int maskrowbytes = m_bitmapMask->GetBytesPerRow() ;
+ unsigned char *destalpha = (unsigned char *) membuf->GetData() ;
+ for ( int y = 0 ; y < h ; ++y , sourcemaskstart += maskrowbytes)
+ {
+ unsigned char *sourcemask = sourcemaskstart ;
+ for ( int x = 0 ; x < w ; ++x , sourcemask += 4 , destalpha += 4 )
+ {
+ *destalpha = 0xFF - *sourcemask ;
+ }
+ }
+ }
+ else
+ {
+ if ( m_hasAlpha )
+ {
+#if wxMAC_USE_PREMULTIPLIED_ALPHA
+ alphaInfo = kCGImageAlphaPremultipliedFirst ;
+#else
+ alphaInfo = kCGImageAlphaFirst ;
+#endif
+ }
+
+ membuf = new wxMemoryBuffer( m_memBuf ) ;
+ }
+
+ CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
+ CGDataProviderRef dataProvider =
+ CGDataProviderCreateWithData(
+ membuf , (const void *)membuf->GetData() , imageSize,
+ wxMacMemoryBufferReleaseProc );
+ image =
+ ::CGImageCreate(
+ w, h, 8 , 32 , 4 * m_width , colorSpace, alphaInfo ,
+ dataProvider, NULL , false , kCGRenderingIntentDefault );
+ CGDataProviderRelease( dataProvider);
+ }
+ else
+ {
+ image = m_cgImageRef ;
+ CGImageRetain( image ) ;
+ }
+
+ if ( m_rawAccessCount == 0 && m_cgImageRef == NULL)
+ {
+ // we keep it for later use
+ m_cgImageRef = image ;
+ CGImageRetain( image ) ;
+ }
+
+ return image ;
+}
+#endif
+
+GWorldPtr wxBitmapRefData::GetHBITMAP(GWorldPtr* mask) const
+{
+ wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
+ if ( mask )
+ {
+ *mask = NULL ;
+ if ( m_bitmapMask )
+ {
+ *mask = (GWorldPtr) m_bitmapMask->GetHBITMAP() ;
+ }
+ else if ( m_hasAlpha )
+ {
+#if !wxMAC_USE_CORE_GRAPHICS
+ if ( m_rawAccessCount > 0 )
+ UpdateAlphaMask() ;
+#else
+ // this structure is not kept in synch when using CG, so if something
+ // is really accessing the GrafPorts, we have to sync it
+ UpdateAlphaMask() ;
+#endif
+
+ *mask = m_hMaskBitmap ;
+ }
+ }
+
+ return m_hBitmap ;
+}
+
+void wxBitmapRefData::UpdateAlphaMask() const
+{
+ if ( m_hasAlpha )
+ {
+ unsigned char *sourcemask = (unsigned char *) GetRawAccess() ;
+ unsigned char *destalphabase = (unsigned char *) m_maskMemBuf.GetData() ;
+
+ int h = GetHeight() ;
+ int w = GetWidth() ;
+
+ for ( int y = 0 ; y < h ; ++y , destalphabase += m_maskBytesPerRow )
+ {
+ unsigned char* destalpha = destalphabase ;
+
+ for ( int x = 0 ; x < w ; ++x , sourcemask += 4 )
+ {
+ // we must have 24 bit depth for non quartz smooth alpha
+ *destalpha++ = 255 ;
+ *destalpha++ = 255 - *sourcemask ;
+ *destalpha++ = 255 - *sourcemask ;
+ *destalpha++ = 255 - *sourcemask ;
+ }
+ }
+ }
+}
+
+void wxBitmapRefData::Free()
+{
+ wxASSERT_MSG( m_rawAccessCount == 0 , wxT("Bitmap still selected when destroyed") ) ;
+
+#ifdef __WXMAC_OSX__
+ if ( m_cgImageRef )
+ {
+ CGImageRelease( m_cgImageRef ) ;
+ m_cgImageRef = NULL ;
+ }
+#endif
+
+ if ( m_iconRef )
+ {
+ ReleaseIconRef( m_iconRef ) ;
+ m_iconRef = NULL ;
+ }
+
+ if ( m_pictHandle )
+ {
+ KillPicture( m_pictHandle ) ;
+ m_pictHandle = NULL ;
+ }
+
+ if ( m_hBitmap )
+ {
+ DisposeGWorld( MAC_WXHBITMAP(m_hBitmap) ) ;
+ m_hBitmap = NULL ;
+ }
+
+ if ( m_hMaskBitmap )
+ {
+ DisposeGWorld( MAC_WXHBITMAP(m_hMaskBitmap) ) ;
+ m_hMaskBitmap = NULL ;
+ }
+
+ if (m_bitmapMask)
+ {
+ delete m_bitmapMask;
+ m_bitmapMask = NULL;
+ }
+}
+
+wxBitmapRefData::~wxBitmapRefData()
+{
+ Free() ;
+}