+// ----------------------------------------------------------------------------
+// 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 = (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, 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 =
+ (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();
+ 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);
+}
+
+static DWORD wxGetDCLayout(HDC hdc)
+{
+ typedef DWORD (WINAPI *GetLayout_t)(HDC);
+ static GetLayout_t
+ pfnGetLayout = (GetLayout_t)wxGDI32DLL.GetSymbol(_T("GetLayout"));
+
+ return pfnGetLayout ? pfnGetLayout(hdc) : (DWORD)-1;
+}
+
+wxLayoutDirection wxDC::GetLayoutDirection() const
+{
+ DWORD layout = wxGetDCLayout(GetHdc());
+
+ if ( layout == (DWORD)-1 )
+ return wxLayout_Default;
+
+ return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight;
+}
+
+void wxDC::SetLayoutDirection(wxLayoutDirection dir)
+{
+ typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
+ static SetLayout_t
+ pfnSetLayout = (SetLayout_t)wxGDI32DLL.GetSymbol(_T("SetLayout"));
+ if ( !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;
+
+ pfnSetLayout(GetHdc(), layout);
+}