summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--canvas/source/cairo/cairo_canvashelper.cxx21
-rw-r--r--vcl/headless/svpgdi.cxx18
-rw-r--r--vcl/win/gdi/gdiimpl.cxx32
3 files changed, 66 insertions, 5 deletions
diff --git a/canvas/source/cairo/cairo_canvashelper.cxx b/canvas/source/cairo/cairo_canvashelper.cxx
index 91bc052b509b..bd86c8977152 100644
--- a/canvas/source/cairo/cairo_canvashelper.cxx
+++ b/canvas/source/cairo/cairo_canvashelper.cxx
@@ -276,6 +276,8 @@ namespace cairocanvas
useStates( viewState, renderState, true );
cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 );
+ // tdf#99165 correction of control poinits not needed here, only hairlines drawn
+ // (see cairo_set_line_width above)
cairo_curve_to( mpCairo.get(),
aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
@@ -949,7 +951,7 @@ namespace cairocanvas
bool bOpToDo = false;
cairo_matrix_t aOrigMatrix, aIdentityMatrix;
- double nX, nY, nBX, nBY, nAX, nAY;
+ double nX, nY, nBX, nBY, nAX, nAY, nLastX, nLastY;
cairo_get_matrix( pCairo, &aOrigMatrix );
cairo_matrix_init_identity( &aIdentityMatrix );
@@ -1022,6 +1024,20 @@ namespace cairocanvas
nBY += 0.5;
}
+ // tdf#99165 if the control points are 'empty', create the mathematical
+ // correct replacement ones to avoid problems with the graphical sub-system
+ if(basegfx::fTools::equal(nAX, nLastX) && basegfx::fTools::equal(nAY, nLastY))
+ {
+ nAX = nLastX + ((nBX - nLastX) * 0.3);
+ nAY = nLastY + ((nBY - nLastY) * 0.3);
+ }
+
+ if(basegfx::fTools::equal(nBX, nX) && basegfx::fTools::equal(nBY, nY))
+ {
+ nBX = nX + ((nAX - nX) * 0.3);
+ nBY = nY + ((nAY - nY) * 0.3);
+ }
+
cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
}
else
@@ -1031,6 +1047,9 @@ namespace cairocanvas
}
bOpToDo = true;
}
+
+ nLastX = nX;
+ nLastY = nY;
}
if( aPolygon.isClosed() )
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index e87811357015..37e0e17bbbe2 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -587,6 +587,8 @@ static void AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon, b
}
const bool bHasCurves = rPolygon.areControlPointsUsed();
+ basegfx::B2DPoint aLast;
+
for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
{
int nClosedIdx = nPointIdx;
@@ -621,6 +623,7 @@ static void AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon, b
{
// first point => just move there
cairo_move_to(cr, aPoint.getX(), aPoint.getY());
+ aLast = aPoint;
continue;
}
@@ -644,9 +647,24 @@ static void AddPolygonToPath(cairo_t* cr, const basegfx::B2DPolygon& rPolygon, b
aCP1 += aHalfPointOfs;
aCP2 += aHalfPointOfs;
}
+
+ // tdf#99165 if the control points are 'empty', create the mathematical
+ // correct replacement ones to avoid problems with the graphical sub-system
+ if(aCP1.equal(aLast))
+ {
+ aCP1 = aLast + ((aCP2 - aLast) * 0.3);
+ }
+
+ if(aCP2.equal(aPoint))
+ {
+ aCP2 = aPoint + ((aCP1 - aPoint) * 0.3);
+ }
+
cairo_curve_to(cr, aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(),
aPoint.getX(), aPoint.getY());
}
+
+ aLast = aPoint;
}
if( bClosePath )
diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx
index 2366fbe21f61..b3a39f162847 100644
--- a/vcl/win/gdi/gdiimpl.cxx
+++ b/vcl/win/gdi/gdiimpl.cxx
@@ -1888,11 +1888,31 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal(
{
const sal_uInt32 nNextIndex((a + 1) % nCount);
const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const bool b1stControlPointUsed(bControls && rPolygon.isNextControlPointUsed(a));
+ const bool b2ndControlPointUsed(bControls && rPolygon.isPrevControlPointUsed(nNextIndex));
- if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ if(b1stControlPointUsed || b2ndControlPointUsed)
{
- const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
- const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+ basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ // tdf#99165 MS Gdiplus cannot handle creating correct extra geometry for fat lines
+ // with LineCap or LineJoin when a bezier segment starts or ends trivial, e.g. has
+ // no 1st or 2nd control point, despite that these are mathematicaly correct definitions
+ // (basegfx can handle that). To solve, create replacement vectors to thre resp. next
+ // control point with 1/3rd of length (the default control vector for these cases).
+ // Only one of this can happen here, else the is(Next|Prev)ControlPointUsed wopuld have
+ // both been false.
+ // Caution: This error (and it's correction) might be necessary for other graphical
+ // sub-systems in a similar way
+ if(!b1stControlPointUsed)
+ {
+ aCa = aCurr + ((aCb - aCurr) * 0.3);
+ }
+ else if(!b2ndControlPointUsed)
+ {
+ aCb = aNext + ((aCa - aNext) * 0.3);
+ }
rGraphicsPath.AddBezier(
static_cast< Gdiplus::REAL >(aCurr.getX()), static_cast< Gdiplus::REAL >(aCurr.getY()),
@@ -2018,7 +2038,11 @@ bool WinSalGraphicsImpl::drawPolyLine(
const Gdiplus::REAL aMiterLimit(15.0);
aPen.SetMiterLimit(aMiterLimit);
- aPen.SetLineJoin(Gdiplus::LineJoinMiter);
+ // tdf#99165 MS's LineJoinMiter creates non standard conform miter additional
+ // graphics, somewhere clipped in some distance from the edge point, dependent
+ // of MiterLimit. The more default-like option is LineJoinMiterClipped, so use
+ // that instead
+ aPen.SetLineJoin(Gdiplus::LineJoinMiterClipped);
break;
}
case basegfx::B2DLineJoin::Round :