+ node = node->GetNext();
+ }
+ WXHBITMAP hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
+ if ( !hBitmap)
+ {
+ wxLogLastError(wxT("CreateCompatibleBitmap"));
+ }
+ wxDCCacheEntry* entry = new wxDCCacheEntry(hBitmap, w, h, depth);
+ AddToBitmapCache(entry);
+ return entry;
+}
+
+wxDCCacheEntry* wxDC::FindDCInCache(wxDCCacheEntry* notThis, WXHDC dc)
+{
+ int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
+ wxList::compatibility_iterator node = sm_dcCache.GetFirst();
+ while (node)
+ {
+ wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
+
+ // Don't return the same one as we already have
+ if (!notThis || (notThis != entry))
+ {
+ if (entry->m_depth == depth)
+ {
+ return entry;
+ }
+ }
+
+ node = node->GetNext();
+ }
+ WXHDC hDC = (WXHDC) ::CreateCompatibleDC((HDC) dc);
+ if ( !hDC)
+ {
+ wxLogLastError(wxT("CreateCompatibleDC"));
+ }
+ wxDCCacheEntry* entry = new wxDCCacheEntry(hDC, depth);
+ AddToDCCache(entry);
+ return entry;
+}
+
+void wxDC::AddToBitmapCache(wxDCCacheEntry* entry)
+{
+ sm_bitmapCache.Append(entry);
+}
+
+void wxDC::AddToDCCache(wxDCCacheEntry* entry)
+{
+ sm_dcCache.Append(entry);
+}
+
+void wxDC::ClearCache()
+{
+ WX_CLEAR_LIST(wxList, sm_dcCache);
+ WX_CLEAR_LIST(wxList, sm_bitmapCache);
+}
+
+// Clean up cache at app exit
+class wxDCModule : public wxModule
+{
+public:
+ virtual bool OnInit() { return true; }
+ virtual void OnExit() { wxDC::ClearCache(); }
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxDCModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
+
+#endif // wxUSE_DC_CACHEING
+
+// ----------------------------------------------------------------------------
+// alpha channel support
+// ----------------------------------------------------------------------------
+
+static bool AlphaBlt(HDC hdcDst,
+ int x, int y, int width, int height,
+ int srcX, int srcY, HDC hdcSrc,
+ const wxBitmap& bmp)
+{
+ wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
+ wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") );
+
+ // do we have AlphaBlend() and company in the headers?
+#if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
+ // yes, now try to see if we have it during run-time
+ typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
+ HDC,int,int,int,int,
+ BLENDFUNCTION);
+
+ static AlphaBlend_t pfnAlphaBlend = wxMSIMG32_SYMBOL(AlphaBlend);
+ if ( pfnAlphaBlend )
+ {
+ BLENDFUNCTION bf;
+ bf.BlendOp = AC_SRC_OVER;
+ bf.BlendFlags = 0;
+ bf.SourceConstantAlpha = 0xff;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+
+ if ( pfnAlphaBlend(hdcDst, x, y, width, height,
+ hdcSrc, srcX, srcY, width, height,
+ bf) )
+ {
+ // skip wxAlphaBlend() call below
+ return true;
+ }
+
+ wxLogLastError(_T("AlphaBlend"));
+ }
+#else
+ wxUnusedVar(hdcSrc);
+#endif // defined(AC_SRC_OVER)
+
+ // AlphaBlend() unavailable of failed: use our own (probably much slower)
+ // implementation
+#ifdef wxHAVE_RAW_BITMAP
+ wxAlphaBlend(hdcDst, x, y, width, height, srcX, srcY, bmp);
+
+ return true;
+#else // !wxHAVE_RAW_BITMAP
+ // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
+ // alpha but at least something will be shown like this)
+ wxUnusedVar(bmp);
+ return false;
+#endif // wxHAVE_RAW_BITMAP
+}
+
+
+// wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
+#ifdef wxHAVE_RAW_BITMAP
+
+static void
+wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
+ int w, int h,
+ int srcX, int srcY, const wxBitmap& bmpSrc)
+{
+ // get the destination DC pixels
+ wxBitmap bmpDst(w, h, 32 /* force creating RGBA DIB */);
+ MemoryHDC hdcMem;
+ SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
+
+ if ( !::BitBlt(hdcMem, 0, 0, w, h, hdcDst, xDst, yDst, SRCCOPY) )
+ {
+ wxLogLastError(_T("BitBlt"));
+ }
+
+ // combine them with the source bitmap using alpha
+ wxAlphaPixelData dataDst(bmpDst),
+ dataSrc((wxBitmap &)bmpSrc);
+
+ wxCHECK_RET( dataDst && dataSrc,
+ _T("failed to get raw data in wxAlphaBlend") );
+
+ wxAlphaPixelData::Iterator pDst(dataDst),
+ pSrc(dataSrc);
+
+ pSrc.Offset(dataSrc, srcX, srcY);
+
+ for ( int y = 0; y < h; y++ )
+ {
+ wxAlphaPixelData::Iterator pDstRowStart = pDst,
+ pSrcRowStart = pSrc;
+
+ for ( int x = 0; x < w; x++ )
+ {
+ // note that source bitmap uses premultiplied alpha (as required by
+ // the real AlphaBlend)
+ const unsigned beta = 255 - pSrc.Alpha();
+
+ pDst.Red() = pSrc.Red() + (beta * pDst.Red() + 127) / 255;
+ pDst.Blue() = pSrc.Blue() + (beta * pDst.Blue() + 127) / 255;
+ pDst.Green() = pSrc.Green() + (beta * pDst.Green() + 127) / 255;
+
+ ++pDst;
+ ++pSrc;
+ }
+
+ pDst = pDstRowStart;
+ pSrc = pSrcRowStart;
+ pDst.OffsetY(dataDst, 1);
+ pSrc.OffsetY(dataSrc, 1);
+ }
+
+ // and finally blit them back to the destination DC
+ if ( !::BitBlt(hdcDst, xDst, yDst, w, h, hdcMem, 0, 0, SRCCOPY) )
+ {
+ wxLogLastError(_T("BitBlt"));
+ }
+}
+
+#endif // #ifdef wxHAVE_RAW_BITMAP
+
+void wxDC::DoGradientFillLinear (const wxRect& rect,
+ const wxColour& initialColour,
+ const wxColour& destColour,
+ wxDirection nDirection)
+{
+ // use native function if we have compile-time support it and can load it
+ // during run-time (linking to it statically would make the program
+ // unusable on earlier Windows versions)
+#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
+ typedef BOOL
+ (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
+ static GradientFill_t pfnGradientFill = wxMSIMG32_SYMBOL(GradientFill);
+
+ if ( pfnGradientFill )
+ {
+ GRADIENT_RECT grect;
+ grect.UpperLeft = 0;
+ grect.LowerRight = 1;
+
+ // invert colours direction if not filling from left-to-right or
+ // top-to-bottom
+ int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0;
+
+ // one vertex for upper left and one for upper-right
+ TRIVERTEX vertices[2];
+
+ vertices[0].x = rect.GetLeft();
+ vertices[0].y = rect.GetTop();
+ vertices[1].x = rect.GetRight();
+ vertices[1].y = rect.GetBottom();
+
+ vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8);
+ vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8);
+ vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8);
+ vertices[firstVertex].Alpha = 0;
+ vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8);
+ vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8);
+ vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
+ vertices[1 - firstVertex].Alpha = 0;
+
+ if ( (*pfnGradientFill)
+ (
+ GetHdc(),
+ vertices,
+ WXSIZEOF(vertices),
+ &grect,
+ 1,
+ nDirection == wxWEST || nDirection == wxEAST
+ ? GRADIENT_FILL_RECT_H
+ : GRADIENT_FILL_RECT_V
+ ) )
+ {
+ // skip call of the base class version below
+ return;
+ }
+
+ wxLogLastError(_T("GradientFill"));
+ }
+#endif // wxUSE_DYNLIB_CLASS
+
+ wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
+}