+wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC, int depth)
+{
+ m_bitmap = 0;
+ m_dc = hDC;
+ m_width = 0;
+ m_height = 0;
+ m_depth = depth;
+}
+
+wxDCCacheEntry::~wxDCCacheEntry()
+{
+ if (m_bitmap)
+ ::DeleteObject((HBITMAP) m_bitmap);
+ if (m_dc)
+ ::DeleteDC((HDC) m_dc);
+}
+
+wxDCCacheEntry* wxMSWDCImpl::FindBitmapInCache(WXHDC dc, int w, int h)
+{
+ int depth = ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
+ wxList::compatibility_iterator node = sm_bitmapCache.GetFirst();
+ while (node)
+ {
+ wxDCCacheEntry* entry = (wxDCCacheEntry*) node->GetData();
+
+ if (entry->m_depth == depth)
+ {
+ if (entry->m_width < w || entry->m_height < h)
+ {
+ ::DeleteObject((HBITMAP) entry->m_bitmap);
+ entry->m_bitmap = (WXHBITMAP) ::CreateCompatibleBitmap((HDC) dc, w, h);
+ if ( !entry->m_bitmap)
+ {
+ wxLogLastError(wxT("CreateCompatibleBitmap"));
+ }
+ entry->m_width = w; entry->m_height = h;
+ return entry;
+ }
+ return entry;
+ }
+
+ 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* wxMSWDCImpl::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 wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry* entry)
+{
+ sm_bitmapCache.Append(entry);
+}
+
+void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry* entry)
+{
+ sm_dcCache.Append(entry);
+}
+
+void wxMSWDCImpl::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() { wxMSWDCImpl::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 dstWidth, int dstHeight,
+ int srcX, int srcY,
+ int srcWidth, int srcHeight,
+ HDC hdcSrc,
+ const wxBitmap& bmp)
+{
+ wxASSERT_MSG( bmp.IsOk() && 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 = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("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, dstWidth, dstHeight,
+ hdcSrc, srcX, srcY, srcWidth, srcHeight,
+ 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, dstWidth, dstHeight, srcX, srcY, srcWidth, srcHeight, 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 dstWidth, int dstHeight,
+ int srcX, int srcY,
+ int srcWidth, int srcHeight,
+ const wxBitmap& bmpSrc)
+{
+ // get the destination DC pixels
+ wxBitmap bmpDst(dstWidth, dstHeight, 32 /* force creating RGBA DIB */);
+ MemoryHDC hdcMem;
+ SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst));
+
+ if ( !::BitBlt(hdcMem, 0, 0, dstWidth, dstHeight, 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);
+
+
+ for ( int y = 0; y < dstHeight; y++ )
+ {
+ wxAlphaPixelData::Iterator pDstRowStart = pDst;
+
+ for ( int x = 0; x < dstWidth; x++ )
+ {
+ // source is point sampled, Alpha StretchBlit is ugly on Win95
+ // (but does not impact performance)
+ pSrc.MoveTo(dataSrc, srcX + (srcWidth*x/dstWidth), srcY + (srcHeight*y/dstHeight));
+
+ // 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;
+ }
+
+ pDst = pDstRowStart;
+ pDst.OffsetY(dataDst, 1);
+ }
+
+ // and finally blit them back to the destination DC
+ if ( !::BitBlt(hdcDst, xDst, yDst, dstWidth, dstHeight, hdcMem, 0, 0, SRCCOPY) )
+ {
+ wxLogLastError(_T("BitBlt"));
+ }
+}
+
+#endif // #ifdef wxHAVE_RAW_BITMAP
+
+void wxMSWDCImpl::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 =
+ (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("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()+1;
+ vertices[1].y = rect.GetBottom()+1;
+
+ 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
+
+ wxDCImpl::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
+}
+
+#if wxUSE_DYNLIB_CLASS
+
+static DWORD wxGetDCLayout(HDC hdc)
+{
+ typedef DWORD (WINAPI *GetLayout_t)(HDC);
+ static GetLayout_t
+ wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(_T("gdi32.dll")));
+
+ return s_pfnGetLayout ? s_pfnGetLayout(hdc) : (DWORD)-1;
+}
+
+wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
+{
+ DWORD layout = wxGetDCLayout(GetHdc());
+
+ if ( layout == (DWORD)-1 )
+ return wxLayout_Default;
+
+ return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight;
+}
+
+void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
+{
+ typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
+ static SetLayout_t
+ wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(_T("gdi32.dll")));
+ if ( !s_pfnSetLayout )
+ return;
+
+ if ( dir == wxLayout_Default )
+ {
+ dir = wxTheApp->GetLayoutDirection();
+ if ( dir == wxLayout_Default )
+ return;
+ }
+
+ DWORD layout = wxGetDCLayout(GetHdc());
+ if ( dir == wxLayout_RightToLeft )
+ layout |= LAYOUT_RTL;
+ else
+ layout &= ~LAYOUT_RTL;
+
+ s_pfnSetLayout(GetHdc(), layout);
+}
+
+#else // !wxUSE_DYNLIB_CLASS
+
+// we can't provide RTL support without dynamic loading, so stub it out
+wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
+{
+ return wxLayout_Default;
+}
+
+void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection WXUNUSED(dir))
+{
+}