Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4109376

FontMetrics inaccurate, core dumps printing unicode

XMLWordPrintable

    • 2d
    • 1.2beta4
    • generic, sparc
    • generic, solaris_2.6
    • Not verified



      Name: rm29839 Date: 02/04/98


      /*****
      Environment:
              JDK 1.2beta2 Solaris 2.6 Sparc
       
      Bug 1:
              FontMetrics are consistently wrong.
              The class below measures the real ascent and descent
              of a font, which does not match the FontMetrics provided
              by the AWT.
       
      Bug 2:
              Given optional command line Font tuples, this class usually
              core dumps printing unicode values above 190 decimal.
       
      Sample (default) output:
       
      ...
      251
      252
      253
      254
      255
       
      java.awt.Font[family=Courier,name=Courier,style=bold,size=19]
      sun.awt.image.BufferedImageGraphics2D[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19],color=java.awt.
      Color[r=255,g=0,b=0]]
       
      Component's FontMetrics:
        sun.awt.motif.X11FontMetrics[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19]ascent=18, descent=5, h
      eight=24]
        ascent: 18 descent: 5
       
      Graphics' FontMetrics:
        sun.awt.font.FontDesignMetrics[font=java.awt.Font[family=Courier,name=Courier,style=bold,size=19]ascent=19, descent=4,
       height=24]
        ascent: 19 descent: 4
       
      Measured:
        ascent: 15 descent: 5
       
       
       
      *****/
      import java.awt.*;
      import java.awt.image.ColorModel;
      import java.awt.image.ImageObserver;
      import java.awt.image.PixelGrabber;
      import java.util.Hashtable;
      import java.lang.reflect.Array;
       
      /** Measures the real ascent & descent. */
      public class FontStats
      {
              private static Hashtable ht = new Hashtable();
       
              // only changed by main(), the unit test routine
              private static boolean ascii = true;
              private static boolean log = false;
       
              // only accessed by main(), the unit test routine
              private static Image im;
       
              // results
              public int realAscent, realDescent;
       
              private FontStats() { }
       
              /** Measure the ascent & descent of the font in the components
                * resolution.
                */
              public static FontStats measure(Component c, Font f)
              {
                      FontStats s = (FontStats) ht.get(f);
                      if (s != null)
                              return s;
       
                      s = buildStats(c, f);
                      if (s != null)
                              ht.put(f, s);
                      return s;
              }
       
              private static FontStats buildStats(Component c, Font f)
              {
                      FontMetrics fm = c.getFontMetrics(f);
       
                      int h = fm.getHeight();
                      int w = fm.charWidth('W');
       
                      // create an oversized image buffer
                      im = c.createImage(2*w, 2*h);
                      if (im == null)
                      {
                              System.err.println("Can't create image yet.");
                              return null;
                      }
                      Graphics g = im.getGraphics();
       
                      char[] ca = new char[1];
                      int start, stop;
                      if (ascii)
                      {
                              start = ' '; // printable ascii subset
                              stop = '~';
                      }
                      else
                      {
                              start = Character.MIN_VALUE; // all unicode chars!
                              stop = Character.MAX_VALUE;
                      }
       
                      // draw all chars on top of each other
                      for (int i = start ; i <= stop ; i++)
                      {
                              ca[0] = (char)i;
                              if (f.canDisplay(ca[0]))
                              {
                                      if (log)
                                      {
                                              System.err.println(i);
                                              System.err.flush();
                                      }
                                      g.drawChars(ca, 0 , 1, 0, h);
                              }
                      }
                      // draw a baseline
                      g.setColor(Color.red);
                      g.drawLine(0, h, 2*w, h);
       
                      // grab the pixels
                      PixelGrabber pg = new PixelGrabber(im, 0, 0, 2*w, 2*h, false);
                      try
                      {
                              if (!pg.grabPixels())
                              {
                                      System.err.println(
                                              "FontMeasurer: Error grabbing pixels.");
                                      return null;
                              }
                      }
                      catch(InterruptedException e)
                      {
                              System.err.println(
                                      "FontMeasurer: Interrupted grabbing pixels.");
                              return null;
                      }
                      if ((pg.getStatus() & ImageObserver.ABORT) != 0)
                      {
                              System.err.println(
                                      "FontMeasurer: Image fetch aborted.");
                              return null;
                      }
                      Object pixObj = pg.getPixels();
                      ColorModel cm = pg.getColorModel();
                      int bg = c.getBackground().getRGBA();
       
                      FontStats fs = measureArray(pixObj, 2*w, 2*h, cm, bg);
       
                      if (log)
                      {
                              System.err.println("\n" + f);
                              System.err.println(g);
                              System.err.println("\nComponent's FontMetrics: ");
                              System.err.println(" " + fm);
                              System.err.println(" ascent: " + fm.getAscent()
                                              + " descent: " + fm.getDescent());
                              FontMetrics fm2 = g.getFontMetrics();
                              System.err.println("\nGraphics' FontMetrics: ");
                              System.err.println(" " + fm2);
                              System.err.println(" ascent: " + fm2.getAscent()
                                              + " descent: " + fm2.getDescent());
                              System.err.println("\nMeasured: ");
                              System.err.println(" ascent: " + fs.realAscent
                                              + " descent: " + fs.realDescent);
                      }
       
                      return fs;
              }
       
              // pix is either a byte[] or an int[]
              private static FontStats measureArray(Object pix, int w, int h,
                                                      ColorModel cm, int rgb_bg)
              {
                      FontStats fs = new FontStats();
                      int index, len, baseline = h/2;
       
                      // this would be faster if I could find a way to convert
                      // rgb_bg into the cm ColorModel.
                      //
                      // looking for the top
                      index = 0;
                      len = Array.getLength(pix);
                      for (index = 0 ; index < len ; index++ )
                              if (cm.getRGB(Array.getInt(pix, index)) != rgb_bg)
                                      break;
       
                      fs.realAscent = baseline - (index/w);
       
                      // looking for the bottom
                      index = len - 1;
                      for (index = len ; --index >= 0 ;)
                              if (cm.getRGB(Array.getInt(pix, index)) != rgb_bg)
                                      break;
       
                      // I am assuming that "below the baseline" means
                      // below the infinitely thin baseline, not below
                      // the pixel row where a baseline line would be
                      // drawn
                      fs.realDescent = (index/w) - baseline + 1;
       
                      return fs;
              }
       
              /** Unit test routine. Also shows the image so that the
                * ascent and descent can be visually confirmed.
                */
              public static void main(String args[])
              {
                      String usage = "java FontStats [ -ascii ] [ FaceName Style Size ]";
                      boolean ascii = false;
                      int len = args.length;
                      Font font = null;
                      if (len == 2 || len > 4)
                      {
                              System.err.println(usage);
                              System.exit(-1);
                      }
                      if (len == 1 || len == 4)
                      {
                              if (!args[0].equals("-ascii"))
                              {
                                      System.err.println(usage);
                                      System.exit(-1);
                              }
                              ascii = true;
                      }
                      if (len == 4 || len == 3)
                      {
                              int size = Integer.parseInt(args[len-1]);
                              String style = args[len-2];
                              String face = args[len-3];
                              int styleI = Font.PLAIN;
                              if (style.equals("PLAIN"))
                                      styleI = Font.PLAIN;
                              else if (style.equals("BOLD"))
                                      styleI = Font.BOLD;
                              else if (style.equals("ITALIC"))
                                      styleI = Font.ITALIC;
                              else
                              {
                                      System.err.println(usage);
                                      System.exit(-1);
                              }
                              font = new Font(face, styleI, size);
                              System.err.println(font);
                      }
                      else
                      {
                              font = new Font("Courier", Font.BOLD, 19);
                      }
                      FontStats.ascii = ascii;
                      FontStats.log = true;
       
                      Frame f = new Frame();
                      ImageCanvas c = new ImageCanvas();
                      c.setSize(100, 100);
       
                      f.add(c);
                      f.pack();
                      f.show();
                      c.setFont(font);
       
                      FontStats fs = FontStats.measure(c, font);
                      c.setImage(fs.im);
              }
      }
       
      class ImageCanvas extends Canvas
      {
              Image im;
              public void setImage(Image im) { this.im = im; repaint(); }
              public void paint(Graphics g)
              { if (im != null) g.drawImage(im, 0, 0, this); }
      }
      (Review ID: 24494)
      ======================================================================

            jkaulorcl Jeet Kaul (Inactive)
            rmandelsunw Ronan Mandel (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: