Optimize drawing horizontal/vertical lines

On DC with a non-rotated coordinate system drawing a filled rectangle with ExtTextOut() Win API is faster than drawing a line with MoveTo()/LineTo() so on such DCs we can use ExtTextOut() to draw horizontal/vertical lines with solid colors and square ends instead of calling MoveTo()/LineTo().

See #18517.
This commit is contained in:
Artur Wieczorek 2019-10-17 17:28:01 +02:00
parent 8064d9420f
commit bae8bb4c45
3 changed files with 56 additions and 1 deletions

View File

@ -1109,6 +1109,8 @@ extern WXDLLIMPEXP_CORE wxSize wxGetHiconSize(HICON hicon);
WXDLLIMPEXP_CORE void wxDrawLine(HDC hdc, int x1, int y1, int x2, int y2);
WXDLLIMPEXP_CORE void wxDrawHVLine(HDC hdc, int x1, int y1, int x2, int y2, COLORREF color, int width);
// fill the client rect of the given window on the provided dc using this brush
inline void wxFillRect(HWND hwnd, HDC hdc, HBRUSH hbr)
{

View File

@ -819,7 +819,31 @@ void wxMSWDCImpl::DoCrossHair(wxCoord x, wxCoord y)
void wxMSWDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
{
wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
// We have optimized function to draw physical vertical or horizontal lines
// with solid color and square ends.
// Because checking wheteher the line would be horizontal/vertical
// in the device coordinate system is complex so we only check whether
// the line is horizontal/vertical in the logical coordinates and use
// optimized function only for DC which coordinate system is for sure
// not rotated (graphics mode of the DC != GM_ADVANCED).
// Moreover, optimized function can be used only for regular lines with pen
// width > 0 because it doesn't support drawing non-scaled 1-pixel wide
// lines when pen width is 0.
if ( (x1 == x2 || y1 == y2) &&
::GetGraphicsMode(GetHdc()) != GM_ADVANCED && // ensure DC is not rotated
m_pen.IsNonTransparent() && // this calls IsOk() too
m_pen.GetStyle() == wxPENSTYLE_SOLID &&
m_pen.GetWidth() > 0 &&
(m_pen.GetWidth() == 1 || m_pen.GetCap() == wxCAP_BUTT)
)
{
wxDrawHVLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2),
wxColourToRGB(m_pen.GetColour()), m_pen.GetWidth());
}
else
{
wxDrawLine(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
}
CalcBoundingBox(x1, y1);
CalcBoundingBox(x2, y2);

View File

@ -209,6 +209,35 @@ void wxDrawLine(HDC hdc, int x1, int y1, int x2, int y2)
MoveToEx(hdc, x1, y1, NULL); LineTo((HDC) hdc, x2, y2);
}
// Function dedicated to drawing horizontal/vertical lines with solid color
// It fills rectangle representing the line with ::ExtTextOut() API which
// apparently is faster than ::MoveTo()/::LineTo() on DC with a non-rotated
// coordinate system.
void wxDrawHVLine(HDC hdc, int x1, int y1, int x2, int y2, COLORREF color, int width)
{
wxASSERT(x1 == x2 || y1 == y2);
int w1 = width / 2;
int w2 = width - w1;
RECT r;
if ( y1 == y2 )
{
if ( x1 == x2 )
return;
::SetRect(&r, x1, y1 - w1, x2, y1 + w2);
}
else
{
::SetRect(&r, x1 - w1, y1, x2 + w2, y2);
}
COLORREF bgColorOrig = ::GetBkColor(hdc);
::SetBkColor(hdc, color);
::ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
::SetBkColor(hdc, bgColorOrig);
}
// ----------------------------------------------------------------------------
// Shell API wrappers