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:
562
src/msw/dc.cpp
562
src/msw/dc.cpp
@@ -41,7 +41,6 @@
|
|||||||
|
|
||||||
#include "wx/msw/dc.h"
|
#include "wx/msw/dc.h"
|
||||||
#include "wx/sysopt.h"
|
#include "wx/sysopt.h"
|
||||||
#include "wx/dynlib.h"
|
|
||||||
|
|
||||||
#ifdef wxHAS_RAW_BITMAP
|
#ifdef wxHAS_RAW_BITMAP
|
||||||
#include "wx/rawbmp.h"
|
#include "wx/rawbmp.h"
|
||||||
@@ -133,27 +132,9 @@ static bool AlphaBlt(wxMSWDCImpl* dcSrc,
|
|||||||
HDC hdcSrc,
|
HDC hdcSrc,
|
||||||
const wxBitmap& bmpSrc);
|
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
|
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
|
// 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
|
// 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.
|
// temporary compatible memory DC to the real target DC) using the same layout.
|
||||||
@@ -225,164 +206,6 @@ private:
|
|||||||
|
|
||||||
#endif // __WXWINCE__/!__WXWINCE__
|
#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
|
// implementation
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -2112,21 +1935,18 @@ void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y)
|
|||||||
|
|
||||||
bool wxMSWDCImpl::CanUseTransformMatrix() const
|
bool wxMSWDCImpl::CanUseTransformMatrix() const
|
||||||
{
|
{
|
||||||
return GdiWorldTransformFuncs::IsOk();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix)
|
bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix)
|
||||||
{
|
{
|
||||||
if ( !GdiWorldTransformFuncs::IsOk() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( matrix.IsIdentity() )
|
if ( matrix.IsIdentity() )
|
||||||
{
|
{
|
||||||
ResetTransformMatrix();
|
ResetTransformMatrix();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_ADVANCED) )
|
if ( !::SetGraphicsMode(GetHdc(), GM_ADVANCED) )
|
||||||
{
|
{
|
||||||
wxLogLastError(wxT("SetGraphicsMode"));
|
wxLogLastError(wxT("SetGraphicsMode"));
|
||||||
return false;
|
return false;
|
||||||
@@ -2144,7 +1964,7 @@ bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix)
|
|||||||
xform.eDx = tr.m_x;
|
xform.eDx = tr.m_x;
|
||||||
xform.eDy = tr.m_y;
|
xform.eDy = tr.m_y;
|
||||||
|
|
||||||
if ( !GdiWorldTransformFuncs::SetWorldTransform()(GetHdc(), &xform) )
|
if ( !::SetWorldTransform(GetHdc(), &xform) )
|
||||||
{
|
{
|
||||||
wxLogLastError(wxT("SetWorldTransform"));
|
wxLogLastError(wxT("SetWorldTransform"));
|
||||||
return false;
|
return false;
|
||||||
@@ -2157,11 +1977,8 @@ wxAffineMatrix2D wxMSWDCImpl::GetTransformMatrix() const
|
|||||||
{
|
{
|
||||||
wxAffineMatrix2D transform;
|
wxAffineMatrix2D transform;
|
||||||
|
|
||||||
if ( !GdiWorldTransformFuncs::IsOk() )
|
|
||||||
return transform;
|
|
||||||
|
|
||||||
XFORM xform;
|
XFORM xform;
|
||||||
if ( !GdiWorldTransformFuncs::GetWorldTransform()(GetHdc(), &xform) )
|
if ( !::GetWorldTransform(GetHdc(), &xform) )
|
||||||
{
|
{
|
||||||
wxLogLastError(wxT("GetWorldTransform"));
|
wxLogLastError(wxT("GetWorldTransform"));
|
||||||
return transform;
|
return transform;
|
||||||
@@ -2176,11 +1993,8 @@ wxAffineMatrix2D wxMSWDCImpl::GetTransformMatrix() const
|
|||||||
|
|
||||||
void wxMSWDCImpl::ResetTransformMatrix()
|
void wxMSWDCImpl::ResetTransformMatrix()
|
||||||
{
|
{
|
||||||
if ( GdiWorldTransformFuncs::IsOk() )
|
::ModifyWorldTransform(GetHdc(), NULL, MWT_IDENTITY);
|
||||||
{
|
::SetGraphicsMode(GetHdc(), GM_COMPATIBLE);
|
||||||
GdiWorldTransformFuncs::ModifyWorldTransform()(GetHdc(), NULL, MWT_IDENTITY);
|
|
||||||
GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_COMPATIBLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
#endif // wxUSE_DC_TRANSFORM_MATRIX
|
||||||
@@ -2720,269 +2534,142 @@ static bool AlphaBlt(wxMSWDCImpl* dcDst,
|
|||||||
wxT("AlphaBlt(): invalid bitmap") );
|
wxT("AlphaBlt(): invalid bitmap") );
|
||||||
wxASSERT_MSG( dcDst && hdcSrc, wxT("AlphaBlt(): invalid HDC") );
|
wxASSERT_MSG( dcDst && hdcSrc, wxT("AlphaBlt(): invalid HDC") );
|
||||||
|
|
||||||
// do we have AlphaBlend() and company in the headers?
|
BLENDFUNCTION bf;
|
||||||
#if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
|
bf.BlendOp = AC_SRC_OVER;
|
||||||
// yes, now try to see if we have it during run-time
|
bf.BlendFlags = 0;
|
||||||
typedef BOOL (WINAPI *AlphaBlend_t)(HDC,int,int,int,int,
|
bf.SourceConstantAlpha = 0xff;
|
||||||
HDC,int,int,int,int,
|
bf.AlphaFormat = AC_SRC_ALPHA;
|
||||||
BLENDFUNCTION);
|
|
||||||
|
|
||||||
static AlphaBlend_t
|
if ( !::AlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
|
||||||
pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(wxT("AlphaBlend"));
|
hdcSrc, srcX, srcY, srcWidth, srcHeight,
|
||||||
if ( pfnAlphaBlend )
|
bf) )
|
||||||
{
|
{
|
||||||
BLENDFUNCTION bf;
|
wxLogLastError(wxT("AlphaBlend"));
|
||||||
bf.BlendOp = AC_SRC_OVER;
|
return false;
|
||||||
bf.BlendFlags = 0;
|
}
|
||||||
bf.SourceConstantAlpha = 0xff;
|
|
||||||
bf.AlphaFormat = AC_SRC_ALPHA;
|
|
||||||
|
|
||||||
if ( pfnAlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
|
// There is an extra complication with drawing bitmaps with alpha
|
||||||
hdcSrc, srcX, srcY, srcWidth, srcHeight,
|
// on bitmaps without alpha: AlphaBlt() modifies the alpha
|
||||||
bf) )
|
// component of the destination bitmap even if it hadn't had it
|
||||||
|
// before which is not only unexpected but corrupts the bitmap as
|
||||||
|
// all its pixels outside of the (x, y, dstWidth, dstHeight) area
|
||||||
|
// are now fully transparent: they already had 0 value of alpha
|
||||||
|
// before but it didn't count as long as all other pixels had 0
|
||||||
|
// alpha as well, but now that some of them are not transparent any
|
||||||
|
// 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 )
|
||||||
|
{
|
||||||
|
// We need to deselect the bitmap from the memory DC it is
|
||||||
|
// currently selected into before modifying it.
|
||||||
|
wxBitmap bmpOld = bmpDst;
|
||||||
|
dcDst->DoSelect(wxNullBitmap);
|
||||||
|
|
||||||
|
// Notice the extra block: we must destroy wxAlphaPixelData
|
||||||
|
// before selecting the bitmap into the DC again.
|
||||||
{
|
{
|
||||||
// There is an extra complication with drawing bitmaps with alpha
|
wxAlphaPixelData data(bmpOld);
|
||||||
// on bitmaps without alpha: AlphaBlt() modifies the alpha
|
if ( data )
|
||||||
// component of the destination bitmap even if it hadn't had it
|
|
||||||
// before which is not only unexpected but corrupts the bitmap as
|
|
||||||
// all its pixels outside of the (x, y, dstWidth, dstHeight) area
|
|
||||||
// are now fully transparent: they already had 0 value of alpha
|
|
||||||
// before but it didn't count as long as all other pixels had 0
|
|
||||||
// alpha as well, but now that some of them are not transparent any
|
|
||||||
// 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.
|
|
||||||
const wxBitmap& bmpDst = dcDst->GetSelectedBitmap();
|
|
||||||
if ( bmpDst.IsOk() && !bmpDst.HasAlpha() && bmpDst.GetDepth() == 32 )
|
|
||||||
{
|
{
|
||||||
// We need to deselect the bitmap from the memory DC it is
|
wxAlphaPixelData::Iterator p(data);
|
||||||
// currently selected into before modifying it.
|
for ( int y = 0; y < data.GetHeight(); y++ )
|
||||||
wxBitmap bmpOld = bmpDst;
|
|
||||||
dcDst->DoSelect(wxNullBitmap);
|
|
||||||
|
|
||||||
// Notice the extra block: we must destroy wxAlphaPixelData
|
|
||||||
// before selecting the bitmap into the DC again.
|
|
||||||
{
|
{
|
||||||
wxAlphaPixelData data(bmpOld);
|
wxAlphaPixelData::Iterator rowStart = p;
|
||||||
if ( data )
|
|
||||||
|
for ( int x = 0; x < data.GetWidth(); x++ )
|
||||||
{
|
{
|
||||||
wxAlphaPixelData::Iterator p(data);
|
// We choose to use wxALPHA_TRANSPARENT instead
|
||||||
for ( int y = 0; y < data.GetHeight(); y++ )
|
// of perhaps more logical wxALPHA_OPAQUE here
|
||||||
{
|
// to ensure that the bitmap remains the same
|
||||||
wxAlphaPixelData::Iterator rowStart = p;
|
// as before, i.e. without any alpha at all.
|
||||||
|
p.Alpha() = wxALPHA_TRANSPARENT;
|
||||||
for ( int x = 0; x < data.GetWidth(); x++ )
|
++p;
|
||||||
{
|
|
||||||
// We choose to use wxALPHA_TRANSPARENT instead
|
|
||||||
// of perhaps more logical wxALPHA_OPAQUE here
|
|
||||||
// to ensure that the bitmap remains the same
|
|
||||||
// as before, i.e. without any alpha at all.
|
|
||||||
p.Alpha() = wxALPHA_TRANSPARENT;
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = rowStart;
|
|
||||||
p.OffsetY(data, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using wxAlphaPixelData sets the internal "has alpha" flag
|
|
||||||
// which is usually what we need, but in this particular case
|
|
||||||
// we use it to get rid of alpha, not set it, so reset it back.
|
|
||||||
bmpOld.ResetAlpha();
|
|
||||||
|
|
||||||
dcDst->DoSelect(bmpOld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip wxAlphaBlend() call below
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLogLastError(wxT("AlphaBlend"));
|
// Using wxAlphaPixelData sets the internal "has alpha" flag
|
||||||
}
|
// which is usually what we need, but in this particular case
|
||||||
#else
|
// we use it to get rid of alpha, not set it, so reset it back.
|
||||||
wxUnusedVar(hdcSrc);
|
bmpOld.ResetAlpha();
|
||||||
#endif // defined(AC_SRC_OVER)
|
|
||||||
|
|
||||||
// AlphaBlend() unavailable of failed: use our own (probably much slower)
|
dcDst->DoSelect(bmpOld);
|
||||||
// implementation
|
}
|
||||||
#ifdef wxHAS_RAW_BITMAP
|
#endif // wxHAS_RAW_BITMAP
|
||||||
wxAlphaBlend(GetHdcOf(*dcDst), x, y, dstWidth, dstHeight,
|
|
||||||
srcX, srcY, srcWidth, srcHeight, bmpSrc);
|
|
||||||
|
|
||||||
return true;
|
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
|
|
||||||
|
|
||||||
void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
|
void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect,
|
||||||
const wxColour& initialColour,
|
const wxColour& initialColour,
|
||||||
const wxColour& destColour,
|
const wxColour& destColour,
|
||||||
wxDirection nDirection)
|
wxDirection nDirection)
|
||||||
{
|
{
|
||||||
// use native function if we have compile-time support it and can load it
|
GRADIENT_RECT grect;
|
||||||
// during run-time (linking to it statically would make the program
|
grect.UpperLeft = 0;
|
||||||
// unusable on earlier Windows versions)
|
grect.LowerRight = 1;
|
||||||
#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 )
|
// 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 ( ::GradientFill
|
||||||
|
(
|
||||||
|
GetHdc(),
|
||||||
|
vertices,
|
||||||
|
WXSIZEOF(vertices),
|
||||||
|
&grect,
|
||||||
|
1,
|
||||||
|
nDirection == wxWEST || nDirection == wxEAST
|
||||||
|
? GRADIENT_FILL_RECT_H
|
||||||
|
: GRADIENT_FILL_RECT_V
|
||||||
|
) )
|
||||||
|
{
|
||||||
|
CalcBoundingBox(rect.GetLeft(), rect.GetBottom());
|
||||||
|
CalcBoundingBox(rect.GetRight(), rect.GetTop());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
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
|
|
||||||
CalcBoundingBox(rect.GetLeft(), rect.GetBottom());
|
|
||||||
CalcBoundingBox(rect.GetRight(), rect.GetTop());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxLogLastError(wxT("GradientFill"));
|
wxLogLastError(wxT("GradientFill"));
|
||||||
}
|
}
|
||||||
#endif // wxUSE_DYNLIB_CLASS
|
|
||||||
|
|
||||||
wxDCImpl::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if wxUSE_DYNLIB_CLASS
|
|
||||||
|
|
||||||
namespace wxMSWImpl
|
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 CreateCompatibleDCWithLayout(HDC hdc)
|
||||||
{
|
{
|
||||||
HDC hdcNew = ::CreateCompatibleDC(hdc);
|
HDC hdcNew = ::CreateCompatibleDC(hdc);
|
||||||
if ( hdcNew )
|
if ( hdcNew )
|
||||||
{
|
{
|
||||||
DWORD dwLayout = wxMSWImpl::GetLayout(hdc);
|
DWORD dwLayout = ::GetLayout(hdc);
|
||||||
if ( dwLayout != GDI_ERROR )
|
if ( dwLayout != GDI_ERROR )
|
||||||
wxMSWImpl::SetLayout(hdcNew, dwLayout);
|
::SetLayout(hdcNew, dwLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdcNew;
|
return hdcNew;
|
||||||
@@ -2992,7 +2679,7 @@ HDC CreateCompatibleDCWithLayout(HDC hdc)
|
|||||||
|
|
||||||
wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
|
wxLayoutDirection wxMSWDCImpl::GetLayoutDirection() const
|
||||||
{
|
{
|
||||||
DWORD layout = wxMSWImpl::GetLayout(GetHdc());
|
DWORD layout = ::GetLayout(GetHdc());
|
||||||
|
|
||||||
if ( layout == GDI_ERROR )
|
if ( layout == GDI_ERROR )
|
||||||
return wxLayout_Default;
|
return wxLayout_Default;
|
||||||
@@ -3009,7 +2696,7 @@ void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD layout = wxMSWImpl::GetLayout(GetHdc());
|
DWORD layout = ::GetLayout(GetHdc());
|
||||||
if ( layout == GDI_ERROR )
|
if ( layout == GDI_ERROR )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -3018,40 +2705,5 @@ void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir)
|
|||||||
else
|
else
|
||||||
layout &= ~LAYOUT_RTL;
|
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
|
|
||||||
|
Reference in New Issue
Block a user