Skip to content

Commit 383e7df

Browse files
author
Laurent Bourgès
committed
8228711: Path rendered incorrectly when it goes outside the clipping region
Fixed closePath() to preserve last position and its outcode in Stroker and TransformingPathConsumer2D.PathClipFilter Reviewed-by: prr, kcr
1 parent c4b6dfb commit 383e7df

File tree

10 files changed

+623
-245
lines changed

10 files changed

+623
-245
lines changed

src/java.desktop/share/classes/sun/java2d/marlin/DDasher.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ final class DDasher implements DPathConsumer2D, MarlinConst {
4747
static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial
4848
static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT);
4949

50+
static final double EPS = 1e-6d;
51+
5052
// More than 24 bits of mantissa means we can no longer accurately
5153
// measure the number of times cycled through the dash array so we
5254
// punt and override the phase to just be 0 past that point.
@@ -269,6 +271,9 @@ public void moveTo(final double x0, final double y0) {
269271

270272
private void emitSeg(double[] buf, int off, int type) {
271273
switch (type) {
274+
case 4:
275+
out.lineTo(buf[off], buf[off + 1]);
276+
return;
272277
case 8:
273278
out.curveTo(buf[off ], buf[off + 1],
274279
buf[off + 2], buf[off + 3],
@@ -278,9 +283,6 @@ private void emitSeg(double[] buf, int off, int type) {
278283
out.quadTo(buf[off ], buf[off + 1],
279284
buf[off + 2], buf[off + 3]);
280285
return;
281-
case 4:
282-
out.lineTo(buf[off], buf[off + 1]);
283-
return;
284286
default:
285287
}
286288
}
@@ -361,7 +363,7 @@ public void lineTo(final double x1, final double y1) {
361363

362364
// basic rejection criteria:
363365
if (sideCode == 0) {
364-
// ovelap clip:
366+
// overlap clip:
365367
if (subdivide) {
366368
// avoid reentrance
367369
subdivide = false;
@@ -416,13 +418,13 @@ private void _lineTo(final double x1, final double y1) {
416418
boolean _dashOn = dashOn;
417419
double _phase = phase;
418420

419-
double leftInThisDashSegment, d;
421+
double leftInThisDashSegment, rem;
420422

421423
while (true) {
422-
d = _dash[_idx];
423-
leftInThisDashSegment = d - _phase;
424+
leftInThisDashSegment = _dash[_idx] - _phase;
425+
rem = len - leftInThisDashSegment;
424426

425-
if (len <= leftInThisDashSegment) {
427+
if (rem <= EPS) {
426428
_curCurvepts[0] = x1;
427429
_curCurvepts[1] = y1;
428430

@@ -431,26 +433,21 @@ private void _lineTo(final double x1, final double y1) {
431433
// Advance phase within current dash segment
432434
_phase += len;
433435

434-
// TODO: compare double values using epsilon:
435-
if (len == leftInThisDashSegment) {
436+
// compare values using epsilon:
437+
if (Math.abs(rem) <= EPS) {
436438
_phase = 0.0d;
437439
_idx = (_idx + 1) % _dashLen;
438440
_dashOn = !_dashOn;
439441
}
440442
break;
441443
}
442444

443-
if (_phase == 0.0d) {
444-
_curCurvepts[0] = cx0 + d * cx;
445-
_curCurvepts[1] = cy0 + d * cy;
446-
} else {
447-
_curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
448-
_curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
449-
}
445+
_curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
446+
_curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
450447

451448
goTo(_curCurvepts, 0, 4, _dashOn);
452449

453-
len -= leftInThisDashSegment;
450+
len = rem;
454451
// Advance to next dash segment
455452
_idx = (_idx + 1) % _dashLen;
456453
_dashOn = !_dashOn;
@@ -506,26 +503,26 @@ public void skipLen() {
506503
_dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
507504
}
508505

509-
double leftInThisDashSegment, d;
506+
double leftInThisDashSegment, rem;
510507

511508
while (true) {
512-
d = _dash[_idx];
513-
leftInThisDashSegment = d - _phase;
509+
leftInThisDashSegment = _dash[_idx] - _phase;
510+
rem = len - leftInThisDashSegment;
514511

515-
if (len <= leftInThisDashSegment) {
512+
if (rem <= EPS) {
516513
// Advance phase within current dash segment
517514
_phase += len;
518515

519-
// TODO: compare double values using epsilon:
520-
if (len == leftInThisDashSegment) {
516+
// compare values using epsilon:
517+
if (Math.abs(rem) <= EPS) {
521518
_phase = 0.0d;
522519
_idx = (_idx + 1) % _dashLen;
523520
_dashOn = !_dashOn;
524521
}
525522
break;
526523
}
527524

528-
len -= leftInThisDashSegment;
525+
len = rem;
529526
// Advance to next dash segment
530527
_idx = (_idx + 1) % _dashLen;
531528
_dashOn = !_dashOn;
@@ -579,7 +576,9 @@ private void somethingTo(final int type) {
579576
goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
580577

581578
_phase += _li.lastSegLen();
582-
if (_phase >= _dash[_idx]) {
579+
580+
// compare values using epsilon:
581+
if (_phase + EPS >= _dash[_idx]) {
583582
_phase = 0.0d;
584583
_idx = (_idx + 1) % _dashLen;
585584
_dashOn = !_dashOn;
@@ -938,7 +937,7 @@ public void curveTo(final double x1, final double y1,
938937

939938
// basic rejection criteria:
940939
if (sideCode == 0) {
941-
// ovelap clip:
940+
// overlap clip:
942941
if (subdivide) {
943942
// avoid reentrance
944943
subdivide = false;
@@ -1024,7 +1023,7 @@ public void quadTo(final double x1, final double y1,
10241023

10251024
// basic rejection criteria:
10261025
if (sideCode == 0) {
1027-
// ovelap clip:
1026+
// overlap clip:
10281027
if (subdivide) {
10291028
// avoid reentrance
10301029
subdivide = false;

src/java.desktop/share/classes/sun/java2d/marlin/DHelpers.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ static int findSubdivPoints(final DCurve c, final double[] pts,
243243
final double y12 = pts[3] - pts[1];
244244
// if the curve is already parallel to either axis we gain nothing
245245
// from rotating it.
246-
if ((y12 != 0.0d && x12 != 0.0d)) {
246+
if ((y12 != 0.0d) && (x12 != 0.0d)) {
247247
// we rotate it so that the first vector in the control polygon is
248248
// parallel to the x-axis. This will ensure that rotated quarter
249249
// circles won't be subdivided.
@@ -764,17 +764,17 @@ void pullAll(final DPathConsumer2D io) {
764764
io.lineTo(_curves[e], _curves[e+1]);
765765
e += 2;
766766
continue;
767-
case TYPE_QUADTO:
768-
io.quadTo(_curves[e], _curves[e+1],
769-
_curves[e+2], _curves[e+3]);
770-
e += 4;
771-
continue;
772767
case TYPE_CUBICTO:
773768
io.curveTo(_curves[e], _curves[e+1],
774769
_curves[e+2], _curves[e+3],
775770
_curves[e+4], _curves[e+5]);
776771
e += 6;
777772
continue;
773+
case TYPE_QUADTO:
774+
io.quadTo(_curves[e], _curves[e+1],
775+
_curves[e+2], _curves[e+3]);
776+
e += 4;
777+
continue;
778778
default:
779779
}
780780
}
@@ -806,17 +806,17 @@ void popAll(final DPathConsumer2D io) {
806806
e -= 2;
807807
io.lineTo(_curves[e], _curves[e+1]);
808808
continue;
809-
case TYPE_QUADTO:
810-
e -= 4;
811-
io.quadTo(_curves[e], _curves[e+1],
812-
_curves[e+2], _curves[e+3]);
813-
continue;
814809
case TYPE_CUBICTO:
815810
e -= 6;
816811
io.curveTo(_curves[e], _curves[e+1],
817812
_curves[e+2], _curves[e+3],
818813
_curves[e+4], _curves[e+5]);
819814
continue;
815+
case TYPE_QUADTO:
816+
e -= 4;
817+
io.quadTo(_curves[e], _curves[e+1],
818+
_curves[e+2], _curves[e+3]);
819+
continue;
820820
default:
821821
}
822822
}

src/java.desktop/share/classes/sun/java2d/marlin/DStroker.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ private void lineTo(final double x1, final double y1,
540540

541541
// basic rejection criteria:
542542
if (sideCode == 0) {
543-
// ovelap clip:
543+
// overlap clip:
544544
if (subdivide) {
545545
// avoid reentrance
546546
subdivide = false;
@@ -634,6 +634,9 @@ public void closePath() {
634634
emitReverse();
635635

636636
this.prev = CLOSE;
637+
this.cx0 = sx0;
638+
this.cy0 = sy0;
639+
this.cOutCode = sOutCode;
637640

638641
if (opened) {
639642
// do not emit close
@@ -668,7 +671,9 @@ private void finish(final int outcode) {
668671
// i.e. if caps must be drawn or not ?
669672
// Solution: use the ClosedPathDetector before Stroker to determine
670673
// if the path is a closed path or not
671-
if (!rdrCtx.closedPath) {
674+
if (rdrCtx.closedPath) {
675+
emitReverse();
676+
} else {
672677
if (outcode == 0) {
673678
// current point = end's cap:
674679
if (capStyle == CAP_ROUND) {
@@ -693,8 +698,6 @@ private void finish(final int outcode) {
693698
}
694699
}
695700
}
696-
} else {
697-
emitReverse();
698701
}
699702
emitClose();
700703
}
@@ -1058,7 +1061,7 @@ public void curveTo(final double x1, final double y1,
10581061

10591062
// basic rejection criteria:
10601063
if (sideCode == 0) {
1061-
// ovelap clip:
1064+
// overlap clip:
10621065
if (subdivide) {
10631066
// avoid reentrance
10641067
subdivide = false;
@@ -1206,7 +1209,7 @@ public void quadTo(final double x1, final double y1,
12061209

12071210
// basic rejection criteria:
12081211
if (sideCode == 0) {
1209-
// ovelap clip:
1212+
// overlap clip:
12101213
if (subdivide) {
12111214
// avoid reentrance
12121215
subdivide = false;

src/java.desktop/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,9 @@ static final class PathClipFilter implements DPathConsumer2D {
530530

531531
private boolean outside = false;
532532

533+
// The starting point of the path
534+
private double sx0, sy0;
535+
533536
// The current point (TODO stupid repeated info)
534537
private double cx0, cy0;
535538

@@ -630,17 +633,26 @@ public void closePath() {
630633
finishPath();
631634

632635
out.closePath();
636+
637+
// back to starting point:
638+
this.cOutCode = DHelpers.outcode(sx0, sy0, clipRect);
639+
this.cx0 = sx0;
640+
this.cy0 = sy0;
633641
}
634642

635643
@Override
636644
public void moveTo(final double x0, final double y0) {
637645
finishPath();
638646

639-
this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
640-
this.outside = false;
641647
out.moveTo(x0, y0);
648+
649+
// update starting point:
650+
this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
642651
this.cx0 = x0;
643652
this.cy0 = y0;
653+
654+
this.sx0 = x0;
655+
this.sy0 = y0;
644656
}
645657

646658
@Override
@@ -655,7 +667,7 @@ public void lineTo(final double xe, final double ye) {
655667

656668
// basic rejection criteria:
657669
if (sideCode == 0) {
658-
// ovelap clip:
670+
// overlap clip:
659671
if (subdivide) {
660672
// avoid reentrance
661673
subdivide = false;
@@ -754,7 +766,7 @@ public void curveTo(final double x1, final double y1,
754766

755767
// basic rejection criteria:
756768
if (sideCode == 0) {
757-
// ovelap clip:
769+
// overlap clip:
758770
if (subdivide) {
759771
// avoid reentrance
760772
subdivide = false;
@@ -816,7 +828,7 @@ public void quadTo(final double x1, final double y1,
816828

817829
// basic rejection criteria:
818830
if (sideCode == 0) {
819-
// ovelap clip:
831+
// overlap clip:
820832
if (subdivide) {
821833
// avoid reentrance
822834
subdivide = false;
@@ -1153,13 +1165,13 @@ PathTracer init(DPathConsumer2D out) {
11531165

11541166
@Override
11551167
public void moveTo(double x0, double y0) {
1156-
log("moveTo (" + x0 + ", " + y0 + ')');
1168+
log("p.moveTo(" + x0 + ", " + y0 + ");");
11571169
out.moveTo(x0, y0);
11581170
}
11591171

11601172
@Override
11611173
public void lineTo(double x1, double y1) {
1162-
log("lineTo (" + x1 + ", " + y1 + ')');
1174+
log("p.lineTo(" + x1 + ", " + y1 + ");");
11631175
out.lineTo(x1, y1);
11641176
}
11651177

@@ -1168,25 +1180,26 @@ public void curveTo(double x1, double y1,
11681180
double x2, double y2,
11691181
double x3, double y3)
11701182
{
1171-
log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ')');
1183+
log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");");
11721184
out.curveTo(x1, y1, x2, y2, x3, y3);
11731185
}
11741186

11751187
@Override
1176-
public void quadTo(double x1, double y1, double x2, double y2) {
1177-
log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ')');
1188+
public void quadTo(double x1, double y1,
1189+
double x2, double y2) {
1190+
log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");");
11781191
out.quadTo(x1, y1, x2, y2);
11791192
}
11801193

11811194
@Override
11821195
public void closePath() {
1183-
log("closePath");
1196+
log("p.closePath();");
11841197
out.closePath();
11851198
}
11861199

11871200
@Override
11881201
public void pathDone() {
1189-
log("pathDone");
1202+
log("p.pathDone();");
11901203
out.pathDone();
11911204
}
11921205

0 commit comments

Comments
 (0)