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 <hermet@lottiefiles.com>

Issue: https://github.com/thorvg/thorvg/issues/2776
Issue: https://github.com/thorvg/thorvg/issues/2712
This commit is contained in:
Mira Grudzinska 2024-10-01 15:17:50 +02:00 committed by Hermet Park
parent 8ebaf06ffd
commit 03bbfd3183
3 changed files with 16 additions and 6 deletions

View file

@ -490,7 +490,7 @@ SwFixed mathSin(SwFixed angle);
void mathSplitCubic(SwPoint* base); void mathSplitCubic(SwPoint* base);
SwFixed mathDiff(SwFixed angle1, SwFixed angle2); SwFixed mathDiff(SwFixed angle1, SwFixed angle2);
SwFixed mathLength(const SwPoint& pt); 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); SwFixed mathMean(SwFixed angle1, SwFixed angle2);
SwPoint mathTransform(const Point* to, const Matrix& transform); SwPoint mathTransform(const Point* to, const Matrix& transform);
bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack); bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack);

View file

@ -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 d1 = base[2] - base[3];
auto d2 = base[1] - base[2]; auto d2 = base[1] - base[2];
@ -54,7 +54,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
if (d2.small()) { if (d2.small()) {
if (d3.small()) { if (d3.small()) {
angleIn = angleMid = angleOut = 0; angleIn = angleMid = angleOut = 0;
return true; return -1; //ignoreable
} else { } else {
angleIn = angleMid = angleOut = mathAtan(d3); 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 theta1 = abs(mathDiff(angleIn, angleMid));
auto theta2 = abs(mathDiff(angleMid, angleOut)); auto theta2 = abs(mathDiff(angleMid, angleOut));
if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return 0; //small size
return false; return 1;
} }

View file

@ -441,13 +441,23 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl
//initialize with current direction //initialize with current direction
angleIn = angleOut = angleMid = stroke.angleIn; 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; if (stroke.firstPt) stroke.angleIn = angleIn;
mathSplitCubic(arc); mathSplitCubic(arc);
arc += 3; arc += 3;
continue; continue;
} }
//ignoreable size
if (valid < 0 && arc == bezStack) {
stroke.center = to;
return;
}
//small size
if (firstArc) { if (firstArc) {
firstArc = false; firstArc = false;
//process corner if necessary //process corner if necessary