Implement 0-width pen consistently in wxGraphicsContext

Emulate a 1-pixel pen width as closely as possible.

This reverts:
334cf1cc91 (Take HiDPI scale into account for wxGCDC 0-width pen, 2021-04-03)
0d80050057 (Make wxGCDC behavior with 0-width wxPen consistent with MSW wxDC, 2021-03-02)

See #19077, #19115
This commit is contained in:
Paul Cornett
2021-04-05 09:56:28 -07:00
parent a2e4cb6cec
commit 52cc838b12
10 changed files with 190 additions and 130 deletions

View File

@@ -441,17 +441,23 @@ public:
virtual bool ShouldOffset() const wxOVERRIDE
{
if ( !m_enableOffset )
if (!m_enableOffset || m_pen.IsNull())
return false;
int penwidth = 0 ;
if ( !m_pen.IsNull() )
{
penwidth = (int)((wxCairoPenData*)m_pen.GetRefData())->GetWidth();
if ( penwidth == 0 )
penwidth = 1;
}
return ( penwidth % 2 ) == 1;
const double width = static_cast<wxCairoPenData*>(m_pen.GetRefData())->GetWidth();
// always offset for 1-pixel width
if (width <= 0)
return true;
// no offset if overall scale is not odd integer
double x = GetContentScaleFactor(), y = x;
cairo_user_to_device_distance(m_context, &x, &y);
if (!wxIsSameDouble(fmod(wxMin(fabs(x), fabs(y)), 2.0), 1.0))
return false;
// offset if pen width is odd integer
return wxIsSameDouble(fmod(width, 2.0), 1.0);
}
virtual void Clip( const wxRegion &region ) wxOVERRIDE;
@@ -844,8 +850,6 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxGraphicsPe
{
Init();
m_width = info.GetWidth();
if (m_width <= 0.0)
m_width = 0.1;
switch ( info.GetCap() )
{
@@ -1017,7 +1021,14 @@ void wxCairoPenData::Apply( wxGraphicsContext* context )
wxCairoPenBrushBaseData::Apply(context);
cairo_t * ctext = (cairo_t*) context->GetNativeContext();
cairo_set_line_width(ctext,m_width);
double width = m_width;
if (width <= 0)
{
double x = context->GetContentScaleFactor(), y = x;
cairo_user_to_device_distance(ctext, &x, &y);
width = 1 / wxMin(fabs(x), fabs(y));
}
cairo_set_line_width(ctext, width);
cairo_set_line_cap(ctext,m_cap);
cairo_set_line_join(ctext,m_join);
cairo_set_dash(ctext, m_lengths, m_count, 0);
@@ -1912,21 +1923,26 @@ wxCairoBitmapData::~wxCairoBitmapData()
class wxCairoOffsetHelper
{
public :
wxCairoOffsetHelper( cairo_t* ctx , bool offset )
wxCairoOffsetHelper(cairo_t* ctx, double scaleFactor, bool offset)
{
m_ctx = ctx;
m_offset = offset;
if ( m_offset )
cairo_translate( m_ctx, 0.5, 0.5 );
m_offset = 0;
if (offset)
{
double x = scaleFactor, y = x;
cairo_user_to_device_distance(ctx, &x, &y);
m_offset = 0.5 / wxMin(fabs(x), fabs(y));
cairo_translate(m_ctx, m_offset, m_offset);
}
}
~wxCairoOffsetHelper( )
{
if ( m_offset )
cairo_translate( m_ctx, -0.5, -0.5 );
if (m_offset > 0)
cairo_translate(m_ctx, -m_offset, -m_offset);
}
public :
private:
cairo_t* m_ctx;
bool m_offset;
double m_offset;
} ;
#if wxUSE_PRINTING_ARCHITECTURE
@@ -1976,7 +1992,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC&
m_width = width;
m_height = height;
m_enableOffset = dc.GetContentScaleFactor() <= 1;
EnableOffset();
#ifdef __WXMSW__
HDC hdc = (HDC)dc.GetHDC();
@@ -2029,7 +2045,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC&
m_width = width;
m_height = height;
m_enableOffset = dc.GetContentScaleFactor() <= 1;
SetContentScaleFactor(dc.GetContentScaleFactor());
#ifdef __WXMSW__
wxBitmap bmp = dc.GetSelectedBitmap();
@@ -2352,7 +2368,7 @@ wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer, HWND hWnd)
{
// See remarks for wxWindowBase::GetContentScaleFactor
double scaleY = ::GetDeviceCaps((HDC)m_mswWindowHDC, LOGPIXELSY) / 96.0f;
m_enableOffset = scaleY <= 1.0;
SetContentScaleFactor(scaleY);
m_mswStateSavedDC = 0;
m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC);
@@ -2393,7 +2409,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
, m_mswWindowHDC(GetHwndOf(window))
#endif
{
m_enableOffset = window->GetContentScaleFactor() <= 1;
EnableOffset();
#ifdef __WXGTK__
// something along these lines (copied from dcclient)
@@ -2605,7 +2621,7 @@ void wxCairoContext::StrokePath( const wxGraphicsPath& path )
{
if ( !m_pen.IsNull() )
{
wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
cairo_append_path(m_context,cp);
((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
@@ -2618,7 +2634,7 @@ void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fi
{
if ( !m_brush.IsNull() )
{
wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
cairo_append_path(m_context,cp);
((wxCairoBrushData*)m_brush.GetRefData())->Apply(this);
@@ -2647,7 +2663,7 @@ void wxCairoContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble
}
if ( !m_pen.IsNull() )
{
wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
cairo_rectangle(m_context, x, y, w, h);
cairo_stroke(m_context);