mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
sw_engine: split long lines to avoid overflow
@Issue: https://github.com/thorvg/thorvg/issues/2651
This commit is contained in:
parent
43cdd4c7ec
commit
cb2a15528d
3 changed files with 114 additions and 90 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,103 +514,116 @@ 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;
|
||||||
SwPoint f2;
|
line[1] = rw.pos;
|
||||||
|
|
||||||
//inside one cell
|
while (true) {
|
||||||
if (e1 == e2) {
|
auto diff = line[0] - line[1];
|
||||||
;
|
auto L = HYPOT(diff);
|
||||||
//any horizontal line
|
|
||||||
} else if (diff.y == 0) {
|
if (L > SHRT_MAX) {
|
||||||
e1.x = e2.x;
|
mathSplitLine(line);
|
||||||
_setCell(rw, e1);
|
++line;
|
||||||
} else if (diff.x == 0) {
|
continue;
|
||||||
//vertical line up
|
|
||||||
if (diff.y > 0) {
|
|
||||||
do {
|
|
||||||
f2.y = ONE_PIXEL;
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * f1.x * 2;
|
|
||||||
f1.y = 0;
|
|
||||||
++e1.y;
|
|
||||||
_setCell(rw, e1);
|
|
||||||
} while(e1.y != e2.y);
|
|
||||||
//vertical line down
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
f2.y = 0;
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * f1.x * 2;
|
|
||||||
f1.y = ONE_PIXEL;
|
|
||||||
--e1.y;
|
|
||||||
_setCell(rw, e1);
|
|
||||||
} while(e1.y != e2.y);
|
|
||||||
}
|
}
|
||||||
//any other line
|
e1 = TRUNC(line[1]);
|
||||||
} else {
|
e2 = TRUNC(line[0]);
|
||||||
Area prod = diff.x * f1.y - diff.y * f1.x;
|
|
||||||
|
|
||||||
/* These macros speed up repetitive divisions by replacing them
|
auto f1 = line[1] - SUBPIXELS(e1);
|
||||||
with multiplications and right shifts. */
|
SwPoint f2;
|
||||||
auto dx_r = static_cast<long>(ULONG_MAX >> PIXEL_BITS) / (diff.x);
|
|
||||||
auto dy_r = static_cast<long>(ULONG_MAX >> PIXEL_BITS) / (diff.y);
|
|
||||||
|
|
||||||
/* The fundamental value `prod' determines which side and the */
|
|
||||||
/* exact coordinate where the line exits current cell. It is */
|
|
||||||
/* also easily updated when moving from one cell to the next. */
|
|
||||||
size_t idx = 0;
|
|
||||||
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 py = diff.y * ONE_PIXEL;
|
|
||||||
|
|
||||||
//left
|
|
||||||
if (prod <= 0 && prod - px > 0) {
|
|
||||||
f2 = {0, SW_UDIV(-prod, -dx_r)};
|
|
||||||
prod -= py;
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
|
||||||
f1 = {ONE_PIXEL, f2.y};
|
|
||||||
--e1.x;
|
|
||||||
//up
|
|
||||||
} else if (prod - px <= 0 && prod - px + py > 0) {
|
|
||||||
prod -= px;
|
|
||||||
f2 = {SW_UDIV(-prod, dy_r), ONE_PIXEL};
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
|
||||||
f1 = {f2.x, 0};
|
|
||||||
++e1.y;
|
|
||||||
//right
|
|
||||||
} else if (prod - px + py <= 0 && prod + py >= 0) {
|
|
||||||
prod += py;
|
|
||||||
f2 = {ONE_PIXEL, SW_UDIV(prod, dx_r)};
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
|
||||||
f1 = {0, f2.y};
|
|
||||||
++e1.x;
|
|
||||||
//down
|
|
||||||
} else {
|
|
||||||
f2 = {SW_UDIV(prod, -dy_r), 0};
|
|
||||||
prod += px;
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
|
||||||
f1 = {f2.x, ONE_PIXEL};
|
|
||||||
--e1.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//inside one cell
|
||||||
|
if (e1 == e2) {
|
||||||
|
;
|
||||||
|
//any horizontal line
|
||||||
|
} else if (diff.y == 0) {
|
||||||
|
e1.x = e2.x;
|
||||||
_setCell(rw, e1);
|
_setCell(rw, e1);
|
||||||
|
} else if (diff.x == 0) {
|
||||||
|
//vertical line up
|
||||||
|
if (diff.y > 0) {
|
||||||
|
do {
|
||||||
|
f2.y = ONE_PIXEL;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
|
f1.y = 0;
|
||||||
|
++e1.y;
|
||||||
|
_setCell(rw, e1);
|
||||||
|
} while(e1.y != e2.y);
|
||||||
|
//vertical line down
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
f2.y = 0;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||||
|
f1.y = ONE_PIXEL;
|
||||||
|
--e1.y;
|
||||||
|
_setCell(rw, e1);
|
||||||
|
} while(e1.y != e2.y);
|
||||||
|
}
|
||||||
|
//any other line
|
||||||
|
} else {
|
||||||
|
Area prod = diff.x * f1.y - diff.y * f1.x;
|
||||||
|
|
||||||
} while(e1 != e2);
|
/* These macros speed up repetitive divisions by replacing them
|
||||||
|
with multiplications and right shifts. */
|
||||||
|
auto dx_r = static_cast<long>(ULONG_MAX >> PIXEL_BITS) / (diff.x);
|
||||||
|
auto dy_r = static_cast<long>(ULONG_MAX >> PIXEL_BITS) / (diff.y);
|
||||||
|
|
||||||
|
/* The fundamental value `prod' determines which side and the */
|
||||||
|
/* exact coordinate where the line exits current cell. It is */
|
||||||
|
/* also easily updated when moving from one cell to the next. */
|
||||||
|
do {
|
||||||
|
auto px = diff.x * ONE_PIXEL;
|
||||||
|
auto py = diff.y * ONE_PIXEL;
|
||||||
|
|
||||||
|
//left
|
||||||
|
if (prod <= 0 && prod - px > 0) {
|
||||||
|
f2 = {0, SW_UDIV(-prod, -dx_r)};
|
||||||
|
prod -= py;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {ONE_PIXEL, f2.y};
|
||||||
|
--e1.x;
|
||||||
|
//up
|
||||||
|
} else if (prod - px <= 0 && prod - px + py > 0) {
|
||||||
|
prod -= px;
|
||||||
|
f2 = {SW_UDIV(-prod, dy_r), ONE_PIXEL};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {f2.x, 0};
|
||||||
|
++e1.y;
|
||||||
|
//right
|
||||||
|
} else if (prod - px + py <= 0 && prod + py >= 0) {
|
||||||
|
prod += py;
|
||||||
|
f2 = {ONE_PIXEL, SW_UDIV(prod, dx_r)};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {0, f2.y};
|
||||||
|
++e1.x;
|
||||||
|
//down
|
||||||
|
} else {
|
||||||
|
f2 = {SW_UDIV(prod, -dy_r), 0};
|
||||||
|
prod += px;
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
f1 = {f2.x, ONE_PIXEL};
|
||||||
|
--e1.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setCell(rw, e1);
|
||||||
|
|
||||||
|
} while(e1 != e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 = {line[0].x - SUBPIXELS(e2.x), line[0].y - SUBPIXELS(e2.y)};
|
||||||
|
rw.cover += (f2.y - f1.y);
|
||||||
|
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||||
|
rw.pos = line[0];
|
||||||
|
|
||||||
|
if (line-- == rw.lineStack) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
f2 = {to.x - SUBPIXELS(e2.x), to.y - SUBPIXELS(e2.y)};
|
|
||||||
rw.cover += (f2.y - f1.y);
|
|
||||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
|
||||||
rw.pos = to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue