Don't crash in wxBitmap::AllocExclusive().

Just use the usual pattern, instead of abusing existing m_refData. In
addition to being cleaner and easier to follow, it also has the benefit
of not crashing when cloning ref data into an UnRef()ed bitmap from
AllocExclusive().

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72298 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík 2012-08-06 12:28:58 +00:00
parent 7a7fa93b0d
commit b9171a1730

View File

@ -39,6 +39,7 @@
#include "wx/image.h" #include "wx/image.h"
#endif #endif
#include "wx/scopedptr.h"
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/msw/dc.h" #include "wx/msw/dc.h"
@ -62,12 +63,14 @@
class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
{ {
public: public:
wxBitmapRefData(); wxBitmapRefData() { Init(); }
wxBitmapRefData(const wxBitmapRefData& data); wxBitmapRefData(const wxBitmapRefData& data);
virtual ~wxBitmapRefData() { Free(); } virtual ~wxBitmapRefData() { Free(); }
virtual void Free(); virtual void Free();
void CopyFromDIB(const wxDIB& dib);
// set the mask object to use as the mask, we take ownership of it // set the mask object to use as the mask, we take ownership of it
void SetMask(wxMask *mask) void SetMask(wxMask *mask)
{ {
@ -114,6 +117,8 @@ public:
bool m_isDIB; bool m_isDIB;
private: private:
void Init();
// optional mask for transparent drawing // optional mask for transparent drawing
wxMask *m_bitmapMask; wxMask *m_bitmapMask;
@ -183,7 +188,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
// wxBitmapRefData // wxBitmapRefData
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxBitmapRefData::wxBitmapRefData() void wxBitmapRefData::Init()
{ {
#if wxDEBUG_LEVEL #if wxDEBUG_LEVEL
m_selectedInto = NULL; m_selectedInto = NULL;
@ -202,23 +207,25 @@ wxBitmapRefData::wxBitmapRefData()
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data) wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
: wxGDIImageRefData(data) : wxGDIImageRefData(data)
{ {
#if wxDEBUG_LEVEL Init();
m_selectedInto = NULL;
#endif
// (deep) copy the mask if present // (deep) copy the mask if present
m_bitmapMask = NULL;
if (data.m_bitmapMask) if (data.m_bitmapMask)
m_bitmapMask = new wxMask(*data.m_bitmapMask); m_bitmapMask = new wxMask(*data.m_bitmapMask);
// FIXME: we don't copy m_hBitmap currently but we should, see wxBitmap:: wxASSERT_MSG( !data.m_dib,
// CloneGDIRefData()
wxASSERT_MSG( !data.m_isDIB,
wxT("can't copy bitmap locked for raw access!") ); wxT("can't copy bitmap locked for raw access!") );
m_isDIB = false;
m_hasAlpha = data.m_hasAlpha; 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() void wxBitmapRefData::Free()
@ -241,6 +248,35 @@ void wxBitmapRefData::Free()
wxDELETE(m_bitmapMask); 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
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxBitmap creation // wxBitmap creation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -250,46 +286,9 @@ wxGDIImageRefData *wxBitmap::CreateData() const
return new wxBitmapRefData; return new wxBitmapRefData;
} }
wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *dataOrig) const wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
{ {
const wxBitmapRefData * return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
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;
} }
bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon, bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon,
@ -427,37 +426,13 @@ bool wxBitmap::CopyFromIcon(const wxIcon& icon, wxBitmapTransparency transp)
bool wxBitmap::CopyFromDIB(const wxDIB& dib) bool wxBitmap::CopyFromDIB(const wxDIB& dib)
{ {
wxCHECK_MSG( dib.IsOk(), false, wxT("invalid DIB in CopyFromDIB") ); wxScopedPtr<wxBitmapRefData> newData(new wxBitmapRefData);
newData->CopyFromDIB(dib);
#ifdef SOMETIMES_USE_DIB if ( !newData->IsOk() )
HBITMAP hbitmap = dib.CreateDDB();
if ( !hbitmap )
return false; return false;
#else // ALWAYS_USE_DIB
HBITMAP hbitmap = const_cast<wxDIB &>(dib).Detach();
#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
UnRef(); UnRef();
m_refData = newData.release();
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
return true; return true;
} }