Package org.jfree.fonts.awt

Source Code of org.jfree.fonts.awt.AWTFontMetrics

/**
* ===========================================
* LibFonts : a free Java font reading library
* ===========================================
*
* Project Info:  http://reporting.pentaho.org/libfonts/
*
* (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* $Id: AWTFontMetrics.java 3523 2007-10-16 11:03:09Z tmorgner $
* ------------
* (C) Copyright 2006-2007, by Pentaho Corporation.
*/
package org.jfree.fonts.awt;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Arrays;

import org.jfree.fonts.encoding.CodePointUtilities;
import org.jfree.fonts.registry.BaselineInfo;
import org.jfree.fonts.registry.FontContext;
import org.jfree.fonts.registry.FontMetrics;
import org.jfree.fonts.LibFontsDefaults;
import org.jfree.fonts.tools.StrictGeomUtility;

/**
* Creation-Date: 16.12.2005, 21:09:39
*
* @author Thomas Morgner
*/
public class AWTFontMetrics implements FontMetrics
{
  private static final Graphics2D[] graphics = new Graphics2D[4];

  private Font font;
  //private FontContext context;
  private java.awt.FontMetrics fontMetrics;
  private long maxCharAdvance;
  private char[] cpBuffer;
  private FontRenderContext frc;
  private long xheight;
  private long ascent;
  private long descent;

  private long[] cachedWidths;
  private BaselineInfo[] cachedBaselines;

  public AWTFontMetrics(final Font font, final FontContext context)
  {
    this.font = font;
    this.frc = new FontRenderContext(null, context.isAntiAliased(), context.isFractionalMetrics());

    final Graphics2D graphics = createGraphics(context);
    this.fontMetrics = graphics.getFontMetrics(font);
    final Rectangle2D rect = this.font.getMaxCharBounds(frc);
    this.maxCharAdvance = StrictGeomUtility.toInternalValue(rect.getWidth());
    this.ascent = StrictGeomUtility.toInternalValue(-rect.getY());
    this.descent = StrictGeomUtility.toInternalValue(rect.getHeight() + rect.getY());

    final GlyphVector gv = font.createGlyphVector(frc, "x");
    final Rectangle2D bounds = gv.getVisualBounds();
    this.xheight = StrictGeomUtility.toInternalValue(bounds.getHeight());

    this.cpBuffer = new char[4];
    this.cachedBaselines = new BaselineInfo[256- 32];
    this.cachedWidths = new long[256- 32];
    Arrays.fill(cachedWidths, -1);
  }

  protected Graphics2D createGraphics(final FontContext context)
  {
    int idx = 0;
    if (context.isAntiAliased())
    {
      idx += 1;
    }
    if (context.isFractionalMetrics())
    {
      idx += 2;
    }

    synchronized(graphics)
    {
      final Graphics2D retval = graphics[idx];
      if (retval == null)
      {
        final BufferedImage image = new BufferedImage
                (1, 1, BufferedImage.TYPE_INT_ARGB);
        final Graphics2D g2 = image.createGraphics();
        if (context.isAntiAliased())
        {
          g2.setRenderingHint
                  (RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        }
        else
        {
          g2.setRenderingHint
                  (RenderingHints.KEY_TEXT_ANTIALIASING,
                          RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        }
        if (context.isFractionalMetrics())
        {
          g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                  RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        }
        else
        {
          g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                  RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
        }
        graphics[idx] = g2;
        return g2;
      }
      return retval;
    }
  }

  public Font getFont()
  {
    return font;
  }

  /**
   * From the baseline to the
   *
   * @return
   */
  public long getAscent()
  {
    return ascent;
  }

  public long getDescent()
  {
    return descent;
  }

  public long getLeading()
  {
    return StrictGeomUtility.toInternalValue(fontMetrics.getLeading());
  }

  /**
   * The height of the lowercase 'x'. This is used as hint, which size the
   * lowercase characters will have.
   *
   * @return
   */
  public long getXHeight()
  {
    return xheight;
  }

  public long getOverlinePosition()
  {
    return getLeading() - Math.max (1000, getMaxHeight() / 20);
  }

  public long getUnderlinePosition()
  {
    return getLeading() + getMaxAscent() + Math.max (1000, getMaxHeight() / 20);
  }

  public long getStrikeThroughPosition()
  {
    return getMaxAscent() - (long) (LibFontsDefaults.DEFAULT_STRIKETHROUGH_POSITION * getXHeight());
  }

  public long getMaxAscent()
  {
    return StrictGeomUtility.toInternalValue(fontMetrics.getMaxAscent());
  }

  public long getMaxDescent()
  {
    return StrictGeomUtility.toInternalValue(fontMetrics.getMaxDescent());
  }

  public long getMaxHeight()
  {
    return getMaxAscent() + getMaxDescent() + getLeading();
  }

  public long getMaxCharAdvance()
  {
    return maxCharAdvance;
  }

  public synchronized long getCharWidth(final int character)
  {
    if (character >=32 && character < 256)
    {
      // can be cached ..
      final int index = character - 32;
      final long cachedWidth = cachedWidths[index];
      if (cachedWidth >= 0)
      {
        return cachedWidth;
      }

      final int retval = CodePointUtilities.toChars(character, cpBuffer, 0);

      if (retval > 0)
      {
        final Rectangle2D lm = font.getStringBounds(cpBuffer, 0, retval, frc);
        final long width = StrictGeomUtility.toInternalValue(lm.getWidth());
        cachedWidths[index] = width;
        return width;
      }
      else
      {
        cachedWidths[index] = 0;
        return 0;
      }
    }

    final int retval = CodePointUtilities.toChars(character, cpBuffer, 0);

    if (retval > 0)
    {
      final Rectangle2D lm = font.getStringBounds(cpBuffer, 0, retval, frc);
      return StrictGeomUtility.toInternalValue(lm.getWidth());
    }
    else
    {
      return 0;
    }
  }

  /**
   * This method is <b>EXPENSIVE</b>.
   * @param previous
   * @param character
   * @return
   */
  public synchronized long getKerning(final int previous, final int character)
  {
    final int retvalC1 = CodePointUtilities.toChars(previous, cpBuffer, 0);
    if (retvalC1 <= 0)
    {
      return 0;
    }

    final int retvalC2 = CodePointUtilities.toChars(character, cpBuffer, retvalC1);
    if (retvalC2 > 0)
    {
      final int limit = (retvalC1 + retvalC2);
      final GlyphVector gv = font.createGlyphVector(frc, new String (cpBuffer, 0, limit));
      final long totalSize = StrictGeomUtility.toInternalValue(gv.getGlyphPosition(limit).getX());
      final long renderedWidth = StrictGeomUtility.toInternalValue(gv.getOutline().getBounds2D().getWidth());
      return totalSize - renderedWidth;
    }
    else
    {
      return 0;
    }
  }

  /**
   * Baselines are defined for scripts, not glyphs. A glyph carries script
   * information most of the time (unless it is a neutral characters or just
   * weird).
   *
   * The baseline info does not take any leading into account.
   *
   * @param c the character that is used to select the script type.
   * @return
   */
  public BaselineInfo getBaselines(final int c, BaselineInfo info)
  {
    final boolean cacheable = (c >=32 && c < 256);
    if (cacheable)
    {
      final BaselineInfo fromCache = cachedBaselines[c - 32];
      if (fromCache != null)
      {
        if (info == null)
        {
          info = new BaselineInfo();
        }
        info.update(fromCache);
        return info;
      }
    }

    cpBuffer[0] = (char) (c & 0xFFFF);
    final LineMetrics lm = font.getLineMetrics(cpBuffer, 0, 1, frc);
    final float[] bls = lm.getBaselineOffsets();
    final int idx = lm.getBaselineIndex();

    if (info == null)
    {
      info = new BaselineInfo();
    }

    // The ascent is local - but we need the global baseline, relative to the
    // MaxAscent.
    final long maxAscent = getMaxAscent();
    final long ascent = StrictGeomUtility.toInternalValue(lm.getAscent());
    final long delta = maxAscent - ascent;
    info.setBaseline(BaselineInfo.MATHEMATICAL, delta + maxAscent - getXHeight());
    info.setBaseline(BaselineInfo.IDEOGRAPHIC, getMaxHeight());
    info.setBaseline(BaselineInfo.MIDDLE, maxAscent / 2);

    final long base = delta + ascent;

    switch (idx)
    {
      case Font.CENTER_BASELINE:
      {
        info.setBaseline(BaselineInfo.CENTRAL, base);
        info.setBaseline(BaselineInfo.ALPHABETIC, base + StrictGeomUtility.toInternalValue(bls[Font.ROMAN_BASELINE]));
        info.setBaseline(BaselineInfo.HANGING, base + StrictGeomUtility.toInternalValue(bls[Font.HANGING_BASELINE]));
        info.setDominantBaseline(BaselineInfo.CENTRAL);
        break;
      }
      case Font.HANGING_BASELINE:
      {
        info.setBaseline(BaselineInfo.CENTRAL, base + StrictGeomUtility.toInternalValue(bls[Font.CENTER_BASELINE]));
        info.setBaseline(BaselineInfo.ALPHABETIC, base + StrictGeomUtility.toInternalValue(bls[Font.ROMAN_BASELINE]));
        info.setBaseline(BaselineInfo.HANGING, base);
        info.setDominantBaseline(BaselineInfo.HANGING);
        break;
      }
      default: // ROMAN Base-line
      {
        info.setBaseline(BaselineInfo.ALPHABETIC, base);
        info.setBaseline(BaselineInfo.CENTRAL, base + StrictGeomUtility.toInternalValue(bls[Font.CENTER_BASELINE]));
        info.setBaseline(BaselineInfo.HANGING, base + StrictGeomUtility.toInternalValue(bls[Font.HANGING_BASELINE]));
        info.setDominantBaseline(BaselineInfo.ALPHABETIC);
        break;
      }
    }

    if (cacheable)
    {
      final BaselineInfo cached = new BaselineInfo();
      cached.update(info);
      cachedBaselines[c - 32] = cached;
    }

    return info;
  }

  /**
   * Returns zero, as the AWT renderer will take care of the italic rendering already. We do not have
   * to apply any special transformations to the font to make it look italic.
   *
   * @return always zero.
   */
  public long getItalicAngle()
  {
    return 0;
  }
}
TOP

Related Classes of org.jfree.fonts.awt.AWTFontMetrics

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.