X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/907173e51df6d2a91d65463ddf6ce810d3fd921a..7ea70037e0931bcf0895b6a3a453765919e2e1c1:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 16e23a409d..e2a27b4aca 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////// -// Name: bitmap.cpp +// Name: src/msw/bitmap.cpp // Purpose: wxBitmap // Author: Julian Smart // Modified by: @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "bitmap.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -28,6 +24,8 @@ #pragma hdrstop #endif +#include "wx/bitmap.h" + #ifndef WX_PRECOMP #include @@ -36,22 +34,19 @@ #include "wx/app.h" #include "wx/palette.h" #include "wx/dcmemory.h" - #include "wx/bitmap.h" #include "wx/icon.h" + #include "wx/log.h" + #include "wx/image.h" #endif #include "wx/msw/private.h" -#include "wx/log.h" #if wxUSE_WXDIB -#include "wx/msw/dib.h" + #include "wx/msw/dib.h" #endif -#include "wx/image.h" -#include "wx/xpmdecod.h" - #ifdef wxHAVE_RAW_BITMAP -#include "wx/rawbmp.h" + #include "wx/rawbmp.h" #endif // missing from mingw32 header @@ -210,8 +205,13 @@ wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data) m_selectedInto = NULL; #endif - // can't copy the mask as the other bitmap destroys it + // (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:: + // CloneRefData() wxASSERT_MSG( !data.m_isDIB, _T("can't copy bitmap locked for raw access!") ); @@ -245,12 +245,6 @@ void wxBitmapRefData::Free() // wxBitmap creation // ---------------------------------------------------------------------------- -// this function should be called from all wxBitmap ctors -void wxBitmap::Init() -{ - // m_refData = NULL; done in the base class ctor -} - wxGDIImageRefData *wxBitmap::CreateData() const { return new wxBitmapRefData; @@ -263,6 +257,10 @@ wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *dataOrig) const 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 = wx_const_cast(wxBitmap *, this); #if wxUSE_WXDIB @@ -275,10 +273,19 @@ wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *dataOrig) const else #endif // wxUSE_WXDIB { - // don't copy the bitmap data, but do copy the size, depth, ... + // copy the bitmap data self->m_refData = new wxBitmapRefData(*data); } + // copy also the mask + wxMask * const maskSrc = data->GetMask(); + if ( maskSrc ) + { + wxBitmapRefData *selfdata = wx_static_cast(wxBitmapRefData *, m_refData); + + selfdata->SetMask(new wxMask(*maskSrc)); + } + return m_refData; } @@ -310,10 +317,37 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor; - // the mask returned by GetIconInfo() is inversed compared to the usual - // wxWin convention - refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h)); - +#if wxUSE_WXDIB + // If the icon is 32 bits per pixel then it may have alpha channel data, + // although there are some icons that are 32 bpp but have no alpha... So + // convert to a DIB and manually check the 4th byte for each pixel. + BITMAP bm; + if ( ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), (LPVOID)&bm) + && bm.bmBitsPixel == 32) + { + wxDIB dib(iconInfo.hbmColor); + if (dib.IsOk()) + { + unsigned char* pixels = dib.GetData(); + for (int idx=0; idxm_hasAlpha = true; + break; + } + } + } + } +#endif + if ( !refData->m_hasAlpha ) + { + // the mask returned by GetIconInfo() is inverted compared to the usual + // wxWin convention + refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h)); + } // delete the old one now as we don't need it any more ::DeleteObject(iconInfo.hbmMask); @@ -393,8 +427,6 @@ wxBitmap::~wxBitmap() wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) { - Init(); - #ifndef __WXMICROWIN__ wxBitmapRefData *refData = new wxBitmapRefData; m_refData = refData; @@ -408,7 +440,7 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) { // we assume that it is in XBM format which is not quite the same as // the format CreateBitmap() wants because the order of bytes in the - // line is inversed! + // line is reversed! const size_t bytesPerLine = (width + 7) / 8; const size_t padding = bytesPerLine % 2; const size_t len = height * ( padding + bytesPerLine ); @@ -429,7 +461,7 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) reversed |= (unsigned char)(val & 0x01); val >>= 1; } - *dst++ = reversed; + *dst++ = ~reversed; } if ( padding ) @@ -457,51 +489,23 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) #endif } -// Create from XPM data -bool wxBitmap::CreateFromXpm(const char **data) -{ -#if wxUSE_IMAGE && wxUSE_XPM - Init(); - - wxCHECK_MSG( data != NULL, false, wxT("invalid bitmap data") ) - - wxXPMDecoder decoder; - wxImage img = decoder.ReadData(data); - wxCHECK_MSG( img.Ok(), false, wxT("invalid bitmap data") ) - - *this = wxBitmap(img); - return true; -#else - wxUnusedVar(data); - return false; -#endif -} - wxBitmap::wxBitmap(int w, int h, int d) { - Init(); - (void)Create(w, h, d); } wxBitmap::wxBitmap(int w, int h, const wxDC& dc) { - Init(); - (void)Create(w, h, dc); } -wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth) +wxBitmap::wxBitmap(const void* data, long type, int width, int height, int depth) { - Init(); - (void)Create(data, type, width, height, depth); } wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) { - Init(); - LoadFile(filename, (int)type); } @@ -775,8 +779,6 @@ wxImage wxBitmap::ConvertToImage() const // wxImage to/from conversions // ---------------------------------------------------------------------------- -#if wxUSE_WXDIB - bool wxBitmap::CreateFromImage(const wxImage& image, int depth) { return CreateFromImage(image, depth, 0); @@ -790,6 +792,8 @@ bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc) return CreateFromImage(image, -1, dc.GetHDC()); } +#if wxUSE_WXDIB + bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) { wxCHECK_MSG( image.Ok(), false, wxT("invalid image") ); @@ -804,6 +808,8 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) if ( !dib.IsOk() ) return false; + if ( depth == -1 ) + depth = dib.GetDepth(); // Get depth from image if none specified // store the bitmap parameters wxBitmapRefData *refData = new wxBitmapRefData; @@ -826,14 +832,14 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) hbitmap = dib.Detach(); refData->m_isDIB = true; - refData->m_depth = dib.GetDepth(); + refData->m_depth = depth; } #ifndef ALWAYS_USE_DIB else // we need to convert DIB to DDB { hbitmap = dib.CreateDDB((HDC)hdc); - refData->m_depth = depth == -1 ? dib.GetDepth() : depth; + refData->m_depth = depth; } #endif // !ALWAYS_USE_DIB @@ -843,9 +849,42 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) // finally also set the mask if we have one if ( image.HasMask() ) { - SetMask(new wxMask(*this, wxColour(image.GetMaskRed(), - image.GetMaskGreen(), - image.GetMaskBlue()))); + const size_t len = 2*((w+15)/16); + BYTE *src = image.GetData(); + BYTE *data = new BYTE[h*len]; + memset(data, 0, h*len); + BYTE r = image.GetMaskRed(), + g = image.GetMaskGreen(), + b = image.GetMaskBlue(); + BYTE *dst = data; + for ( int y = 0; y < h; y++, dst += len ) + { + BYTE *dstLine = dst; + BYTE mask = 0x80; + for ( int x = 0; x < w; x++, src += 3 ) + { + if (src[0] != r || src[1] != g || src[2] != b) + *dstLine |= mask; + + if ( (mask >>= 1) == 0 ) + { + dstLine++; + mask = 0x80; + } + } + } + + hbitmap = ::CreateBitmap(w, h, 1, 1, data); + if ( !hbitmap ) + { + wxLogLastError(_T("CreateBitmap(mask)")); + } + else + { + SetMask(new wxMask((WXHBITMAP)hbitmap)); + } + + delete[] data; } return true; @@ -934,7 +973,22 @@ wxImage wxBitmap::ConvertToImage() const return image; } -#endif // wxUSE_WXDIB +#else // !wxUSE_WXDIB + +bool +wxBitmap::CreateFromImage(const wxImage& WXUNUSED(image), + int WXUNUSED(depth), + WXHDC WXUNUSED(hdc)) +{ + return false; +} + +wxImage wxBitmap::ConvertToImage() const +{ + return wxImage(); +} + +#endif // wxUSE_WXDIB/!wxUSE_WXDIB #endif // wxUSE_IMAGE @@ -954,7 +1008,7 @@ bool wxBitmap::LoadFile(const wxString& filename, long type) return handler->LoadFile(this, filename, type, -1, -1); } -#if wxUSE_IMAGE +#if wxUSE_IMAGE && wxUSE_WXDIB else // no bitmap handler found { wxImage image; @@ -970,7 +1024,7 @@ bool wxBitmap::LoadFile(const wxString& filename, long type) return false; } -bool wxBitmap::Create(void *data, long type, int width, int height, int depth) +bool wxBitmap::Create(const void* data, long type, int width, int height, int depth) { UnRef(); @@ -998,7 +1052,7 @@ bool wxBitmap::SaveFile(const wxString& filename, { return handler->SaveFile(this, filename, type, palette); } -#if wxUSE_IMAGE +#if wxUSE_IMAGE && wxUSE_WXDIB else // no bitmap handler found { // FIXME what about palette? shouldn't we use it? @@ -1031,7 +1085,7 @@ wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const #ifndef __WXMICROWIN__ // handle alpha channel, if any if (HasAlpha()) - ret.UseAlpha(); + ret.UseAlpha(); // copy bitmap data MemoryHDC dcSrc, @@ -1092,6 +1146,15 @@ wxMask *wxBitmap::GetMask() const return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL; } +wxBitmap wxBitmap::GetMaskBitmap() const +{ + wxBitmap bmp; + wxMask *mask = GetMask(); + if ( mask ) + bmp.SetHBITMAP(mask->GetMaskBitmap()); + return bmp; +} + #ifdef __WXDEBUG__ wxDC *wxBitmap::GetSelectedInto() const @@ -1181,7 +1244,7 @@ void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) HBITMAP hDIB; if ( !GetBitmapData()->m_isDIB ) { - wxCHECK_MSG( !GetBitmapData()->m_dib, FALSE, + wxCHECK_MSG( !GetBitmapData()->m_dib, NULL, _T("GetRawData() may be called only once") ); wxDIB *dib = new wxDIB(*this); @@ -1282,6 +1345,39 @@ wxMask::wxMask() m_maskBitmap = 0; } +// Copy constructor +wxMask::wxMask(const wxMask &mask) + : wxObject() +{ + BITMAP bmp; + + HDC srcDC = CreateCompatibleDC(0); + HDC destDC = CreateCompatibleDC(0); + + // GetBitmapDimensionEx won't work if SetBitmapDimensionEx wasn't used + // so we'll use GetObject() API here: + if (::GetObject((HGDIOBJ)mask.m_maskBitmap, sizeof(bmp), &bmp) == 0) + { + wxFAIL_MSG(wxT("Cannot retrieve the dimensions of the wxMask to copy")); + return; + } + + // create our HBITMAP + int w = bmp.bmWidth, h = bmp.bmHeight; + m_maskBitmap = (WXHBITMAP)CreateCompatibleBitmap(srcDC, w, h); + + // copy the mask's HBITMAP into our HBITMAP + SelectObject(srcDC, (HBITMAP) mask.m_maskBitmap); + SelectObject(destDC, (HBITMAP) m_maskBitmap); + + BitBlt(destDC, 0, 0, w, h, srcDC, 0, 0, SRCCOPY); + + SelectObject(srcDC, 0); + DeleteDC(srcDC); + SelectObject(destDC, 0); + DeleteDC(destDC); +} + // Construct a mask from a bitmap and a colour indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) @@ -1447,13 +1543,13 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) // ---------------------------------------------------------------------------- bool wxBitmapHandler::Create(wxGDIImage *image, - void *data, + const void* data, long flags, int width, int height, int depth) { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - return bitmap ? Create(bitmap, data, flags, width, height, depth) : false; + return bitmap && Create(bitmap, data, flags, width, height, depth); } bool wxBitmapHandler::Load(wxGDIImage *image, @@ -1463,7 +1559,7 @@ bool wxBitmapHandler::Load(wxGDIImage *image, { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - return bitmap ? LoadFile(bitmap, name, flags, width, height) : false; + return bitmap && LoadFile(bitmap, name, flags, width, height); } bool wxBitmapHandler::Save(wxGDIImage *image, @@ -1472,11 +1568,11 @@ bool wxBitmapHandler::Save(wxGDIImage *image, { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - return bitmap ? SaveFile(bitmap, name, type) : false; + return bitmap && SaveFile(bitmap, name, type); } bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), - void *WXUNUSED(data), + const void* WXUNUSED(data), long WXUNUSED(type), int WXUNUSED(width), int WXUNUSED(height), @@ -1530,7 +1626,7 @@ bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel, // this value must be 1, 4, 8 or 24 so PixelDepth can only be lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel); lpDIBheader->bmiHeader.biCompression = BI_RGB; - lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3; + lpDIBheader->bmiHeader.biSizeImage = (xSize * abs(ySize) * bitsPerPixel) >> 3; lpDIBheader->bmiHeader.biClrUsed = 256; @@ -1570,7 +1666,33 @@ HICON wxBitmapToIconOrCursor(const wxBitmap& bmp, return 0; } - wxMask *mask = bmp.GetMask(); + if ( bmp.HasAlpha() ) + { + // 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); + + ICONINFO iconInfo; + wxZeroMemory(iconInfo); + iconInfo.fIcon = iconWanted; // do we want an icon or a cursor? + if ( !iconWanted ) + { + iconInfo.xHotspot = hotSpotX; + iconInfo.yHotspot = hotSpotY; + } + + iconInfo.hbmMask = hMonoBitmap; + iconInfo.hbmColor = GetHbitmapOf(bmp); + + HICON hicon = ::CreateIconIndirect(&iconInfo); + + ::DeleteObject(hMonoBitmap); + + return hicon; + } + + wxMask* mask = bmp.GetMask(); + if ( !mask ) { // we must have a mask for an icon, so even if it's probably incorrect, @@ -1607,7 +1729,7 @@ HICON wxBitmapToIconOrCursor(const wxBitmap& bmp, HICON hicon = ::CreateIconIndirect(&iconInfo); - if ( !bmp.GetMask() ) + if ( !bmp.GetMask() && !bmp.HasAlpha() ) { // we created the mask, now delete it delete mask;