+ wxCHECK_MSG( source, false, _T("wxDC::Blit(): NULL wxDC pointer") );
+
+ WXMICROWIN_CHECK_HDC_RET(false)
+
+ // if either the source or destination has alpha channel, we must use
+ // AlphaBlt() as other function don't handle it correctly
+ const wxBitmap& bmpSrc = source->m_selectedBitmap;
+ if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() ||
+ (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) )
+ {
+ if ( AlphaBlt(GetHdc(), xdest, ydest, width, height,
+ xsrc, ysrc, GetHdcOf(*source), bmpSrc) )
+ return true;
+ }
+
+ wxMask *mask = NULL;
+ if ( useMask )
+ {
+ mask = bmpSrc.GetMask();
+
+ if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) )
+ {
+ // don't give assert here because this would break existing
+ // programs - just silently ignore useMask parameter
+ useMask = false;
+ }
+ }
+
+ if (xsrcMask == -1 && ysrcMask == -1)
+ {
+ xsrcMask = xsrc; ysrcMask = ysrc;
+ }
+
+ COLORREF old_textground = ::GetTextColor(GetHdc());
+ COLORREF old_background = ::GetBkColor(GetHdc());
+ if (m_textForegroundColour.Ok())
+ {
+ ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() );
+ }
+ if (m_textBackgroundColour.Ok())
+ {
+ ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
+ }
+
+ DWORD dwRop;
+ switch (rop)
+ {
+ case wxXOR: dwRop = SRCINVERT; break;
+ case wxINVERT: dwRop = DSTINVERT; break;
+ case wxOR_REVERSE: dwRop = 0x00DD0228; break;
+ case wxAND_REVERSE: dwRop = SRCERASE; break;
+ case wxCLEAR: dwRop = BLACKNESS; break;
+ case wxSET: dwRop = WHITENESS; break;
+ case wxOR_INVERT: dwRop = MERGEPAINT; break;
+ case wxAND: dwRop = SRCAND; break;
+ case wxOR: dwRop = SRCPAINT; break;
+ case wxEQUIV: dwRop = 0x00990066; break;
+ case wxNAND: dwRop = 0x007700E6; break;
+ case wxAND_INVERT: dwRop = 0x00220326; break;
+ case wxCOPY: dwRop = SRCCOPY; break;
+ case wxNO_OP: dwRop = DSTCOPY; break;
+ case wxSRC_INVERT: dwRop = NOTSRCCOPY; break;
+ case wxNOR: dwRop = NOTSRCCOPY; break;
+ default:
+ wxFAIL_MSG( wxT("unsupported logical function") );
+ return false;
+ }
+
+ bool success = false;
+
+ if (useMask)
+ {
+#ifdef __WIN32__
+ // we want the part of the image corresponding to the mask to be
+ // transparent, so use "DSTCOPY" ROP for the mask points (the usual
+ // meaning of fg and bg is inverted which corresponds to wxWin notion
+ // of the mask which is also contrary to the Windows one)
+
+ // On some systems, MaskBlt succeeds yet is much much slower
+ // than the wxWidgets fall-back implementation. So we need
+ // to be able to switch this on and off at runtime.
+#if wxUSE_SYSTEM_OPTIONS
+ if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
+#endif
+ {
+ success = ::MaskBlt
+ (
+ GetHdc(),
+ xdest, ydest, width, height,
+ GetHdcOf(*source),
+ xsrc, ysrc,
+ (HBITMAP)mask->GetMaskBitmap(),
+ xsrcMask, ysrcMask,
+ MAKEROP4(dwRop, DSTCOPY)
+ ) != 0;
+ }
+
+ if ( !success )
+#endif // Win32
+ {
+ // Blit bitmap with mask
+ HDC dc_mask ;
+ HDC dc_buffer ;
+ HBITMAP buffer_bmap ;
+
+#if wxUSE_DC_CACHEING
+ // create a temp buffer bitmap and DCs to access it and the mask
+ wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, source->GetHDC());
+ dc_mask = (HDC) dcCacheEntry1->m_dc;
+
+ wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC());
+ dc_buffer = (HDC) dcCacheEntry2->m_dc;
+
+ wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(),
+ width, height);
+
+ buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap;
+#else // !wxUSE_DC_CACHEING
+ // create a temp buffer bitmap and DCs to access it and the mask
+ dc_mask = ::CreateCompatibleDC(GetHdcOf(*source));
+ dc_buffer = ::CreateCompatibleDC(GetHdc());
+ buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height);
+#endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
+ HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap());
+ HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap);
+
+ // copy dest to buffer
+ if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
+ GetHdc(), xdest, ydest, SRCCOPY) )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+
+ // copy src to buffer using selected raster op
+ if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
+ GetHdcOf(*source), xsrc, ysrc, dwRop) )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+
+ // set masked area in buffer to BLACK (pixel value 0)
+ COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255));
+ COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0));
+ if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height,
+ dc_mask, xsrcMask, ysrcMask, SRCAND) )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+
+ // set unmasked area in dest to BLACK
+ ::SetBkColor(GetHdc(), RGB(0, 0, 0));
+ ::SetTextColor(GetHdc(), RGB(255, 255, 255));
+ if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height,
+ dc_mask, xsrcMask, ysrcMask, SRCAND) )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+ ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values
+ ::SetTextColor(GetHdc(), prevCol);
+
+ // OR buffer to dest
+ success = ::BitBlt(GetHdc(), xdest, ydest,
+ (int)width, (int)height,
+ dc_buffer, 0, 0, SRCPAINT) != 0;
+ if ( !success )
+ {
+ wxLogLastError(wxT("BitBlt"));
+ }
+
+ // tidy up temporary DCs and bitmap
+ ::SelectObject(dc_mask, hOldMaskBitmap);
+ ::SelectObject(dc_buffer, hOldBufferBitmap);
+
+#if !wxUSE_DC_CACHEING
+ {
+ ::DeleteDC(dc_mask);
+ ::DeleteDC(dc_buffer);
+ ::DeleteObject(buffer_bmap);
+ }
+#endif
+ }
+ }
+ else // no mask, just BitBlt() it
+ {
+ // if we already have a DIB, draw it using StretchDIBits(), otherwise
+ // use StretchBlt() if available and finally fall back to BitBlt()
+
+ // FIXME: use appropriate WinCE functions
+#ifndef __WXWINCE__
+ const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS);
+ if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) )
+ {
+ DIBSECTION ds;
+ wxZeroMemory(ds);
+
+ if ( ::GetObject(GetHbitmapOf(bmpSrc),
+ sizeof(ds),
+ &ds) == sizeof(ds) )
+ {
+ StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
+
+ // Figure out what co-ordinate system we're supposed to specify
+ // ysrc in.
+ const LONG hDIB = ds.dsBmih.biHeight;
+ if ( hDIB > 0 )
+ {
+ // reflect ysrc
+ ysrc = hDIB - (ysrc + height);
+ }
+
+ if ( ::StretchDIBits(GetHdc(),
+ xdest, ydest,
+ width, height,
+ xsrc, ysrc,
+ width, height,
+ ds.dsBm.bmBits,
+ (LPBITMAPINFO)&ds.dsBmih,
+ DIB_RGB_COLORS,
+ SRCCOPY
+ ) == (int)GDI_ERROR )
+ {
+ // On Win9x this API fails most (all?) of the time, so
+ // logging it becomes quite distracting. Since it falls
+ // back to the code below this is not really serious, so
+ // don't log it.
+ //wxLogLastError(wxT("StretchDIBits"));
+ }
+ else
+ {
+ success = true;
+ }
+ }
+ }
+
+ if ( !success && (caps & RC_STRETCHBLT) )
+#endif
+ // __WXWINCE__
+ {
+#ifndef __WXWINCE__
+ StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR);
+#endif
+
+ if ( !::StretchBlt
+ (
+ GetHdc(),
+ xdest, ydest, width, height,
+ GetHdcOf(*source),
+ xsrc, ysrc, width, height,
+ dwRop
+ ) )
+ {
+ wxLogLastError(_T("StretchBlt"));
+ }
+ else
+ {
+ success = true;
+ }
+ }
+
+ if ( !success )
+ {
+ if ( !::BitBlt
+ (
+ GetHdc(),
+ xdest, ydest,
+ (int)width, (int)height,
+ GetHdcOf(*source),
+ xsrc, ysrc,
+ dwRop
+ ) )
+ {
+ wxLogLastError(_T("BitBlt"));
+ }
+ else
+ {
+ success = true;
+ }
+ }
+ }
+
+ ::SetTextColor(GetHdc(), old_textground);
+ ::SetBkColor(GetHdc(), old_background);
+
+ return success;