123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- /*
- * 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.fonts;
-
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
-
- import org.apache.fop.complexscripts.fonts.Positionable;
- import org.apache.fop.complexscripts.fonts.Substitutable;
- import org.apache.fop.render.java2d.CustomFontMetricsMapper;
- import org.apache.fop.util.CharUtilities;
-
- /**
- * This class holds font state information and provides access to the font
- * metrics.
- */
- public class Font implements Substitutable, Positionable {
-
- /** Extra Bold font weight */
- public static final int WEIGHT_EXTRA_BOLD = 800;
-
- /** Bold font weight */
- public static final int WEIGHT_BOLD = 700;
-
- /** Normal font weight */
- public static final int WEIGHT_NORMAL = 400;
-
- /** Light font weight */
- public static final int WEIGHT_LIGHT = 200;
-
- /** Normal font style */
- public static final String STYLE_NORMAL = "normal";
-
- /** Italic font style */
- public static final String STYLE_ITALIC = "italic";
-
- /** Oblique font style */
- public static final String STYLE_OBLIQUE = "oblique";
-
- /** Inclined font style */
- public static final String STYLE_INCLINED = "inclined";
-
- /** Default selection priority */
- public static final int PRIORITY_DEFAULT = 0;
-
- /** Default fallback key */
- public static final FontTriplet DEFAULT_FONT = new FontTriplet(
- "any", STYLE_NORMAL, WEIGHT_NORMAL, PRIORITY_DEFAULT);
-
- /** logger */
- private static Log log = LogFactory.getLog(Font.class);
-
- private final String fontName;
- private final FontTriplet triplet;
- private final int fontSize;
-
- /**
- * normal or small-caps font
- */
- //private int fontVariant;
-
- private final FontMetrics metric;
-
- /**
- * Main constructor
- * @param key key of the font
- * @param triplet the font triplet that was used to lookup this font (may be null)
- * @param met font metrics
- * @param fontSize font size
- */
- public Font(String key, FontTriplet triplet, FontMetrics met, int fontSize) {
- this.fontName = key;
- this.triplet = triplet;
- this.metric = met;
- this.fontSize = fontSize;
- }
-
- /**
- * Returns the associated font metrics object.
- * @return the font metrics
- */
- public FontMetrics getFontMetrics() {
- return this.metric;
- }
-
- /**
- * Determines whether the font is a multibyte font.
- * @return True if it is multibyte
- */
- public boolean isMultiByte() {
- return getFontMetrics().isMultiByte();
- }
-
- /**
- * Returns the font's ascender.
- * @return the ascender
- */
- public int getAscender() {
- return metric.getAscender(fontSize) / 1000;
- }
-
- /**
- * Returns the font's CapHeight.
- * @return the capital height
- */
- public int getCapHeight() {
- return metric.getCapHeight(fontSize) / 1000;
- }
-
- /**
- * Returns the font's Descender.
- * @return the descender
- */
- public int getDescender() {
- return metric.getDescender(fontSize) / 1000;
- }
-
- /**
- * Returns the font's name.
- * @return the font name
- */
- public String getFontName() {
- return fontName;
- }
-
- /** @return the font triplet that selected this font */
- public FontTriplet getFontTriplet() {
- return this.triplet;
- }
-
- /**
- * Returns the font size
- * @return the font size
- */
- public int getFontSize() {
- return fontSize;
- }
-
- /**
- * Returns the XHeight
- * @return the XHeight
- */
- public int getXHeight() {
- return metric.getXHeight(fontSize) / 1000;
- }
-
- /** @return true if the font has kerning info */
- public boolean hasKerning() {
- return metric.hasKerningInfo();
- }
-
- /** @return true if the font has feature (i.e., at least one lookup matches) */
- public boolean hasFeature(int tableType, String script, String language, String feature) {
- return metric.hasFeature(tableType, script, language, feature);
- }
-
- /**
- * Returns the font's kerning table
- * @return the kerning table
- */
- public Map<Integer, Map<Integer, Integer>> getKerning() {
- if (metric.hasKerningInfo()) {
- return metric.getKerningInfo();
- } else {
- return Collections.emptyMap();
- }
- }
-
- /**
- * Returns the amount of kerning between two characters.
- *
- * The value returned measures in pt. So it is already adjusted for font size.
- *
- * @param ch1 first character
- * @param ch2 second character
- * @return the distance to adjust for kerning, 0 if there's no kerning
- */
- public int getKernValue(int ch1, int ch2) {
- // Isolate surrogate pair
- if ((ch1 >= 0xD800) && (ch1 <= 0xE000)) {
- return 0;
- } else if ((ch2 >= 0xD800) && (ch2 <= 0xE000)) {
- return 0;
- }
-
- Map<Integer, Integer> kernPair = getKerning().get(ch1);
- if (kernPair != null) {
- Integer width = kernPair.get(ch2);
- if (width != null) {
- return width * getFontSize() / 1000;
- }
- }
- return 0;
- }
-
- /**
- * Returns the width of a character
- * @param charnum character to look up
- * @return width of the character
- */
- public int getWidth(int charnum) {
- // returns width of given character number in millipoints
- return (metric.getWidth(charnum, fontSize) / 1000);
- }
-
- /**
- * Map a java character (unicode) to a font character.
- * Default uses CodePointMapping.
- * @param c character to map
- * @return the mapped character
- */
- public char mapChar(char c) {
-
- if (metric instanceof org.apache.fop.fonts.Typeface) {
- return ((org.apache.fop.fonts.Typeface)metric).mapChar(c);
- }
-
- // Use default CodePointMapping
- char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
- if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) {
- c = d;
- } else {
- log.warn("Glyph " + (int) c + " not available in font " + fontName);
- c = Typeface.NOT_FOUND;
- }
-
- return c;
- }
-
- /**
- * Map a unicode code point to a font character.
- * Default uses CodePointMapping.
- * @param cp code point to map
- * @return the mapped character
- */
- public int mapCodePoint(int cp) {
- FontMetrics fontMetrics = getRealFontMetrics();
-
- if (fontMetrics instanceof CIDFont) {
- return ((CIDFont) fontMetrics).mapCodePoint(cp);
- }
-
- if (CharUtilities.isBmpCodePoint(cp)) {
- return mapChar((char) cp);
- }
-
- return Typeface.NOT_FOUND;
- }
-
- /**
- * Determines whether this font contains a particular character/glyph.
- * @param c character to check
- * @return True if the character is supported, False otherwise
- */
- public boolean hasChar(char c) {
- if (metric instanceof org.apache.fop.fonts.Typeface) {
- return ((org.apache.fop.fonts.Typeface)metric).hasChar(c);
- } else {
- // Use default CodePointMapping
- return (CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c) > 0);
- }
- }
-
- /**
- * Determines whether this font contains a particular code point/glyph.
- * @param cp code point to check
- * @return True if the code point is supported, False otherwise
- */
- public boolean hasCodePoint(int cp) {
- FontMetrics realFont = getRealFontMetrics();
-
- if (realFont instanceof CIDFont) {
- return ((CIDFont) realFont).hasCodePoint(cp);
- }
-
- if (CharUtilities.isBmpCodePoint(cp)) {
- return hasChar((char) cp);
- }
-
- return false;
- }
-
- /**
- * Get the real underlying font if it is wrapped inside some container such as a {@link LazyFont} or a
- * {@link CustomFontMetricsMapper}.
- *
- * @return instance of the font
- */
- private FontMetrics getRealFontMetrics() {
- FontMetrics realFontMetrics = metric;
-
- if (realFontMetrics instanceof CustomFontMetricsMapper) {
- realFontMetrics = ((CustomFontMetricsMapper) realFontMetrics).getRealFont();
- }
-
- if (realFontMetrics instanceof LazyFont) {
- return ((LazyFont) realFontMetrics).getRealFont();
- }
-
- return realFontMetrics;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- StringBuffer sbuf = new StringBuffer(super.toString());
- sbuf.append('{');
- /*
- sbuf.append(fontFamily);
- sbuf.append(',');*/
- sbuf.append(fontName);
- sbuf.append(',');
- sbuf.append(fontSize);
- /*
- sbuf.append(',');
- sbuf.append(fontStyle);
- sbuf.append(',');
- sbuf.append(fontWeight);*/
- sbuf.append('}');
- return sbuf.toString();
- }
-
- /**
- * Helper method for getting the width of a unicode char
- * from the current fontstate.
- * This also performs some guessing on widths on various
- * versions of space that might not exists in the font.
- * @param c character to inspect
- * @return the width of the character or -1 if no width available
- */
- public int getCharWidth(char c) {
- int width;
-
- if ((c == '\n') || (c == '\r') || (c == '\t') || (c == '\u00A0')) {
- width = getCharWidth(' ');
- } else {
- if (hasChar(c)) {
- int mappedChar = mapChar(c);
- width = getWidth(mappedChar);
- } else {
- width = -1;
- }
- if (width <= 0) {
- // Estimate the width of spaces not represented in
- // the font
- int em = getFontSize(); //http://en.wikipedia.org/wiki/Em_(typography)
- int en = em / 2; //http://en.wikipedia.org/wiki/En_(typography)
-
- if (c == ' ') {
- width = em;
- } else if (c == '\u2000') {
- width = en;
- } else if (c == '\u2001') {
- width = em;
- } else if (c == '\u2002') {
- width = em / 2;
- } else if (c == '\u2003') {
- width = getFontSize();
- } else if (c == '\u2004') {
- width = em / 3;
- } else if (c == '\u2005') {
- width = em / 4;
- } else if (c == '\u2006') {
- width = em / 6;
- } else if (c == '\u2007') {
- width = getCharWidth('0');
- } else if (c == '\u2008') {
- width = getCharWidth('.');
- } else if (c == '\u2009') {
- width = em / 5;
- } else if (c == '\u200A') {
- width = em / 10;
- } else if (c == '\u200B') {
- width = 0;
- } else if (c == '\u202F') {
- width = getCharWidth(' ') / 2;
- } else if (c == '\u2060') {
- width = 0;
- } else if (c == '\u3000') {
- width = getCharWidth(' ') * 2;
- } else if (c == '\ufeff') {
- width = 0;
- } else {
- //Will be internally replaced by "#" if not found
- width = getWidth(mapChar(c));
- }
- }
- }
-
- return width;
- }
-
- /**
- * Helper method for getting the width of a unicode char
- * from the current fontstate.
- * This also performs some guessing on widths on various
- * versions of space that might not exists in the font.
- * @param c character to inspect
- * @return the width of the character or -1 if no width available
- */
- public int getCharWidth(int c) {
- if (c < 0x10000) {
- return getCharWidth((char) c);
- }
-
- if (hasCodePoint(c)) {
- int mappedChar = mapCodePoint(c);
- return getWidth(mappedChar);
- }
-
- return -1;
- }
-
- /**
- * Calculates the word width.
- * @param word text to get width for
- * @return the width of the text
- */
- public int getWordWidth(String word) {
- if (word == null) {
- return 0;
- }
- int wordLength = word.length();
- int width = 0;
- char[] characters = new char[wordLength];
- word.getChars(0, wordLength, characters, 0);
- for (int i = 0; i < wordLength; i++) {
- width += getCharWidth(characters[i]);
- }
- return width;
- }
-
- /** {@inheritDoc} */
- public boolean performsSubstitution() {
- if (metric instanceof Substitutable) {
- Substitutable s = (Substitutable) metric;
- return s.performsSubstitution();
- } else {
- return false;
- }
- }
-
- /** {@inheritDoc} */
- public CharSequence performSubstitution(CharSequence cs,
- String script, String language, List associations, boolean retainControls) {
- if (metric instanceof Substitutable) {
- Substitutable s = (Substitutable) metric;
- return s.performSubstitution(cs, script, language, associations, retainControls);
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- /** {@inheritDoc} */
- public CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa,
- String script, String language, List associations) {
- if (metric instanceof Substitutable) {
- Substitutable s = (Substitutable) metric;
- return s.reorderCombiningMarks(cs, gpa, script, language, associations);
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- /** {@inheritDoc} */
- public boolean performsPositioning() {
- if (metric instanceof Positionable) {
- Positionable p = (Positionable) metric;
- return p.performsPositioning();
- } else {
- return false;
- }
- }
-
- /** {@inheritDoc} */
- public int[][] performPositioning(CharSequence cs, String script, String language, int fontSize) {
- if (metric instanceof Positionable) {
- Positionable p = (Positionable) metric;
- return p.performPositioning(cs, script, language, fontSize);
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- /** {@inheritDoc} */
- public int[][] performPositioning(CharSequence cs, String script, String language) {
- return performPositioning(cs, script, language, fontSize);
- }
-
- }
|