// Author: Julian Smart
// Modified by:
// Created: 04/01/98
-// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/image.h"
#endif
+#include "wx/scopedptr.h"
#include "wx/msw/private.h"
#include "wx/msw/dc.h"
#endif // no CLR_INVALID
// ----------------------------------------------------------------------------
-// Bitmap data
+// wxBitmapRefData
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
{
public:
- wxBitmapRefData();
+ wxBitmapRefData() { Init(); }
wxBitmapRefData(const wxBitmapRefData& data);
virtual ~wxBitmapRefData() { Free(); }
virtual void Free();
+ void CopyFromDIB(const wxDIB& dib);
+
// set the mask object to use as the mask, we take ownership of it
void SetMask(wxMask *mask)
{
// MSW-specific
// ------------
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL
// this field is solely for error checking: we detect selecting a bitmap
// into more than one DC at once or deleting a bitmap still selected into a
// DC (both are serious programming errors under Windows)
wxDC *m_selectedInto;
-#endif // __WXDEBUG__
+#endif // wxDEBUG_LEVEL
#if wxUSE_WXDIB
// when GetRawData() is called for a DDB we need to convert it to a DIB
bool m_isDIB;
private:
+ void Init();
+
// optional mask for transparent drawing
wxMask *m_bitmapMask;
// wxBitmapRefData
// ----------------------------------------------------------------------------
-wxBitmapRefData::wxBitmapRefData()
+void wxBitmapRefData::Init()
{
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL
m_selectedInto = NULL;
#endif
m_bitmapMask = NULL;
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
: wxGDIImageRefData(data)
{
-#ifdef __WXDEBUG__
- m_selectedInto = NULL;
-#endif
+ Init();
// (deep) copy the mask if present
- m_bitmapMask = NULL;
if (data.m_bitmapMask)
m_bitmapMask = new wxMask(*data.m_bitmapMask);
- // FIXME: we don't copy m_hBitmap currently but we should, see wxBitmap::
- // CloneGDIRefData()
-
- wxASSERT_MSG( !data.m_isDIB,
- _T("can't copy bitmap locked for raw access!") );
- m_isDIB = false;
+ wxASSERT_MSG( !data.m_dib,
+ wxT("can't copy bitmap locked for raw access!") );
m_hasAlpha = data.m_hasAlpha;
+
+#if wxUSE_WXDIB
+ // copy the other bitmap
+ if ( data.m_hBitmap )
+ {
+ wxDIB dib((HBITMAP)(data.m_hBitmap));
+ CopyFromDIB(dib);
+ }
+#endif // wxUSE_WXDIB
}
void wxBitmapRefData::Free()
wxT("deleting bitmap still selected into wxMemoryDC") );
#if wxUSE_WXDIB
- wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") );
+ wxASSERT_MSG( !m_dib, wxT("forgot to call wxBitmap::UngetRawData()!") );
#endif
if ( m_hBitmap)
}
}
- delete m_bitmapMask;
- m_bitmapMask = NULL;
+ wxDELETE(m_bitmapMask);
+}
+
+void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
+{
+ wxCHECK_RET( !IsOk(), "bitmap already initialized" );
+ wxCHECK_RET( dib.IsOk(), wxT("invalid DIB in CopyFromDIB") );
+
+#ifdef SOMETIMES_USE_DIB
+ HBITMAP hbitmap = dib.CreateDDB();
+ if ( !hbitmap )
+ return;
+ m_isDIB = false;
+#else // ALWAYS_USE_DIB
+ HBITMAP hbitmap = const_cast<wxDIB &>(dib).Detach();
+ m_isDIB = true;
+#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
+
+ m_width = dib.GetWidth();
+ m_height = dib.GetHeight();
+ m_depth = dib.GetDepth();
+
+ m_hBitmap = (WXHBITMAP)hbitmap;
+
+#if wxUSE_PALETTE
+ wxPalette *palette = dib.CreatePalette();
+ if ( palette )
+ m_bitmapPalette = *palette;
+ delete palette;
+#endif // wxUSE_PALETTE
}
// ----------------------------------------------------------------------------
return new wxBitmapRefData;
}
-wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *dataOrig) const
+wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
{
- const wxBitmapRefData *
- data = static_cast<const wxBitmapRefData *>(dataOrig);
- if ( !data )
- return NULL;
-
- // FIXME: this method is backwards, it should just create a new
- // wxBitmapRefData using its copy ctor but instead it modifies this
- // bitmap itself and then returns its m_refData -- which works, of
- // course (except in !wxUSE_WXDIB), but is completely illogical
- wxBitmap *self = const_cast<wxBitmap *>(this);
-
- wxBitmapRefData *selfdata;
-#if wxUSE_WXDIB
- // copy the other bitmap
- if ( data->m_hBitmap )
- {
- wxDIB dib((HBITMAP)(data->m_hBitmap));
- self->CopyFromDIB(dib);
-
- selfdata = static_cast<wxBitmapRefData *>(m_refData);
- selfdata->m_hasAlpha = data->m_hasAlpha;
- }
- else
-#endif // wxUSE_WXDIB
- {
- // copy the bitmap data
- selfdata = new wxBitmapRefData(*data);
- self->m_refData = selfdata;
- }
-
- // copy also the mask
- wxMask * const maskSrc = data->GetMask();
- if ( maskSrc )
- {
- selfdata->SetMask(new wxMask(*maskSrc));
- }
-
- return selfdata;
+ return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
}
bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon,
switch ( transp )
{
default:
- wxFAIL_MSG( _T("unknown wxBitmapTransparency value") );
+ wxFAIL_MSG( wxT("unknown wxBitmapTransparency value") );
case wxBitmapTransparency_None:
// nothing to do, refData->m_hasAlpha is false by default
wxDIB dib(iconInfo.hbmColor);
if (dib.IsOk())
{
- const unsigned char* pixels = dib.GetData();
- for (int idx = 0; idx < w*h*4; idx+=4)
+ unsigned char* const pixels = dib.GetData();
+ int idx;
+ for ( idx = 0; idx < w*h*4; idx += 4 )
{
if (pixels[idx+3] != 0)
{
break;
}
}
+
+ if ( refData->m_hasAlpha )
+ {
+ // If we do have alpha, ensure we use premultiplied
+ // data for our pixels as this is what the bitmaps
+ // created in other ways do and this is necessary
+ // for e.g. AlphaBlend() to work with this bitmap.
+ for ( idx = 0; idx < w*h*4; idx += 4 )
+ {
+ const unsigned char a = pixels[idx+3];
+
+ pixels[idx] = ((pixels[idx] *a) + 127)/255;
+ pixels[idx+1] = ((pixels[idx+1]*a) + 127)/255;
+ pixels[idx+2] = ((pixels[idx+2]*a) + 127)/255;
+ }
+
+ ::DeleteObject(refData->m_hBitmap);
+ refData->m_hBitmap = dib.Detach();
+ }
}
}
}
{
UnRef();
- if ( !cursor.Ok() )
+ if ( !cursor.IsOk() )
return false;
return CopyFromIconOrCursor(cursor, transp);
{
UnRef();
- if ( !icon.Ok() )
+ if ( !icon.IsOk() )
return false;
return CopyFromIconOrCursor(icon, transp);
bool wxBitmap::CopyFromDIB(const wxDIB& dib)
{
- wxCHECK_MSG( dib.IsOk(), false, _T("invalid DIB in CopyFromDIB") );
-
-#ifdef SOMETIMES_USE_DIB
- HBITMAP hbitmap = dib.CreateDDB();
- if ( !hbitmap )
+ wxScopedPtr<wxBitmapRefData> newData(new wxBitmapRefData);
+ newData->CopyFromDIB(dib);
+ if ( !newData->IsOk() )
return false;
-#else // ALWAYS_USE_DIB
- HBITMAP hbitmap = ((wxDIB &)dib).Detach(); // const_cast
-#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
UnRef();
-
- wxBitmapRefData *refData = new wxBitmapRefData;
- m_refData = refData;
-
- refData->m_width = dib.GetWidth();
- refData->m_height = dib.GetHeight();
- refData->m_depth = dib.GetDepth();
-
- refData->m_hBitmap = (WXHBITMAP)hbitmap;
-
-#if wxUSE_PALETTE
- wxPalette *palette = dib.CreatePalette();
- if ( palette )
- {
- refData->m_bitmapPalette = *palette;
- }
-
- delete palette;
-#endif // wxUSE_PALETTE
-
+ m_refData = newData.release();
return true;
}
else
{
// bits should already be in Windows standard format
- data = (char *)bits; // const_cast is harmless
+ data = const_cast<char *>(bits);
}
HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
#endif
}
-wxBitmap::wxBitmap(int w, int h, int d)
-{
- (void)Create(w, h, d);
-}
-
wxBitmap::wxBitmap(int w, int h, const wxDC& dc)
{
(void)Create(w, h, dc);
bool wxBitmap::Create(int width, int height, const wxDC& dc)
{
- wxCHECK_MSG( dc.IsOk(), false, _T("invalid HDC in wxBitmap::Create()") );
+ wxCHECK_MSG( dc.IsOk(), false, wxT("invalid HDC in wxBitmap::Create()") );
const wxMSWDCImpl *impl = wxDynamicCast( dc.GetImpl(), wxMSWDCImpl );
SetHBITMAP((WXHBITMAP)hbmp);
- return Ok();
+ return IsOk();
}
#if wxUSE_IMAGE
// so the 'depth' argument is ignored.
// TODO: transparency (create a mask image)
- if (!Ok())
+ if (!IsOk())
{
wxFAIL_MSG( wxT("bitmap is invalid") );
return wxNullImage;
wxImage image;
- wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
+ wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc)
{
wxCHECK_MSG( dc.IsOk(), false,
- _T("invalid HDC in wxBitmap::CreateFromImage()") );
+ wxT("invalid HDC in wxBitmap::CreateFromImage()") );
const wxMSWDCImpl *impl = wxDynamicCast( dc.GetImpl(), wxMSWDCImpl );
bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
{
- wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
+ wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
UnRef();
return false;
const bool hasAlpha = image.HasAlpha();
-
+
if (depth == -1)
depth = dib.GetDepth();
hbitmap = ::CreateBitmap(w, h, 1, 1, data);
if ( !hbitmap )
{
- wxLogLastError(_T("CreateBitmap(mask)"));
+ wxLogLastError(wxT("CreateBitmap(mask)"));
}
else
{
// and then DIB to our wxImage
wxImage image = dib.ConvertToImage();
- if ( !image.Ok() )
+ if ( !image.IsOk() )
{
return wxNullImage;
}
else // no bitmap handler found
{
wxImage image;
- if ( image.LoadFile( filename, type ) && image.Ok() )
+ if ( image.LoadFile( filename, type ) && image.IsOk() )
{
*this = wxBitmap(image);
{
// FIXME what about palette? shouldn't we use it?
wxImage image = ConvertToImage();
- if ( image.Ok() )
+ if ( image.IsOk() )
{
return image.SaveFile(filename, type);
}
wxBitmap wxBitmap::GetSubBitmapOfHDC( const wxRect& rect, WXHDC hdc ) const
{
- wxCHECK_MSG( Ok() &&
+ wxCHECK_MSG( IsOk() &&
(rect.x >= 0) && (rect.y >= 0) &&
(rect.x+rect.width <= GetWidth()) &&
(rect.y+rect.height <= GetHeight()),
wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
wxBitmap ret( rect.width, rect.height, GetDepth() );
- wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
+ wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
#ifndef __WXMICROWIN__
// handle alpha channel, if any
if ( !selectDst )
{
- wxLogLastError(_T("SelectObject(destBitmap)"));
+ wxLogLastError(wxT("SelectObject(destBitmap)"));
}
if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
(HDC)hdc, rect.x, rect.y, SRCCOPY) )
{
- wxLogLastError(_T("BitBlt"));
+ wxLogLastError(wxT("BitBlt"));
}
}
if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
dcSrc, rect.x, rect.y, SRCCOPY) )
{
- wxLogLastError(_T("BitBlt"));
+ wxLogLastError(wxT("BitBlt"));
}
wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
return GetBitmapData() ? GetBitmapData()->GetMask() : NULL;
}
-wxBitmap wxBitmap::GetMaskBitmap() const
-{
- wxBitmap bmp;
- wxMask *mask = GetMask();
- if ( mask )
- bmp.SetHBITMAP(mask->GetMaskBitmap());
- return bmp;
-}
-
-#ifdef __WXDEBUG__
-
wxDC *wxBitmap::GetSelectedInto() const
{
+#if wxDEBUG_LEVEL
return GetBitmapData() ? GetBitmapData()->m_selectedInto : NULL;
-}
-
+#else
+ return NULL;
#endif
+}
void wxBitmap::UseAlpha()
{
// wxBitmap setters
// ----------------------------------------------------------------------------
-#ifdef __WXDEBUG__
-
void wxBitmap::SetSelectedInto(wxDC *dc)
{
+#if wxDEBUG_LEVEL
if ( GetBitmapData() )
GetBitmapData()->m_selectedInto = dc;
-}
-
+#else
+ wxUnusedVar(dc);
#endif
+}
#if wxUSE_PALETTE
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
{
#if wxUSE_WXDIB
- if ( !Ok() )
+ if ( !IsOk() )
{
// no bitmap, no data (raw or otherwise)
return NULL;
if ( !GetBitmapData()->m_isDIB )
{
wxCHECK_MSG( !GetBitmapData()->m_dib, NULL,
- _T("GetRawData() may be called only once") );
+ wxT("GetRawData() may be called only once") );
wxDIB *dib = new wxDIB(*this);
if ( !dib->IsOk() )
DIBSECTION ds;
if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) )
{
- wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") );
+ wxFAIL_MSG( wxT("failed to get DIBSECTION from a DIB?") );
return NULL;
}
// check that the bitmap is in correct format
if ( ds.dsBm.bmBitsPixel != bpp )
{
- wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") );
+ wxFAIL_MSG( wxT("incorrect bitmap type in wxBitmap::GetRawData()") );
return NULL;
}
void wxBitmap::UngetRawData(wxPixelDataBase& dataBase)
{
#if wxUSE_WXDIB
- if ( !Ok() )
+ if ( !IsOk() )
return;
if ( !&dataBase )
bool wxMask::Create(const wxBitmap& bitmap)
{
#ifndef __WXMICROWIN__
- wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, false,
- _T("can't create mask from invalid or not monochrome bitmap") );
+ wxCHECK_MSG( bitmap.IsOk() && bitmap.GetDepth() == 1, false,
+ wxT("can't create mask from invalid or not monochrome bitmap") );
if ( m_maskBitmap )
{
}
#if wxUSE_PALETTE
- if (bitmap.Ok() && bitmap.GetPalette()->Ok())
+ if (bitmap.IsOk() && bitmap.GetPalette()->IsOk())
{
unsigned char red, green, blue;
if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
{
#ifndef __WXMICROWIN__
- wxCHECK_MSG( bitmap.Ok(), false, _T("invalid bitmap in wxMask::Create") );
+ wxCHECK_MSG( bitmap.IsOk(), false, wxT("invalid bitmap in wxMask::Create") );
if ( m_maskBitmap )
{
// SelectObject() will fail
wxASSERT_MSG( !bitmap.GetSelectedInto(),
- _T("bitmap can't be selected in another DC") );
+ wxT("bitmap can't be selected in another DC") );
HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
if ( !hbmpSrcOld )
#endif // __WXMICROWIN__/!__WXMICROWIN__
}
+wxBitmap wxMask::GetBitmap() const
+{
+ wxBitmap bmp;
+ bmp.SetHBITMAP(m_maskBitmap);
+ return bmp;
+}
+
// ----------------------------------------------------------------------------
// wxBitmapHandler
// ----------------------------------------------------------------------------
int hotSpotX,
int hotSpotY)
{
- if ( !bmp.Ok() )
+ if ( !bmp.IsOk() )
{
// we can't create an icon/cursor form nothing
return 0;
if ( bmp.HasAlpha() )
{
+ HBITMAP hbmp;
+
+#if wxUSE_WXDIB && wxUSE_IMAGE
+ // CreateIconIndirect() requires non-pre-multiplied pixel data on input
+ // as it does pre-multiplication internally itself so we need to create
+ // a special DIB in such format to pass to it. This is inefficient but
+ // better than creating an icon with wrong colours.
+ AutoHBITMAP hbmpRelease;
+ hbmp = wxDIB(bmp.ConvertToImage(),
+ wxDIB::PixelFormat_NotPreMultiplied).Detach();
+ hbmpRelease.Init(hbmp);
+#else // !(wxUSE_WXDIB && wxUSE_IMAGE)
+ hbmp = GetHbitmapOf(bmp);
+#endif // wxUSE_WXDIB && wxUSE_IMAGE
+
// Create an empty mask bitmap.
// it doesn't seem to work if we mess with the mask at all.
- HBITMAP hMonoBitmap = CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL);
+ AutoHBITMAP
+ hMonoBitmap(CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL));
ICONINFO iconInfo;
wxZeroMemory(iconInfo);
}
iconInfo.hbmMask = hMonoBitmap;
- iconInfo.hbmColor = GetHbitmapOf(bmp);
-
- HICON hicon = ::CreateIconIndirect(&iconInfo);
+ iconInfo.hbmColor = hbmp;
- ::DeleteObject(hMonoBitmap);
-
- return hicon;
+ return ::CreateIconIndirect(&iconInfo);
}
wxMask* mask = bmp.GetMask();
iconInfo.yHotspot = hotSpotY;
}
- iconInfo.hbmMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap());
+ AutoHBITMAP hbmpMask(wxInvertMask((HBITMAP)mask->GetMaskBitmap()));
+ iconInfo.hbmMask = hbmpMask;
iconInfo.hbmColor = GetHbitmapOf(bmp);
// black out the transparent area to preserve background colour, because
if ( !::BitBlt(dcDst, 0, 0, bmp.GetWidth(), bmp.GetHeight(),
dcSrc, 0, 0, SRCAND) )
{
- wxLogLastError(_T("BitBlt"));
+ wxLogLastError(wxT("BitBlt"));
}
}
delete mask;
}
- // delete the inverted mask bitmap we created as well
- ::DeleteObject(iconInfo.hbmMask);
-
return hicon;
}
HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
{
#ifndef __WXMICROWIN__
- wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") );
+ wxCHECK_MSG( hbmpMask, 0, wxT("invalid bitmap in wxInvertMask") );
// get width/height from the bitmap if not given
if ( !w || !h )