From 03bbfd3183c64675d62df077ac2c9370e493b105 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 1 Oct 2024 15:17:50 +0200 Subject: [PATCH] sw_engine: ignore small cubics During the stroke's outline calculation, the function handling small cubics set all angles to zero. When the cubic was small but not zero, this resulted in incorrect outlines. Now such curves are ignored. Co-Authored-By: Hermet Park Issue: https://github.com/thorvg/thorvg/issues/2776 Issue: https://github.com/thorvg/thorvg/issues/2712 --- src/renderer/sw_engine/tvgSwCommon.h | 2 +- src/renderer/sw_engine/tvgSwMath.cpp | 8 ++++---- src/renderer/sw_engine/tvgSwStroke.cpp | 12 +++++++++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/renderer/sw_engine/tvgSwCommon.h b/src/renderer/sw_engine/tvgSwCommon.h index 9df20bb5..f8491bbf 100644 --- a/src/renderer/sw_engine/tvgSwCommon.h +++ b/src/renderer/sw_engine/tvgSwCommon.h @@ -490,7 +490,7 @@ SwFixed mathSin(SwFixed angle); void mathSplitCubic(SwPoint* base); SwFixed mathDiff(SwFixed angle1, SwFixed angle2); SwFixed mathLength(const SwPoint& pt); -bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); +int mathCubicAngle(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); SwPoint mathTransform(const Point* to, const Matrix& transform); bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack); diff --git a/src/renderer/sw_engine/tvgSwMath.cpp b/src/renderer/sw_engine/tvgSwMath.cpp index 1093edd6..0b85d890 100644 --- a/src/renderer/sw_engine/tvgSwMath.cpp +++ b/src/renderer/sw_engine/tvgSwMath.cpp @@ -44,7 +44,7 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2) } -bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut) +int mathCubicAngle(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut) { auto d1 = base[2] - base[3]; auto d2 = base[1] - base[2]; @@ -54,7 +54,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw if (d2.small()) { if (d3.small()) { angleIn = angleMid = angleOut = 0; - return true; + return -1; //ignoreable } else { angleIn = angleMid = angleOut = mathAtan(d3); } @@ -90,8 +90,8 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw auto theta1 = abs(mathDiff(angleIn, angleMid)); auto theta2 = abs(mathDiff(angleMid, angleOut)); - if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; - return false; + if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return 0; //small size + return 1; } diff --git a/src/renderer/sw_engine/tvgSwStroke.cpp b/src/renderer/sw_engine/tvgSwStroke.cpp index 9a27f03d..e195f72a 100644 --- a/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/src/renderer/sw_engine/tvgSwStroke.cpp @@ -441,13 +441,23 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //initialize with current direction angleIn = angleOut = angleMid = stroke.angleIn; - if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) { + auto valid = mathCubicAngle(arc, angleIn, angleMid, angleOut); + + //valid size + if (valid > 0 && arc < limit) { if (stroke.firstPt) stroke.angleIn = angleIn; mathSplitCubic(arc); arc += 3; continue; } + //ignoreable size + if (valid < 0 && arc == bezStack) { + stroke.center = to; + return; + } + + //small size if (firstArc) { firstArc = false; //process corner if necessary