changeset 9562:beb3731f19b6

8032219: [macosx] Scrollbars looks bad under retina in Motif and Metal L&F Reviewed-by: pchelko, flar
author serb
date Mon, 07 Apr 2014 15:34:27 +0400
parents 9683a286c88d
children bf44dd06cd4e
files src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java src/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java src/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java src/share/classes/sun/swing/SwingUtilities2.java test/javax/swing/SwingUtilities/8032219/DrawRect.java
diffstat 6 files changed, 289 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java	Wed Apr 02 15:23:08 2014 +0400
+++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java	Mon Apr 07 15:34:27 2014 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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
@@ -24,17 +24,19 @@
  */
 package com.sun.java.swing.plaf.motif;
 
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.swing.plaf.*;
-import javax.swing.border.*;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Rectangle;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JScrollBar;
+import javax.swing.plaf.ComponentUI;
 import javax.swing.plaf.basic.BasicScrollBarUI;
 
-import java.awt.Dimension;
-import java.awt.Insets;
-import java.awt.Rectangle;
-import java.awt.Graphics;
-import java.awt.Color;
+import static sun.swing.SwingUtilities2.drawHLine;
+import static sun.swing.SwingUtilities2.drawVLine;
 
 
 /**
@@ -74,17 +76,13 @@
         return new MotifScrollBarButton(orientation);
     }
 
-
     public void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)  {
         g.setColor(trackColor);
         g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height);
     }
 
-
-    public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
-    {
-
-        if(thumbBounds.isEmpty() || !scrollbar.isEnabled())     {
+    public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
+        if (thumbBounds.isEmpty() || !scrollbar.isEnabled()) {
             return;
         }
 
@@ -93,15 +91,15 @@
 
         g.translate(thumbBounds.x, thumbBounds.y);
         g.setColor(thumbColor);
-        g.fillRect(0, 0, w-1, h-1);
+        g.fillRect(0, 0, w - 1, h - 1);
 
         g.setColor(thumbHighlightColor);
-        g.drawLine(0, 0, 0, h-1);
-        g.drawLine(1, 0, w-1, 0);
+        drawVLine(g, 0, 0, h - 1);
+        drawHLine(g, 1, w - 1, 0);
 
         g.setColor(thumbLightShadowColor);
-        g.drawLine(1, h-1, w-1, h-1);
-        g.drawLine(w-1, 1, w-1, h-2);
+        drawHLine(g, 1, w - 1, h - 1);
+        drawVLine(g, w - 1, 1, h - 2);
 
         g.translate(-thumbBounds.x, -thumbBounds.y);
     }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java	Wed Apr 02 15:23:08 2014 +0400
+++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java	Mon Apr 07 15:34:27 2014 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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
@@ -25,14 +25,17 @@
 
 package com.sun.java.swing.plaf.motif;
 
-import java.awt.*;
-import java.awt.event.*;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Rectangle;
 
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.swing.plaf.*;
+import javax.swing.JComponent;
+import javax.swing.JSlider;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicSliderUI;
 
-import javax.swing.plaf.basic.BasicSliderUI;
+import static sun.swing.SwingUtilities2.drawHLine;
+import static sun.swing.SwingUtilities2.drawVLine;
 
 /**
  * Motif Slider
@@ -123,15 +126,15 @@
 
             // highlight
             g.setColor(getHighlightColor());
-            g.drawLine(0, 1, w - 1, 1);             // top
-            g.drawLine(0, 1, 0, h);                     // left
-            g.drawLine(w/2, 2, w/2, h-1);       // center
+            drawHLine(g, 0, w - 1, 1);      // top
+            drawVLine(g, 0, 1, h);          // left
+            drawVLine(g, w / 2, 2, h - 1);  // center
 
             // shadow
             g.setColor(getShadowColor());
-            g.drawLine(0, h, w - 1, h);         // bottom
-            g.drawLine(w - 1, 1, w - 1, h);     // right
-            g.drawLine(w/2 - 1, 2, w/2 - 1, h); // center
+            drawHLine(g, 0, w - 1, h);      // bottom
+            drawVLine(g, w - 1, 1, h);      // right
+            drawVLine(g, w / 2 - 1, 2, h);  // center
 
             g.translate(-x, -(knobBounds.y-1));
         }
@@ -143,15 +146,15 @@
 
             // highlight
             g.setColor(getHighlightColor());
-            g.drawLine(1, y, w, y);                     // top
-            g.drawLine(1, y+1, 1, y+h-1);               // left
-            g.drawLine(2, y+h/2, w-1, y+h/2);           // center
+            drawHLine(g, 1, w, y);             // top
+            drawVLine(g, 1, y + 1, y + h - 1); // left
+            drawHLine(g, 2, w - 1, y + h / 2); // center
 
             // shadow
             g.setColor(getShadowColor());
-            g.drawLine(2, y+h-1, w, y+h-1);             // bottom
-            g.drawLine(w, y+h-1, w, y);                 // right
-            g.drawLine(2, y+h/2-1, w-1, y+h/2-1);       // center
+            drawHLine(g, 2, w, y + h - 1);        // bottom
+            drawVLine(g, w, y + h - 1, y);        // right
+            drawHLine(g, 2, w - 1, y + h / 2 - 1);// center
 
             g.translate(-(knobBounds.x-1), 0);
         }
--- a/src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java	Wed Apr 02 15:23:08 2014 +0400
+++ b/src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java	Mon Apr 07 15:34:27 2014 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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
@@ -37,6 +37,10 @@
 import javax.swing.event.*;
 import javax.swing.plaf.*;
 
+import static sun.swing.SwingUtilities2.drawHLine;
+import static sun.swing.SwingUtilities2.drawRect;
+import static sun.swing.SwingUtilities2.drawVLine;
+
 
 /**
  * Implementation of ScrollBarUI for the Basic Look and Feel
@@ -572,17 +576,17 @@
         g.translate(thumbBounds.x, thumbBounds.y);
 
         g.setColor(thumbDarkShadowColor);
-        g.drawRect(0, 0, w-1, h-1);
+        drawRect(g, 0, 0, w - 1, h - 1);
         g.setColor(thumbColor);
-        g.fillRect(0, 0, w-1, h-1);
+        g.fillRect(0, 0, w - 1, h - 1);
 
         g.setColor(thumbHighlightColor);
-        g.drawLine(1, 1, 1, h-2);
-        g.drawLine(2, 1, w-3, 1);
+        drawVLine(g, 1, 1, h - 2);
+        drawHLine(g, 2, w - 3, 1);
 
         g.setColor(thumbLightShadowColor);
-        g.drawLine(2, h-2, w-2, h-2);
-        g.drawLine(w-2, 1, w-2, h-3);
+        drawHLine(g, 2, w - 2, h - 2);
+        drawVLine(g, w - 2, 1, h - 3);
 
         g.translate(-thumbBounds.x, -thumbBounds.y);
     }
--- a/src/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java	Wed Apr 02 15:23:08 2014 +0400
+++ b/src/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java	Mon Apr 07 15:34:27 2014 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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
@@ -25,33 +25,23 @@
 
 package javax.swing.plaf.metal;
 
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.LayoutManager;
-import java.awt.Adjustable;
-import java.awt.event.AdjustmentListener;
-import java.awt.event.AdjustmentEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
+import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.Graphics;
-import java.awt.Dimension;
 import java.awt.Rectangle;
-import java.awt.Point;
-import java.awt.Insets;
-import java.awt.Color;
-import java.awt.IllegalComponentStateException;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 
-import java.beans.*;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JScrollBar;
+import javax.swing.UIManager;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.basic.BasicScrollBarUI;
 
-import javax.swing.*;
-import javax.swing.event.*;
-
-import javax.swing.plaf.*;
-import javax.swing.plaf.basic.BasicScrollBarUI;
+import static sun.swing.SwingUtilities2.drawHLine;
+import static sun.swing.SwingUtilities2.drawRect;
+import static sun.swing.SwingUtilities2.drawVLine;
 
 
 /**
@@ -159,21 +149,21 @@
 
             if ( c.isEnabled() ) {
                 g.setColor( darkShadowColor );
-                g.drawLine( 0, 0, 0, trackBounds.height - 1 );
-                g.drawLine( trackBounds.width - 2, 0, trackBounds.width - 2, trackBounds.height - 1 );
-                g.drawLine( 2, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1);
-                g.drawLine( 2, 0, trackBounds.width - 2, 0 );
+                drawVLine(g, 0, 0, trackBounds.height - 1);
+                drawVLine(g, trackBounds.width - 2, 0, trackBounds.height - 1);
+                drawHLine(g, 2, trackBounds.width - 1, trackBounds.height - 1);
+                drawHLine(g, 2, trackBounds.width - 2, 0);
 
                 g.setColor( shadowColor );
                 //      g.setColor( Color.red);
-                g.drawLine( 1, 1, 1, trackBounds.height - 2 );
-                g.drawLine( 1, 1, trackBounds.width - 3, 1 );
+                drawVLine(g, 1, 1, trackBounds.height - 2);
+                drawHLine(g, 1, trackBounds.width - 3, 1);
                 if (scrollbar.getValue() != scrollbar.getMaximum()) {  // thumb shadow
                     int y = thumbRect.y + thumbRect.height - trackBounds.y;
-                    g.drawLine( 1, y, trackBounds.width-1, y);
+                    drawHLine(g, 1, trackBounds.width - 1, y);
                 }
                 g.setColor(highlightColor);
-                g.drawLine( trackBounds.width - 1, 0, trackBounds.width - 1, trackBounds.height - 1 );
+                drawVLine(g, trackBounds.width - 1, 0, trackBounds.height - 1);
             } else {
                 MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
             }
@@ -193,19 +183,19 @@
 
             if ( c.isEnabled() ) {
                 g.setColor( darkShadowColor );
-                g.drawLine( 0, 0, trackBounds.width - 1, 0 );  // top
-                g.drawLine( 0, 2, 0, trackBounds.height - 2 ); // left
-                g.drawLine( 0, trackBounds.height - 2, trackBounds.width - 1, trackBounds.height - 2 ); // bottom
-                g.drawLine( trackBounds.width - 1, 2, trackBounds.width - 1, trackBounds.height - 1 ); // right
+                drawHLine(g, 0, trackBounds.width - 1, 0);  // top
+                drawVLine(g, 0, 2, trackBounds.height - 2); // left
+                drawHLine(g, 0, trackBounds.width - 1, trackBounds.height - 2 ); // bottom
+                drawVLine(g, trackBounds.width - 1, 2,  trackBounds.height - 1 ); // right
 
                 g.setColor( shadowColor );
                 //      g.setColor( Color.red);
-                g.drawLine( 1, 1, trackBounds.width - 2, 1 );  // top
-                g.drawLine( 1, 1, 1, trackBounds.height - 3 ); // left
-                g.drawLine( 0, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1 ); // bottom
+                drawHLine(g, 1, trackBounds.width - 2, 1 );  // top
+                drawVLine(g, 1, 1, trackBounds.height - 3 ); // left
+                drawHLine(g, 0, trackBounds.width - 1, trackBounds.height - 1 ); // bottom
                 if (scrollbar.getValue() != scrollbar.getMaximum()) {  // thumb shadow
                     int x = thumbRect.x + thumbRect.width - trackBounds.x;
-                    g.drawLine( x, 1, x, trackBounds.height-1);
+                    drawVLine(g, x, 1, trackBounds.height-1);
                 }
             } else {
                 MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
@@ -247,11 +237,11 @@
             g.fillRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
 
             g.setColor( thumbShadow );
-            g.drawRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
+            drawRect(g, 0, 0, thumbBounds.width - 2, thumbBounds.height - 1);
 
             g.setColor( thumbHighlightColor );
-            g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
-            g.drawLine( 1, 1, 1, thumbBounds.height - 2 );
+            drawHLine(g, 1, thumbBounds.width - 3, 1);
+            drawVLine(g, 1, 1, thumbBounds.height - 2);
 
             bumps.setBumpArea( thumbBounds.width - 6, thumbBounds.height - 7 );
             bumps.paintIcon( c, g, 3, 4 );
@@ -273,11 +263,11 @@
             g.fillRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
 
             g.setColor( thumbShadow );
-            g.drawRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
+            drawRect(g, 0, 0, thumbBounds.width - 1, thumbBounds.height - 2);
 
             g.setColor( thumbHighlightColor );
-            g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
-            g.drawLine( 1, 1, 1, thumbBounds.height - 3 );
+            drawHLine(g, 1, thumbBounds.width - 3, 1);
+            drawVLine(g, 1, 1, thumbBounds.height - 3);
 
             bumps.setBumpArea( thumbBounds.width - 7, thumbBounds.height - 6 );
             bumps.paintIcon( c, g, 4, 3 );
@@ -310,11 +300,11 @@
             }
 
             g.setColor(thumbShadow);
-            g.drawRect(0, 0, thumbBounds.width - 2, thumbBounds.height - 1);
+            drawRect(g, 0, 0, thumbBounds.width - 2, thumbBounds.height - 1);
 
             g.setColor(thumbHighlightColor);
-            g.drawLine(1, 1, thumbBounds.width - 3, 1);
-            g.drawLine(1, 1, 1, thumbBounds.height - 2);
+            drawHLine(g, 1, thumbBounds.width - 3, 1);
+            drawVLine(g, 1, 1, thumbBounds.height - 2);
 
             MetalUtils.drawGradient(c, g, "ScrollBar.gradient", 2, 2,
                                     thumbBounds.width - 4,
@@ -352,11 +342,11 @@
             }
 
             g.setColor(thumbShadow);
-            g.drawRect(0, 0, thumbBounds.width - 1, thumbBounds.height - 2);
+            drawRect(g, 0, 0, thumbBounds.width - 1, thumbBounds.height - 2);
 
             g.setColor(thumbHighlightColor);
-            g.drawLine(1, 1, thumbBounds.width - 2, 1);
-            g.drawLine(1, 1, 1, thumbBounds.height - 3);
+            drawHLine(g, 1, thumbBounds.width - 2, 1);
+            drawVLine(g, 1, 1, thumbBounds.height - 3);
 
             MetalUtils.drawGradient(c, g, "ScrollBar.gradient", 2, 2,
                                     thumbBounds.width - 3,
--- a/src/share/classes/sun/swing/SwingUtilities2.java	Wed Apr 02 15:23:08 2014 +0400
+++ b/src/share/classes/sun/swing/SwingUtilities2.java	Mon Apr 07 15:34:27 2014 +0400
@@ -926,6 +926,77 @@
         return retVal;
     }
 
+    /**
+     * This method should be used for drawing a borders over a filled rectangle.
+     * Draws vertical line, using the current color, between the points {@code
+     * (x, y1)} and {@code (x, y2)} in graphics context's coordinate system.
+     * Note: it use {@code Graphics.fillRect()} internally.
+     *
+     * @param g  Graphics to draw the line to.
+     * @param x  the <i>x</i> coordinate.
+     * @param y1 the first point's <i>y</i> coordinate.
+     * @param y2 the second point's <i>y</i> coordinate.
+     */
+    public static void drawVLine(Graphics g, int x, int y1, int y2) {
+        if (y2 < y1) {
+            final int temp = y2;
+            y2 = y1;
+            y1 = temp;
+        }
+        g.fillRect(x, y1, 1, y2 - y1 + 1);
+    }
+
+    /**
+     * This method should be used for drawing a borders over a filled rectangle.
+     * Draws horizontal line, using the current color, between the points {@code
+     * (x1, y)} and {@code (x2, y)} in graphics context's coordinate system.
+     * Note: it use {@code Graphics.fillRect()} internally.
+     *
+     * @param g  Graphics to draw the line to.
+     * @param x1 the first point's <i>x</i> coordinate.
+     * @param x2 the second point's <i>x</i> coordinate.
+     * @param y  the <i>y</i> coordinate.
+     */
+    public static void drawHLine(Graphics g, int x1, int x2, int y) {
+        if (x2 < x1) {
+            final int temp = x2;
+            x2 = x1;
+            x1 = temp;
+        }
+        g.fillRect(x1, y, x2 - x1 + 1, 1);
+    }
+
+    /**
+     * This method should be used for drawing a borders over a filled rectangle.
+     * Draws the outline of the specified rectangle. The left and right edges of
+     * the rectangle are at {@code x} and {@code x + w}. The top and bottom
+     * edges are at {@code y} and {@code y + h}. The rectangle is drawn using
+     * the graphics context's current color. Note: it use {@code
+     * Graphics.fillRect()} internally.
+     *
+     * @param g Graphics to draw the rectangle to.
+     * @param x the <i>x</i> coordinate of the rectangle to be drawn.
+     * @param y the <i>y</i> coordinate of the rectangle to be drawn.
+     * @param w the w of the rectangle to be drawn.
+     * @param h the h of the rectangle to be drawn.
+     * @see SwingUtilities2#drawVLine(java.awt.Graphics, int, int, int)
+     * @see SwingUtilities2#drawHLine(java.awt.Graphics, int, int, int)
+     */
+    public static void drawRect(Graphics g, int x, int y, int w, int h) {
+        if (w < 0 || h < 0) {
+            return;
+        }
+
+        if (h == 0 || w == 0) {
+            g.fillRect(x, y, w + 1, h + 1);
+        } else {
+            g.fillRect(x, y, w, 1);
+            g.fillRect(x + w, y, 1, h);
+            g.fillRect(x + 1, y + h, w, 1);
+            g.fillRect(x, y + 1, 1, h);
+        }
+    }
+
     private static TextLayout createTextLayout(JComponent c, String s,
                                             Font f, FontRenderContext frc) {
         Object shaper = (c == null ?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/SwingUtilities/8032219/DrawRect.java	Mon Apr 07 15:34:27 2014 +0400
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. 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.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.swing.SwingUtilities2;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+/**
+ * @test
+ * @bug 8032219
+ * @author Sergey Bylokhov
+ */
+public final class DrawRect {
+
+    private static final int size = 50;
+
+    private static final Rectangle[] rects = {
+            new Rectangle(0, 0, 1, 1),
+            new Rectangle(0, 0, 1, 2),
+            new Rectangle(0, 0, 2, 1),
+            new Rectangle(10, 10, 10, 10),
+            new Rectangle(10, 10, -1, -1),
+            new Rectangle(-1, -1, 10, 10),
+            new Rectangle(-1, -1, -10, -10),
+            new Rectangle(0, 0, size, size),
+    };
+
+    private static final Rectangle[] vlines = {new Rectangle(0, 0, 0, 0),
+            new Rectangle(0, 0, 0, 1),
+            new Rectangle(0, 0, 0, -1),
+            new Rectangle(1, 1, 0, 1),
+            new Rectangle(1, 1, 0, -1),
+            new Rectangle(15, 15, 0, 10),
+            new Rectangle(15, 15, 0, -10),
+    };
+    private static final Rectangle[] hlines = {new Rectangle(0, 0, 0, 0),
+            new Rectangle(0, 0, 1, 0),
+            new Rectangle(0, 0, -1, 0),
+            new Rectangle(1, 1, 1, 0),
+            new Rectangle(1, 1, -1, 0),
+            new Rectangle(15, 15, 10, 0),
+            new Rectangle(15, 15, -10, 0),
+    };
+
+    public static void main(final String[] args) throws IOException {
+        BufferedImage gold = new BufferedImage(size, size,
+                                               BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g = gold.createGraphics();
+        BufferedImage bi = new BufferedImage(size, size,
+                                             BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g2d = bi.createGraphics();
+        g2d.setColor(new Color(0, 250, 0, 100));
+        g2d.setBackground(Color.BLACK);
+        g.setColor(new Color(0, 250, 0, 100));
+        g.setBackground(Color.BLACK);
+        // Rectangle
+        for (final Rectangle r : rects) {
+            g.clearRect(0, 0, size, size);
+            g2d.clearRect(0, 0, size, size);
+            g.drawRect(r.x, r.y, r.width, r.height);
+            SwingUtilities2.drawRect(g2d, r.x, r.y, r.width, r.height);
+            test(gold, bi);
+        }
+        // Vertical Line
+        for (final Rectangle l : vlines) {
+            g.clearRect(0, 0, size, size);
+            g2d.clearRect(0, 0, size, size);
+            g.drawLine(l.x, l.y, l.x + l.width, l.y + l.height);
+            SwingUtilities2.drawVLine(g2d, l.x, l.y, l.y + l.height);
+            test(gold, bi);
+        }
+        // Horizontal Line
+        for (final Rectangle l : hlines) {
+            g.clearRect(0, 0, size, size);
+            g2d.clearRect(0, 0, size, size);
+            g.drawLine(l.x, l.y, l.x + l.width, l.y + l.height);
+            SwingUtilities2.drawHLine(g2d, l.x, l.x+l.width, l.y);
+            test(gold, bi);
+        }
+
+        g.dispose();
+        g2d.dispose();
+    }
+
+    private static void test(final BufferedImage gold, final BufferedImage bi)
+            throws IOException {
+        for (int x = 0; x < size; x++) {
+            for (int y = 0; y < size; y++) {
+                if (gold.getRGB(x, y) != bi.getRGB(x, y)) {
+                    ImageIO.write(gold, "png", new File("gold.png"));
+                    ImageIO.write(bi, "png", new File("image.png"));
+                    throw new RuntimeException("wrong color");
+                }
+            }
+        }
+    }
+}
\ No newline at end of file