diff options
author | Alexey Ushakov <alexey.v.ushakov@gmail.com> | 2019-10-27 21:45:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-27 21:45:42 +0300 |
commit | 33b1cbb01bb979911e74fd15dd8cdb87f956578b (patch) | |
tree | 3e84880bc278e79ff3834d7c142f87978fa5a406 | |
parent | 56104efff2922a38381a71ecf76993fbf583507f (diff) | |
parent | 168d3c02cd105f953599e77136ae41dc2746c03f (diff) | |
download | jdk8u_jdk-33b1cbb01bb979911e74fd15dd8cdb87f956578b.tar.gz |
Merge pull request #27 from bourgesl/masterjb8u232-b1638.3jb8u232-b1638jb8u222-b1638.2
Marlin-renderer bug fix in the path clipper
9 files changed, 119 insertions, 89 deletions
diff --git a/src/share/classes/sun/java2d/marlin/DDasher.java b/src/share/classes/sun/java2d/marlin/DDasher.java index cb1ce79ee4..98d540f026 100644 --- a/src/share/classes/sun/java2d/marlin/DDasher.java +++ b/src/share/classes/sun/java2d/marlin/DDasher.java @@ -47,6 +47,8 @@ final class DDasher implements DPathConsumer2D, MarlinConst { static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT); + static final double EPS = 1e-6d; + // More than 24 bits of mantissa means we can no longer accurately // measure the number of times cycled through the dash array so we // punt and override the phase to just be 0 past that point. @@ -361,7 +363,7 @@ final class DDasher implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -416,13 +418,13 @@ final class DDasher implements DPathConsumer2D, MarlinConst { boolean _dashOn = dashOn; double _phase = phase; - double leftInThisDashSegment, d; + double leftInThisDashSegment, rem; while (true) { - d = _dash[_idx]; - leftInThisDashSegment = d - _phase; + leftInThisDashSegment = _dash[_idx] - _phase; + rem = len - leftInThisDashSegment; - if (len <= leftInThisDashSegment) { + if (rem <= EPS) { _curCurvepts[0] = x1; _curCurvepts[1] = y1; @@ -431,8 +433,8 @@ final class DDasher implements DPathConsumer2D, MarlinConst { // Advance phase within current dash segment _phase += len; - // TODO: compare double values using epsilon: - if (len == leftInThisDashSegment) { + // compare values using epsilon: + if (Math.abs(rem) <= EPS) { _phase = 0.0d; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -440,17 +442,12 @@ final class DDasher implements DPathConsumer2D, MarlinConst { break; } - if (_phase == 0.0d) { - _curCurvepts[0] = cx0 + d * cx; - _curCurvepts[1] = cy0 + d * cy; - } else { - _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; - _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; - } + _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; + _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; goTo(_curCurvepts, 0, 4, _dashOn); - len -= leftInThisDashSegment; + len = rem; // Advance to next dash segment _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -506,18 +503,18 @@ final class DDasher implements DPathConsumer2D, MarlinConst { _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L; } - double leftInThisDashSegment, d; + double leftInThisDashSegment, rem; while (true) { - d = _dash[_idx]; - leftInThisDashSegment = d - _phase; + leftInThisDashSegment = _dash[_idx] - _phase; + rem = len - leftInThisDashSegment; - if (len <= leftInThisDashSegment) { + if (rem <= EPS) { // Advance phase within current dash segment _phase += len; - // TODO: compare double values using epsilon: - if (len == leftInThisDashSegment) { + // compare values using epsilon: + if (Math.abs(rem) <= EPS) { _phase = 0.0d; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -525,7 +522,7 @@ final class DDasher implements DPathConsumer2D, MarlinConst { break; } - len -= leftInThisDashSegment; + len = rem; // Advance to next dash segment _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -579,7 +576,9 @@ final class DDasher implements DPathConsumer2D, MarlinConst { goTo(_curCurvepts, curCurveoff + 2, type, _dashOn); _phase += _li.lastSegLen(); - if (_phase >= _dash[_idx]) { + + // compare values using epsilon: + if (_phase + EPS >= _dash[_idx]) { _phase = 0.0d; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -938,7 +937,7 @@ final class DDasher implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1024,7 +1023,7 @@ final class DDasher implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; diff --git a/src/share/classes/sun/java2d/marlin/DHelpers.java b/src/share/classes/sun/java2d/marlin/DHelpers.java index 6136e3f60a..cb9f9449c0 100644 --- a/src/share/classes/sun/java2d/marlin/DHelpers.java +++ b/src/share/classes/sun/java2d/marlin/DHelpers.java @@ -243,7 +243,7 @@ final class DHelpers implements MarlinConst { final double y12 = pts[3] - pts[1]; // if the curve is already parallel to either axis we gain nothing // from rotating it. - if ((y12 != 0.0d && x12 != 0.0d)) { + if ((y12 != 0.0d) && (x12 != 0.0d)) { // we rotate it so that the first vector in the control polygon is // parallel to the x-axis. This will ensure that rotated quarter // circles won't be subdivided. diff --git a/src/share/classes/sun/java2d/marlin/DStroker.java b/src/share/classes/sun/java2d/marlin/DStroker.java index 5fecec848a..bd14b8fe44 100644 --- a/src/share/classes/sun/java2d/marlin/DStroker.java +++ b/src/share/classes/sun/java2d/marlin/DStroker.java @@ -540,7 +540,7 @@ final class DStroker implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -634,6 +634,9 @@ final class DStroker implements DPathConsumer2D, MarlinConst { emitReverse(); this.prev = CLOSE; + this.cx0 = sx0; + this.cy0 = sy0; + this.cOutCode = sOutCode; if (opened) { // do not emit close @@ -668,7 +671,9 @@ final class DStroker implements DPathConsumer2D, MarlinConst { // i.e. if caps must be drawn or not ? // Solution: use the ClosedPathDetector before Stroker to determine // if the path is a closed path or not - if (!rdrCtx.closedPath) { + if (rdrCtx.closedPath) { + emitReverse(); + } else { if (outcode == 0) { // current point = end's cap: if (capStyle == CAP_ROUND) { @@ -693,8 +698,6 @@ final class DStroker implements DPathConsumer2D, MarlinConst { } } } - } else { - emitReverse(); } emitClose(); } @@ -1058,7 +1061,7 @@ final class DStroker implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1206,7 +1209,7 @@ final class DStroker implements DPathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; diff --git a/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java index 353f9defe7..17667295f4 100644 --- a/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java +++ b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java @@ -530,6 +530,9 @@ final class DTransformingPathConsumer2D { private boolean outside = false; + // The starting point of the path + private double sx0, sy0; + // The current point (TODO stupid repeated info) private double cx0, cy0; @@ -630,17 +633,26 @@ final class DTransformingPathConsumer2D { finishPath(); out.closePath(); + + // back to starting point: + this.cOutCode = DHelpers.outcode(sx0, sy0, clipRect); + this.cx0 = sx0; + this.cy0 = sy0; } @Override public void moveTo(final double x0, final double y0) { finishPath(); - this.cOutCode = DHelpers.outcode(x0, y0, clipRect); - this.outside = false; out.moveTo(x0, y0); + + // update starting point: + this.cOutCode = DHelpers.outcode(x0, y0, clipRect); this.cx0 = x0; this.cy0 = y0; + + this.sx0 = x0; + this.sy0 = y0; } @Override @@ -655,7 +667,7 @@ final class DTransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -754,7 +766,7 @@ final class DTransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -816,7 +828,7 @@ final class DTransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1153,13 +1165,13 @@ final class DTransformingPathConsumer2D { @Override public void moveTo(double x0, double y0) { - log("moveTo (" + x0 + ", " + y0 + ')'); + log("p.moveTo(" + x0 + ", " + y0 + ");"); out.moveTo(x0, y0); } @Override public void lineTo(double x1, double y1) { - log("lineTo (" + x1 + ", " + y1 + ')'); + log("p.lineTo(" + x1 + ", " + y1 + ");"); out.lineTo(x1, y1); } @@ -1168,25 +1180,26 @@ final class DTransformingPathConsumer2D { double x2, double y2, double x3, double y3) { - log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ')'); + log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");"); out.curveTo(x1, y1, x2, y2, x3, y3); } @Override - public void quadTo(double x1, double y1, double x2, double y2) { - log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ')'); + public void quadTo(double x1, double y1, + double x2, double y2) { + log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");"); out.quadTo(x1, y1, x2, y2); } @Override public void closePath() { - log("closePath"); + log("p.closePath();"); out.closePath(); } @Override public void pathDone() { - log("pathDone"); + log("p.pathDone();"); out.pathDone(); } diff --git a/src/share/classes/sun/java2d/marlin/Dasher.java b/src/share/classes/sun/java2d/marlin/Dasher.java index c28311bb2a..c69fe09f20 100644 --- a/src/share/classes/sun/java2d/marlin/Dasher.java +++ b/src/share/classes/sun/java2d/marlin/Dasher.java @@ -48,6 +48,8 @@ final class Dasher implements PathConsumer2D, MarlinConst { static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT); + static final float EPS = 1e-6f; + // More than 24 bits of mantissa means we can no longer accurately // measure the number of times cycled through the dash array so we // punt and override the phase to just be 0 past that point. @@ -362,7 +364,7 @@ final class Dasher implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -417,13 +419,13 @@ final class Dasher implements PathConsumer2D, MarlinConst { boolean _dashOn = dashOn; float _phase = phase; - float leftInThisDashSegment, d; + float leftInThisDashSegment, rem; while (true) { - d = _dash[_idx]; - leftInThisDashSegment = d - _phase; + leftInThisDashSegment = _dash[_idx] - _phase; + rem = len - leftInThisDashSegment; - if (len <= leftInThisDashSegment) { + if (rem <= EPS) { _curCurvepts[0] = x1; _curCurvepts[1] = y1; @@ -432,8 +434,8 @@ final class Dasher implements PathConsumer2D, MarlinConst { // Advance phase within current dash segment _phase += len; - // TODO: compare float values using epsilon: - if (len == leftInThisDashSegment) { + // compare values using epsilon: + if (Math.abs(rem) <= EPS) { _phase = 0.0f; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -441,17 +443,12 @@ final class Dasher implements PathConsumer2D, MarlinConst { break; } - if (_phase == 0.0f) { - _curCurvepts[0] = cx0 + d * cx; - _curCurvepts[1] = cy0 + d * cy; - } else { - _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; - _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; - } + _curCurvepts[0] = cx0 + leftInThisDashSegment * cx; + _curCurvepts[1] = cy0 + leftInThisDashSegment * cy; goTo(_curCurvepts, 0, 4, _dashOn); - len -= leftInThisDashSegment; + len = rem; // Advance to next dash segment _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -507,18 +504,18 @@ final class Dasher implements PathConsumer2D, MarlinConst { _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L; } - float leftInThisDashSegment, d; + float leftInThisDashSegment, rem; while (true) { - d = _dash[_idx]; - leftInThisDashSegment = d - _phase; + leftInThisDashSegment = _dash[_idx] - _phase; + rem = len - leftInThisDashSegment; - if (len <= leftInThisDashSegment) { + if (rem <= EPS) { // Advance phase within current dash segment _phase += len; - // TODO: compare float values using epsilon: - if (len == leftInThisDashSegment) { + // compare values using epsilon: + if (Math.abs(rem) <= EPS) { _phase = 0.0f; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -526,7 +523,7 @@ final class Dasher implements PathConsumer2D, MarlinConst { break; } - len -= leftInThisDashSegment; + len = rem; // Advance to next dash segment _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -580,7 +577,9 @@ final class Dasher implements PathConsumer2D, MarlinConst { goTo(_curCurvepts, curCurveoff + 2, type, _dashOn); _phase += _li.lastSegLen(); - if (_phase >= _dash[_idx]) { + + // compare values using epsilon: + if (_phase + EPS >= _dash[_idx]) { _phase = 0.0f; _idx = (_idx + 1) % _dashLen; _dashOn = !_dashOn; @@ -939,7 +938,7 @@ final class Dasher implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1025,7 +1024,7 @@ final class Dasher implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; diff --git a/src/share/classes/sun/java2d/marlin/Helpers.java b/src/share/classes/sun/java2d/marlin/Helpers.java index 513d287e1a..2043ab3ce6 100644 --- a/src/share/classes/sun/java2d/marlin/Helpers.java +++ b/src/share/classes/sun/java2d/marlin/Helpers.java @@ -251,7 +251,7 @@ final class Helpers implements MarlinConst { final float y12 = pts[3] - pts[1]; // if the curve is already parallel to either axis we gain nothing // from rotating it. - if ((y12 != 0.0f && x12 != 0.0f)) { + if ((y12 != 0.0f) && (x12 != 0.0f)) { // we rotate it so that the first vector in the control polygon is // parallel to the x-axis. This will ensure that rotated quarter // circles won't be subdivided. diff --git a/src/share/classes/sun/java2d/marlin/Stroker.java b/src/share/classes/sun/java2d/marlin/Stroker.java index 1e18941a0c..255e0fe0ae 100644 --- a/src/share/classes/sun/java2d/marlin/Stroker.java +++ b/src/share/classes/sun/java2d/marlin/Stroker.java @@ -542,7 +542,7 @@ final class Stroker implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -636,6 +636,9 @@ final class Stroker implements PathConsumer2D, MarlinConst { emitReverse(); this.prev = CLOSE; + this.cx0 = sx0; + this.cy0 = sy0; + this.cOutCode = sOutCode; if (opened) { // do not emit close @@ -670,7 +673,9 @@ final class Stroker implements PathConsumer2D, MarlinConst { // i.e. if caps must be drawn or not ? // Solution: use the ClosedPathDetector before Stroker to determine // if the path is a closed path or not - if (!rdrCtx.closedPath) { + if (rdrCtx.closedPath) { + emitReverse(); + } else { if (outcode == 0) { // current point = end's cap: if (capStyle == CAP_ROUND) { @@ -695,8 +700,6 @@ final class Stroker implements PathConsumer2D, MarlinConst { } } } - } else { - emitReverse(); } emitClose(); } @@ -1060,7 +1063,7 @@ final class Stroker implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1208,7 +1211,7 @@ final class Stroker implements PathConsumer2D, MarlinConst { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; diff --git a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java index fb4c34f0a2..f8af398eef 100644 --- a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java +++ b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java @@ -531,6 +531,9 @@ final class TransformingPathConsumer2D { private boolean outside = false; + // The starting point of the path + private float sx0, sy0; + // The current point (TODO stupid repeated info) private float cx0, cy0; @@ -631,17 +634,26 @@ final class TransformingPathConsumer2D { finishPath(); out.closePath(); + + // back to starting point: + this.cOutCode = Helpers.outcode(sx0, sy0, clipRect); + this.cx0 = sx0; + this.cy0 = sy0; } @Override public void moveTo(final float x0, final float y0) { finishPath(); - this.cOutCode = Helpers.outcode(x0, y0, clipRect); - this.outside = false; out.moveTo(x0, y0); + + // update starting point: + this.cOutCode = Helpers.outcode(x0, y0, clipRect); this.cx0 = x0; this.cy0 = y0; + + this.sx0 = x0; + this.sy0 = y0; } @Override @@ -656,7 +668,7 @@ final class TransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -755,7 +767,7 @@ final class TransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -817,7 +829,7 @@ final class TransformingPathConsumer2D { // basic rejection criteria: if (sideCode == 0) { - // ovelap clip: + // overlap clip: if (subdivide) { // avoid reentrance subdivide = false; @@ -1154,13 +1166,13 @@ final class TransformingPathConsumer2D { @Override public void moveTo(float x0, float y0) { - log("moveTo (" + x0 + ", " + y0 + ')'); + log("p.moveTo(" + x0 + ", " + y0 + ");"); out.moveTo(x0, y0); } @Override public void lineTo(float x1, float y1) { - log("lineTo (" + x1 + ", " + y1 + ')'); + log("p.lineTo(" + x1 + ", " + y1 + ");"); out.lineTo(x1, y1); } @@ -1169,25 +1181,26 @@ final class TransformingPathConsumer2D { float x2, float y2, float x3, float y3) { - log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ')'); + log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");"); out.curveTo(x1, y1, x2, y2, x3, y3); } @Override - public void quadTo(float x1, float y1, float x2, float y2) { - log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ')'); + public void quadTo(float x1, float y1, + float x2, float y2) { + log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");"); out.quadTo(x1, y1, x2, y2); } @Override public void closePath() { - log("closePath"); + log("p.closePath();"); out.closePath(); } @Override public void pathDone() { - log("pathDone"); + log("p.pathDone();"); out.pathDone(); } diff --git a/src/share/classes/sun/java2d/marlin/Version.java b/src/share/classes/sun/java2d/marlin/Version.java index 5a6976f4db..1be473616c 100644 --- a/src/share/classes/sun/java2d/marlin/Version.java +++ b/src/share/classes/sun/java2d/marlin/Version.java @@ -27,7 +27,7 @@ package sun.java2d.marlin; public final class Version { - private static final String VERSION = "marlin-0.9.3-Unsafe-OpenJDK"; + private static final String VERSION = "marlin-0.9.3.1-Unsafe-OpenJDK"; public static String getVersion() { return VERSION; |