Make wxGC offsetting consistent across scales
In order to avoid drawing anomalies with wxGCDC on HiDPI displays, the shift
must be half a logical unit rather than half a device unit, and it needs to be
applied regardless of the scale factor. An exception is made for the zero-width
(one logical pixel) pen, which uses a half logical pixel shift. This reverts
d43b2862c3 (Fix drawing rectangle with width 1 pen using wxGCDC and HiDPI, 2023-04-25)
See #23485
This commit is contained in:
parent
dede4b9326
commit
6857dc8e63
5 changed files with 149 additions and 153 deletions
|
|
@ -70,27 +70,6 @@ static wxCompositionMode TranslateRasterOp(wxRasterOperationMode function)
|
|||
return wxCOMPOSITION_INVALID;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class OffsetDisabler
|
||||
{
|
||||
wxGraphicsContext* const m_gc;
|
||||
const bool m_enable;
|
||||
public:
|
||||
explicit OffsetDisabler(wxGraphicsContext* gc)
|
||||
: m_gc(gc)
|
||||
, m_enable(gc->OffsetEnabled())
|
||||
{
|
||||
gc->EnableOffset(false);
|
||||
}
|
||||
~OffsetDisabler()
|
||||
{
|
||||
m_gc->EnableOffset(m_enable);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxDC bridge class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -991,17 +970,14 @@ void wxGCDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
|
|||
|
||||
CalcBoundingBox(wxPoint(x, y), wxSize(w, h));
|
||||
|
||||
if (m_pen.IsNonTransparent() && m_pen.GetWidth() == 1)
|
||||
if (m_pen.IsNonTransparent())
|
||||
{
|
||||
// Match raster-based wxDC implementations, which draw the line
|
||||
// along the inside edge of the solid rectangle
|
||||
OffsetDisabler offsetDisabler(m_graphicContext);
|
||||
if (w < 0) { w = -w; x -= w; }
|
||||
if (h < 0) { h = -h; y -= h; }
|
||||
m_graphicContext->DrawRectangle(x + 0.5, y + 0.5, w - 1, h - 1);
|
||||
w--;
|
||||
h--;
|
||||
}
|
||||
else
|
||||
m_graphicContext->DrawRectangle(x, y, w, h);
|
||||
m_graphicContext->DrawRectangle(x, y, w, h);
|
||||
}
|
||||
|
||||
void wxGCDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
|
||||
|
|
@ -1022,15 +998,14 @@ void wxGCDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
|
|||
|
||||
CalcBoundingBox(wxPoint(x, y), wxSize(w, h));
|
||||
|
||||
if (m_pen.IsNonTransparent() && m_pen.GetWidth() == 1)
|
||||
if (m_pen.IsNonTransparent())
|
||||
{
|
||||
OffsetDisabler offsetDisabler(m_graphicContext);
|
||||
if (w < 0) { w = -w; x -= w; }
|
||||
if (h < 0) { h = -h; y -= h; }
|
||||
m_graphicContext->DrawRoundedRectangle(x + 0.5, y + 0.5, w - 1, h - 1, radius);
|
||||
w--;
|
||||
h--;
|
||||
}
|
||||
else
|
||||
m_graphicContext->DrawRoundedRectangle(x, y, w, h, radius);
|
||||
m_graphicContext->DrawRoundedRectangle(x, y, w, h, radius);
|
||||
}
|
||||
|
||||
void wxGCDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
|
||||
|
|
|
|||
|
|
@ -450,14 +450,9 @@ public:
|
|||
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);
|
||||
const int w = int(width);
|
||||
return (w & 1) && wxIsSameDouble(width, w);
|
||||
}
|
||||
|
||||
virtual void Clip( const wxRegion ®ion ) override;
|
||||
|
|
@ -586,6 +581,8 @@ protected:
|
|||
CGContextRef m_cgContext;
|
||||
#endif // __WXMAC__
|
||||
|
||||
class OffsetHelper;
|
||||
|
||||
private:
|
||||
cairo_t* m_context;
|
||||
cairo_matrix_t m_internalTransform;
|
||||
|
|
@ -1044,7 +1041,11 @@ void wxCairoPenData::Apply( wxGraphicsContext* context )
|
|||
double width = m_width;
|
||||
if (width <= 0)
|
||||
{
|
||||
double x = context->GetContentScaleFactor(), y = x;
|
||||
double x = 1, y = x;
|
||||
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0)
|
||||
if (cairo_version() >= CAIRO_VERSION_ENCODE(1,14,0))
|
||||
cairo_surface_get_device_scale(cairo_get_target(ctext), &x, &y);
|
||||
#endif
|
||||
cairo_user_to_device_distance(ctext, &x, &y);
|
||||
width = 1 / wxMin(fabs(x), fabs(y));
|
||||
}
|
||||
|
|
@ -1954,29 +1955,45 @@ wxCairoBitmapData::~wxCairoBitmapData()
|
|||
// wxCairoContext implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class wxCairoOffsetHelper
|
||||
class wxCairoContext::OffsetHelper
|
||||
{
|
||||
public :
|
||||
wxCairoOffsetHelper(cairo_t* ctx, double scaleFactor, bool offset)
|
||||
OffsetHelper(bool shouldOffset, cairo_t* cr, const wxGraphicsPen& pen)
|
||||
{
|
||||
m_ctx = ctx;
|
||||
m_offset = 0;
|
||||
if (offset)
|
||||
m_shouldOffset = shouldOffset;
|
||||
if (!shouldOffset)
|
||||
return;
|
||||
|
||||
m_cr = cr;
|
||||
m_offsetX = m_offsetY = 0.5;
|
||||
|
||||
const double width = static_cast<wxCairoPenData*>(pen.GetRefData())->GetWidth();
|
||||
if (width <= 0)
|
||||
{
|
||||
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);
|
||||
// For 1-pixel pen width, offset by half a device pixel
|
||||
|
||||
double sx = 1, sy = sx;
|
||||
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,14,0)
|
||||
if (cairo_version() >= CAIRO_VERSION_ENCODE(1,14,0))
|
||||
cairo_surface_get_device_scale(cairo_get_target(cr), &sx, &sy);
|
||||
#endif
|
||||
cairo_user_to_device_distance(cr, &sx, &sy);
|
||||
|
||||
m_offsetX /= sx;
|
||||
m_offsetY /= sy;
|
||||
}
|
||||
|
||||
cairo_translate(cr, m_offsetX, m_offsetY);
|
||||
}
|
||||
~wxCairoOffsetHelper( )
|
||||
~OffsetHelper()
|
||||
{
|
||||
if (m_offset > 0)
|
||||
cairo_translate(m_ctx, -m_offset, -m_offset);
|
||||
if (m_shouldOffset)
|
||||
cairo_translate(m_cr, -m_offsetX, -m_offsetY);
|
||||
}
|
||||
private:
|
||||
cairo_t* m_ctx;
|
||||
double m_offset;
|
||||
cairo_t* m_cr;
|
||||
double m_offsetX, m_offsetY;
|
||||
bool m_shouldOffset;
|
||||
} ;
|
||||
|
||||
#if wxUSE_PRINTING_ARCHITECTURE
|
||||
|
|
@ -2741,7 +2758,7 @@ void wxCairoContext::StrokePath( const wxGraphicsPath& path )
|
|||
{
|
||||
if ( !m_pen.IsNull() )
|
||||
{
|
||||
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(ShouldOffset(), m_context, m_pen);
|
||||
cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
|
||||
cairo_append_path(m_context,cp);
|
||||
((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
|
||||
|
|
@ -2754,7 +2771,7 @@ void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fi
|
|||
{
|
||||
if ( !m_brush.IsNull() )
|
||||
{
|
||||
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(ShouldOffset(), m_context, m_pen);
|
||||
cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
|
||||
cairo_append_path(m_context,cp);
|
||||
((wxCairoBrushData*)m_brush.GetRefData())->Apply(this);
|
||||
|
|
@ -2783,7 +2800,7 @@ void wxCairoContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble
|
|||
}
|
||||
if ( !m_pen.IsNull() )
|
||||
{
|
||||
wxCairoOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(ShouldOffset(), m_context, m_pen);
|
||||
((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
|
||||
cairo_rectangle(m_context, x, y, w, h);
|
||||
cairo_stroke(m_context);
|
||||
|
|
|
|||
|
|
@ -485,6 +485,8 @@ public:
|
|||
virtual WXHDC GetNativeHDC() override;
|
||||
virtual void ReleaseNativeHDC(WXHDC hdc) override;
|
||||
|
||||
class OffsetHelper;
|
||||
|
||||
protected:
|
||||
// Used from ctors (including those in the derived classes) and takes
|
||||
|
||||
|
|
@ -1827,32 +1829,42 @@ void * wxGDIPlusMatrixData::GetNativeMatrix() const
|
|||
// wxGDIPlusContext implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class wxGDIPlusOffsetHelper
|
||||
class wxGDIPlusContext::OffsetHelper
|
||||
{
|
||||
public :
|
||||
wxGDIPlusOffsetHelper(Graphics* gr, double scaleFactor, bool offset)
|
||||
OffsetHelper(wxGDIPlusContext* gc, Graphics* gr, const wxGraphicsPen& pen)
|
||||
{
|
||||
m_shouldOffset = gc->ShouldOffset();
|
||||
if (!m_shouldOffset)
|
||||
return;
|
||||
|
||||
m_gr = gr;
|
||||
m_offset = 0;
|
||||
if (offset)
|
||||
m_offsetX = m_offsetY = 0.5f;
|
||||
|
||||
const double width = static_cast<wxGDIPlusPenData*>(pen.GetRefData())->GetWidth();
|
||||
if (width <= 0)
|
||||
{
|
||||
// For 1-pixel pen width, offset by half a device pixel
|
||||
Matrix matrix;
|
||||
gr->GetTransform(&matrix);
|
||||
const float f = float(scaleFactor);
|
||||
const float f = float(gc->GetContentScaleFactor());
|
||||
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);
|
||||
m_offsetX /= pt.X;
|
||||
m_offsetY /= pt.Y;
|
||||
}
|
||||
|
||||
gr->TranslateTransform(m_offsetX, m_offsetY);
|
||||
}
|
||||
~wxGDIPlusOffsetHelper( )
|
||||
~OffsetHelper()
|
||||
{
|
||||
if (m_offset > 0)
|
||||
m_gr->TranslateTransform(-m_offset, -m_offset);
|
||||
if (m_shouldOffset)
|
||||
m_gr->TranslateTransform(-m_offsetX, -m_offsetY);
|
||||
}
|
||||
public :
|
||||
Graphics* m_gr;
|
||||
float m_offset;
|
||||
float m_offsetX, m_offsetY;
|
||||
bool m_shouldOffset;
|
||||
} ;
|
||||
|
||||
wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDouble width, wxDouble height )
|
||||
|
|
@ -1991,7 +2003,7 @@ void wxGDIPlusContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDoub
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(this, m_context, m_pen);
|
||||
Brush *brush = m_brush.IsNull() ? nullptr : ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush();
|
||||
Pen *pen = m_pen.IsNull() ? nullptr : ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen();
|
||||
|
||||
|
|
@ -2030,7 +2042,7 @@ void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
|
|||
|
||||
if ( !m_pen.IsNull() )
|
||||
{
|
||||
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(this, m_context, m_pen);
|
||||
PointF *cpoints = new PointF[n];
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
|
|
@ -2048,7 +2060,7 @@ void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPol
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(this, m_context, m_pen);
|
||||
PointF *cpoints = new PointF[n];
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
|
|
@ -2071,7 +2083,7 @@ void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
|
|||
|
||||
if ( !m_pen.IsNull() )
|
||||
{
|
||||
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(this, m_context, m_pen);
|
||||
m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
|
||||
}
|
||||
}
|
||||
|
|
@ -2083,7 +2095,7 @@ void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode
|
|||
|
||||
if ( !m_brush.IsNull() )
|
||||
{
|
||||
wxGDIPlusOffsetHelper helper(m_context, GetContentScaleFactor(), ShouldOffset());
|
||||
OffsetHelper helper(this, m_context, m_pen);
|
||||
((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
|
||||
m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
|
||||
(GraphicsPath*) path.GetNativePath());
|
||||
|
|
@ -2477,15 +2489,9 @@ bool wxGDIPlusContext::ShouldOffset() const
|
|||
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);
|
||||
const int w = int(width);
|
||||
return (w & 1) && wxIsSameDouble(width, w);
|
||||
}
|
||||
|
||||
void* wxGDIPlusContext::GetNativeContext()
|
||||
|
|
|
|||
|
|
@ -1101,36 +1101,6 @@ wxCOMPtr<ID2D1Geometry> wxD2DConvertRegionToGeometry(ID2D1Factory* direct2dFacto
|
|||
return wxCOMPtr<ID2D1Geometry>(resultGeometry);
|
||||
}
|
||||
|
||||
class wxD2DOffsetHelper
|
||||
{
|
||||
public:
|
||||
explicit wxD2DOffsetHelper(wxGraphicsContext* g)
|
||||
: m_context(g)
|
||||
{
|
||||
m_offset = 0;
|
||||
if (m_context->ShouldOffset())
|
||||
{
|
||||
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_offset > 0)
|
||||
{
|
||||
m_context->Translate(-m_offset, -m_offset);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
wxGraphicsContext* m_context;
|
||||
double m_offset;
|
||||
};
|
||||
|
||||
bool operator==(const D2D1::Matrix3x2F& lhs, const D2D1::Matrix3x2F& rhs)
|
||||
{
|
||||
return
|
||||
|
|
@ -4004,6 +3974,8 @@ public:
|
|||
WXHDC GetNativeHDC() override;
|
||||
void ReleaseNativeHDC(WXHDC hdc) override;
|
||||
|
||||
class OffsetHelper;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
|
|
@ -4065,6 +4037,41 @@ private:
|
|||
wxDECLARE_NO_COPY_CLASS(wxD2DContext);
|
||||
};
|
||||
|
||||
class wxD2DContext::OffsetHelper
|
||||
{
|
||||
public:
|
||||
OffsetHelper(wxD2DContext* gc, const wxGraphicsPen& pen)
|
||||
{
|
||||
m_shouldOffset = gc->ShouldOffset();
|
||||
if (!m_shouldOffset)
|
||||
return;
|
||||
|
||||
m_gc = gc;
|
||||
m_offsetX = m_offsetY = 0.5;
|
||||
|
||||
const float width = wxGetD2DPenData(pen)->GetWidth();
|
||||
if (width <= 0)
|
||||
{
|
||||
// For 1-pixel pen width, offset by half a device pixel
|
||||
double x = gc->GetContentScaleFactor(), y = x;
|
||||
gc->GetTransform().TransformDistance(&x, &y);
|
||||
m_offsetX /= x;
|
||||
m_offsetY /= y;
|
||||
}
|
||||
gc->Translate(m_offsetX, m_offsetY);
|
||||
}
|
||||
~OffsetHelper()
|
||||
{
|
||||
if (m_shouldOffset)
|
||||
m_gc->Translate(-m_offsetX, -m_offsetY);
|
||||
}
|
||||
|
||||
private:
|
||||
wxD2DContext* m_gc;
|
||||
double m_offsetX, m_offsetY;
|
||||
bool m_shouldOffset;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxD2DContext implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -4391,7 +4398,7 @@ void wxD2DContext::StrokePath(const wxGraphicsPath& p)
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxD2DOffsetHelper helper(this);
|
||||
OffsetHelper helper(this, m_pen);
|
||||
|
||||
EnsureInitialized();
|
||||
AdjustRenderTargetSize();
|
||||
|
|
@ -4762,21 +4769,15 @@ bool wxD2DContext::ShouldOffset() const
|
|||
if (!m_enableOffset || m_pen.IsNull())
|
||||
return false;
|
||||
|
||||
wxD2DPenData* const penData = wxGetD2DPenData(m_pen);
|
||||
const float width = wxGetD2DPenData(m_pen)->GetWidth();
|
||||
|
||||
// always offset for 1-pixel width
|
||||
if (penData->IsZeroWidth())
|
||||
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(double(penData->GetWidth()), 2.0), 1.0);
|
||||
const int w = int(width);
|
||||
return (w & 1) && width == float(w);
|
||||
}
|
||||
|
||||
void wxD2DContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
|
||||
|
|
@ -4861,7 +4862,7 @@ void wxD2DContext::DrawRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxD2DOffsetHelper helper(this);
|
||||
OffsetHelper helper(this, m_pen);
|
||||
|
||||
EnsureInitialized();
|
||||
AdjustRenderTargetSize();
|
||||
|
|
@ -4890,7 +4891,7 @@ void wxD2DContext::DrawRoundedRectangle(wxDouble x, wxDouble y, wxDouble w, wxDo
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxD2DOffsetHelper helper(this);
|
||||
OffsetHelper helper(this, m_pen);
|
||||
|
||||
EnsureInitialized();
|
||||
AdjustRenderTargetSize();
|
||||
|
|
@ -4920,7 +4921,7 @@ void wxD2DContext::DrawEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxD2DOffsetHelper helper(this);
|
||||
OffsetHelper helper(this, m_pen);
|
||||
|
||||
EnsureInitialized();
|
||||
AdjustRenderTargetSize();
|
||||
|
|
|
|||
|
|
@ -1481,15 +1481,9 @@ public:
|
|||
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);
|
||||
const int w = int(width);
|
||||
return (w & 1) && wxIsSameDouble(width, w);
|
||||
}
|
||||
//
|
||||
// text
|
||||
|
|
@ -1517,6 +1511,8 @@ public:
|
|||
|
||||
void SetNativeContext( CGContextRef cg );
|
||||
|
||||
class OffsetHelper;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext);
|
||||
|
||||
private:
|
||||
|
|
@ -1560,34 +1556,35 @@ private:
|
|||
// wxMacCoreGraphicsContext implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class wxQuartzOffsetHelper
|
||||
class wxMacCoreGraphicsContext::OffsetHelper
|
||||
{
|
||||
public :
|
||||
wxQuartzOffsetHelper( CGContextRef cg, double scaleFactor, bool offset )
|
||||
OffsetHelper(bool shouldOffset, CGContextRef cg, const wxGraphicsPen& pen)
|
||||
{
|
||||
m_shouldOffset = shouldOffset;
|
||||
if (!shouldOffset)
|
||||
return;
|
||||
|
||||
m_offset = CGSizeMake(0.5, 0.5);
|
||||
m_cg = cg;
|
||||
m_offset = offset;
|
||||
if ( m_offset )
|
||||
double width = static_cast<wxMacCoreGraphicsPenData*>(pen.GetRefData())->GetWidth();
|
||||
if (width <= 0)
|
||||
{
|
||||
const double f = 0.5 / scaleFactor;
|
||||
m_userOffset = CGSizeMake(f, f);
|
||||
CGContextTranslateCTM( m_cg, m_userOffset.width , m_userOffset.height );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_userOffset = CGSizeMake(0.0, 0.0);
|
||||
// For 1-pixel pen width, offset by half a device pixel
|
||||
m_offset = CGContextConvertSizeToUserSpace(cg, m_offset);
|
||||
}
|
||||
|
||||
CGContextTranslateCTM(cg, m_offset.width, m_offset.height);
|
||||
}
|
||||
~wxQuartzOffsetHelper( )
|
||||
~OffsetHelper()
|
||||
{
|
||||
if ( m_offset )
|
||||
CGContextTranslateCTM( m_cg, -m_userOffset.width , -m_userOffset.height );
|
||||
if (m_shouldOffset)
|
||||
CGContextTranslateCTM(m_cg, -m_offset.width, -m_offset.height);
|
||||
}
|
||||
public :
|
||||
CGSize m_userOffset;
|
||||
CGSize m_offset;
|
||||
CGContextRef m_cg;
|
||||
bool m_offset;
|
||||
bool m_shouldOffset;
|
||||
} ;
|
||||
|
||||
void wxMacCoreGraphicsContext::Init()
|
||||
|
|
@ -2253,7 +2250,7 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
|
|||
if (m_composition == wxCOMPOSITION_DEST)
|
||||
return;
|
||||
|
||||
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
|
||||
OffsetHelper helper(ShouldOffset(), m_cgContext, m_pen);
|
||||
wxMacCoreGraphicsPenData* penData = (wxMacCoreGraphicsPenData*)m_pen.GetRefData();
|
||||
|
||||
penData->Apply(this);
|
||||
|
|
@ -2333,7 +2330,7 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF
|
|||
if ( !m_pen.IsNull() )
|
||||
((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
|
||||
|
||||
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
|
||||
OffsetHelper helper(ShouldOffset(), m_cgContext, m_pen);
|
||||
|
||||
CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
|
||||
CGContextDrawPath( m_cgContext , mode );
|
||||
|
|
@ -2747,7 +2744,7 @@ void wxMacCoreGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w
|
|||
|
||||
if ( !m_pen.IsNull() )
|
||||
{
|
||||
wxQuartzOffsetHelper helper( m_cgContext, GetContentScaleFactor(), ShouldOffset() );
|
||||
OffsetHelper helper(ShouldOffset(), m_cgContext, m_pen);
|
||||
((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
|
||||
CGContextStrokeRect(m_cgContext, rect);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue