X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8e9ff8157389edec60f1e86bca2139dc0e635ebc..716645d36139d6522822b7ae80e509e812c6c693:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 99e6867101..bdff57bb68 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -1,4 +1,4 @@ -///////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// // Name: bitmap.cpp // Purpose: wxBitmap // Author: Julian Smart @@ -40,8 +40,6 @@ #include "wx/icon.h" #endif -//#include "device.h" - #include "wx/msw/private.h" #include "wx/log.h" @@ -57,6 +55,60 @@ #define CLR_INVALID ((COLORREF)-1) #endif // no CLR_INVALID +// ---------------------------------------------------------------------------- +// Bitmap data +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData +{ +public: + wxBitmapRefData(); + virtual ~wxBitmapRefData() { Free(); } + + virtual void Free(); + + // set the mask object to use as the mask, we take ownership of it + void SetMask(wxMask *mask) + { + delete m_bitmapMask; + m_bitmapMask = mask; + } + + // set the HBITMAP to use as the mask + void SetMask(HBITMAP hbmpMask) + { + SetMask(new wxMask((WXHBITMAP)hbmpMask)); + } + + // return the mask + wxMask *GetMask() const { return m_bitmapMask; } + +public: + int m_numColors; +#if wxUSE_PALETTE + wxPalette m_bitmapPalette; +#endif // wxUSE_PALETTE + + // MSW-specific + // ------------ + + // 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; + +#if wxUSE_DIB_FOR_BITMAP + // file mapping handle for large DIB's + HANDLE m_hFileMap; +#endif // wxUSE_DIB_FOR_BITMAP + +private: + // optional mask for transparent drawing + wxMask *m_bitmapMask; + + DECLARE_NO_COPY_CLASS(wxBitmapRefData) +}; + // ---------------------------------------------------------------------------- // macros // ---------------------------------------------------------------------------- @@ -76,11 +128,13 @@ IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) wxBitmapRefData::wxBitmapRefData() { - m_quality = 0; m_selectedInto = NULL; m_numColors = 0; m_bitmapMask = NULL; m_hBitmap = (WXHBITMAP) NULL; +#if wxUSE_DIB_FOR_BITMAP + m_hFileMap = 0; +#endif // wxUSE_DIB_FOR_BITMAP } void wxBitmapRefData::Free() @@ -90,15 +144,21 @@ void wxBitmapRefData::Free() if ( m_hBitmap) { - // printf("About to delete bitmap %d\n", (int) (HBITMAP) m_hBitmap); -#if 1 if ( !::DeleteObject((HBITMAP)m_hBitmap) ) { wxLogLastError(wxT("DeleteObject(hbitmap)")); } -#endif } +#if wxUSE_DIB_FOR_BITMAP + if ( m_hFileMap ) + { + ::CloseHandle(m_hFileMap); + + m_hFileMap = 0; + } +#endif // wxUSE_DIB_FOR_BITMAP + delete m_bitmapMask; m_bitmapMask = NULL; } @@ -114,6 +174,11 @@ void wxBitmap::Init() } +wxGDIImageRefData *wxBitmap::CreateData() const +{ + return new wxBitmapRefData; +} + #ifdef __WIN32__ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) @@ -144,8 +209,7 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) // the mask returned by GetIconInfo() is inversed compared to the usual // wxWin convention - refData->m_bitmapMask = new wxMask((WXHBITMAP) - wxInvertMask(iconInfo.hbmMask, w, h)); + refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h)); // delete the old one now as we don't need it any more @@ -341,41 +405,121 @@ bool wxBitmap::Create(int w, int h, int d) m_refData = new wxBitmapRefData; - GetBitmapData()->m_width = w; - GetBitmapData()->m_height = h; - GetBitmapData()->m_depth = d; - - HBITMAP hbmp; -#ifndef __WXMICROWIN__ - if ( d > 0 ) +#if wxUSE_DIB_FOR_BITMAP + if ( w && h && d >= 16 ) { - hbmp = ::CreateBitmap(w, h, 1, d, NULL); - if ( !hbmp ) - { - wxLogLastError(wxT("CreateBitmap")); - } + if ( !CreateDIB(w, h, d) ) + return FALSE; } else -#endif +#endif // wxUSE_DIB_FOR_BITMAP { - ScreenHDC dc; - hbmp = ::CreateCompatibleBitmap(dc, w, h); - if ( !hbmp ) + GetBitmapData()->m_width = w; + GetBitmapData()->m_height = h; + GetBitmapData()->m_depth = d; + + HBITMAP hbmp; +#ifndef __WXMICROWIN__ + if ( d > 0 ) { - wxLogLastError(wxT("CreateCompatibleBitmap")); + hbmp = ::CreateBitmap(w, h, 1, d, NULL); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateBitmap")); + } } + else +#endif // !__WXMICROWIN__ + { + ScreenHDC dc; + hbmp = ::CreateCompatibleBitmap(dc, w, h); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateCompatibleBitmap")); + } - GetBitmapData()->m_depth = wxDisplayDepth(); - } + GetBitmapData()->m_depth = wxDisplayDepth(); + } - SetHBITMAP((WXHBITMAP)hbmp); + SetHBITMAP((WXHBITMAP)hbmp); #if WXWIN_COMPATIBILITY_2 - GetBitmapData()->m_ok = hbmp != 0; + GetBitmapData()->m_ok = hbmp != 0; #endif // WXWIN_COMPATIBILITY_2 + } + return Ok(); } +#if wxUSE_DIB_FOR_BITMAP + +void *wxBitmap::CreateDIB(int width, int height, int depth) +{ + void *dibBits; + const int infosize = sizeof(BITMAPINFOHEADER); + + BITMAPINFO *info = (BITMAPINFO *)malloc(infosize); + if ( info ) + { + memset(info, 0, infosize); + + info->bmiHeader.biSize = infosize; + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = depth; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSizeImage = + (((width * (depth/8)) + sizeof(DWORD) - 1) / + sizeof(DWORD) * sizeof(DWORD)) * height; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + GetBitmapData()->m_hFileMap = ::CreateFileMapping + ( + INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE | SEC_COMMIT, + 0, + info->bmiHeader.biSizeImage, + 0 + ); + + // No need to report an error here. If it fails, we just won't use a + // file mapping and CreateDIBSection will just allocate memory for us. + GetBitmapData()->m_handle = + (WXHANDLE)::CreateDIBSection + ( + 0, + info, + DIB_RGB_COLORS, + &dibBits, + GetBitmapData()->m_hFileMap, + 0 + ); + + if ( !GetBitmapData()->m_handle ) + wxLogLastError(wxT("CreateDIBSection")); + + SetWidth(width); + SetHeight(height); + SetDepth(depth); + + free(info); + } + else + { + wxFAIL_MSG( wxT("could not allocate memory for DIB header") ); + + dibBits = NULL; + } + + return dibBits; +} + +#endif // wxUSE_DIB_FOR_BITMAP + // ---------------------------------------------------------------------------- // wxImage to/from conversions // ---------------------------------------------------------------------------- @@ -397,7 +541,6 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) // so the 'depth' argument is ignored. HDC hScreenDC = ::GetDC(NULL); - // printf("Screen planes = %d, bpp = %d\n", hScreenDC->psd->planes, hScreenDC->psd->bpp); int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); @@ -483,7 +626,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) ::SelectObject(hMaskDC, hOldMaskBitmap); ::DeleteDC(hMaskDC); - ((wxBitmapRefData*)m_refData)->m_bitmapMask = new wxMask((WXHBITMAP) hMaskBitmap); + ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap); } SetWidth(image.GetWidth()); @@ -503,16 +646,56 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) return TRUE; -#else +#else // !__WXMICROWIN__ wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) m_refData = new wxBitmapRefData(); +#if wxUSE_DIB_FOR_BITMAP + int h = image.GetHeight(); + int w = image.GetWidth(); + unsigned char *dibBits = (unsigned char*)CreateDIB(w, h, 24); + if ( !dibBits ) + return FALSE; + + // DIBs are stored in bottom to top order so we need to copy bits line by + // line and starting from the end + const int srcBytesPerLine = w * 3; + const int dstBytesPerLine = (srcBytesPerLine + sizeof(DWORD) - 1) / + sizeof(DWORD) * sizeof(DWORD); + const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine); + for ( int i = 0; i < h; i++ ) + { + // copy one DIB line + int x = w; + const unsigned char *rgbBits = src; + while ( x-- ) + { + // also, the order of RGB is inversed for DIBs + *dibBits++ = rgbBits[2]; + *dibBits++ = rgbBits[1]; + *dibBits++ = rgbBits[0]; + + rgbBits += 3; + } + + // pass to the next line + src -= srcBytesPerLine; + dibBits += dstBytesPerLine - srcBytesPerLine; + } + + if ( image.HasMask() ) + { + SetMask(new wxMask(*this, wxColour(image.GetMaskRed(), + image.GetMaskGreen(), + image.GetMaskBlue()))); + } +#else // wxUSE_DIB_FOR_BITMAP // sizeLimit is the MS upper limit for the DIB size #ifdef WIN32 int sizeLimit = 1024*768*3; #else - int sizeLimit = 0x7fff ; + int sizeLimit = 0x7fff; #endif // width and height of the device-dependent bitmap @@ -726,6 +909,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) ::ReleaseDC(NULL, hdc); free(lpDIBh); free(lpBits); +#endif // wxUSE_DIB_FOR_BITMAP #if WXWIN_COMPATIBILITY_2 // check the wxBitmap object @@ -733,7 +917,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) #endif // WXWIN_COMPATIBILITY_2 return TRUE; -#endif +#endif // __WXMICROWIN__/!__WXMICROWIN__ } wxImage wxBitmap::ConvertToImage() const @@ -799,8 +983,7 @@ wxImage wxBitmap::ConvertToImage() const return image; -#else // __MICROWIN__ - +#else // !__WXMICROWIN__ wxImage image; wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); @@ -925,7 +1108,7 @@ wxImage wxBitmap::ConvertToImage() const free(lpBits); return image; -#endif +#endif // __WXMICROWIN__/!__WXMICROWIN__ } #endif // wxUSE_IMAGE @@ -948,7 +1131,7 @@ bool wxBitmap::LoadFile(const wxString& filename, long type) wxImage image; if ( image.LoadFile( filename, type ) && image.Ok() ) { - *this = image.ConvertToBitmap(); + *this = wxBitmap(image); return TRUE; } @@ -966,7 +1149,7 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth) if ( !handler ) { - wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type); + wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type); return FALSE; } @@ -990,7 +1173,7 @@ bool wxBitmap::SaveFile(const wxString& filename, else { // FIXME what about palette? shouldn't we use it? - wxImage image( *this ); + wxImage image = ConvertToImage(); if ( image.Ok() ) { return image.SaveFile(filename, type); @@ -1057,21 +1240,49 @@ wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const // wxBitmap accessors // ---------------------------------------------------------------------------- -void wxBitmap::SetQuality(int q) +wxPalette* wxBitmap::GetPalette() const { - EnsureHasData(); + return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette + : (wxPalette *) NULL; +} - GetBitmapData()->m_quality = q; +wxMask *wxBitmap::GetMask() const +{ + return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL; } -#if WXWIN_COMPATIBILITY_2 -void wxBitmap::SetOk(bool isOk) +wxDC *wxBitmap::GetSelectedInto() const { - EnsureHasData(); + return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL; +} - GetBitmapData()->m_ok = isOk; +#if wxUSE_DIB_FOR_BITMAP + +bool wxBitmap::IsDIB() const +{ + return GetBitmapData() && GetBitmapData()->m_hFileMap != NULL; +} + +#endif // wxUSE_DIB_FOR_BITMAP + +#if WXWIN_COMPATIBILITY_2_4 + +int wxBitmap::GetQuality() const +{ + return 0; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxBitmap setters +// ---------------------------------------------------------------------------- + +void wxBitmap::SetSelectedInto(wxDC *dc) +{ + if ( GetBitmapData() ) + GetBitmapData()->m_selectedInto = dc; } -#endif // WXWIN_COMPATIBILITY_2 #if wxUSE_PALETTE @@ -1088,9 +1299,32 @@ void wxBitmap::SetMask(wxMask *mask) { EnsureHasData(); - GetBitmapData()->m_bitmapMask = mask; + GetBitmapData()->SetMask(mask); +} + +#if WXWIN_COMPATIBILITY_2 + +void wxBitmap::SetOk(bool isOk) +{ + EnsureHasData(); + + GetBitmapData()->m_ok = isOk; } +#endif // WXWIN_COMPATIBILITY_2 + +#if WXWIN_COMPATIBILITY_2_4 + +void wxBitmap::SetQuality(int WXUNUSED(quality)) +{ +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// TODO: to be replaced by something better +// ---------------------------------------------------------------------------- + // Creates a bitmap that matches the device context, from // an arbitray bitmap. At present, the original bitmap must have an // associated palette. TODO: use a default palette if no palette exists. @@ -1265,7 +1499,7 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) // scan the bitmap for the transparent colour and set the corresponding // pixels in the mask to BLACK and the rest to WHITE - COLORREF maskColour = RGB(colour.Red(), colour.Green(), colour.Blue()); + COLORREF maskColour = wxColourToPalRGB(colour); m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0); HDC srcDC = ::CreateCompatibleDC(NULL);