Remove dynamic loading of GDI functions from wxMSW wxDC code.

All of these functions (AlphaBlend(), SetLayout(), SetWorldTransform(), ...)
are available in XP which is the minimally required version.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77029 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-08-09 14:21:06 +00:00
parent 992671d2a7
commit 2bebe217c1

View File

@@ -41,7 +41,6 @@
#include "wx/msw/dc.h"
#include "wx/sysopt.h"
#include "wx/dynlib.h"
#ifdef wxHAS_RAW_BITMAP
#include "wx/rawbmp.h"
@@ -133,27 +132,9 @@ static bool AlphaBlt(wxMSWDCImpl* dcSrc,
HDC hdcSrc,
const wxBitmap& bmpSrc);
#ifdef wxHAS_RAW_BITMAP
// our (limited) AlphaBlend() replacement for Windows versions not providing it
static void
wxAlphaBlend(HDC hdcDst, int xDst, int yDst,
int dstWidth, int dstHeight,
int srcX, int srcY,
int srcWidth, int srcHeight,
const wxBitmap& bmpSrc);
#endif // wxHAS_RAW_BITMAP
namespace wxMSWImpl
{
// Wrappers for the dynamically loaded {Set,Get}Layout() functions. They work
// in exactly the same way as the standard functions and return GDI_ERROR if
// they're not actually available.
DWORD GetLayout(HDC hdc);
DWORD SetLayout(HDC hdc, DWORD dwLayout);
// Create a compatible HDC and copy the layout of the source DC to it. This is
// necessary in order to draw bitmaps (which are usually blitted from a
// temporary compatible memory DC to the real target DC) using the same layout.
@@ -225,164 +206,6 @@ private:
#endif // __WXWINCE__/!__WXWINCE__
#if wxUSE_DYNLIB_CLASS
// helper class to cache dynamically loaded libraries and not attempt reloading
// them if it fails
class wxOnceOnlyDLLLoader
{
public:
// ctor argument must be a literal string as we don't make a copy of it!
wxOnceOnlyDLLLoader(const wxChar *dllName)
: m_dllName(dllName)
{
}
// return the symbol with the given name or NULL if the DLL not loaded
// or symbol not present
void *GetSymbol(const wxChar *name)
{
// we're prepared to handle errors here
wxLogNull noLog;
if ( m_dllName )
{
m_dll.Load(m_dllName);
// reset the name whether we succeeded or failed so that we don't
// try again the next time
m_dllName = NULL;
}
return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL;
}
void Unload()
{
if ( m_dll.IsLoaded() )
{
m_dll.Unload();
}
}
private:
wxDynamicLibrary m_dll;
const wxChar *m_dllName;
};
static wxOnceOnlyDLLLoader wxMSIMG32DLL(wxT("msimg32"));
// we must ensure that DLLs are unloaded before the static objects cleanup time
// because we may hit the notorious DllMain() dead lock in this case if wx is
// used as a DLL (attempting to unload another DLL from inside DllMain() hangs
// under Windows because it tries to reacquire the same lock)
class wxGDIDLLsCleanupModule : public wxModule
{
public:
virtual bool OnInit() { return true; }
virtual void OnExit() { wxMSIMG32DLL.Unload(); }
private:
DECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule, wxModule)
namespace
{
#if wxUSE_DC_TRANSFORM_MATRIX
// Class used to dynamically load world transform related API functions.
class GdiWorldTransformFuncs
{
public:
static bool IsOk()
{
if ( !ms_worldTransformSymbolsLoaded )
LoadWorldTransformSymbols();
return ms_pfnSetGraphicsMode &&
ms_pfnSetWorldTransform &&
ms_pfnGetWorldTransform &&
ms_pfnModifyWorldTransform;
}
typedef int (WINAPI *SetGraphicsMode_t)(HDC, int);
static SetGraphicsMode_t SetGraphicsMode()
{
if ( !ms_worldTransformSymbolsLoaded )
LoadWorldTransformSymbols();
return ms_pfnSetGraphicsMode;
}
typedef BOOL (WINAPI *SetWorldTransform_t)(HDC, const XFORM *);
static SetWorldTransform_t SetWorldTransform()
{
if ( !ms_worldTransformSymbolsLoaded )
LoadWorldTransformSymbols();
return ms_pfnSetWorldTransform;
}
typedef BOOL (WINAPI *GetWorldTransform_t)(HDC, LPXFORM);
static GetWorldTransform_t GetWorldTransform()
{
if ( !ms_worldTransformSymbolsLoaded )
LoadWorldTransformSymbols();
return ms_pfnGetWorldTransform;
}
typedef BOOL (WINAPI *ModifyWorldTransform_t)(HDC, const XFORM *, DWORD);
static ModifyWorldTransform_t ModifyWorldTransform()
{
if ( !ms_worldTransformSymbolsLoaded )
LoadWorldTransformSymbols();
return ms_pfnModifyWorldTransform;
}
private:
static void LoadWorldTransformSymbols()
{
wxDynamicLibrary dll(wxT("gdi32.dll"));
wxDL_INIT_FUNC(ms_pfn, SetGraphicsMode, dll);
wxDL_INIT_FUNC(ms_pfn, SetWorldTransform, dll);
wxDL_INIT_FUNC(ms_pfn, GetWorldTransform, dll);
wxDL_INIT_FUNC(ms_pfn, ModifyWorldTransform, dll);
ms_worldTransformSymbolsLoaded = true;
}
static SetGraphicsMode_t ms_pfnSetGraphicsMode;
static SetWorldTransform_t ms_pfnSetWorldTransform;
static GetWorldTransform_t ms_pfnGetWorldTransform;
static ModifyWorldTransform_t ms_pfnModifyWorldTransform;
static bool ms_worldTransformSymbolsLoaded;
};
GdiWorldTransformFuncs::SetGraphicsMode_t
GdiWorldTransformFuncs::ms_pfnSetGraphicsMode = NULL;
GdiWorldTransformFuncs::SetWorldTransform_t
GdiWorldTransformFuncs::ms_pfnSetWorldTransform = NULL;
GdiWorldTransformFuncs::GetWorldTransform_t
GdiWorldTransformFuncs::ms_pfnGetWorldTransform = NULL;
GdiWorldTransformFuncs::ModifyWorldTransform_t
GdiWorldTransformFuncs::ms_pfnModifyWorldTransform = NULL;
bool GdiWorldTransformFuncs::ms_worldTransformSymbolsLoaded = false;
#endif // wxUSE_DC_TRANSFORM_MATRIX
} // anonymous namespace
#endif // wxUSE_DYNLIB_CLASS
// ===========================================================================
// implementation
// ===========================================================================
@@ -2112,21 +1935,18 @@ void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y)
bool wxMSWDCImpl::CanUseTransformMatrix() const
{
return GdiWorldTransformFuncs::IsOk();
return true;
}
bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix)
{
if ( !GdiWorldTransformFuncs::IsOk() )
return false;
if ( matrix.IsIdentity() )
{
ResetTransformMatrix();
return true;
}
if ( !GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_ADVANCED) )
if ( !::SetGraphicsMode(GetHdc(), GM_ADVANCED) )
{
wxLogLastError(wxT("SetGraphicsMode"));
return false;
@@ -2144,7 +1964,7 @@ bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix)
xform.eDx = tr.m_x;
xform.eDy = tr.m_y;
if ( !GdiWorldTransformFuncs::SetWorldTransform()(GetHdc(), &xform) )
if ( !::SetWorldTransform(GetHdc(), &xform) )
{
wxLogLastError(wxT("SetWorldTransform"));
return false;
@@ -2157,11 +1977,8 @@ wxAffineMatrix2D wxMSWDCImpl::GetTransformMatrix() const
{
wxAffineMatrix2D transform;
if ( !GdiWorldTransformFuncs::IsOk() )
return transform;
XFORM xform;
if ( !GdiWorldTransformFuncs::GetWorldTransform()(GetHdc(), &xform) )
if ( !::GetWorldTransform(GetHdc(), &xform) )
{
wxLogLastError(wxT("GetWorldTransform"));
return transform;
@@ -2176,11 +1993,8 @@ wxAffineMatrix2D wxMSWDCImpl::GetTransformMatrix() const
void wxMSWDCImpl::ResetTransformMatrix()
{
if ( GdiWorldTransformFuncs::IsOk() )
{
GdiWorldTransformFuncs::ModifyWorldTransform()(GetHdc(), NULL, MWT_IDENTITY);
GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_COMPATIBLE);
}
::ModifyWorldTransform(GetHdc(), NULL, MWT_IDENTITY);
::SetGraphicsMode(GetHdc(), GM_COMPATIBLE);
}
#endif // wxUSE_DC_TRANSFORM_MATRIX
@@ -2720,27 +2534,20 @@ static bool AlphaBlt(wxMSWDCImpl* dcDst,
wxT("AlphaBlt(): invalid bitmap") );
wxASSERT_MSG( dcDst && hdcSrc, wxT("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(wxT("AlphaBlend"));
if ( pfnAlphaBlend )
{
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xff;
bf.AlphaFormat = AC_SRC_ALPHA;
if ( pfnAlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
if ( !::AlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
hdcSrc, srcX, srcY, srcWidth, srcHeight,
bf) )
{
wxLogLastError(wxT("AlphaBlend"));
return false;
}
// There is an extra complication with drawing bitmaps with alpha
// on bitmaps without alpha: AlphaBlt() modifies the alpha
// component of the destination bitmap even if it hadn't had it
@@ -2752,6 +2559,7 @@ static bool AlphaBlt(wxMSWDCImpl* dcDst,
// more, the rest of pixels with 0 alpha is transparent. So undo
// this to avoid "losing" the existing bitmap contents outside of
// the area affected by AlphaBlt(), see #14403.
#ifdef wxHAS_RAW_BITMAP
const wxBitmap& bmpDst = dcDst->GetSelectedBitmap();
if ( bmpDst.IsOk() && !bmpDst.HasAlpha() && bmpDst.GetDepth() == 32 )
{
@@ -2794,114 +2602,17 @@ static bool AlphaBlt(wxMSWDCImpl* dcDst,
dcDst->DoSelect(bmpOld);
}
// skip wxAlphaBlend() call below
return true;
}
wxLogLastError(wxT("AlphaBlend"));
}
#else
wxUnusedVar(hdcSrc);
#endif // defined(AC_SRC_OVER)
// AlphaBlend() unavailable of failed: use our own (probably much slower)
// implementation
#ifdef wxHAS_RAW_BITMAP
wxAlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
srcX, srcY, srcWidth, srcHeight, bmpSrc);
return true;
#else // !wxHAS_RAW_BITMAP
// no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
// alpha but at least something will be shown like this)
wxUnusedVar(bmpSrc);
return false;
#endif // wxHAS_RAW_BITMAP/!wxHAS_RAW_BITMAP
}
// wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
#ifdef wxHAS_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(wxT("BitBlt"));
}
// combine them with the source bitmap using alpha
wxAlphaPixelData dataDst(bmpDst),
dataSrc((wxBitmap &)bmpSrc);
wxCHECK_RET( dataDst && dataSrc,
wxT("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(wxT("BitBlt"));
}
}
#endif // wxHAS_RAW_BITMAP
return true;
}
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(wxT("GradientFill"));
if ( pfnGradientFill )
{
GRADIENT_RECT grect;
grect.UpperLeft = 0;
grect.LowerRight = 1;
@@ -2927,7 +2638,7 @@ void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8);
vertices[1 - firstVertex].Alpha = 0;
if ( (*pfnGradientFill)
if ( ::GradientFill
(
GetHdc(),
vertices,
@@ -2939,50 +2650,26 @@ void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
: GRADIENT_FILL_RECT_V
) )
{
// skip call of the base class version below
CalcBoundingBox(rect.GetLeft(), rect.GetBottom());
CalcBoundingBox(rect.GetRight(), rect.GetTop());
return;
}
else
{
wxLogLastError(wxT("GradientFill"));
}
#endif // wxUSE_DYNLIB_CLASS
wxDCImpl::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
}
#if wxUSE_DYNLIB_CLASS
namespace wxMSWImpl
{
DWORD GetLayout(HDC hdc)
{
typedef DWORD (WINAPI *GetLayout_t)(HDC);
static GetLayout_t
wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(wxT("gdi32.dll")));
return s_pfnGetLayout ? s_pfnGetLayout(hdc) : GDI_ERROR;
}
DWORD SetLayout(HDC hdc, DWORD dwLayout)
{
typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD);
static SetLayout_t
wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(wxT("gdi32.dll")));
return s_pfnSetLayout ? s_pfnSetLayout(hdc, dwLayout) : GDI_ERROR;
}
HDC CreateCompatibleDCWithLayout(HDC hdc)
{
HDC hdcNew = ::CreateCompatibleDC(hdc);
if ( hdcNew )
{
DWORD dwLayout = wxMSWImpl::GetLayout(hdc);
DWORD dwLayout = ::GetLayout(hdc);
if ( dwLayout != GDI_ERROR )
wxMSWImpl::SetLayout(hdcNew, dwLayout);
::SetLayout(hdcNew, dwLayout);
}
return hdcNew;
@@ -2992,7 +2679,7 @@ HDC CreateCompatibleDCWithLayout(HDC hdc)
wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
{
DWORD layout = wxMSWImpl::GetLayout(GetHdc());
DWORD layout = ::GetLayout(GetHdc());
if ( layout == GDI_ERROR )
return wxLayout_Default;
@@ -3009,7 +2696,7 @@ void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
return;
}
DWORD layout = wxMSWImpl::GetLayout(GetHdc());
DWORD layout = ::GetLayout(GetHdc());
if ( layout == GDI_ERROR )
return;
@@ -3018,40 +2705,5 @@ void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
else
layout &= ~LAYOUT_RTL;
wxMSWImpl::SetLayout(GetHdc(), layout);
::SetLayout(GetHdc(), layout);
}
#else // !wxUSE_DYNLIB_CLASS
// Provide stubs to avoid ifdefs in the code using these functions.
namespace wxMSWImpl
{
DWORD GetLayout(HDC WXUNUSED(hdc))
{
return GDI_ERROR;
}
DWORD SetLayout(HDC WXUNUSED(hdc), DWORD WXUNUSED(dwLayout))
{
return GDI_ERROR;
}
HDC CreateCompatibleDCWithLayout(HDC hdc)
{
return ::CreateCompatibleDC(hdc);
}
} // namespace wxMSWImpl
// 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))
{
}
#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS