1 /* 2 * Copyright (c) 2014, 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 /* @test 25 @bug 8016833 26 @summary underlines and strikethroughs should be painted at the correct 27 positions for different kind of text styles: normal, superscript and subscript 28 @author Anton Nashatyrev 29 @run main bug8016833 30 */ 31 import javax.swing.*; 32 import javax.swing.text.BadLocationException; 33 import javax.swing.text.Style; 34 import javax.swing.text.StyleConstants; 35 import javax.swing.text.StyledDocument; 36 import java.awt.*; 37 import java.awt.image.BufferedImage; 38 import java.lang.reflect.InvocationTargetException; 39 40 public class bug8016833 { 41 drawText(final Graphics g, final boolean underline, final boolean strikethrough, final boolean background)42 void drawText(final Graphics g, final boolean underline, final boolean strikethrough, final boolean background) { 43 drawText(g, "mama", underline, strikethrough, background); 44 } 45 drawText(final Graphics g, final String text, final boolean underline, final boolean strikethrough, final boolean background)46 void drawText(final Graphics g, final String text, final boolean underline, final boolean strikethrough, final boolean background) { 47 try { 48 SwingUtilities.invokeAndWait(new Runnable() { 49 @Override 50 public void run() { 51 final JTextPane comp = new JTextPane(); 52 final StyledDocument doc = comp.getStyledDocument(); 53 54 Style style = comp.addStyle("superscript", null); 55 setNormalStyle(style); 56 57 if (underline) { 58 StyleConstants.setUnderline(style, true); 59 } 60 if (strikethrough) { 61 StyleConstants.setStrikeThrough(style, true); 62 } 63 if (background) { 64 StyleConstants.setBackground(style, Color.BLUE); 65 } 66 try { 67 doc.insertString(doc.getLength(), "mama", style); 68 } catch (BadLocationException e) { 69 throw new RuntimeException(e); 70 } 71 72 comp.setSize(200, 100); 73 comp.paint(g); 74 } 75 }); 76 } catch (InterruptedException e) { 77 throw new RuntimeException(e); 78 } catch (InvocationTargetException e) { 79 throw new RuntimeException(e); 80 } 81 } 82 setNormalStyle(Style style)83 void setNormalStyle(Style style) { 84 StyleConstants.setSuperscript(style, true); 85 } 86 getEmptyPixel()87 int getEmptyPixel() { 88 return 0xFFFFFFFF; 89 } 90 isPixelEmpty(int argb)91 boolean isPixelEmpty(int argb) { 92 return (argb & 0x00FFFFFF) == (getEmptyPixel() & 0x00FFFFFF); 93 } 94 isLineEmpty(BufferedImage img, int coord, boolean isHorizontal)95 boolean isLineEmpty(BufferedImage img, int coord, boolean isHorizontal) { 96 int len = isHorizontal ? img.getWidth() : img.getHeight(); 97 for (int i = 0; i < len; i++) { 98 int pixel = isHorizontal ? img.getRGB(i, coord) : img.getRGB(coord, i); 99 if (!isPixelEmpty(pixel)) { 100 return false; 101 } 102 } 103 return true; 104 } 105 getPixelsOutline(BufferedImage img)106 Rectangle getPixelsOutline(BufferedImage img) { 107 int x1 = 0; 108 while (x1 < img.getWidth() && isLineEmpty(img, x1, false)) { 109 x1++; 110 } 111 int x2 = img.getWidth() - 1; 112 while (x2 >= 0 && isLineEmpty(img, x2, false)) { 113 x2--; 114 } 115 int y1 = 0; 116 while (y1 < img.getHeight() && isLineEmpty(img, y1, true)) { 117 y1++; 118 } 119 int y2 = img.getHeight() - 1; 120 while (y2 >= 0 && isLineEmpty(img, y2, true)) { 121 y2--; 122 } 123 124 return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1); 125 } 126 createImage()127 BufferedImage createImage() { 128 final BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB); 129 try { 130 SwingUtilities.invokeAndWait(new Runnable() { 131 @Override 132 public void run() { 133 Graphics g = img.getGraphics(); 134 g.setColor(new Color(getEmptyPixel())); 135 g.fillRect(0, 0, 10000, 10000); 136 } 137 }); 138 } catch (InterruptedException e) { 139 throw new RuntimeException(e); 140 } catch (InvocationTargetException e) { 141 throw new RuntimeException(e); 142 } 143 return img; 144 } 145 subPixels(int pix1, int pix2)146 int subPixels(int pix1, int pix2) { 147 if (pix1 == pix2) { 148 return getEmptyPixel(); 149 } 150 return pix1; 151 } 152 153 /** 154 * Subtracts img2 from img1 155 */ subImages(BufferedImage img1, BufferedImage img2)156 BufferedImage subImages(BufferedImage img1, BufferedImage img2) { 157 if (img1.getHeight() != img2.getHeight() || 158 img1.getWidth() != img2.getWidth()) { 159 throw new RuntimeException("Different sizes"); 160 } 161 BufferedImage ret = new BufferedImage(img1.getWidth(), img1.getHeight(), img1.getType()); 162 163 for (int x = 0; x < ret.getWidth(); x++) { 164 for (int y = 0; y < ret.getHeight(); y++) { 165 ret.setRGB(x, y, subPixels(img1.getRGB(x, y), img2.getRGB(x, y))); 166 } 167 } 168 return ret; 169 } 170 testUnderline()171 void testUnderline() { 172 System.out.println(" testUnderline()"); 173 174 final BufferedImage img1 = createImage(); 175 drawText(img1.getGraphics(), true, false, false); 176 final Rectangle out1 = getPixelsOutline(img1); 177 System.out.println(" Underlined: " + out1); 178 179 final BufferedImage img2 = createImage(); 180 drawText(img2.getGraphics(), false, false, false); 181 final Rectangle out2 = getPixelsOutline(img2); 182 System.out.println(" Normal: " + out2); 183 184 final BufferedImage img3 = subImages(img1, img2); 185 final Rectangle out3 = getPixelsOutline(img3); 186 System.out.println(" Sub: " + out3); 187 188 // underline is not too thick 189 assertTrue(out3.getHeight() <= 2); 190 // not too wide 191 assertTrue(out3.getWidth() * 0.8 < out2.getWidth()); 192 // not too low 193 assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) < 4); 194 // not too high 195 assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) > 0); 196 } 197 198 void testStrikthrough() { 199 System.out.println(" testStrikthrough()"); 200 201 final BufferedImage img1 = createImage(); 202 drawText(img1.getGraphics(), false, true, false); 203 final Rectangle out1 = getPixelsOutline(img1); 204 System.out.println(" Striked: " + out1); 205 206 final BufferedImage img2 = createImage(); 207 drawText(img2.getGraphics(), false, false, false); 208 final Rectangle out2 = getPixelsOutline(img2); 209 System.out.println(" Normal: " + out2); 210 211 final BufferedImage img3 = subImages(img1, img2); 212 final Rectangle out3 = getPixelsOutline(img3); 213 System.out.println(" Sub: " + out3); 214 215 // strikethrough is not too thick 216 assertTrue(out3.getHeight() <= 2); 217 // not too wide 218 assertTrue(out3.getWidth() * 0.8 < out2.getWidth()); 219 // not too low 220 assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) < 0); 221 // not too high 222 assertTrue(out3.getY() - out1.getY() > 1); 223 } 224 void assertTrue(boolean b) { 225 if (!b) { 226 throw new RuntimeException("Assertion failed"); 227 } 228 } 229 230 static void testSuperScript() { 231 System.out.println("testSuperScript()"); 232 bug8016833 b = new bug8016833() { 233 @Override 234 void setNormalStyle(Style style) { 235 StyleConstants.setSuperscript(style, true); 236 } 237 }; 238 b.testUnderline(); 239 b.testStrikthrough(); 240 } 241 242 static void testSubScript() { 243 System.out.println("testSubScript()"); 244 bug8016833 b = new bug8016833() { 245 @Override 246 void setNormalStyle(Style style) { 247 StyleConstants.setSubscript(style, true); 248 } 249 }; 250 b.testUnderline(); 251 b.testStrikthrough(); 252 } 253 254 static void testNormalScript() { 255 System.out.println("testNormalScript()"); 256 bug8016833 b = new bug8016833() { 257 @Override 258 void setNormalStyle(Style style) { 259 } 260 }; 261 b.testUnderline(); 262 b.testStrikthrough(); 263 } 264 265 public static void main(String[] args) { 266 testSubScript(); 267 testSuperScript(); 268 testNormalScript(); 269 } 270 } 271