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/4122177> [JavaJDK15] Font bounds returned by TextLayout significantly off. 27 * @library ../../../regtesthelpers 28 * @build VisibilityValidator 29 * @build Waypoint 30 * @build RobotUtilities 31 * @build BITestUtils 32 * @summary com.apple.junit.java.text.TextBounds; 33 * @run junit Bounds01 34 */ 35 36 /** 37 * 38 * Paints a series of red strings, overwrites them with a 1/2 alpha blue wash, then looks for bright red 39 * uncovered pixels. 40 * 41 **/ 42 43 // classes necessary for this test 44 45 import junit.framework.*; 46 47 import java.awt.*; 48 import java.awt.font.FontRenderContext; 49 import java.awt.font.TextLayout; 50 import java.awt.geom.Point2D; 51 import java.awt.geom.Rectangle2D; 52 import java.awt.image.BufferedImage; 53 import java.io.File; 54 import java.util.Vector; 55 56 import test.java.awt.regtesthelpers.VisibilityValidator; 57 import test.java.awt.regtesthelpers.Waypoint; 58 import test.java.awt.regtesthelpers.RobotUtilities; 59 import test.java.awt.regtesthelpers.BITestUtils; 60 61 public class Bounds01 extends TestCase { 62 static final int WIDTH = 600; 63 static final int HEIGHT = 200; 64 65 static final int slop = 1; 66 static final int sizes[] = { 9, 12, 18, 37 }; // Use reduced set to make the test run fast 67 68 static final int styles[] = { Font.PLAIN, Font.BOLD }; 69 static final String names[] = { "Serif", "Helvetica", "DIALOG"}; 70 71 protected Vector<Font> fonts; 72 protected BufferedImage bi; 73 protected Waypoint painted = new Waypoint(); 74 protected Robot robot; 75 76 class TestFrame extends Frame 77 { 78 static final long serialVersionUID = 0; 79 Image img = null; 80 81 public TestFrame(Image img) { 82 this.img = img; 83 setUndecorated(true); 84 setBounds( 50, 50, Bounds01.WIDTH, Bounds01.HEIGHT); 85 } 86 87 public void paint( Graphics g ) { 88 super.paint( g ); 89 g.setColor( Color.black ); 90 if (img != null) { 91 g.drawImage( img, 0, 0, this ); 92 } 93 else { 94 g.drawString( "null image", 30, 30); 95 } 96 painted.clear(); 97 } 98 } 99 100 protected void setUp() throws Exception{ 101 // this is to wake the screen out of sleep 102 robot = new Robot(); 103 robot.mouseMove(10, 10); 104 robot.mouseMove(0, 0); 105 Thread.sleep(1000); 106 107 fonts = new Vector<Font>(); 108 for (String name : names) { 109 for (int size : sizes) { 110 for (int style : styles) { 111 Font font = new Font(name, style, size); 112 assertNotNull(font); 113 fonts.add(font); 114 } 115 } 116 } 117 118 // Get the default (or compatible) buffered image 119 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 120 GraphicsDevice gd = ge.getDefaultScreenDevice(); 121 GraphicsConfiguration gc = gd.getDefaultConfiguration(); 122 bi = gc.createCompatibleImage( WIDTH,HEIGHT ); 123 } 124 125 public void testFontBounds() throws Exception { 126 127 for (Font font : fonts) { 128 129 Graphics2D ig = (Graphics2D) bi.getGraphics(); 130 131 // Use the most percise mode available 132 RenderingHints hints = ig.getRenderingHints(); 133 hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 134 hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 135 ig.setRenderingHints(hints); 136 137 ig.setColor(Color.black); 138 ig.fillRect(0, 0, Bounds01.WIDTH, Bounds01.HEIGHT); 139 140 String testString = "Covered by bounds rect +1?"; 141 142 // Draw centered and a little in from the left 143 Point2D.Float loc = new Point2D.Float(20, Bounds01.HEIGHT / 2); 144 145 FontRenderContext frc = ig.getFontRenderContext(); 146 assertNotNull(frc); 147 148 TextLayout layout = new TextLayout(testString, font, frc); 149 assertNotNull(layout); 150 151 Rectangle2D cover1 = layout.getBounds(); 152 assertNotNull(cover1); 153 154 // cutting the cover rect a little slack, since anti-aliasing and fractional text 155 // can account for off-by-one errors which over/under shoot the bounding box 156 157 cover1.setRect(cover1.getX() + loc.getX() - slop, 158 cover1.getY() + loc.getY() - slop, 159 cover1.getWidth() + (slop * 2), 160 cover1.getHeight() + (slop * 2)); 161 162 // Draw test string in red 163 ig.setColor(Color.red); 164 layout.draw(ig, (float) loc.getX(), (float) loc.getY()); 165 166 // cover1 with blue bounding box 167 ig.setColor(new Color(0, 0, 0xFF, 0x80)); 168 ig.fill(cover1); 169 ig.dispose(); 170 171 TestFrame frame = new TestFrame(bi); 172 painted.reset(); 173 try { 174 // Bring the window up and make sure at least one paint has occured 175 VisibilityValidator.setVisibleAndConfirm(frame); 176 painted.requireClear(); 177 assertTrue("Did not get a paint call", painted.isValid()); 178 179 // Slow machines have a slight delay before the window is truely visible 180 // We need time for the tick-flusher to go 181 Thread.sleep(150); 182 183 // Grab the area where text should be and look for bright red pixels. 184 Rectangle rect = new Rectangle((int) cover1.getX() - 10 + frame.getX(), (int) cover1.getY() - 10 + frame.getY(), (int) cover1.getWidth() + 20, (int) cover1.getHeight() + 20); 185 BufferedImage image = (new Robot()).createScreenCapture(rect); 186 187 boolean someRed = false; 188 boolean pixelsOK = true; 189 int sizeX = image.getWidth(); 190 int sizeY = image.getHeight(); 191 192 File f = null; 193 String failurefile = "Bounds01_" + System.currentTimeMillis() + font; 194 for (int x = 0; x < sizeX; x++) { 195 for (int y = 0; y < sizeY; y++) { 196 Color c = new Color(image.getRGB(x, y)); 197 boolean pixelOK = c.getRed() < 255; 198 199 if (!pixelOK) { 200 pixelsOK = false; 201 } 202 203 if (c.getRed() > 0) { 204 someRed = true; 205 } 206 } 207 } 208 209 if (!pixelsOK) { 210 // Dump the screen 211 f = RobotUtilities.screenshot(failurefile, new File(System.getProperty("java.io.tmpdir"))); 212 assertNotNull("Problem creating error file", f); 213 214 // Dump just the smaller (original) image we checked 215 java.io.File outputFile1 = new File(System.getProperty("java.io.tmpdir"), failurefile + "Image.png"); 216 javax.imageio.ImageIO.write(image, "png", outputFile1); 217 218 // Dump the image we checked in Hex, too 219 BITestUtils.pixelLogfileHex(image, failurefile + "Hex"); 220 } 221 222 assertTrue(font + "apparently did not paint at all. Probable error in testcase.", someRed); 223 assertTrue(font + "not covered. See file " + failurefile, pixelsOK); 224 225 } 226 finally { 227 frame.dispose(); 228 } 229 } 230 231 } 232 233 // Boilerplate 234 public static Test suite() { 235 return new TestSuite(Bounds01.class); 236 } 237 238 public static void main (String[] args) throws RuntimeException { 239 String name = System.getProperty("os.name"); 240 if (name.equals("Mac OS X")) { 241 // This test uses a font that may not exist on other platforms 242 TestResult tr = junit.textui.TestRunner.run(suite()); 243 if((tr.errorCount() != 0) || (tr.failureCount() != 0)) { 244 throw new RuntimeException("### Unexpected JUnit errors or failures."); 245 } 246 } 247 } 248 } 249