org.apache.fop.fonts.Font Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The newest version!
/*
* 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: Font.java 1827168 2018-03-19 08:49:57Z ssteiner $ */
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> 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 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);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy