X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a58a12e9b7196c339c1c1d282ede158a70644e07..d624fd67f82a90d74c7f796b241508663367134f:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index f8c01f727d..72de5d6db8 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -289,23 +289,34 @@ void wxDC::Clear() void wxDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style) { - (void)ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), - col.GetPixel(), - style == wxFLOOD_SURFACE ? FLOODFILLSURFACE - : FLOODFILLBORDER); + if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), + col.GetPixel(), + style == wxFLOOD_SURFACE ? FLOODFILLSURFACE + : FLOODFILLBORDER) ) + { + // quoting from the MSDN docs: + // + // Following are some of the reasons this function might fail: + // + // * The filling could not be completed. + // * The specified point has the boundary color specified by the + // crColor parameter (if FLOODFILLBORDER was requested). + // * The specified point does not have the color specified by + // crColor (if FLOODFILLSURFACE was requested) + // * The point is outside the clipping region that is, it is not + // visible on the device. + // + wxLogLastError("ExtFloodFill"); + } CalcBoundingBox(x, y); } bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const { - // added by steve 29.12.94 (copied from DrawPoint) - // returns TRUE for pixels in the color of the current pen - // and FALSE for all other pixels colors - // if col is non-NULL return the color of the pixel - // get the color of the pixel COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)); + // get the color of the pen COLORREF pencolor = 0x00ffffff; if (m_pen.Ok()) @@ -314,12 +325,16 @@ bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const } // return the color of the pixel - if(col) - col->Set(GetRValue(pixelcolor),GetGValue(pixelcolor),GetBValue(pixelcolor)); + if( col ) + { + col->Set(GetRValue(pixelcolor), + GetGValue(pixelcolor), + GetBValue(pixelcolor)); + } - // check, if color of the pixels is the same as the color - // of the current pen - return(pixelcolor==pencolor); + // check, if color of the pixels is the same as the color of the current + // pen and return TRUE if it is, FALSE otherwise + return pixelcolor == pencolor; } void wxDC::DoCrossHair(wxCoord x, wxCoord y) @@ -497,74 +512,55 @@ 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) + COLORREF colFgOld = 0, + colBgOld = 0; + + if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) { + colFgOld = ::GetTextColor(GetHdc()); + colBgOld = ::GetBkColor(GetHdc()); - 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_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_backgroundMode == wxTRANSPARENT) - SetBkMode(GetHdc(), TRANSPARENT); - else - SetBkMode(GetHdc(), OPAQUE); + if ( m_textBackgroundColour.Ok() ) + { + // 0 in mask becomes text color + ::SetTextColor(GetHdc(), m_textBackgroundColour.GetPixel()); + } + + // VZ: IMHO this does strictly nothing here + SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT + : OPAQUE); } wxCoord x2 = x + width; wxCoord y2 = y + height; - /* MATTHEW: [6] new normalization */ -#if WX_STANDARD_GRAPHICS - bool do_brush, do_pen; - - do_brush = m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT; - do_pen = m_pen.Ok() && m_pen.GetStyle() != wxTRANSPARENT; - - if (do_brush) { - HPEN orig_pen = NULL; - - if (do_pen || !m_pen.Ok()) - orig_pen = (HPEN) ::SelectObject(GetHdc(), (HPEN) ::GetStockObject(NULL_PEN)); - - (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), - XLOG2DEV(x2) + 1, YLOG2DEV(y2) + 1); - - if (do_pen || !m_pen.Ok()) - ::SelectObject(GetHdc() , orig_pen); + // Windows draws the filled rectangles without outline (i.e. drawn with a + // transparent pen) one pixel smaller in both directions and we want them + // to have the same size regardless of which pen is used - adjust + if ( m_pen.GetStyle() == wxTRANSPARENT ) + { + x2++; + y2++; } - if (do_pen) { - HBRUSH orig_brush = NULL; - - if (do_brush || !m_brush.Ok()) - orig_brush = (HBRUSH) ::SelectObject(GetHdc(), (HBRUSH) ::GetStockObject(NULL_BRUSH)); - - (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), - XLOG2DEV(x2), YLOG2DEV(y2)); - if (do_brush || !m_brush.Ok()) - ::SelectObject(GetHdc(), orig_brush); - } -#else (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); -#endif CalcBoundingBox(x, y); CalcBoundingBox(x2, y2); - if (m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) + if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) { - ::SetBkMode(GetHdc(), TRANSPARENT); - ::SetTextColor(GetHdc(), old_textground); - ::SetBkColor(GetHdc(), old_background); + // restore the colours we changed + ::SetBkMode(GetHdc(), TRANSPARENT); + ::SetTextColor(GetHdc(), colFgOld); + ::SetBkColor(GetHdc(), colBgOld); } } @@ -661,7 +657,61 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask int width = bmp.GetWidth(), height = bmp.GetHeight(); - if ( !useMask ) + HBITMAP hbmpMask = 0; + + if ( useMask ) + { + wxMask *mask = bmp.GetMask(); + if ( mask ) + hbmpMask = (HBITMAP)mask->GetMaskBitmap(); + + if ( !hbmpMask ) + { + // don't give assert here because this would break existing + // programs - just silently ignore useMask parameter + useMask = FALSE; + } + } + + if ( useMask ) + { +#ifdef __WIN32__ + HDC hdcMem = ::CreateCompatibleDC(GetHdc()); + ::SelectObject(hdcMem, GetHbitmapOf(bmp)); + + // this will only work if the transparent part of our bitmap is black + // because it is combined with the destination rectangle using OR, so + // it won't be really transparent otherwise - I don't know what to do + // about it, may be use MAKEROP4(SRCCOPY, DSTINVERT) twice? Or create a + // copy of the bitmap with the transparent part replaced with black + // pixels? + + // GRG: now this works regardless of what the source bitmap + // contains in the area which is to be transparent. + // + bool ok = ::MaskBlt(GetHdc(), x, y, width, height, + hdcMem, 0, 0, + hbmpMask, 0, 0, + MAKEROP4(SRCCOPY, 0x00AA0029)) != 0; + ::DeleteDC(hdcMem); + + if ( !ok ) +#endif // Win32 + { + // VZ: this is incorrect, Blit() doesn't (and can't) draw + // transparently, but it's still better than nothing at all + // GRG: Blit() *should* draw transparently when there is a mask + + // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level + wxMemoryDC memDC; + memDC.SelectObject(bmp); + + Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); + + memDC.SelectObject(wxNullBitmap); + } + } + else // no mask, just use BitBlt() { HDC cdc = GetHdc(); HDC memdc = ::CreateCompatibleDC( cdc ); @@ -687,16 +737,6 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask ::SetTextColor(GetHdc(), old_textground); ::SetBkColor(GetHdc(), old_background); } - else - { - // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level - wxMemoryDC memDC; - memDC.SelectObject(bmp); - - Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); - - memDC.SelectObject(wxNullBitmap); - } } void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y) @@ -782,6 +822,7 @@ void wxDC::DoDrawRotatedText(const wxString& text, DrawAnyText(text, x, y); (void)::SelectObject(GetHdc(), hfontOld); + (void)::DeleteObject(hfont); } // call the bounding box by adding all four vertices of the rectangle @@ -995,37 +1036,40 @@ void wxDC::SetLogicalFunction(int function) { m_logicalFunction = function; - SetRop((WXHDC) m_hDC); + SetRop(m_hDC); } void wxDC::SetRop(WXHDC dc) { - if (!dc || m_logicalFunction < 0) + if ( !dc || m_logicalFunction < 0 ) return; - int c_rop; - // These may be wrong + int rop; + switch (m_logicalFunction) { - // case wxXOR: c_rop = R2_XORPEN; break; - case wxXOR: c_rop = R2_NOTXORPEN; break; - case wxINVERT: c_rop = R2_NOT; break; - case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break; - case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break; - case wxCLEAR: c_rop = R2_WHITE; break; - case wxSET: c_rop = R2_BLACK; break; - case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break; - case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break; - case wxAND: c_rop = R2_MASKPEN; break; - case wxOR: c_rop = R2_MERGEPEN; break; - case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break; - case wxEQUIV: - case wxNAND: - case wxCOPY: - default: - c_rop = R2_COPYPEN; break; + case wxXOR: rop = R2_XORPEN; break; + case wxINVERT: rop = R2_NOT; break; + case wxOR_REVERSE: rop = R2_MERGEPENNOT; break; + case wxAND_REVERSE: rop = R2_MASKPENNOT; break; + case wxCLEAR: rop = R2_WHITE; break; + case wxSET: rop = R2_BLACK; break; + case wxOR_INVERT: rop = R2_MERGENOTPEN; break; + case wxAND: rop = R2_MASKPEN; break; + case wxOR: rop = R2_MERGEPEN; break; + case wxEQUIV: rop = R2_NOTXORPEN; break; + case wxNAND: rop = R2_NOTMASKPEN; break; + case wxAND_INVERT: rop = R2_MASKNOTPEN; break; + case wxCOPY: rop = R2_COPYPEN; break; + case wxNO_OP: rop = R2_NOP; break; + case wxSRC_INVERT: rop = R2_NOTCOPYPEN; break; + case wxNOR: rop = R2_NOTMERGEPEN; break; + default: + wxFAIL_MSG( wxT("unsupported logical function") ); + return; } - SetROP2((HDC) dc, c_rop); + + SetROP2(GetHdc(), rop); } bool wxDC::StartDoc(const wxString& message) @@ -1255,8 +1299,12 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, const wxBitmap& bmp = source->m_selectedBitmap; mask = bmp.GetMask(); - wxCHECK_MSG( bmp.Ok() && mask && mask->GetMaskBitmap(), FALSE, - _T("can't blit with mask without mask") ); + if ( !(bmp.Ok() && mask && mask->GetMaskBitmap()) ) + { + // don't give assert here because this would break existing + // programs - just silently ignore useMask parameter + useMask = FALSE; + } } COLORREF old_textground = ::GetTextColor(GetHdc()); @@ -1270,40 +1318,74 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); } - 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; + DWORD dwRop = SRCCOPY; + switch (rop) + { + case wxXOR: dwRop = SRCINVERT; break; + case wxINVERT: dwRop = DSTINVERT; break; + case wxOR_REVERSE: dwRop = 0x00DD0228; break; + case wxAND_REVERSE: dwRop = SRCERASE; break; + case wxCLEAR: dwRop = BLACKNESS; break; + case wxSET: dwRop = WHITENESS; break; + case wxOR_INVERT: dwRop = MERGEPAINT; break; + case wxAND: dwRop = SRCAND; break; + case wxOR: dwRop = SRCPAINT; break; + case wxEQUIV: dwRop = 0x00990066; break; + case wxNAND: dwRop = 0x007700E6; break; + case wxAND_INVERT: dwRop = 0x00220326; break; + case wxCOPY: dwRop = SRCCOPY; break; + case wxNO_OP: dwRop = 0x00AA0029; break; + case wxSRC_INVERT: dwRop = NOTSRCCOPY; break; + case wxNOR: dwRop = NOTSRCCOPY; break; + default: + wxFAIL_MSG( wxT("unsupported logical function") ); + return FALSE; + } bool success; if (useMask) { #ifdef __WIN32__ + // prepare the mask bitmap HBITMAP hbmpMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap()); + // select the correct brush: the current one by default, background one + // if none + HBRUSH hbrNew; + if ( m_brush.Ok() ) + { + hbrNew = (HBRUSH)m_brush.GetResourceHandle(); + } + else if ( m_backgroundBrush.Ok() ) + { + hbrNew = (HBRUSH)m_backgroundBrush.GetResourceHandle(); + } + else + { + hbrNew = 0; + } + + HGDIOBJ hbrOld = hbrNew ? ::SelectObject(GetHdc(), hbrNew) : 0; + // 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); + // GRG: PATCOPY is not transparent, as can be seen when blitting + // over a pattern: the 'transparent' area would be filled + // with the selected colour. We should use NOP instead, or + // do MaskBlt + BitBlt. + // success = ::MaskBlt(GetHdc(), xdest, ydest, width, height, GetHdcOf(*source), xsrc, ysrc, hbmpMask, 0, 0, - MAKEROP4(PATCOPY, dwRop)) != 0; + MAKEROP4(0x00AA0029, dwRop)) != 0; + + if ( hbrNew ) + { + (void)::SelectObject(GetHdc(), hbrOld); + } - (void)::SelectObject(GetHdc(), hbrOld); - ::DeleteObject(hbrOld); ::DeleteObject(hbmpMask); if ( !success ) @@ -1379,7 +1461,6 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxLogLastError("BitBlt"); } } - ::SetTextColor(GetHdc(), old_textground); ::SetBkColor(GetHdc(), old_background);