4 Replies Latest reply on Jun 11, 2009 9:16 PM by 843807

    GlyphVector bounds and kerning, ligatures

    843807
      IS THIS A BUG?? Shouldn't GlyphVector report positions/bounds for glyphs which reflect kerning and ligatures, i.e., shouldn't it yield metrics which correspond to what is actually rendered by Graphics2D.drawString() or TextLayout.draw()? If not, what does provide this service? Below is a little app which will throw up a frame showing a string rendered in black, the GlyphVector's logicalBounds in yellow fill, and the logicalBounds of each glyph in red. You can see the bounding rectangles creep ahead as kerns and ligatures are encountered. I had to pick a font that actually does kerning and ligatures, DejaVu Sans, because on my system (JDK1.6-u13 on Ubuntu 9.04) the default fonts do not.
      package examples;
      
      import java.util.*;
      import java.awt.*;
      import java.awt.font.*;
      import java.awt.geom.*;
      import static java.awt.font.TextAttribute.*;
      import javax.swing.*;
      
      
      public class GlyphVectorBounds {
      
          public static void main(String[] args) {
              JFrame f = new JFrame();
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              JPanel p = new XPanel();
              p.setBackground(Color.WHITE);
              p.setOpaque(true);
              f.setContentPane(p);
              f.setSize(750, 150);
              f.setVisible(true);
          }
      
          static class XPanel extends JPanel {
              String text = "Tiffany's Terrific Toffee Taffy";
              Font baseFont = new Font("DejaVu Sans", Font.PLAIN, 48);
              Map attr= new HashMap();
              {
                  attr.put(KERNING, KERNING_ON);
                  attr.put(LIGATURES, LIGATURES_ON);
              }
              AffineTransform trans = AffineTransform.getTranslateInstance(20, 70);
      
              protected void paintComponent(Graphics g) {
                  super.paintComponent(g);
                  Graphics2D g2 = (Graphics2D) g;
                  g2.setTransform(trans);
                  Font font = baseFont.deriveFont(attr);
                  g2.setFont(font);
                  FontRenderContext frc = g2.getFontRenderContext();
                  GlyphVector gv = font.createGlyphVector(frc, text);
                  Rectangle2D vb = gv.getLogicalBounds();
                  g2.setColor(Color.YELLOW);
                  g2.fill(vb);
                  g2.setColor(Color.RED);
                  for (int i=0; i<gv.getNumGlyphs(); i++) {
                      Shape gb = gv.getGlyphLogicalBounds(i);
                      g2.draw(gb);
                  }
                  g2.setColor(Color.BLACK);
                  g2.drawString(text, 0, 0);
              }
          }
      
      }
      Edited by: slovelace on Jun 5, 2009 12:06 AM

      Edited by: slovelace on Jun 5, 2009 2:43 AM

      Edited by: slovelace on Jun 5, 2009 4:11 PM
        • 1. Re: GlyphVector bounds and kerning, ligatures
          pietblok
          Hi,

          You may replace:
                   GlyphVector gv = font.createGlyphVector(frc, text);
          with:
                   char[] chars = text.toCharArray();
                   GlyphVector gv = font.layoutGlyphVector(frc, chars, 0,
                        chars.length, Font.LAYOUT_LEFT_TO_RIGHT);
          Piet
          • 2. Re: GlyphVector bounds and kerning, ligatures
            843807
            Thanks for the reply. I see that this works, but I can't say that my question, "IS THIS A BUG??", has been completely answered (did tick the option to give you the stars, though). Maybe this is just a documentation bug - here's the doc string for Font.createGlyphVector():

            Creates a GlyphVector by mapping characters to glyphs one-to-one based on the Unicode cmap in this Font. This method does no other processing besides the mapping of glyphs to characters. This means that this method is not useful for some scripts, such as Arabic, Hebrew, Thai, and Indic, that require reordering, shaping, or ligature substitution.

            And here's the opening one for layoutGlyphVector():

            Returns a new GlyphVector object, performing full layout of the text if possible. Full layout is required for complex text, such as Arabic or Hindi. Support for different scripts depends on the font and implementation.

            But I'm not using Arabic, Hebrew, Thai or Hindi. I'm dealing with English, which is to say Latin characters, in the usual way, though I am expecting "usual" to include kerning and ligatures. Okay, so maybe I should have spotted the phrase "ligature substitution" and thrown English into the list with Arabic, Hebrew, Thai, and Hindi. But what about kerning? Try typing the word "To" into any decent word processor (like the message window I'm typing into now) using any decent proportional font (any font smart enough to handle kerning - this excludes whatever Java is defaulting to on my system - is it Nimbus?) and you will see the "o" tucked part way under the arm of the "T". If this isn't done, the spacing looks horrible. I'm saying that kerning is routine, not a cause for setting the complexity flag. Or if for engineering reasons the complexity flag needs to be set, then the docs need to be changed.

            So there's my rant. Thanks again for the solution.
            • 3. Re: GlyphVector bounds and kerning, ligatures
              pietblok
              Yes, I think you are right when you spot an omission in the docs. It should state that full layout is needed not only for some languages, but for kerning as well.

              BTW, the solution works also when you pass a flag parameter of zero. So, it's not the complexity flag itself that does the trick, it is the method that will do a full layout, in contrast to the createGlyphVector methods.

              Thanks for the dukes. But they didn't arrive yet. Did you only tick a "answered" button or did you as well tick a "award" button? I don't exactly know how the mechanism works.

              Piet
              • 4. Re: GlyphVector bounds and kerning, ligatures
                843807
                Right. Dukes are on their way (this was my first post).

                Steve