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 <rdar://problem/3663334> SJSC: 1.4.2DP1: Using a GradientPaint (x, y, color1, x, y, color2, true) hangs AWT thread
  27  * @summary com.apple.junit.java.graphics.GradientPaint
  28  * @library ../../regtesthelpers
  29  * @build VisibilityValidator
  30  * @run main R3663334GradientTests
  31  */
  32 
  33 import test.java.awt.regtesthelpers.VisibilityValidator;
  34 import junit.framework.*;
  35 import javax.swing.*;
  36 import java.awt.*;
  37 
  38 
  39 public class R3663334GradientTests extends TestCase {
  40 
  41         private static final boolean DEBUG = false;
  42 
  43         // Use primary colors to simplify the check that we get back a reasonable gradient
  44         private static final Color kGradientPrimary1 = Color.blue;
  45         private static final Color kGradientPrimary2 = Color.green;
  46         private static final int kColorThreshhold = 32;
  47 
  48         // A color used to check that things draw at all.  Since we use green and blue elsewhere, we choose red here
  49         private static final Color kBackgroundColor = Color.red;
  50 
  51         private Robot robot;
  52         private DisplayFrame m = null;
  53 
  54         // State machine for testXXX() & DisplayFrame
  55         private volatile int state = 0;
  56         static final int BEFORE_TEST = 0;
  57         static final int DOING_TEST = 1;
  58         static final int AFTER_TEST = 2;
  59 
  60         class DisplayFrame extends JFrame {
  61             int width;
  62             int height;
  63 
  64             public DisplayFrame( Dimension gradientSize ) {
  65                 super("DisplayFrame");
  66                 this.width  = (int) gradientSize.getWidth();
  67                 this.height = (int) gradientSize.getHeight();
  68                 setBounds (20, 20, 400, 400);
  69             }
  70 
  71             public void makeVisible() throws Exception {
  72             }
  73 
  74             public void drawBackdrop (Graphics g) {
  75                     Dimension size = getSize();
  76                     g.setColor(kBackgroundColor);
  77                     g.fillRect(0, 0, size.width, size.height);
  78             }
  79 
  80             public void drawGradient (Graphics g) {
  81                     // fill with white
  82                     Dimension size = getSize();
  83                     g.setColor(Color.white); // anything but kBackgroundColor
  84                     g.fillRect(0, 0, size.width, size.height);
  85 
  86                     // note that a zero-sized gradient paint may be transparent
  87                     Graphics2D g2d = (Graphics2D) g;
  88                     if (DEBUG) System.err.println("Constructing gradient paint");
  89                     GradientPaint gp = new GradientPaint (20, 20, kGradientPrimary1, 20+width, 20+height, kGradientPrimary2, true);
  90                     if (DEBUG) System.err.println("Setting gradient paint");
  91                     g2d.setPaint(gp);
  92                     if (DEBUG) System.err.println("Using gradient paint");
  93                     g.fillRect (0,0,getWidth(),getHeight());
  94             }
  95 
  96             public void paint (Graphics g) {
  97                 switch (state) {
  98                     case BEFORE_TEST:
  99                         drawBackdrop(g);
 100                         break;
 101 
 102                     case DOING_TEST:
 103                         drawGradient(g);
 104                         break;
 105 
 106                     case AFTER_TEST:
 107                         drawBackdrop(g);
 108                         break;
 109                 }
 110             }
 111         }
 112 
 113         protected void setUp() throws Exception {
 114             robot = new Robot();
 115         }
 116 
 117         protected void tearDown() throws Exception {
 118             m.dispose();
 119         }
 120 
 121         public void testGradientPaintDrawsReasonableColors() throws Exception {
 122             Dimension gradientSize = new Dimension(100,10);
 123             m = new DisplayFrame(gradientSize);
 124             VisibilityValidator.setVisibleAndConfirm(m);
 125 
 126             // Now do some heavily bullet-proofed checks that we are visible
 127 
 128             // 1 make sure the frame is up - loop until the frame is and we see the red backdrop
 129             state = BEFORE_TEST;
 130             assertTrue("Problems waiting for background to draw.", waitOnCenterColor(m, EXPECT_BACKGROUND) );
 131 
 132             // 2 loop until the frame is changes from red to something else
 133             state = DOING_TEST;
 134             m.repaint();
 135             assertTrue("Problems waiting for gradient to draw.", waitOnCenterColor(m, !EXPECT_BACKGROUND));
 136             // checkForGoodColors();
 137 
 138             // 3 loop until the frame changes back to the red backdrop
 139             state = AFTER_TEST;
 140             m.repaint();
 141             assertTrue("Problems waiting for old background to draw.", waitOnCenterColor(m, EXPECT_BACKGROUND) );
 142         }
 143 
 144         public void testZeroSizedGradientPaintDoesntHang() throws Exception {
 145             Dimension gradientSize = new Dimension(0,0);
 146             m = new DisplayFrame(gradientSize);
 147             VisibilityValidator.setVisibleAndConfirm(m);
 148 
 149             // Now do some heavily bullet-proofed checks that we are visible
 150 
 151             // 1) make sure the frame is up - loop until the frame is and we see the red backdrop
 152             state = BEFORE_TEST;
 153             assertTrue("Problems waiting for background to draw.", waitOnCenterColor(m, EXPECT_BACKGROUND) );
 154 
 155             // 2) loop until the frame is changes from red to something else
 156             state = DOING_TEST;
 157             m.repaint();
 158             assertTrue("Problems waiting for gradient to draw.", waitOnCenterColor(m, !EXPECT_BACKGROUND));
 159 
 160             // 3) loop until the frame changes back to the red backdrop
 161             state = AFTER_TEST;
 162             m.repaint();
 163             assertTrue("Problems waiting for old background to draw.", waitOnCenterColor(m, EXPECT_BACKGROUND));
 164         }
 165 
 166 
 167         // Test for valid colors.  Poke around the center some.   Note that the colors used in the gradient for this testcase were specially
 168         // chosen to make these checks easier; this code will not work for any random Gradient fill.
 169 
 170         void checkForGoodColors() throws Exception {
 171             Rectangle r = m.getBounds();
 172 
 173             assertTrue( "Needs a reasonable sized rectangle", r.getWidth() > 10);
 174             assertTrue( "Needs a reasonable sized rectangle", r.getHeight() > 10);
 175 
 176             int x = (int) r.getX() + (int) r.getWidth() / 2;
 177             int y = (int) r.getY() + (int) r.getHeight() / 2;
 178 
 179             for (int i = -4; i <=4; i++) {
 180                 for (int j = -4; j <=4; j++) {
 181                     Color c = null;
 182                     c = robot.getPixelColor(x+i, y+j);
 183                     // Is c reasonable based on gradient parameters?
 184                     // We used primary colors for the two ends of the gradient, so the sum of the colors should be close to 255
 185                     assertTrue( "Unexpected color in gradient fill", c.getRed() + c.getGreen() + c.getBlue() > (255 - kColorThreshhold) );
 186                     assertTrue( "Unexpected color in gradient fill", c.getRed() + c.getGreen() + c.getBlue() <= 255 );
 187 
 188                     // We avoided red altogether, so we shouldnt have much red
 189                     assertTrue( "Unexpected color in gradient fill", c.getRed() < kColorThreshhold );
 190                 }
 191             }
 192         }
 193 
 194         // A loop that actively tries to repaint the component until the color of the center pixel does something interesting.
 195         // Note the the result needs to be checked afterwards, as the loop times out after a bit (kPaintingTimeoutMillis)
 196         //
 197         //  a) expectBackground == true  ( waits for us to match the background)
 198         //  b) expectBackground == false ( waits for us to NOT match the background)
 199 
 200         static final int kPaintingTimeoutMillis = 10000;
 201         static final boolean EXPECT_BACKGROUND = true;
 202 
 203         public boolean waitOnCenterColor(Component comp, boolean expectBackground) throws Exception {
 204             boolean gotExpectedColor = false;
 205             Rectangle r = comp.getBounds();
 206             int x = (int) r.getX() + (int) r.getWidth() / 2;
 207             int y = (int) r.getY() + (int) r.getHeight() / 2;
 208 
 209             Color c = null;
 210             long endtime = System.currentTimeMillis() + kPaintingTimeoutMillis;
 211             while (System.currentTimeMillis() < endtime) {
 212                 c = robot.getPixelColor(x, y);
 213                 if (DEBUG) System.err.println(c);
 214                 // Loop until we see what we expect to see, or we timeout
 215                 if (VisibilityValidator.colorMatch(kBackgroundColor, c) == expectBackground) {
 216                     gotExpectedColor = true;
 217                     break;  // we see what we expect, continue
 218                 }
 219 
 220                 // loop needs to actively repaint, as sometimes paints are not synchronous
 221                 m.repaint();
 222                 Thread.sleep(250); // a vaguely reasonable time to wait for a repaint to finish
 223             }
 224 
 225             return (gotExpectedColor);
 226         }
 227 
 228         // Boilerplate below
 229 
 230         public static Test suite() {
 231             return new TestSuite(R3663334GradientTests.class);
 232         }
 233 
 234     public static void main (String[] args) throws RuntimeException {
 235         TestResult tr = junit.textui.TestRunner.run(suite());
 236         if ((tr.errorCount() != 0) || (tr.failureCount() != 0)) {
 237             throw new RuntimeException("### FAILED: unexpected JUnit errors or failures.");
 238         }
 239     }
 240 
 241 
 242 }