X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/dbe6f5f00beefc0901945758693b6d79295904ad..9154a136d5e1d79a4be2cf012e4a815fdc6df3ff:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 03375ff108..3828683e73 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -54,7 +54,11 @@ #endif #ifndef AC_SRC_ALPHA -#define AC_SRC_ALPHA 1 + #define AC_SRC_ALPHA 1 +#endif + +#ifndef LAYOUT_RTL + #define LAYOUT_RTL 1 #endif /* Quaternary raster codes */ @@ -126,16 +130,21 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } // return true if we could draw the bitmap in one way or the other, false // otherwise static bool AlphaBlt(HDC hdcDst, - int x, int y, int w, int h, - int srcX, int srcY, HDC hdcSrc, - const wxBitmap& bmpSrc); + int x, int y, int dstWidth, int dstHeight, + int srcX, int srcY, + int srcWidth, int srcHeight, + HDC hdcSrc, + const wxBitmap& bmp); #ifdef wxHAVE_RAW_BITMAP // our (limited) AlphaBlend() replacement for Windows versions not providing it static void -wxAlphaBlend(HDC hdcDst, int x, int y, int w, int h, - int srcX, int srcY, const wxBitmap& bmp); +wxAlphaBlend(HDC hdcDst, int xDst, int yDst, + int dstWidth, int dstHeight, + int srcX, int srcY, + int srcWidth, int srcHeight, + const wxBitmap& bmpSrc); #endif // wxHAVE_RAW_BITMAP @@ -196,36 +205,44 @@ private: DECLARE_NO_COPY_CLASS(StretchBltModeChanger) }; -// support for dynamic loading of msimg32.dll which we use for some functions -class wxMSImg32DLL +// helper class to cache dynamically loaded libraries and not attempt reloading +// them if it fails +class wxOnceOnlyDLLLoader { public: - // return the symbol with the given name if the DLL not loaded or symbol - // not present - static void *GetSymbol(const wxChar *name) + // 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 ( !ms_triedToLoad ) + if ( m_dllName ) { - ms_triedToLoad = true; - ms_dll.Load(_T("msimg32")); + 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 ms_dll.IsLoaded() ? ms_dll.GetSymbol(name) : NULL; + return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL; } private: - static wxDynamicLibrary ms_dll; - static bool ms_triedToLoad; + wxDynamicLibrary m_dll; + const wxChar *m_dllName; }; -wxDynamicLibrary wxMSImg32DLL::ms_dll; -bool wxMSImg32DLL::ms_triedToLoad = false; - -// helper macro for getting the symbols from msimg32.dll: it supposes that a -// type "name_t" is defined and casts the returned symbol to it automatically -#define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name)) +static wxOnceOnlyDLLLoader wxGDI32DLL(_T("gdi32")); +static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32")); // =========================================================================== // implementation @@ -918,7 +935,7 @@ void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) // transparent pen) one pixel smaller in both directions and we want them // to have the same size regardless of which pen is used - adjust - // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. + // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR. if ( m_pen.GetStyle() == wxTRANSPARENT ) { // Apparently not needed for WinCE (see e.g. Life! demo) @@ -1171,7 +1188,7 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask MemoryHDC hdcMem; SelectInHDC select(hdcMem, GetHbitmapOf(bmp)); - if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, hdcMem, bmp) ) + if ( AlphaBlt(GetHdc(), x, y, width, height, 0, 0, width, height, hdcMem, bmp) ) return; } @@ -1233,7 +1250,8 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask // Rather than reproduce wxDC::Blit, let's do it at the wxWin API // level wxMemoryDC memDC; - memDC.SelectObject(bmp); + + memDC.SelectObjectAsSource(bmp); Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); @@ -2033,12 +2051,23 @@ wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const // --------------------------------------------------------------------------- // bit blit // --------------------------------------------------------------------------- - -bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, - wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, +bool wxDC::DoBlit(wxCoord dstX, wxCoord dstY, + wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, + wxCoord srcX, wxCoord srcY, int rop, bool useMask, - wxCoord xsrcMask, wxCoord ysrcMask) + wxCoord srcMaskX, wxCoord srcMaskY) +{ + return DoStretchBlit(dstX, dstY, dstWidth, dstHeight, source, srcX, srcY, dstWidth, dstHeight, rop, useMask, srcMaskX, srcMaskY); +} + +bool wxDC::DoStretchBlit(wxCoord xdest, wxCoord ydest, + wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + wxCoord srcWidth, wxCoord srcHeight, + int rop, bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask) { wxCHECK_MSG( source, false, _T("wxDC::Blit(): NULL wxDC pointer") ); @@ -2050,8 +2079,8 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() || (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) ) { - if ( AlphaBlt(GetHdc(), xdest, ydest, width, height, - xsrc, ysrc, GetHdcOf(*source), bmpSrc) ) + if ( AlphaBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight, + xsrc, ysrc, srcWidth, srcHeight, GetHdcOf(*source), bmpSrc) ) return true; } @@ -2125,16 +2154,19 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) #endif { - success = ::MaskBlt - ( + if ( dstWidth == srcWidth && dstHeight == srcHeight ) + { + success = ::MaskBlt + ( GetHdc(), - xdest, ydest, width, height, + xdest, ydest, dstWidth, dstHeight, GetHdcOf(*source), xsrc, ysrc, (HBITMAP)mask->GetMaskBitmap(), xsrcMask, ysrcMask, MAKEROP4(dwRop, DSTCOPY) - ) != 0; + ) != 0; + } } if ( !success ) @@ -2154,55 +2186,59 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, dc_buffer = (HDC) dcCacheEntry2->m_dc; wxDCCacheEntry* bitmapCacheEntry = FindBitmapInCache(GetHDC(), - width, height); + dstWidth, dstHeight); buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap; #else // !wxUSE_DC_CACHEING // create a temp buffer bitmap and DCs to access it and the mask dc_mask = ::CreateCompatibleDC(GetHdcOf(*source)); dc_buffer = ::CreateCompatibleDC(GetHdc()); - buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height); + buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), dstWidth, dstHeight); #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING HGDIOBJ hOldMaskBitmap = ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap()); HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap); // copy dest to buffer - if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, + if ( !::BitBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, GetHdc(), xdest, ydest, SRCCOPY) ) { wxLogLastError(wxT("BitBlt")); } +#ifndef __WXWINCE__ + StretchBltModeChanger changeMode(dc_buffer, COLORONCOLOR); +#endif + // copy src to buffer using selected raster op - if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, - GetHdcOf(*source), xsrc, ysrc, dwRop) ) + if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, + GetHdcOf(*source), xsrc, ysrc, srcWidth, srcHeight, dwRop) ) { - wxLogLastError(wxT("BitBlt")); + wxLogLastError(wxT("StretchBlt")); } // set masked area in buffer to BLACK (pixel value 0) COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255)); COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0)); - if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, - dc_mask, xsrcMask, ysrcMask, SRCAND) ) + if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, + dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) ) { - wxLogLastError(wxT("BitBlt")); + wxLogLastError(wxT("StretchBlt")); } // set unmasked area in dest to BLACK ::SetBkColor(GetHdc(), RGB(0, 0, 0)); ::SetTextColor(GetHdc(), RGB(255, 255, 255)); - if ( !::BitBlt(GetHdc(), xdest, ydest, (int)width, (int)height, - dc_mask, xsrcMask, ysrcMask, SRCAND) ) + if ( !::StretchBlt(GetHdc(), xdest, ydest, (int)dstWidth, (int)dstHeight, + dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) ) { - wxLogLastError(wxT("BitBlt")); + wxLogLastError(wxT("StretchBlt")); } ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values ::SetTextColor(GetHdc(), prevCol); // OR buffer to dest success = ::BitBlt(GetHdc(), xdest, ydest, - (int)width, (int)height, + (int)dstWidth, (int)dstHeight, dc_buffer, 0, 0, SRCPAINT) != 0; if ( !success ) { @@ -2247,14 +2283,14 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, if ( hDIB > 0 ) { // reflect ysrc - ysrc = hDIB - (ysrc + height); + ysrc = hDIB - (ysrc + dstHeight); } if ( ::StretchDIBits(GetHdc(), xdest, ydest, - width, height, + dstWidth, dstHeight, xsrc, ysrc, - width, height, + srcWidth, srcHeight, ds.dsBm.bmBits, (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, @@ -2285,9 +2321,9 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, if ( !::StretchBlt ( GetHdc(), - xdest, ydest, width, height, + xdest, ydest, dstWidth, dstHeight, GetHdcOf(*source), - xsrc, ysrc, width, height, + xsrc, ysrc, srcWidth, srcHeight, dwRop ) ) { @@ -2305,7 +2341,7 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, ( GetHdc(), xdest, ydest, - (int)width, (int)height, + (int)dstWidth, (int)dstHeight, GetHdcOf(*source), xsrc, ysrc, dwRop @@ -2527,8 +2563,10 @@ IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) // ---------------------------------------------------------------------------- static bool AlphaBlt(HDC hdcDst, - int x, int y, int width, int height, - int srcX, int srcY, HDC hdcSrc, + int x, int y, int dstWidth, int dstHeight, + int srcX, int srcY, + int srcWidth, int srcHeight, + HDC hdcSrc, const wxBitmap& bmp) { wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); @@ -2541,7 +2579,8 @@ static bool AlphaBlt(HDC hdcDst, HDC,int,int,int,int, BLENDFUNCTION); - static AlphaBlend_t pfnAlphaBlend = wxMSIMG32_SYMBOL(AlphaBlend); + static AlphaBlend_t + pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend")); if ( pfnAlphaBlend ) { BLENDFUNCTION bf; @@ -2550,8 +2589,8 @@ static bool AlphaBlt(HDC hdcDst, bf.SourceConstantAlpha = 0xff; bf.AlphaFormat = AC_SRC_ALPHA; - if ( pfnAlphaBlend(hdcDst, x, y, width, height, - hdcSrc, srcX, srcY, width, height, + if ( pfnAlphaBlend(hdcDst, x, y, dstWidth, dstHeight, + hdcSrc, srcX, srcY, srcWidth, srcHeight, bf) ) { // skip wxAlphaBlend() call below @@ -2567,7 +2606,7 @@ static bool AlphaBlt(HDC hdcDst, // AlphaBlend() unavailable of failed: use our own (probably much slower) // implementation #ifdef wxHAVE_RAW_BITMAP - wxAlphaBlend(hdcDst, x, y, width, height, srcX, srcY, bmp); + wxAlphaBlend(hdcDst, x, y, dstWidth, dstHeight, srcX, srcY, srcWidth, srcHeight, bmp); return true; #else // !wxHAVE_RAW_BITMAP @@ -2584,15 +2623,17 @@ static bool AlphaBlt(HDC hdcDst, static void wxAlphaBlend(HDC hdcDst, int xDst, int yDst, - int w, int h, - int srcX, int srcY, const wxBitmap& bmpSrc) + int dstWidth, int dstHeight, + int srcX, int srcY, + int srcWidth, int srcHeight, + const wxBitmap& bmpSrc) { // get the destination DC pixels - wxBitmap bmpDst(w, h, 32 /* force creating RGBA DIB */); + wxBitmap bmpDst(dstWidth, dstHeight, 32 /* force creating RGBA DIB */); MemoryHDC hdcMem; SelectInHDC select(hdcMem, GetHbitmapOf(bmpDst)); - if ( !::BitBlt(hdcMem, 0, 0, w, h, hdcDst, xDst, yDst, SRCCOPY) ) + if ( !::BitBlt(hdcMem, 0, 0, dstWidth, dstHeight, hdcDst, xDst, yDst, SRCCOPY) ) { wxLogLastError(_T("BitBlt")); } @@ -2607,15 +2648,17 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, wxAlphaPixelData::Iterator pDst(dataDst), pSrc(dataSrc); - pSrc.Offset(dataSrc, srcX, srcY); - for ( int y = 0; y < h; y++ ) + for ( int y = 0; y < dstHeight; y++ ) { - wxAlphaPixelData::Iterator pDstRowStart = pDst, - pSrcRowStart = pSrc; + wxAlphaPixelData::Iterator pDstRowStart = pDst; - for ( int x = 0; x < w; x++ ) + 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(); @@ -2625,17 +2668,14 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, 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) ) + if ( !::BitBlt(hdcDst, xDst, yDst, dstWidth, dstHeight, hdcMem, 0, 0, SRCCOPY) ) { wxLogLastError(_T("BitBlt")); } @@ -2654,7 +2694,8 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, #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); + static GradientFill_t pfnGradientFill = + (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill")); if ( pfnGradientFill ) { @@ -2671,8 +2712,8 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, vertices[0].x = rect.GetLeft(); vertices[0].y = rect.GetTop(); - vertices[1].x = rect.GetRight(); - vertices[1].y = rect.GetBottom(); + 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); @@ -2705,3 +2746,46 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, 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); +}