Hi,

Xerxes RÄnby wrote:
Hello, during bug testing of icedtea6 on various embedded and stationary hardware i have stumbled across some rendering issues of java2d when running under icedtea6.

Testcase:
http://java.sun.com/products/java-media/2D/samples/java2demo/Java2Demo.html

Sourcecode available from:
http://java.sun.com/products/java-media/2D/samples/java2demo/Java2D.zip

Attaching two patches and adding 2d-dev to cc list to get feedback on the patches.


5. and 6. The last two issues are related. the specified joinType are not applyed to lines that gets inserted using closePath.
   public void drawDemo(int w, int h, Graphics2D g2) {
       BasicStroke bs = new BasicStroke(bswidth,
                                   BasicStroke.CAP_BUTT, joinType);
       GeneralPath p = new GeneralPath();
       p.moveTo(- w / 4.0f, - h / 12.0f);
       p.lineTo(+ w / 4.0f, - h / 12.0f);
       p.lineTo(- w / 6.0f, + h / 4.0f);
       p.lineTo(+     0.0f, - h / 4.0f);
       p.lineTo(+ w / 6.0f, + h / 4.0f);
p.closePath(); // <----- issue 6: this should have create a correct join. instead a round join are allways used. p.closePath(); // <----- issue 5: this should have create a correct join. the rendering of the start line should
Is the second closePath() supposed to do anything?
// have been updated when the second closepath was instructed.
       g2.translate(w/2, h/2);
       g2.setColor(Color.black);
       g2.draw(bs.createStrokedShape(p));
   }


issue5-internal-joint.patch fixes the internal joint on the bottom right corner of the star. The external round join issue is fixed by an OpenJDK7 patch [1]. This has already been backported to IcedTea6. issue6-extra-line-closing-joint.patch removes the extra line that is drawn on the top left corner of the star, fixing that issue.

Each patch also includes a jtreg test for the bug.

The second attached picture without pink markings displays how the testcase looks using Sun's properitary java2d for reference.

Cheers.
Xerxes

Cheers,
Omair

[1] http://hg.openjdk.java.net/jdk7/2d/jdk/rev/9318628e8eee
diff -r 9d89e1ada1c8 -r 100e6e0825ee HACKING
--- a/HACKING	Wed Apr 29 16:01:07 2009 +0200
+++ b/HACKING	Wed Apr 29 13:46:09 2009 -0400
@@ -93,6 +93,7 @@
 * icedtea-jtreg-jrunscript.patch: Fix jrunscript test so it works with newer versions of rhino (by comparing the actual numbers).
 * icedtea-ignore-unrecognized-options.patch: Add -XX:+IgnoreUnrecognizedVMOptions flag to hotspot (S6788376).
 * icedtea-java2d-mitre-join.patch: Backport fix for mitre join decoration (S6812600).
+* icedtea-java2d-stroker-internal-joint.patch: Fix penultimate joint created by GeneralPath.closePath().
 
 The following patches are only applied to OpenJDK6 in IcedTea6:
 
diff -r 9d89e1ada1c8 -r 100e6e0825ee Makefile.am
--- a/Makefile.am	Wed Apr 29 16:01:07 2009 +0200
+++ b/Makefile.am	Wed Apr 29 13:46:09 2009 -0400
@@ -678,6 +678,7 @@
 	patches/icedtea-network-unreachable.patch \
 	patches/icedtea-dnd-filelists.patch \
 	patches/icedtea-java2d-mitre-join.patch \
+	patches/icedtea-java2d-stroker-internal-joint.patch \
 	$(DISTRIBUTION_PATCHES)
 
 stamps/extract.stamp: stamps/download.stamp
diff -r 9d89e1ada1c8 -r 100e6e0825ee patches/icedtea-java2d-stroker-internal-joint.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/icedtea-java2d-stroker-internal-joint.patch	Wed Apr 29 13:46:09 2009 -0400
@@ -0,0 +1,98 @@
+--- openjdk/jdk/src/share/classes/sun/java2d/pisces/Stroker.java.orig	2009-04-29 13:30:24.000000000 -0400
++++ openjdk/jdk/src/share/classes/sun/java2d/pisces/Stroker.java	2009-04-29 13:31:05.000000000 -0400
+@@ -614,6 +614,8 @@
+                           ROUND_JOIN_INTERNAL_THRESHOLD);
+         }
+ 
++        emitLineTo(x0, y0, !ccw);
++
+         emitLineTo(x0 + mx, y0 + my);
+         emitLineTo(sx0 + mx, sy0 + my);
+ 
+--- /dev/null	2009-04-15 13:37:55.776002308 -0400
++++ openjdk/jdk/test/sun/pisces/MiterInternalJointTest.java	2009-04-29 13:41:30.000000000 -0400
+@@ -0,0 +1,84 @@
++/*
++ * Copyright 2009 Red Hat, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++/*
++  @test
++  @summary Check that the penultimate joint created using 
++           generalPath.closePath() is correct
++  @author Omair Majid <[email protected]>
++  @run main MiterInternalJointTest
++ */
++
++
++import java.awt.BasicStroke;
++import java.awt.Color;
++import java.awt.Graphics2D;
++import java.awt.geom.GeneralPath;
++import java.awt.image.BufferedImage;
++
++public class MiterInternalJointTest {
++
++    static final int WIDTH = 200;
++    static final int HEIGHT = 200;
++
++    static final int x0 = 50, y0 = 50;
++    static final int x1 = 150, y1 = 50;
++    static final int x2 = 100, y2 = 100;
++
++    private static BufferedImage createTestImage() {
++        final BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
++                BufferedImage.TYPE_INT_BGR);
++        Graphics2D g = image.createGraphics();
++
++        g.setColor(Color.BLACK);
++        g.fillRect(0, 0, WIDTH, HEIGHT);
++
++        float wideStrokeWidth = 20.0f;
++        BasicStroke wideStroke = new BasicStroke(wideStrokeWidth,
++                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, wideStrokeWidth);
++        float thinStrokeWidth = 3.0f;
++        BasicStroke thinStroke = new BasicStroke(thinStrokeWidth,
++                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, thinStrokeWidth);
++
++        g.setColor(Color.WHITE);
++        GeneralPath path = new GeneralPath();
++        path.moveTo(x0, y0);
++        path.lineTo(x1, y1);
++        path.lineTo(x2, y2);
++        path.closePath();
++        path.closePath();
++        g.setStroke(thinStroke);
++        g.draw(wideStroke.createStrokedShape(path));
++
++        return image;
++    }
++
++    public static void main(String[] args) {
++
++        BufferedImage testImage = createTestImage();
++
++        int color = testImage.getRGB(x2,y2);
++        System.out.println("Color seen: #" + Integer.toHexString(color));
++        if (color != Color.WHITE.getRGB()) {
++            throw new RuntimeException(
++                    "Test Failed; expected to see a white vertex above the bottom of the triangle");
++        }
++
++    }
++}

diff -r 100e6e0825ee -r d8106a6bd266 HACKING
--- a/HACKING	Wed Apr 29 13:46:09 2009 -0400
+++ b/HACKING	Wed Apr 29 14:09:02 2009 -0400
@@ -94,6 +94,7 @@
 * icedtea-ignore-unrecognized-options.patch: Add -XX:+IgnoreUnrecognizedVMOptions flag to hotspot (S6788376).
 * icedtea-java2d-mitre-join.patch: Backport fix for mitre join decoration (S6812600).
 * icedtea-java2d-stroker-internal-joint.patch: Fix penultimate joint created by GeneralPath.closePath().
+* icedtea-java2d-stroker-internal-close-joint.patch: Fix final joint created by GeneralPath.closePath().
 
 The following patches are only applied to OpenJDK6 in IcedTea6:
 
diff -r 100e6e0825ee -r d8106a6bd266 Makefile.am
--- a/Makefile.am	Wed Apr 29 13:46:09 2009 -0400
+++ b/Makefile.am	Wed Apr 29 14:09:02 2009 -0400
@@ -679,6 +679,7 @@
 	patches/icedtea-dnd-filelists.patch \
 	patches/icedtea-java2d-mitre-join.patch \
 	patches/icedtea-java2d-stroker-internal-joint.patch \
+	patches/icedtea-java2d-stroker-internal-close-joint.patch \
 	$(DISTRIBUTION_PATCHES)
 
 stamps/extract.stamp: stamps/download.stamp
diff -r 100e6e0825ee -r d8106a6bd266 patches/icedtea-java2d-stroker-internal-close-joint.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/icedtea-java2d-stroker-internal-close-joint.patch	Wed Apr 29 14:09:02 2009 -0400
@@ -0,0 +1,96 @@
+--- openjdk/jdk/src/share/classes/sun/java2d/pisces/Stroker.java.orig	2009-04-29 14:01:43.000000000 -0400
++++ openjdk/jdk/src/share/classes/sun/java2d/pisces/Stroker.java	2009-04-29 14:00:03.000000000 -0400
+@@ -633,7 +633,7 @@
+         }
+ 
+         emitLineTo(sx0 + mx0, sy0 + my0);
+-        emitLineTo(sx0 - mx0, sy0 - my0);  // same as reverse[0], reverse[1]
++        emitMoveTo(sx0, sy0);  // same as reverse[0], reverse[1]
+ 
+         // Draw final join on the inside
+         if (ccw) {
+--- /dev/null	2009-04-15 13:37:55.776002308 -0400
++++ openjdk/jdk/test/sun/pisces/MiterInternalCloseJointTest.java	2009-04-29 13:59:31.000000000 -0400
+@@ -0,0 +1,82 @@
++/*
++ * Copyright 2009 Red Hat, Inc.  All Rights Reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++/*
++  @test
++  @summary Check that the final joint created using 
++           generalPath.closePath() is correct
++  @author Omair Majid <[email protected]>
++  @run main MiterInternalCloseJointTest
++ */
++import java.awt.BasicStroke;
++import java.awt.Color;
++import java.awt.Graphics2D;
++import java.awt.geom.GeneralPath;
++import java.awt.image.BufferedImage;
++
++public class MiterInternalCloseJointTest {
++
++    static final int WIDTH = 200;
++    static final int HEIGHT = 200;
++
++    static final int x0 = 50, y0 = 50;
++    static final int x1 = 150, y1 = 50;
++    static final int x2 = 100, y2 = 100;
++
++    private static BufferedImage createTestImage() {
++        final BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
++                BufferedImage.TYPE_INT_BGR);
++        Graphics2D g = image.createGraphics();
++
++        g.setColor(Color.BLACK);
++        g.fillRect(0, 0, WIDTH, HEIGHT);
++
++        float wideStrokeWidth = 20.0f;
++        BasicStroke wideStroke = new BasicStroke(wideStrokeWidth,
++                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, wideStrokeWidth);
++        float thinStrokeWidth = 3.0f;
++        BasicStroke thinStroke = new BasicStroke(thinStrokeWidth,
++                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, thinStrokeWidth);
++
++        g.setColor(Color.WHITE);
++        GeneralPath path = new GeneralPath();
++        path.moveTo(x0, y0);
++        path.lineTo(x1, y1);
++        path.lineTo(x2, y2);
++        path.closePath();
++        path.closePath();
++        g.setStroke(thinStroke);
++        g.draw(wideStroke.createStrokedShape(path));
++
++        return image;
++    }
++
++    public static void main(String[] args) {
++
++        BufferedImage testImage = createTestImage();
++
++        int color = testImage.getRGB(x0,y0-5);
++        System.out.println("Color seen: #" + Integer.toHexString(color));
++        if (color == Color.WHITE.getRGB()) {
++            throw new RuntimeException(
++                    "Test Failed; did not expected to see a white line at the start of the path");
++        }
++
++    }
++}

Reply via email to