1 /*
   2  * @test
   3  * @bug 4337267
   4  * @summary test that numeric shaping works in Swing components
   5  * @author Sergey Groznyh
   6  * @run main bug4337267
   7  */
   8 
   9 import java.awt.Component;
  10 import java.awt.Dimension;
  11 import java.awt.Graphics;
  12 import java.awt.font.NumericShaper;
  13 import java.awt.font.TextAttribute;
  14 import java.awt.image.BufferedImage;
  15 import javax.swing.BoxLayout;
  16 import javax.swing.JComponent;
  17 import javax.swing.JFrame;
  18 import javax.swing.JLabel;
  19 import javax.swing.JPanel;
  20 import javax.swing.JTextArea;
  21 import javax.swing.SwingUtilities;
  22 
  23 public class bug4337267 {
  24     TestJPanel p1, p2;
  25     TestBufferedImage i1, i2;
  26     JComponent[] printq;
  27     JFrame window;
  28     static boolean testFailed = false;
  29     static boolean done = false;
  30 
  31     String shaped =
  32             "000 (E) 111 (A) \u0641\u0642\u0643 \u0662\u0662\u0662 (E) 333";
  33     String text = "000 (E) 111 (A) \u0641\u0642\u0643 222 (E) 333";
  34 
  35     void run() {
  36         initUI();
  37         testTextComponent();
  38         testNonTextComponentHTML();
  39         testNonTextComponentPlain();
  40 
  41         doneTask();
  42     }
  43 
  44     void initUI() {
  45         window = new JFrame("bug4337267");
  46         window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  47         window.setSize(800, 600);
  48         Component content = createContentPane();
  49         window.add(content);
  50         window.setVisible(true);
  51     }
  52 
  53     Runnable printComponents = new Runnable() {
  54         public void run() {
  55             printComponent(printq[0], i1);
  56             printComponent(printq[1], i2);
  57         }
  58     };
  59 
  60     Runnable compareRasters = new Runnable() {
  61         public void run() {
  62             assertEquals(p1.image, p2.image);
  63             assertEquals(i1, i2);
  64         }
  65     };
  66 
  67     void doneTask() {
  68         final Object monitor = this;
  69         SwingUtilities.invokeLater(new Runnable() {
  70             public void run() {
  71                 done = true;
  72                 synchronized(monitor) {
  73                     monitor.notify();
  74                 }
  75             }
  76         });
  77     }
  78 
  79 
  80     void fail(String message) {
  81         testFailed = true;
  82         throw new RuntimeException(message);
  83     }
  84 
  85     void assertEquals(Object o1, Object o2) {
  86         if ((o1 == null) && (o2 != null)) {
  87             fail("Expected null, got " + o2);
  88         } else if ((o1 != null) && (o2 == null)) {
  89             fail("Expected " + o1 + ", got null");
  90         } else if (!o1.equals(o2)) {
  91             fail("Expected " + o1 + ", got " + o2);
  92         }
  93     }
  94 
  95     void testTextComponent() {
  96         System.out.println("testTextComponent:");
  97         JTextArea area1 = new JTextArea();
  98         injectComponent(p1, area1, false);
  99         area1.setText(shaped);
 100         JTextArea area2 = new JTextArea();
 101         injectComponent(p2, area2, true);
 102         area2.setText(text);
 103         window.repaint();
 104         printq = new JComponent[] { area1, area2 };
 105         SwingUtilities.invokeLater(printComponents);
 106         SwingUtilities.invokeLater(compareRasters);
 107     }
 108 
 109     void testNonTextComponentHTML() {
 110         System.out.println("testNonTextComponentHTML:");
 111         JLabel label1 = new JLabel();
 112         injectComponent(p1, label1, false);
 113         label1.setText("<html>" + shaped);
 114         JLabel label2 = new JLabel();
 115         injectComponent(p2, label2, true);
 116         label2.setText("<html>" + text);
 117         window.repaint();
 118         printq = new JComponent[] { label1, label2 };
 119         SwingUtilities.invokeLater(printComponents);
 120         SwingUtilities.invokeLater(compareRasters);
 121     }
 122 
 123     void testNonTextComponentPlain() {
 124         System.out.println("testNonTextComponentHTML:");
 125         JLabel label1 = new JLabel();
 126         injectComponent(p1, label1, false);
 127         label1.setText(shaped);
 128         JLabel label2 = new JLabel();
 129         injectComponent(p2, label2, true);
 130         label2.setText(text);
 131         window.repaint();
 132         printq = new JComponent[] { label1, label2 };
 133         SwingUtilities.invokeLater(printComponents);
 134         SwingUtilities.invokeLater(compareRasters);
 135     }
 136 
 137     void setShaping(JComponent c) {
 138         c.putClientProperty(TextAttribute.NUMERIC_SHAPING,
 139                     NumericShaper.getContextualShaper(NumericShaper.ARABIC));
 140     }
 141 
 142     void injectComponent(JComponent p, JComponent c, boolean shape) {
 143         if (shape) {
 144             setShaping(c);
 145         }
 146         p.removeAll();
 147         p.add(c);
 148     }
 149 
 150     void printComponent(JComponent c, TestBufferedImage i) {
 151         Graphics g = i.getGraphics();
 152         g.setColor(c.getBackground());
 153         g.fillRect(0, 0, i.getWidth(), i.getHeight());
 154         c.print(g);
 155     }
 156 
 157     Component createContentPane() {
 158         Dimension size = new Dimension(500, 100);
 159         i1 = new TestBufferedImage(size.width, size.height,
 160                                                 BufferedImage.TYPE_INT_ARGB);
 161         i2 = new TestBufferedImage(size.width, size.height,
 162                                                 BufferedImage.TYPE_INT_ARGB);
 163         p1 = new TestJPanel();
 164         p1.setPreferredSize(size);
 165         p2 = new TestJPanel();
 166         p2.setPreferredSize(size);
 167         JPanel panel = new JPanel();
 168         panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 169         panel.add(p1);
 170         panel.add(p2);
 171 
 172         return panel;
 173     }
 174 
 175     static class TestBufferedImage extends BufferedImage {
 176         int MAX_GLITCHES = 0;
 177 
 178         TestBufferedImage(int width, int height, int imageType) {
 179             super(width, height, imageType);
 180         }
 181 
 182         @Override
 183         public boolean equals(Object other) {
 184             if (! (other instanceof TestBufferedImage)) {
 185                 return false;
 186             }
 187             TestBufferedImage image2 = (TestBufferedImage) other;
 188             int width = getWidth();
 189             int height = getHeight();
 190             if ((image2.getWidth() != width) || (image2.getHeight() != height)) {
 191                 return false;
 192             }
 193             int glitches = 0;
 194             for (int x = 0; x < width; x++) {
 195                 for (int y = 0; y < height; y++) {
 196                     int rgb1 = getRGB(x, y);
 197                     int rgb2 = image2.getRGB(x, y);
 198                     if (rgb1 != rgb2) {
 199                         //System.out.println(x+" "+y+" "+rgb1+" "+rgb2);
 200                         glitches++;
 201                     }
 202                 }
 203             }
 204             return glitches <= MAX_GLITCHES;
 205         }
 206     }
 207 
 208     static class TestJPanel extends JPanel {
 209         TestBufferedImage image = createImage(new Dimension(1, 1));
 210 
 211         TestBufferedImage createImage(Dimension d) {
 212             return new TestBufferedImage(d.width, d.height,
 213                                                 BufferedImage.TYPE_INT_ARGB);
 214         }
 215 
 216         public void setPreferredSize(Dimension size) {
 217             super.setPreferredSize(size);
 218             image = createImage(size);
 219         }
 220 
 221         public void paint(Graphics g) {
 222             Graphics g0 = image.getGraphics();
 223             super.paint(g0);
 224             g.drawImage(image, 0, 0, this);
 225         }
 226     }
 227 
 228 
 229 
 230     public static void main(String[] args) throws Throwable {
 231         final bug4337267 test = new bug4337267();
 232         SwingUtilities.invokeLater(new Runnable() {
 233             public void run() {
 234                 test.run();
 235             }
 236         });
 237 
 238          synchronized(test) {
 239             while (!done) {
 240                 try {
 241                     test.wait();
 242                 } catch (InterruptedException ex) {
 243                     // do nothing
 244                 }
 245             }
 246         }
 247 
 248         if (testFailed) {
 249             throw new RuntimeException("FAIL");
 250         }
 251 
 252         System.out.println("OK");
 253     }
 254 }