123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.render.java2d;
-
- // Java
- import java.awt.Font;
- import java.awt.FontMetrics;
- import java.awt.Graphics2D;
- import java.awt.RenderingHints;
- import java.awt.font.LineMetrics;
- import java.awt.font.TextAttribute;
- import java.awt.font.TextLayout;
- import java.awt.geom.Rectangle2D;
- import java.awt.image.BufferedImage;
- import java.util.Map;
-
- /**
- * This is a FontMetrics to be used for AWT rendering.
- * It instanciates a font, depening on family and style
- * values. The java.awt.FontMetrics for this font is then
- * created to be used for the actual measurement.
- * Since layout is word by word and since it is expected that
- * two subsequent words often share the same style, the
- * Font and FontMetrics is buffered and only changed if needed.
- * <p>
- * Since FontState and FontInfo multiply all factors by
- * size, we assume a "standard" font of FONT_SIZE.
- */
- public class Java2DFontMetrics {
-
- /**
- * Font size standard used for metric measurements
- */
- public static final int FONT_SIZE = 1;
-
- /**
- * This factor multiplies the calculated values to scale
- * to FOP internal measurements
- */
- public static final int FONT_FACTOR = (1000 * 1000) / FONT_SIZE;
-
- /**
- * The width of all 256 character, if requested
- */
- private int[] width;
-
- /**
- * The typical height of a small cap latter (often derived from "x", value in mpt)
- */
- private int xHeight;
-
- /**
- * The highest point of the font above the baseline (usually derived from "d", value in mpt)
- */
- private int ascender;
-
- /**
- * The lowest point of the font under the baseline (usually derived from "p", value in mpt)
- */
- private int descender;
-
- /**
- * Buffered font.
- * f1 is bufferd for metric measurements during layout.
- * fSized is buffered for display purposes
- */
- private Font f1; // , fSized;
-
- /**
- * The family type of the font last used
- */
- private String family = "";
-
- /**
- * The style of the font last used
- */
- private int style;
-
- /**
- * The size of the font last used
- */
- private float size;
-
- /**
- * The FontMetrics object used to calculate character width etc.
- */
- private FontMetrics fmt;
-
- /** A LineMetrics to access high-resolution metrics information. */
- private LineMetrics lineMetrics;
-
- /**
- * Temp graphics object needed to get the font metrics
- */
- private final Graphics2D graphics;
-
- /**
- * Creates a Graphics2D object for the sole purpose of getting font metrics.
- * @return a Graphics2D object
- */
- private static Graphics2D createFontMetricsGraphics2D() {
- BufferedImage fontImage = new BufferedImage(100, 100,
- BufferedImage.TYPE_INT_RGB);
- Graphics2D graphics2D = fontImage.createGraphics();
- //The next line is important to get accurate font metrics!
- graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
- RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- return graphics2D;
- }
-
- /**
- * Constructs a new Font-metrics.
- */
- public Java2DFontMetrics() {
- this.graphics = createFontMetricsGraphics2D();
- }
-
- /**
- * Determines the font's maximum ascent of the Font described by the current
- * FontMetrics object
- * @param family font family (java name) to use
- * @param style font style (java def.) to use
- * @param size font size
- * @return ascent in milliponts
- */
- public int getMaxAscent(String family, int style, int size) {
- setFont(family, style, size);
- return Math.round(lineMetrics.getAscent() * FONT_FACTOR);
- }
-
- /**
- * Determines the font ascent of the Font described by this
- * FontMetrics object
- * @param family font family (java name) to use
- * @param style font style (java def.) to use
- * @param size font size
- * @return ascent in milliponts
- */
- public int getAscender(String family, int style, int size) {
- setFont(family, style, size);
- return ascender * 1000;
-
- // workaround for sun bug on FontMetrics.getAscent()
- // http://developer.java.sun.com/developer/bugParade/bugs/4399887.html
- /*
- * Bug 4399887 has status Closed, not a bug. The comments on the bug
- * are:
- * The submitter is incorrectly assuming that the string he has used
- * is displaying characters which represent those with the maximum
- * ascent in the font. If (for example) the unicode character
- * \u00c1 which is the A-acute character used in many European
- * languages is placed in the bodu of the "Wrong" string it can be
- * seen that the JDK is exactly correct in its determination of the
- * ascent of the font.
- * If the bounds of a particular string are interesting then the
- * Rectangle FontMetrics.getStringBounds(..) method can be called.
- * The y value of the rectangle is the offset from the origin
- * (baseline) apparently needed by the sample test program
- *
- * xxxxx@xxxxx 2001-05-15
- */
- /* I don't think this is right.
- int realAscent = fmt.getAscent()
- - (fmt.getDescent() + fmt.getLeading());
- return FONT_FACTOR * realAscent;
- */
- }
-
-
- /**
- * The size of a capital letter measured from the font's baseline
- * @param family font family
- * @param style font style
- * @param size font size
- * @return capital height in millipoints
- */
- public int getCapHeight(String family, int style, int size) {
- // currently just gets Ascent value but maybe should use
- // getMaxAcent() at some stage
- return getAscender(family, style, size);
- }
-
- /**
- * Determines the font descent of the Font described by this
- * FontMetrics object
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return descent in milliponts
- */
- public int getDescender(String family, int style, int size) {
- setFont(family, style, size);
- return descender * 1000;
- }
-
- /**
- * Determines the typical font height of a small cap letter
- * FontMetrics object
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return font height in milliponts
- */
- public int getXHeight(String family, int style, int size) {
- setFont(family, style, size);
- return xHeight * 1000;
- }
-
- public int getUnderlinePosition(String family, int style, int size) {
- setFont(family, style, size);
- return -Math.round(lineMetrics.getUnderlineOffset());
- }
-
- public int getUnderlineThickness(String family, int style, int size) {
- setFont(family, style, size);
- return Math.round(lineMetrics.getUnderlineThickness());
- }
-
- public int getStrikeoutPosition(String family, int style, int size) {
- setFont(family, style, size);
- return -Math.round(lineMetrics.getStrikethroughOffset());
- }
-
- public int getStrikeoutThickness(String family, int style, int size) {
- setFont(family, style, size);
- return Math.round(lineMetrics.getStrikethroughThickness());
- }
-
- /**
- * Returns width (in 1/1000ths of point size) of character at
- * code point i
- * @param i the character for which to get the width
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return character width in millipoints
- */
- public int width(int i, String family, int style, int size) {
- int w;
- setFont(family, style, size);
- w = internalCharWidth(i) * 1000;
- return w;
- }
-
- private int internalCharWidth(int i) {
- //w = (int)(fmt.charWidth(i) * 1000); //Not accurate enough!
- char[] ch = {(char)i};
- Rectangle2D rect = fmt.getStringBounds(ch, 0, 1, this.graphics);
- return (int)Math.round(rect.getWidth() * 1000);
- }
-
- /**
- * Return widths (in 1/1000ths of point size) of all
- * characters
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return array of character widths in millipoints
- */
- public int[] getWidths(String family, int style, int size) {
- int i;
-
- if (width == null) {
- width = new int[256];
- }
- setFont(family, style, size);
- for (i = 0; i < 256; i++) {
- width[i] = 1000 * internalCharWidth(i);
- }
- return width;
- }
-
- private Font getBaseFont(String family, int style, float size) {
- Map atts = new java.util.HashMap();
- atts.put(TextAttribute.FAMILY, family);
- if ((style & Font.BOLD) != 0) {
- atts.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
- }
- if ((style & Font.ITALIC) != 0) {
- atts.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
- }
- atts.put(TextAttribute.SIZE, size); //size in pt
- return new Font(atts);
- }
-
- /**
- * Checks whether the font for which values are
- * requested is the one used immediately before or
- * whether it is a new one
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return true if the font was changed, false otherwise
- */
- private boolean setFont(String family, int style, int size) {
- boolean changed = false;
- float s = size / 1000f;
-
- if (f1 == null) {
- f1 = getBaseFont(family, style, s);
- fmt = graphics.getFontMetrics(f1);
- changed = true;
- } else {
- if ((this.style != style) || !this.family.equals(family)
- || this.size != s) {
- if (family.equals(this.family)) {
- f1 = f1.deriveFont(style, s);
- } else {
- f1 = getBaseFont(family, style, s);
- }
- fmt = graphics.getFontMetrics(f1);
- changed = true;
- }
- // else the font is unchanged from last time
- }
- if (changed) {
- //x-Height
- TextLayout layout = new TextLayout("x", f1, graphics.getFontRenderContext());
- Rectangle2D rect = layout.getBounds();
- xHeight = (int)Math.round(-rect.getY() * 1000);
-
- //PostScript-compatible ascent
- layout = new TextLayout("d", f1, graphics.getFontRenderContext());
- rect = layout.getBounds();
- ascender = (int)Math.round(-rect.getY() * 1000);
-
- //PostScript-compatible descent
- layout = new TextLayout("p", f1, graphics.getFontRenderContext());
- rect = layout.getBounds();
- descender = (int)Math.round((rect.getY() + rect.getHeight()) * -1000);
-
- //Alternative way to get metrics but the ascender is again wrong for our purposes
- lineMetrics = f1.getLineMetrics("", graphics.getFontRenderContext());
- }
- // save the family and style for later comparison
- this.family = family;
- this.style = style;
- this.size = s;
- return changed;
- }
-
-
- /**
- * Returns a java.awt.Font instance for the desired
- * family, style and size type.
- * This is here, so that the font-mapping
- * of FOP-defined fonts to java-fonts can be done
- * in one place and does not need to occur in
- * AWTFontRenderer.
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @return font with the desired characeristics.
- */
- public java.awt.Font getFont(String family, int style, int size) {
- setFont(family, style, size);
- return f1;
- /*
- * if( setFont(family,style, size) ) fSized = null;
- * if( fSized == null || this.size != size ) {
- * fSized = f1.deriveFont( size / 1000f );
- * }
- * this.size = size;
- * return fSized;
- */
- }
-
- /**
- * Indicates whether the font contains a particular character/glyph.
- * @param family font family (jave name) to use
- * @param style font style (jave def.) to use
- * @param size font size
- * @param c the glyph to check
- * @return true if the character is supported
- */
- public boolean hasChar(String family, int style, int size, char c) {
- setFont(family, style, size);
- return f1.canDisplay(c);
- }
-
- }
-
-
-
-
-
|