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

@@ -878,6 +878,9 @@ public:
void DisableOffset() { EnableOffset(false); }
bool OffsetEnabled() const { return m_enableOffset; }
void SetContentScaleFactor(double contentScaleFactor);
double GetContentScaleFactor() const { return m_contentScaleFactor; }
protected:
// These fields must be initialized in the derived class ctors.
wxDouble m_width,
@@ -912,6 +915,7 @@ private:
// Create() or the associated window of the wxDC this context was created
// from.
wxWindow* const m_window;
double m_contentScaleFactor;
wxDECLARE_NO_COPY_CLASS(wxGraphicsContext);
wxDECLARE_ABSTRACT_CLASS(wxGraphicsContext);

View File

@@ -522,36 +522,10 @@ void wxGCDCImpl::SetFont( const wxFont &font )
void wxGCDCImpl::SetPen( const wxPen &pen )
{
m_pen = pen;
if (m_graphicContext == NULL)
return;
wxPenStyle style;
if (!pen.IsOk() || (style = pen.GetStyle()) == wxPENSTYLE_TRANSPARENT)
if ( m_graphicContext )
{
m_graphicContext->SetPen(wxGraphicsPen());
return;
m_graphicContext->SetPen( m_pen );
}
// 0-width pen is 1 pixel wide with MSW wxDC
const int w = pen.GetWidth();
const double width = w ? double(w) : 1 / (wxMin(m_scaleX, m_scaleY) * m_contentScaleFactor);
wxGraphicsPenInfo info(pen.GetColour(), width, style);
info.Join(pen.GetJoin()).Cap(pen.GetCap());
if (style == wxPENSTYLE_USER_DASH)
{
wxDash* dashes;
if (int n = pen.GetDashes(&dashes))
info.Dashes(n, dashes);
}
else if (style == wxPENSTYLE_STIPPLE)
{
if (const wxBitmap* stipple = pen.GetStipple())
info.Stipple(*stipple);
}
m_graphicContext->SetPen(m_graphicContext->CreatePen(info));
}
void wxGCDCImpl::SetBrush( const wxBrush &brush )

View File

@@ -572,6 +572,7 @@ wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer,
m_enableOffset(false),
m_window(window)
{
m_contentScaleFactor = window ? window->GetContentScaleFactor() : 1.0;
}
wxGraphicsContext::~wxGraphicsContext()
@@ -605,6 +606,12 @@ void wxGraphicsContext::EnableOffset(bool enable)
m_enableOffset = enable;
}
void wxGraphicsContext::SetContentScaleFactor(double contentScaleFactor)
{
m_enableOffset = true;
m_contentScaleFactor = contentScaleFactor;
}
#if 0
void wxGraphicsContext::SetAlpha( wxDouble WXUNUSED(alpha) )
{

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);

View File

@@ -407,7 +407,7 @@ wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
AdjustForRTL(cr);
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
cairo_destroy(cr);
gc->EnableOffset(m_contentScaleFactor <= 1);
gc->SetContentScaleFactor(m_contentScaleFactor);
SetGraphicsContext(gc);
GtkAllocation a;
gtk_widget_get_allocation(widget, &a);
@@ -456,7 +456,7 @@ wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window)
AdjustForRTL(cr);
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
cairo_destroy(cr);
gc->EnableOffset(m_contentScaleFactor <= 1);
gc->SetContentScaleFactor(m_contentScaleFactor);
SetGraphicsContext(gc);
if (!gtk_widget_get_has_window(widget))
{
@@ -480,7 +480,7 @@ wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)
wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event");
InitSize(gtk_widget_get_window(window->m_wxwindow));
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
gc->EnableOffset(m_contentScaleFactor <= 1);
gc->SetContentScaleFactor(m_contentScaleFactor);
SetGraphicsContext(gc);
// context is already adjusted for RTL
m_layoutDir = window->GetLayoutDirection();
@@ -510,7 +510,7 @@ wxScreenDCImpl::wxScreenDCImpl(wxScreenDC* owner)
cairo_t* cr = gdk_cairo_create(window);
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
cairo_destroy(cr);
gc->EnableOffset(m_contentScaleFactor <= 1);
gc->SetContentScaleFactor(m_contentScaleFactor);
SetGraphicsContext(gc);
}
@@ -573,7 +573,7 @@ void wxMemoryDCImpl::Setup()
AdjustForRTL(cr);
gc = wxGraphicsContext::CreateFromNative(cr);
cairo_destroy(cr);
gc->EnableOffset(m_contentScaleFactor <= 1);
gc->SetContentScaleFactor(m_contentScaleFactor);
}
SetGraphicsContext(gc);
}
@@ -583,7 +583,7 @@ wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr, wxWindow* window, wxLayoutDirection dir,
: wxDC(new wxGTKCairoDCImpl(this, window, dir, width))
{
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
gc->EnableOffset(window->GetContentScaleFactor() <= 1);
gc->SetContentScaleFactor(window->GetContentScaleFactor());
SetGraphicsContext(gc);
if (dir == wxLayout_Default)
SetLayoutDirection(window->GetLayoutDirection());

View File

@@ -827,8 +827,6 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer,
{
Init();
m_width = info.GetWidth();
if (m_width <= 0.0)
m_width = 0.1;
m_pen = new Pen(wxColourToColor(info.GetColour()), m_width );
@@ -1827,21 +1825,29 @@ void * wxGDIPlusMatrixData::GetNativeMatrix() const
class wxGDIPlusOffsetHelper
{
public :
wxGDIPlusOffsetHelper( Graphics* gr , bool offset )
wxGDIPlusOffsetHelper(Graphics* gr, double scaleFactor, bool offset)
{
m_gr = gr;
m_offset = offset;
if ( m_offset )
m_gr->TranslateTransform( 0.5, 0.5 );
m_offset = 0;
if (offset)
{
Matrix matrix;
gr->GetTransform(&matrix);
const float f = float(scaleFactor);
PointF pt(f, f);
matrix.TransformVectors(&pt);
m_offset = 0.5f / wxMin(std::abs(pt.X), std::abs(pt.Y));
m_gr->TranslateTransform(m_offset, m_offset);
}
}
~wxGDIPlusOffsetHelper( )
{
if ( m_offset )
m_gr->TranslateTransform( -0.5, -0.5 );
if (m_offset > 0)
m_gr->TranslateTransform(-m_offset, -m_offset);
}
public :
Graphics* m_gr;
bool m_offset;
float m_offset;
} ;
wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDouble width, wxDouble height )
@@ -1952,7 +1958,7 @@ void wxGDIPlusContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDoub
if (m_composition == wxCOMPOSITION_DEST)
return;
wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
Brush *brush = m_brush.IsNull() ? NULL : ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush();
Pen *pen = m_pen.IsNull() ? NULL : ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen();
@@ -1991,7 +1997,7 @@ void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
if ( !m_pen.IsNull() )
{
wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
PointF *cpoints = new PointF[n];
for (size_t i = 0; i < n; i++)
{
@@ -2009,7 +2015,7 @@ void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPol
if (m_composition == wxCOMPOSITION_DEST)
return;
wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
PointF *cpoints = new PointF[n];
for (size_t i = 0; i < n; i++)
{
@@ -2032,7 +2038,7 @@ void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
if ( !m_pen.IsNull() )
{
wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
}
}
@@ -2044,7 +2050,7 @@ void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode
if ( !m_brush.IsNull() )
{
wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
(GraphicsPath*) path.GetNativePath());
@@ -2429,17 +2435,24 @@ void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble
bool wxGDIPlusContext::ShouldOffset() const
{
if ( !m_enableOffset )
if (!m_enableOffset || m_pen.IsNull())
return false;
int penwidth = 0 ;
if ( !m_pen.IsNull() )
{
penwidth = (int)((wxGDIPlusPenData*)m_pen.GetRefData())->GetWidth();
if ( penwidth == 0 )
penwidth = 1;
}
return ( penwidth % 2 ) == 1;
double width = static_cast<wxGDIPlusPenData*>(m_pen.GetRefData())->GetWidth();
// always offset for 1-pixel width
if (width <= 0)
return true;
// no offset if overall scale is not odd integer
const wxGraphicsMatrix matrix(GetTransform());
double x = GetContentScaleFactor(), y = x;
matrix.TransformDistance(&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);
}
void* wxGDIPlusContext::GetNativeContext()

View File

@@ -1107,24 +1107,31 @@ wxCOMPtr<ID2D1Geometry> wxD2DConvertRegionToGeometry(ID2D1Factory* direct2dFacto
class wxD2DOffsetHelper
{
public:
wxD2DOffsetHelper(wxGraphicsContext* g) : m_context(g)
wxD2DOffsetHelper(wxGraphicsContext* g, double scaleFactor)
: m_context(g)
{
m_offset = 0;
if (m_context->ShouldOffset())
{
m_context->Translate(0.5, 0.5);
const wxGraphicsMatrix matrix(m_context->GetTransform());
double x = m_context->GetContentScaleFactor(), y = x;
matrix.TransformDistance(&x, &y);
m_offset = 0.5 / wxMin(fabs(x), fabs(y));
m_context->Translate(m_offset, m_offset);
}
}
~wxD2DOffsetHelper()
{
if (m_context->ShouldOffset())
if (m_offset > 0)
{
m_context->Translate(-0.5, -0.5);
m_context->Translate(-m_offset, -m_offset);
}
}
private:
wxGraphicsContext* m_context;
double m_offset;
};
bool operator==(const D2D1::Matrix3x2F& lhs, const D2D1::Matrix3x2F& rhs)
@@ -3033,6 +3040,8 @@ public:
ID2D1Brush* GetBrush();
FLOAT GetWidth();
bool IsZeroWidth() const;
void SetWidth(const wxGraphicsContext* context);
ID2D1StrokeStyle* GetStrokeStyle();
@@ -3146,6 +3155,17 @@ void wxD2DPenData::CreateStrokeStyle(ID2D1Factory* const direct2dfactory)
delete[] dashes;
}
void wxD2DPenData::SetWidth(const wxGraphicsContext* context)
{
if (m_penInfo.GetWidth() <= 0)
{
const wxGraphicsMatrix matrix(context->GetTransform());
double x = context->GetContentScaleFactor(), y = x;
matrix.TransformDistance(&x, &y);
m_width = 1 / wxMin(fabs(x), fabs(y));
}
}
ID2D1Brush* wxD2DPenData::GetBrush()
{
return m_stippleBrush->GetBrush();
@@ -3156,6 +3176,11 @@ FLOAT wxD2DPenData::GetWidth()
return m_width;
}
bool wxD2DPenData::IsZeroWidth() const
{
return m_penInfo.GetWidth() <= 0;
}
ID2D1StrokeStyle* wxD2DPenData::GetStrokeStyle()
{
return m_strokeStyle;
@@ -4321,7 +4346,7 @@ void wxD2DContext::StrokePath(const wxGraphicsPath& p)
if (m_composition == wxCOMPOSITION_DEST)
return;
wxD2DOffsetHelper helper(this);
wxD2DOffsetHelper helper(this, GetContentScaleFactor());
EnsureInitialized();
AdjustRenderTargetSize();
@@ -4332,6 +4357,7 @@ void wxD2DContext::StrokePath(const wxGraphicsPath& p)
if (!m_pen.IsNull())
{
wxD2DPenData* penData = wxGetD2DPenData(m_pen);
penData->SetWidth(this);
penData->Bind(this);
ID2D1Brush* nativeBrush = penData->GetBrush();
GetRenderTarget()->DrawGeometry((ID2D1Geometry*)pathData->GetNativePath(), nativeBrush, penData->GetWidth(), penData->GetStrokeStyle());
@@ -4690,19 +4716,24 @@ void wxD2DContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& wi
bool wxD2DContext::ShouldOffset() const
{
if (!m_enableOffset)
{
if (!m_enableOffset || m_pen.IsNull())
return false;
}
int penWidth = 0;
if (!m_pen.IsNull())
{
penWidth = wxGetD2DPenData(m_pen)->GetWidth();
penWidth = wxMax(penWidth, 1);
}
wxD2DPenData* const penData = wxGetD2DPenData(m_pen);
return (penWidth % 2) == 1;
// always offset for 1-pixel width
if (penData->IsZeroWidth())
return true;
// no offset if overall scale is not odd integer
const wxGraphicsMatrix matrix(GetTransform());
double x = GetContentScaleFactor(), y = x;
matrix.TransformDistance(&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(double(penData->GetWidth()), 2.0), 1.0);
}
void wxD2DContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
@@ -4779,7 +4810,7 @@ void wxD2DContext::DrawRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
if (m_composition == wxCOMPOSITION_DEST)
return;
wxD2DOffsetHelper helper(this);
wxD2DOffsetHelper helper(this, GetContentScaleFactor());
EnsureInitialized();
AdjustRenderTargetSize();
@@ -4797,6 +4828,7 @@ void wxD2DContext::DrawRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
if (!m_pen.IsNull())
{
wxD2DPenData* penData = wxGetD2DPenData(m_pen);
penData->SetWidth(this);
penData->Bind(this);
GetRenderTarget()->DrawRectangle(rect, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
}
@@ -4807,7 +4839,7 @@ void wxD2DContext::DrawRoundedRectangle(wxDouble x, wxDouble y, wxDouble w, wxDo
if (m_composition == wxCOMPOSITION_DEST)
return;
wxD2DOffsetHelper helper(this);
wxD2DOffsetHelper helper(this, GetContentScaleFactor());
EnsureInitialized();
AdjustRenderTargetSize();
@@ -4826,6 +4858,7 @@ void wxD2DContext::DrawRoundedRectangle(wxDouble x, wxDouble y, wxDouble w, wxDo
if (!m_pen.IsNull())
{
wxD2DPenData* penData = wxGetD2DPenData(m_pen);
penData->SetWidth(this);
penData->Bind(this);
GetRenderTarget()->DrawRoundedRectangle(roundedRect, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
}
@@ -4836,7 +4869,7 @@ void wxD2DContext::DrawEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
if (m_composition == wxCOMPOSITION_DEST)
return;
wxD2DOffsetHelper helper(this);
wxD2DOffsetHelper helper(this, GetContentScaleFactor());
EnsureInitialized();
AdjustRenderTargetSize();
@@ -4857,6 +4890,7 @@ void wxD2DContext::DrawEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
if (!m_pen.IsNull())
{
wxD2DPenData* penData = wxGetD2DPenData(m_pen);
penData->SetWidth(this);
penData->Bind(this);
GetRenderTarget()->DrawEllipse(ellipse, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
}

View File

@@ -76,7 +76,7 @@ wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window )
CGContextTranslateCTM( cg , -window->MacGetLeftBorderSize() , -window->MacGetTopBorderSize() );
wxGraphicsContext* context = wxGraphicsContext::CreateFromNative( cg );
context->EnableOffset(m_contentScaleFactor <= 1);
context->SetContentScaleFactor(m_contentScaleFactor);
SetGraphicsContext( context );
}
DoSetClippingRegion( 0 , 0 , m_width , m_height ) ;

View File

@@ -743,8 +743,6 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer
// TODO: * m_dc->m_scaleX
m_width = info.GetWidth();
if (m_width <= 0.0)
m_width = (CGFloat) 0.1;
switch ( info.GetCap() )
{
@@ -912,7 +910,15 @@ void wxMacCoreGraphicsPenData::Init()
void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context )
{
CGContextRef cg = (CGContextRef) context->GetNativeContext();
CGContextSetLineWidth( cg , m_width );
double width = m_width;
if (width <= 0)
{
const double scaleFactor = context->GetContentScaleFactor();
CGSize s = { scaleFactor, scaleFactor };
s = CGContextConvertSizeToUserSpace(cg, s);
width = 1 / wxMin(fabs(s.width), fabs(s.height));
}
CGContextSetLineWidth( cg, width );
CGContextSetLineJoin( cg , m_join );
CGContextSetLineDash( cg , 0 , m_lengths , m_count );
@@ -1391,12 +1397,6 @@ public:
~wxMacCoreGraphicsContext();
// Enable offset on non-high DPI displays, i.e. those with scale factor <= 1.
void SetEnableOffsetFromScaleFactor(double factor)
{
m_enableOffset = factor <= 1.0;
}
void Init();
virtual void StartPage( wxDouble width, wxDouble height ) wxOVERRIDE;
@@ -1474,17 +1474,24 @@ 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)((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->GetWidth();
if ( penwidth == 0 )
penwidth = 1;
}
return ( penwidth % 2 ) == 1;
double width = static_cast<wxMacCoreGraphicsPenData*>(m_pen.GetRefData())->GetWidth();
// always offset for 1-pixel width
if (width <= 0)
return true;
// no offset if overall scale is not odd integer
const double scaleFactor = GetContentScaleFactor();
CGSize s = { scaleFactor, scaleFactor };
s = CGContextConvertSizeToUserSpace(m_cgContext, s);
if (!wxIsSameDouble(fmod(wxMin(fabs(s.width), fabs(s.height)), 2.0), 1.0))
return false;
// offset if pen width is odd integer
return wxIsSameDouble(fmod(width, 2.0), 1.0);
}
//
// text
@@ -1555,13 +1562,16 @@ private:
class wxQuartzOffsetHelper
{
public :
wxQuartzOffsetHelper( CGContextRef cg , bool offset )
wxQuartzOffsetHelper( CGContextRef cg, double scaleFactor, bool offset )
{
m_cg = cg;
m_offset = offset;
if ( m_offset )
{
m_userOffset = CGContextConvertSizeToUserSpace( m_cg, CGSizeMake( 0.5 , 0.5 ) );
const CGSize s = { scaleFactor, scaleFactor };
m_userOffset = CGContextConvertSizeToUserSpace(m_cg, s);
m_userOffset.width = 0.5 / m_userOffset.width;
m_userOffset.height = 0.5 / m_userOffset.height;
CGContextTranslateCTM( m_cg, m_userOffset.width , m_userOffset.height );
}
else
@@ -1615,7 +1625,7 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer
{
Init();
SetEnableOffsetFromScaleFactor(window->GetContentScaleFactor());
EnableOffset();
wxSize sz = window->GetSize();
m_width = sz.x;
m_height = sz.y;
@@ -2136,7 +2146,7 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
if (m_composition == wxCOMPOSITION_DEST)
return;
wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
wxMacCoreGraphicsPenData* penData = (wxMacCoreGraphicsPenData*)m_pen.GetRefData();
penData->Apply(this);
@@ -2216,7 +2226,7 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF
if ( !m_pen.IsNull() )
((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
CGContextDrawPath( m_cgContext , mode );
@@ -2624,9 +2634,9 @@ void wxMacCoreGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w
CGContextFillRect(m_cgContext, rect);
}
wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
if ( !m_pen.IsNull() )
{
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
CGContextStrokeRect(m_cgContext, rect);
}
@@ -2850,7 +2860,7 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC&
CGContextRef cgctx = (CGContextRef)(win->MacGetCGContextRef());
wxMacCoreGraphicsContext *context =
new wxMacCoreGraphicsContext( this, cgctx, sz.x, sz.y, win );
context->SetEnableOffsetFromScaleFactor(dc.GetContentScaleFactor());
context->SetContentScaleFactor(dc.GetContentScaleFactor());
return context;
}
@@ -2865,7 +2875,7 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC&
mem_impl->GetSize( &w, &h );
wxMacCoreGraphicsContext* context = new wxMacCoreGraphicsContext( this,
(CGContextRef)(mem_impl->GetGraphicsContext()->GetNativeContext()), (wxDouble) w, (wxDouble) h );
context->SetEnableOffsetFromScaleFactor(dc.GetContentScaleFactor());
context->SetContentScaleFactor(dc.GetContentScaleFactor());
return context;
}
#endif

View File

@@ -89,7 +89,9 @@ void wxMemoryDCImpl::DoSelect( const wxBitmap& bitmap )
CGContextSetStrokeColorSpace( bmCtx, genericColorSpace );
SetGraphicsContext( wxGraphicsContext::CreateFromNative( bmCtx ) );
if (m_graphicContext)
m_graphicContext->EnableOffset(m_contentScaleFactor <= 1);
{
m_graphicContext->SetContentScaleFactor(m_contentScaleFactor);
}
}
m_ok = (m_graphicContext != NULL) ;
}