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 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 // fill the client rect of the given window on the provided dc using this brush
inline void wxFillRect(HWND hwnd, HDC hdc, HBRUSH hbr) 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) 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(x1, y1);
CalcBoundingBox(x2, y2); 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); 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 // Shell API wrappers