Oops, I forgot to attach the patch. ----- Original Message ----- From: "Denis Lila" <dl...@redhat.com> To: "Jon VanAlten" <jon.vanal...@redhat.com> Cc: 2d-dev@openjdk.java.net Sent: Wednesday, June 16, 2010 4:28:27 PM GMT -05:00 US/Canada Eastern Subject: Re: [OpenJDK 2D-Dev] Corner case drawing wide lines of zero length
So, I've been looking at this a bit more, and I noticed that there was a problem when a non-diagonal affine transformation was in effect. This was because scaledLineWidth2 was being used to draw the end caps, but this variable is valid only when the linear transformation in effect is of the form [[n, 0], [0, n]]. I also simplified, somewhat, the drawing of round end caps. Denis. ----- Original Message ----- From: "Denis Lila" <dl...@redhat.com> To: "Jon VanAlten" <jon.vanal...@redhat.com> Cc: 2d-dev@openjdk.java.net Sent: Monday, June 14, 2010 5:04:46 PM GMT -05:00 US/Canada Eastern Subject: Re: [OpenJDK 2D-Dev] Corner case drawing wide lines of zero length I can see one slight problem with this. moveTo will check whether "if (prev == LINE_TO) {" in line 488. This should be changed to "if (prev == LINE_TO || atLeastOneLine) {". If this is not done, and if there are many moveTo's, each followed by a lineTo to a line of 0 length, no end caps will be drawn for any of the lines except perhaps the last lineTo. See bug 197: http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=197 for reproducers, effects, and some more discussion on this. Regards, Denis Lila. ----- Original Message ----- From: "jon vanalten" <jon.vanal...@redhat.com> To: 2d-dev@openjdk.java.net Sent: Tuesday, June 8, 2010 10:10:21 AM GMT -05:00 US/Canada Eastern Subject: Re: [OpenJDK 2D-Dev] Corner case drawing wide lines of zero length <BUMP> Hi, I sent this a while ago. Wondering if anyone has any feedback? thanks in advance, jon ----- "jon vanalten" <jon.vanal...@redhat.com> wrote: > Hi, > > I am new to this list, hopefully it is okay that I post a potential > fix to a very minor rendering bug. > > I've been looking at a bug reported downstream at IcedTea: > > http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=383 > > To summarize, if a line is drawn via Graphics2D.drawLine() of zero > length but thickness greater than 1, the endcap decorations are not > rendered. This is because the sun.java2d.pisces.Stroker class ignores > such line segments. This is ideal in most situations drawing complex > shapes, but when such a line segment is the entire shape the end > result nothing at all is rendered. The closed-source Sun JDK > implementation does render endcap decorations in this case, and the > documentation of the BasicStroke class related to this suggests that > they should be rendered. > > I've put together a (possibly straw-man) fix. Please do pick it > apart, I have never looked at the graphics implementation before > trying to tackle this bug. I basically add a boolean to indicate that > the finish() step should be taken if *any* lineTo() call has occurred, > and in the finish() step detect if there are any segments and if no > manually draw in the caps (while allowing normal behaviour in other > cases). > > See webrev at: > > http://icedtea.classpath.org/~vanaltj/webrevs/2d/zeroline/webrev/ > (or download) > http://icedtea.classpath.org/~vanaltj/webrevs/2d/zeroline/webrev.zip > > Your comments are appreciated. > > cheers, > > jon
exporting patch: # HG changeset patch # User Denis Lila <dl...@redhat.com> # Date 1276719099 14400 # Node ID fbb880ba2ed9acb8348112f7f3c26bd8bd49e8d2 # Parent 8b55669c7b7a5982860dfcf6ccfe6c26e311da30 Fixed bug where 0 length lines don't have end caps. diff --git a/src/share/classes/sun/java2d/pisces/Stroker.java b/src/share/classes/sun/java2d/pisces/Stroker.java --- a/src/share/classes/sun/java2d/pisces/Stroker.java +++ b/src/share/classes/sun/java2d/pisces/Stroker.java @@ -514,6 +514,7 @@ lineToImpl(sx0, sy0, joinToOrigin); lineToOrigin = false; } else if (x1 == x0 && y1 == y0) { + this.prev = LINE_TO; return; } else if (x1 == sx0 && y1 == sy0) { lineToOrigin = true; @@ -687,21 +688,47 @@ } private void finish() { + boolean zeroLength = (sx0 == x0 && sy0 == y0 && rindex == 0); if (capStyle == CAP_ROUND) { - drawRoundJoin(x0, y0, - omx, omy, -omx, -omy, 1, false, false, - ROUND_JOIN_THRESHOLD); + if (zeroLength) { + int dx = (int)scaledLineWidth2; + int dy = (int)((long)m10 * lineWidth2 >> 16); + drawRoundJoin(x0, y0, dx, dy, -dx, -dy, 1, false, false, ROUND_JOIN_THRESHOLD); + drawRoundJoin(x0, y0, -dx, -dy, dx, dy, 1, false, false, ROUND_JOIN_THRESHOLD); + } else { + drawRoundJoin(x0, y0, + omx, omy, -omx, -omy, 1, false, false, + ROUND_JOIN_THRESHOLD); + } } else if (capStyle == CAP_SQUARE) { - long ldx = (long)(px0 - x0); - long ldy = (long)(py0 - y0); - long llen = lineLength(ldx, ldy); - long s = (long)lineWidth2*65536/llen; + if (zeroLength) { + long w2 = lineWidth2; + int m00_p_m01 = m00 + m01; + int m10_p_m11 = m10 + m11; + int m00_m_m01 = m00 - m01; + int m10_m_m11 = m10 - m11; + emitMoveTo(x0 + (int)(w2 * m00_p_m01 >> 16), + y0 + (int)(w2 * m10_p_m11 >> 16)); + emitLineTo(x0 + (int)(w2 * (-m00_m_m01) >> 16), + y0 + (int)(w2 * (-m10_m_m11) >> 16)); + emitLineTo(x0 + (int)(w2 * (-m00_p_m01) >> 16), + y0 + (int)(w2 * (-m10_p_m11) >> 16)); + emitLineTo(x0 + (int)(w2 * m00_m_m01 >> 16), + y0 + (int)(w2 * m10_m_m11 >> 16)); + emitLineTo(x0 + (int)(w2 * m00_p_m01 >> 16), + y0 + (int)(w2 * m10_p_m11 >> 16)); + } else { + long ldx = (long)(px0 - x0); + long ldy = (long)(py0 - y0); + long llen = lineLength(ldx, ldy); + long s = (long)lineWidth2*65536/llen; - int capx = x0 - (int)(ldx*s >> 16); - int capy = y0 - (int)(ldy*s >> 16); + int capx = x0 - (int)(ldx*s >> 16); + int capy = y0 - (int)(ldy*s >> 16); - emitLineTo(capx + omx, capy + omy); - emitLineTo(capx - omx, capy - omy); + emitLineTo(capx + omx, capy + omy); + emitLineTo(capx - omx, capy - omy); + } } for (int i = rindex - 2; i >= 0; i -= 2) { @@ -709,21 +736,23 @@ } this.rindex = 0; - if (capStyle == CAP_ROUND) { - drawRoundJoin(sx0, sy0, - -mx0, -my0, mx0, my0, 1, false, false, - ROUND_JOIN_THRESHOLD); - } else if (capStyle == CAP_SQUARE) { - long ldx = (long)(sx1 - sx0); - long ldy = (long)(sy1 - sy0); - long llen = lineLength(ldx, ldy); - long s = (long)lineWidth2*65536/llen; + if (!zeroLength) { + if (capStyle == CAP_ROUND) { + drawRoundJoin(sx0, sy0, + -mx0, -my0, mx0, my0, 1, false, false, + ROUND_JOIN_THRESHOLD); + } else if (capStyle == CAP_SQUARE) { + long ldx = (long)(sx1 - sx0); + long ldy = (long)(sy1 - sy0); + long llen = lineLength(ldx, ldy); + long s = (long)lineWidth2*65536/llen; - int capx = sx0 - (int)(ldx*s >> 16); - int capy = sy0 - (int)(ldy*s >> 16); + int capx = sx0 - (int)(ldx*s >> 16); + int capy = sy0 - (int)(ldy*s >> 16); - emitLineTo(capx - mx0, capy - my0); - emitLineTo(capx + mx0, capy + my0); + emitLineTo(capx - mx0, capy - my0); + emitLineTo(capx + mx0, capy + my0); + } } emitClose();