/* * 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. */ /* @test @bug 8016833 @summary underlines and strikethroughs should be painted at the correct positions for different kind of text styles: normal, superscript and subscript @author Anton Nashatyrev @run main bug8016833 */ import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import java.awt.*; import java.awt.image.BufferedImage; import java.lang.reflect.InvocationTargetException; public class bug8016833 { void drawText(final Graphics g, final boolean underline, final boolean strikethrough, final boolean background) { drawText(g, "mama", underline, strikethrough, background); } void drawText(final Graphics g, final String text, final boolean underline, final boolean strikethrough, final boolean background) { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { final JTextPane comp = new JTextPane(); final StyledDocument doc = comp.getStyledDocument(); Style style = comp.addStyle("superscript", null); setNormalStyle(style); if (underline) { StyleConstants.setUnderline(style, true); } if (strikethrough) { StyleConstants.setStrikeThrough(style, true); } if (background) { StyleConstants.setBackground(style, Color.BLUE); } try { doc.insertString(doc.getLength(), "mama", style); } catch (BadLocationException e) { throw new RuntimeException(e); } comp.setSize(200, 100); comp.paint(g); } }); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } void setNormalStyle(Style style) { StyleConstants.setSuperscript(style, true); } int getEmptyPixel() { return 0xFFFFFFFF; } boolean isPixelEmpty(int argb) { return (argb & 0x00FFFFFF) == (getEmptyPixel() & 0x00FFFFFF); } boolean isLineEmpty(BufferedImage img, int coord, boolean isHorizontal) { int len = isHorizontal ? img.getWidth() : img.getHeight(); for (int i = 0; i < len; i++) { int pixel = isHorizontal ? img.getRGB(i, coord) : img.getRGB(coord, i); if (!isPixelEmpty(pixel)) { return false; } } return true; } Rectangle getPixelsOutline(BufferedImage img) { int x1 = 0; while (x1 < img.getWidth() && isLineEmpty(img, x1, false)) { x1++; } int x2 = img.getWidth() - 1; while (x2 >= 0 && isLineEmpty(img, x2, false)) { x2--; } int y1 = 0; while (y1 < img.getHeight() && isLineEmpty(img, y1, true)) { y1++; } int y2 = img.getHeight() - 1; while (y2 >= 0 && isLineEmpty(img, y2, true)) { y2--; } return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1); } BufferedImage createImage() { final BufferedImage img = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB); try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { Graphics g = img.getGraphics(); g.setColor(new Color(getEmptyPixel())); g.fillRect(0, 0, 10000, 10000); } }); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } return img; } int subPixels(int pix1, int pix2) { if (pix1 == pix2) { return getEmptyPixel(); } return pix1; } /** * Subtracts img2 from img1 */ BufferedImage subImages(BufferedImage img1, BufferedImage img2) { if (img1.getHeight() != img2.getHeight() || img1.getWidth() != img2.getWidth()) { throw new RuntimeException("Different sizes"); } BufferedImage ret = new BufferedImage(img1.getWidth(), img1.getHeight(), img1.getType()); for (int x = 0; x < ret.getWidth(); x++) { for (int y = 0; y < ret.getHeight(); y++) { ret.setRGB(x, y, subPixels(img1.getRGB(x, y), img2.getRGB(x, y))); } } return ret; } void testUnderline() { System.out.println(" testUnderline()"); final BufferedImage img1 = createImage(); drawText(img1.getGraphics(), true, false, false); final Rectangle out1 = getPixelsOutline(img1); System.out.println(" Underlined: " + out1); final BufferedImage img2 = createImage(); drawText(img2.getGraphics(), false, false, false); final Rectangle out2 = getPixelsOutline(img2); System.out.println(" Normal: " + out2); final BufferedImage img3 = subImages(img1, img2); final Rectangle out3 = getPixelsOutline(img3); System.out.println(" Sub: " + out3); // underline is not too thick assertTrue(out3.getHeight() <= 2); // not too wide assertTrue(out3.getWidth() * 0.8 < out2.getWidth()); // not too low assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) < 4); // not too high assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) > 0); } void testStrikthrough() { System.out.println(" testStrikthrough()"); final BufferedImage img1 = createImage(); drawText(img1.getGraphics(), false, true, false); final Rectangle out1 = getPixelsOutline(img1); System.out.println(" Striked: " + out1); final BufferedImage img2 = createImage(); drawText(img2.getGraphics(), false, false, false); final Rectangle out2 = getPixelsOutline(img2); System.out.println(" Normal: " + out2); final BufferedImage img3 = subImages(img1, img2); final Rectangle out3 = getPixelsOutline(img3); System.out.println(" Sub: " + out3); // strikethrough is not too thick assertTrue(out3.getHeight() <= 2); // not too wide assertTrue(out3.getWidth() * 0.8 < out2.getWidth()); // not too low assertTrue(out3.getY() - (out1.getY() + out2.getHeight() - 1) < 0); // not too high assertTrue(out3.getY() - out1.getY() > 1); } void assertTrue(boolean b) { if (!b) { throw new RuntimeException("Assertion failed"); } } static void testSuperScript() { System.out.println("testSuperScript()"); bug8016833 b = new bug8016833() { @Override void setNormalStyle(Style style) { StyleConstants.setSuperscript(style, true); } }; b.testUnderline(); b.testStrikthrough(); } static void testSubScript() { System.out.println("testSubScript()"); bug8016833 b = new bug8016833() { @Override void setNormalStyle(Style style) { StyleConstants.setSubscript(style, true); } }; b.testUnderline(); b.testStrikthrough(); } static void testNormalScript() { System.out.println("testNormalScript()"); bug8016833 b = new bug8016833() { @Override void setNormalStyle(Style style) { } }; b.testUnderline(); b.testStrikthrough(); } public static void main(String[] args) { testSubScript(); testSuperScript(); testNormalScript(); } }