sw_engine: split long lines to avoid overflow

@Issue: https://github.com/thorvg/thorvg/issues/2651
This commit is contained in:
Mira Grudzinska 2024-10-08 23:53:24 +07:00 committed by Hermet Park
parent 43cdd4c7ec
commit cb2a15528d
3 changed files with 114 additions and 90 deletions

View file

@ -488,6 +488,7 @@ SwFixed mathAtan(const SwPoint& pt);
SwFixed mathCos(SwFixed angle); SwFixed mathCos(SwFixed angle);
SwFixed mathSin(SwFixed angle); SwFixed mathSin(SwFixed angle);
void mathSplitCubic(SwPoint* base); void mathSplitCubic(SwPoint* base);
void mathSplitLine(SwPoint* base);
SwFixed mathDiff(SwFixed angle1, SwFixed angle2); SwFixed mathDiff(SwFixed angle1, SwFixed angle2);
SwFixed mathLength(const SwPoint& pt); SwFixed mathLength(const SwPoint& pt);
int mathCubicAngle(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); int mathCubicAngle(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);

View file

@ -242,6 +242,15 @@ void mathSplitCubic(SwPoint* base)
} }
void mathSplitLine(SwPoint* base)
{
base[2] = base[1];
base[1].x = (base[0].x + base[1].x) >> 1;
base[1].y = (base[0].y + base[1].y) >> 1;
}
SwFixed mathDiff(SwFixed angle1, SwFixed angle2) SwFixed mathDiff(SwFixed angle1, SwFixed angle2)
{ {
auto delta = angle2 - angle1; auto delta = angle2 - angle1;

View file

@ -235,6 +235,7 @@ struct RleWorker
SwPoint pos; SwPoint pos;
SwPoint bezStack[32 * 3 + 1]; SwPoint bezStack[32 * 3 + 1];
SwPoint lineStack[32 + 1];
int levStack[32]; int levStack[32];
SwOutline* outline; SwOutline* outline;
@ -513,8 +514,23 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
return; return;
} }
auto diff = to - rw.pos; auto line = rw.lineStack;
auto f1 = rw.pos - SUBPIXELS(e1); line[0] = to;
line[1] = rw.pos;
while (true) {
auto diff = line[0] - line[1];
auto L = HYPOT(diff);
if (L > SHRT_MAX) {
mathSplitLine(line);
++line;
continue;
}
e1 = TRUNC(line[1]);
e2 = TRUNC(line[0]);
auto f1 = line[1] - SUBPIXELS(e1);
SwPoint f2; SwPoint f2;
//inside one cell //inside one cell
@ -558,12 +574,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
/* The fundamental value `prod' determines which side and the */ /* The fundamental value `prod' determines which side and the */
/* exact coordinate where the line exits current cell. It is */ /* exact coordinate where the line exits current cell. It is */
/* also easily updated when moving from one cell to the next. */ /* also easily updated when moving from one cell to the next. */
size_t idx = 0;
do { do {
if (++idx > 1000000000) {
TVGERR("SW_ENGINE", "Iteration limit reached during RLE generation. The resulting render may be incorrect.");
break;
}
auto px = diff.x * ONE_PIXEL; auto px = diff.x * ONE_PIXEL;
auto py = diff.y * ONE_PIXEL; auto py = diff.y * ONE_PIXEL;
@ -606,10 +617,13 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
} while(e1 != e2); } while(e1 != e2);
} }
f2 = {to.x - SUBPIXELS(e2.x), to.y - SUBPIXELS(e2.y)}; f2 = {line[0].x - SUBPIXELS(e2.x), line[0].y - SUBPIXELS(e2.y)};
rw.cover += (f2.y - f1.y); rw.cover += (f2.y - f1.y);
rw.area += (f2.y - f1.y) * (f1.x + f2.x); rw.area += (f2.y - f1.y) * (f1.x + f2.x);
rw.pos = to; rw.pos = line[0];
if (line-- == rw.lineStack) return;
}
} }