1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary Filling Java GeneralPath shapes using the even-odd winding rule doesn't work correctly when a GradientPaint or TexturePaint is used.
  27  * @summary com.apple.junit.java.graphics.color
  28  * @library ../regtesthelpers
  29  * @build VisibilityValidator
  30  * @run main R5214320TestEvenOddGradientFill
  31  */
  32 
  33 import test.java.awt.regtesthelpers.VisibilityValidator;
  34 import junit.framework.*;
  35 import javax.swing.*;
  36 import java.awt.*;
  37 import java.awt.geom.AffineTransform;
  38 import java.awt.geom.GeneralPath;
  39 import java.awt.geom.Path2D;
  40 import java.awt.image.BufferedImage;
  41 
  42 /*
  43  * Filling Java GeneralPath shapes using the even-odd winding rule doesn't work correctly when a GradientPaint or TexturePaint is used.
  44  *
  45  * Steps to Reproduce
  46  *
  47  * The following code generates a Java GeneralPath consisting of a outer rectangle (clockwise) and an inner rectangle (also clockwise), using the even-odd winding rule.
  48  *
  49  * GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
  50  * gp.append(new Rectangle(0, 0, 200, 200), false);
  51  * gp.closePath();
  52  * gp.append(new Rectangle(50, 50, 100, 100), false);
  53  * gp.closePath();
  54  *
  55  * g2d.setPaint(new GradientPaint(0f, 0f, Color.BLUE, 200f, 200f, Color.YELLOW));
  56  * g2d.fill(gp);
  57  *
  58  * gp.transform(AffineTransform.getTranslateInstance(200, 0));
  59  * g2d.setPaint(Color.ORANGE);
  60  * g2d.fill(gp);
  61  *
  62  * Expected Result
  63  *
  64  * The filled shapes should look like square donuts - i.e., a square shape with a square hole in the center.
  65  *
  66  * Actual Result
  67  *
  68  * When filled using a solid color, the outer loop is filled and the inner loop is empty (as it should be).  When filled using a GradientPaint or TexturePaint, the inner rectangle is also filled (which is incorrect).
  69  *
  70  * Regression
  71  *
  72  * This code works correctly under Windows.
  73  */
  74 public class R5214320TestEvenOddGradientFill extends TestCase {
  75     private final static int INNER_LENGTH = 100;
  76     private final static int OUTER_LENGTH = 200;
  77     private final static int INNER_X = (OUTER_LENGTH - INNER_LENGTH)/2;
  78     private final static int INNER_Y = INNER_X;
  79     private final static Color FRAME_BACKGROUND = Color.white;
  80 
  81     private JFrame frame = null;
  82     private Robot robot;
  83 
  84     protected void setUp() throws Exception {
  85         if (robot == null) {
  86             robot = new Robot();
  87         }
  88 
  89         frame = new JFrame("TestEventOdd");
  90         frame.setBackground(FRAME_BACKGROUND);
  91         frame.getContentPane().add(new EvenOddFill());
  92         frame.setSize(3*OUTER_LENGTH, OUTER_LENGTH+20);
  93     }
  94 
  95     private static class EvenOddFill extends Panel {
  96 
  97         public void paint(Graphics g) {
  98             Graphics2D g2d = (Graphics2D)g;
  99 
 100             GeneralPath gp = new GeneralPath(Path2D.WIND_EVEN_ODD);
 101             gp.append(new Rectangle(0, 0, OUTER_LENGTH, OUTER_LENGTH), false);
 102             gp.closePath();
 103             gp.append(new Rectangle(INNER_X, INNER_Y, INNER_LENGTH, INNER_LENGTH), false);
 104             gp.closePath();
 105 
 106             g2d.setPaint(new GradientPaint(0f, 0f, Color.BLUE, 200f, 200f, Color.YELLOW));
 107             g2d.fill(gp);
 108 
 109             gp.transform(AffineTransform.getTranslateInstance(OUTER_LENGTH, 0));
 110             BufferedImage bi = new BufferedImage(2,2,BufferedImage.TYPE_INT_RGB);
 111             bi.setRGB(0, 0, 0xffffffff); bi.setRGB(1, 0, 0xffffffff);
 112             bi.setRGB(0, 1, 0xffffffff); bi.setRGB(1, 1, 0xff0000ff);
 113             TexturePaint bluedots = new TexturePaint(bi,new Rectangle(0,0,2,2));
 114             g2d.setPaint(bluedots);
 115             g2d.fill(gp);
 116 
 117             gp.transform(AffineTransform.getTranslateInstance(OUTER_LENGTH, 0));
 118             g2d.setPaint(Color.ORANGE);
 119             g2d.fill(gp);
 120         }
 121     }
 122 
 123     public void testEvenOddFill() throws Exception {
 124         VisibilityValidator.setVisibleAndConfirm(frame);
 125         Thread.sleep(125); // Let humans see it too...
 126         Point loc = frame.getLocationOnScreen();
 127         loc.x = loc.x + OUTER_LENGTH/2;
 128         loc.y = loc.y + OUTER_LENGTH/2;
 129         robot.mouseMove(loc.x, loc.y);
 130         //System.out.println("robot.getPixelColor("+loc.x+", "+loc.y+"): "+robot.getPixelColor(loc.x, loc.y));
 131         assertTrue("Timed out without seeing a square donut for the first even-odd fill", VisibilityValidator.waitForColor(frame, loc.x, loc.y, FRAME_BACKGROUND));
 132     }
 133 
 134     protected void tearDown() {
 135            frame.dispose();
 136         }
 137 
 138 
 139     public static Test suite() {
 140         return new TestSuite(R5214320TestEvenOddGradientFill.class);
 141     }
 142 
 143     public static void main (String[] args) throws RuntimeException {
 144         TestResult tr = junit.textui.TestRunner.run(suite());
 145         if ((tr.errorCount() != 0) || (tr.failureCount() != 0)) {
 146             throw new RuntimeException("### FAILED: unexpected JUnit errors or failures.");
 147         }
 148     }
 149 }