X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4314ec480ecfdd8c0d170e570978d6d2134fc8be..34153050fe525ca6c46f259b638fae5590a87290:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 7031bf7bd9..0744dc251e 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -45,6 +45,8 @@ #include #include +#include "wx/msw/private.h" // needs to be before #include + #if wxUSE_COMMON_DIALOGS #if wxUSE_NORLANDER_HEADERS #include @@ -56,11 +58,7 @@ #include #endif -#include "wx/msw/private.h" - -#if !USE_SHARED_LIBRARY - IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) -#endif +IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) // --------------------------------------------------------------------------- // constants @@ -264,7 +262,11 @@ void wxDC::Clear() } else { - wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); + // No, I think we should simply ignore this if printing on e.g. + // a printer DC. + // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); + if (!m_selectedBitmap.Ok()) + return; rect.left = 0; rect.top = 0; rect.right = m_selectedBitmap.GetWidth(); @@ -408,6 +410,28 @@ void wxDC::DoDrawPoint(wxCoord x, wxCoord y) void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle) { + COLORREF old_textground = ::GetTextColor(GetHdc()); + COLORREF old_background = ::GetBkColor(GetHdc()); + if (m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) + { + + if (m_textForegroundColour.Ok()) + { //just the oposite from what is expected see help on pattern brush + // 1 in mask becomes bk color + ::SetBkColor(GetHdc(), m_textForegroundColour.GetPixel() ); + } + if (m_textBackgroundColour.Ok()) + { //just the oposite from what is expected + // 0 in mask becomes text color + ::SetTextColor(GetHdc(), m_textBackgroundColour.GetPixel() ); + } + + if (m_backgroundMode == wxTRANSPARENT) + SetBkMode(GetHdc(), TRANSPARENT); + else + SetBkMode(GetHdc(), OPAQUE); + } + // Do things less efficiently if we have offsets if (xoffset != 0 || yoffset != 0) { @@ -435,6 +459,13 @@ void wxDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffs (void)Polygon(GetHdc(), (POINT*) points, n); SetPolyFillMode(GetHdc(),prev); } + + if (m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) + { + ::SetBkMode(GetHdc(), TRANSPARENT); + ::SetTextColor(GetHdc(), old_textground); + ::SetBkColor(GetHdc(), old_background); + } } void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) @@ -466,6 +497,28 @@ void wxDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { + COLORREF old_textground = ::GetTextColor(GetHdc()); + COLORREF old_background = ::GetBkColor(GetHdc()); + if (m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) + { + + if (m_textForegroundColour.Ok()) + { //just the oposite from what is expected see help on pattern brush + // 1 in mask becomes bk color + ::SetBkColor(GetHdc(), m_textForegroundColour.GetPixel() ); + } + if (m_textBackgroundColour.Ok()) + { //just the oposite from what is expected + // 0 in mask becomes text color + ::SetTextColor(GetHdc(), m_textBackgroundColour.GetPixel() ); + } + + if (m_backgroundMode == wxTRANSPARENT) + SetBkMode(GetHdc(), TRANSPARENT); + else + SetBkMode(GetHdc(), OPAQUE); + } + wxCoord x2 = x + width; wxCoord y2 = y + height; @@ -506,6 +559,13 @@ void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) CalcBoundingBox(x, y); CalcBoundingBox(x2, y2); + + if (m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) + { + ::SetBkMode(GetHdc(), TRANSPARENT); + ::SetTextColor(GetHdc(), old_textground); + ::SetBkColor(GetHdc(), old_background); + } } void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius) @@ -586,25 +646,22 @@ void wxDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,d void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) { -#if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__) - ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), (HICON) icon.GetHICON(), - icon.GetWidth(), icon.GetHeight(), 0, 0, DI_NORMAL); -#else - ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), (HICON) icon.GetHICON()); -#endif + wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") ); + + ::DrawIcon(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon)); CalcBoundingBox(x, y); - CalcBoundingBox(x+icon.GetWidth(), y+icon.GetHeight()); + CalcBoundingBox(x + icon.GetWidth(), y + icon.GetHeight()); } void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask ) { - if (!bmp.Ok()) - return; + wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); - // If we're not drawing transparently, and not drawing to a printer, - // optimize this function to use Windows functions. - if (!useMask && !IsKindOf(CLASSINFO(wxPrinterDC))) + int width = bmp.GetWidth(), + height = bmp.GetHeight(); + + if ( !useMask ) { HDC cdc = GetHdc(); HDC memdc = ::CreateCompatibleDC( cdc ); @@ -612,9 +669,23 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") ); + COLORREF old_textground = ::GetTextColor(GetHdc()); + COLORREF old_background = ::GetBkColor(GetHdc()); + if (m_textForegroundColour.Ok()) + { + ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() ); + } + if (m_textBackgroundColour.Ok()) + { + ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); + } + ::SelectObject( memdc, hbitmap ); - ::BitBlt( cdc, x, y, bmp.GetWidth(), bmp.GetHeight(), memdc, 0, 0, SRCCOPY); + ::BitBlt( cdc, x, y, width, height, memdc, 0, 0, SRCCOPY); ::DeleteDC( memdc ); + + ::SetTextColor(GetHdc(), old_textground); + ::SetBkColor(GetHdc(), old_background); } else { @@ -622,17 +693,7 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask wxMemoryDC memDC; memDC.SelectObject(bmp); - /* Not sure if we need this. The mask should leave the - * masked areas as per the original background of this DC. - */ - /* - // There might be transparent areas, so make these - // the same colour as this DC - memDC.SetBackground(* GetBackground()); - memDC.Clear(); - */ - - Blit(x, y, bmp.GetWidth(), bmp.GetHeight(), & memDC, 0, 0, wxCOPY, useMask); + Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); memDC.SelectObject(wxNullBitmap); } @@ -666,7 +727,7 @@ void wxDC::DrawAnyText(const wxString& text, wxCoord x, wxCoord y) : OPAQUE); if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), - text.c_str(), text.length()) != 0 ) + text.c_str(), text.length()) == 0 ) { wxLogLastError("TextOut"); } @@ -684,28 +745,39 @@ void wxDC::DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle) { - if ( angle == 0.0 ) + // we test that we have some font because otherwise we should still use the + // "else" part below to avoid that DrawRotatedText(angle = 180) and + // DrawRotatedText(angle = 0) use different fonts (we can't use the default + // font for drawing rotated fonts unfortunately) + if ( (angle == 0.0) && m_font.Ok() ) { DoDrawText(text, x, y); } else { + // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so + // can't have non zero orientation/escapement + wxFont font = m_font.Ok() ? m_font : *wxNORMAL_FONT; + HFONT hfont = (HFONT)font.GetResourceHandle(); LOGFONT lf; - wxFillLogFont(&lf, &m_font); + if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 ) + { + wxLogLastError("GetObject(hfont)"); + } // GDI wants the angle in tenth of degree long angle10 = (long)(angle * 10); lf.lfEscapement = angle10; lf. lfOrientation = angle10; - HFONT hfont = ::CreateFontIndirect(&lf); + hfont = ::CreateFontIndirect(&lf); if ( !hfont ) { wxLogLastError("CreateFont"); } else { - HFONT hfontOld = ::SelectObject(GetHdc(), hfont); + HFONT hfontOld = (HFONT)::SelectObject(GetHdc(), hfont); DrawAnyText(text, x, y); @@ -723,7 +795,6 @@ void wxDC::DoDrawRotatedText(const wxString& text, // "upper left" and "upper right" CalcBoundingBox(x, y); CalcBoundingBox(x + w*cos(rad), y - h*sin(rad)); - CalcBoundingBox(x + h*sin(rad), y + h*cos(rad)); // "bottom left" and "bottom right" x += (wxCoord)(h*sin(rad)); @@ -916,7 +987,7 @@ void wxDC::SetBackgroundMode(int mode) if (m_backgroundMode == wxTRANSPARENT) ::SetBkMode(GetHdc(), TRANSPARENT); else - ::SetBkMode(GetHdc(), OPAQUE); + ::SetBkMode(GetHdc(), OPAQUE); */ } @@ -1172,16 +1243,26 @@ 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, int rop, bool useMask) + +bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, + wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, + int rop, bool useMask) { - wxCoord xdest1 = xdest; - wxCoord ydest1 = ydest; - wxCoord xsrc1 = xsrc; - wxCoord ysrc1 = ysrc; + wxMask *mask = NULL; + if ( useMask ) + { + const wxBitmap& bmp = source->m_selectedBitmap; + mask = bmp.GetMask(); + + if ( !(bmp.Ok() && mask && mask->GetMaskBitmap()) ) + { + // don't give assert here because this would break existing + // programs - just silently ignore useMask parameter + useMask = FALSE; + } + } - // Chris Breeze 18/5/98: use text foreground/background colours - // when blitting from 1-bit bitmaps COLORREF old_textground = ::GetTextColor(GetHdc()); COLORREF old_background = ::GetBkColor(GetHdc()); if (m_textForegroundColour.Ok()) @@ -1194,147 +1275,115 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, } DWORD dwRop = rop == wxCOPY ? SRCCOPY : - rop == wxCLEAR ? WHITENESS : - rop == wxSET ? BLACKNESS : - rop == wxINVERT ? DSTINVERT : - rop == wxAND ? MERGECOPY : - rop == wxOR ? MERGEPAINT : - rop == wxSRC_INVERT ? NOTSRCCOPY : - rop == wxXOR ? SRCINVERT : - rop == wxOR_REVERSE ? MERGEPAINT : - rop == wxAND_REVERSE ? SRCERASE : - rop == wxSRC_OR ? SRCPAINT : - rop == wxSRC_AND ? SRCAND : - SRCCOPY; - - bool success = TRUE; - if (useMask && source->m_selectedBitmap.Ok() && source->m_selectedBitmap.GetMask()) + rop == wxCLEAR ? WHITENESS : + rop == wxSET ? BLACKNESS : + rop == wxINVERT ? DSTINVERT : + rop == wxAND ? MERGECOPY : + rop == wxOR ? MERGEPAINT : + rop == wxSRC_INVERT ? NOTSRCCOPY : + rop == wxXOR ? SRCINVERT : + rop == wxOR_REVERSE ? MERGEPAINT : + rop == wxAND_REVERSE ? SRCERASE : + rop == wxSRC_OR ? SRCPAINT : + rop == wxSRC_AND ? SRCAND : + SRCCOPY; + + bool success; + + if (useMask) { - -#if 0 // __WIN32__ - // Not implemented under Win95 (or maybe a specific device?) - if (MaskBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, - (HDC) source->m_hDC, xsrc1, ysrc1, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap(), - 0, 0, 0xAACC0020)) - { - // Success - } - else -#endif +#ifdef __WIN32__ + HBITMAP hbmpMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap()); + + // we want the part of the image corresponding to the mask to be + // transparent, i.e. do PATCOPY there and apply dwRop elsewhere + const wxColour& colBg = m_backgroundBrush.GetColour(); + HBRUSH hbrBg = (HBRUSH)::CreateSolidBrush(wxColourToRGB(colBg)); + HBRUSH hbrOld = (HBRUSH)::SelectObject(GetHdc(), hbrBg); + + success = ::MaskBlt(GetHdc(), xdest, ydest, width, height, + GetHdcOf(*source), xsrc, ysrc, + hbmpMask, 0, 0, + MAKEROP4(PATCOPY, dwRop)) != 0; + + (void)::SelectObject(GetHdc(), hbrOld); + ::DeleteObject(hbrOld); + ::DeleteObject(hbmpMask); + + if ( !success ) +#endif // Win32 { - // Old code -#if 0 - HDC dc_mask = CreateCompatibleDC((HDC) source->m_hDC); - ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap()); - success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, - dc_mask, xsrc1, ysrc1, 0x00220326 /* NOTSRCAND */) != 0); - success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, - (HDC) source->m_hDC, xsrc1, ysrc1, SRCPAINT) != 0); - ::SelectObject(dc_mask, 0); - ::DeleteDC(dc_mask); -#endif - // New code from Chris Breeze, 15/7/98 // Blit bitmap with mask - if (IsKindOf(CLASSINFO(wxPrinterDC))) + // create a temp buffer bitmap and DCs to access it and the mask + HDC dc_mask = ::CreateCompatibleDC(GetHdcOf(*source)); + HDC dc_buffer = ::CreateCompatibleDC(GetHdc()); + HBITMAP buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height); + ::SelectObject(dc_mask, (HBITMAP) mask->GetMaskBitmap()); + ::SelectObject(dc_buffer, buffer_bmap); + + // copy dest to buffer + if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, + GetHdc(), xdest, ydest, SRCCOPY) ) { - // If we are printing source colours are screen colours - // not printer colours and so we need copy the bitmap - // pixel by pixel. - RECT rect; - HDC dc_mask = ::CreateCompatibleDC((HDC) source->m_hDC); - HDC dc_src = (HDC) source->m_hDC; - - ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap()); - for (int x = 0; x < width; x++) - { - for (int y = 0; y < height; y++) - { - COLORREF cref = ::GetPixel(dc_mask, x, y); - if (cref) - { - HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y)); - rect.left = xdest1 + x; rect.right = rect.left + 1; - rect.top = ydest1 + y; rect.bottom = rect.top + 1; - ::FillRect(GetHdc(), &rect, brush); - ::DeleteObject(brush); - } - } - } - ::SelectObject(dc_mask, 0); - ::DeleteDC(dc_mask); + wxLogLastError("BitBlt"); } - else + + // copy src to buffer using selected raster op + if ( !::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, + GetHdcOf(*source), xsrc, ysrc, dwRop) ) { - // create a temp buffer bitmap and DCs to access it and the mask - HDC dc_mask = ::CreateCompatibleDC((HDC) source->m_hDC); - HDC dc_buffer = ::CreateCompatibleDC(GetHdc()); - HBITMAP buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), width, height); - ::SelectObject(dc_mask, (HBITMAP) source->m_selectedBitmap.GetMask()->GetMaskBitmap()); - ::SelectObject(dc_buffer, buffer_bmap); - - // copy dest to buffer - ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, - GetHdc(), xdest1, ydest1, SRCCOPY); - - // copy src to buffer using selected raster op - ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, - (HDC) source->m_hDC, xsrc1, ysrc1, dwRop); - - // 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)); - ::BitBlt(dc_buffer, 0, 0, (int)width, (int)height, - dc_mask, xsrc1, ysrc1, SRCAND); - - // set unmasked area in dest to BLACK - ::SetBkColor(GetHdc(), RGB(0, 0, 0)); - ::SetTextColor(GetHdc(), RGB(255, 255, 255)); - ::BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, - dc_mask, xsrc1, ysrc1, SRCAND); - ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values - ::SetTextColor(GetHdc(), prevCol); - - // OR buffer to dest - success = (::BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, - dc_buffer, 0, 0, SRCPAINT) != 0); - - // tidy up temporary DCs and bitmap - ::SelectObject(dc_mask, 0); - ::DeleteDC(dc_mask); - ::SelectObject(dc_buffer, 0); - ::DeleteDC(dc_buffer); - ::DeleteObject(buffer_bmap); + wxLogLastError("BitBlt"); } - } - } - else - { - if (IsKindOf(CLASSINFO(wxPrinterDC))) - { - // If we are printing, source colours are screen colours - // not printer colours and so we need copy the bitmap - // pixel by pixel. - HDC dc_src = (HDC) source->m_hDC; - RECT rect; - for (int x = 0; x < width; x++) + + // 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, xsrc, ysrc, SRCAND) ) { - for (int y = 0; y < height; y++) - { - HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y)); - rect.left = xdest1 + x; rect.right = rect.left + 1; - rect.top = ydest1 + y; rect.bottom = rect.top + 1; - ::FillRect(GetHdc(), &rect, brush); - ::DeleteObject(brush); - } + wxLogLastError("BitBlt"); } + + // 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, xsrc, ysrc, SRCAND) ) + { + wxLogLastError("BitBlt"); + } + ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values + ::SetTextColor(GetHdc(), prevCol); + + // OR buffer to dest + success = ::BitBlt(GetHdc(), xdest, ydest, + (int)width, (int)height, + dc_buffer, 0, 0, SRCPAINT) != 0; + if ( !success ) + { + wxLogLastError("BitBlt"); + } + + // tidy up temporary DCs and bitmap + ::SelectObject(dc_mask, 0); + ::DeleteDC(dc_mask); + ::SelectObject(dc_buffer, 0); + ::DeleteDC(dc_buffer); + ::DeleteObject(buffer_bmap); } - else + } + else // no mask, just BitBlt() it + { + success = ::BitBlt(GetHdc(), xdest, ydest, + (int)width, (int)height, + GetHdcOf(*source), xsrc, ysrc, dwRop) != 0; + if ( !success ) { - success = (BitBlt(GetHdc(), xdest1, ydest1, (int)width, (int)height, (HDC) source->m_hDC, - xsrc1, ysrc1, dwRop) != 0); + wxLogLastError("BitBlt"); } } + ::SetTextColor(GetHdc(), old_textground); ::SetBkColor(GetHdc(), old_background);