/* * 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.afp.fonts; import java.awt.Rectangle; import java.io.UnsupportedEncodingException; import java.nio.charset.CharacterCodingException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPConstants; import org.apache.fop.afp.AFPEventProducer; import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; import org.apache.fop.afp.util.AFPResourceAccessor; import org.apache.fop.afp.util.StringUtils; /** * The IBM Font Object Content Architecture (FOCA) supports presentation * of character shapes by defining their characteristics, which include * font description information for identifying the characters, font metric * information for positioning the characters, and character shape information * for presenting the character images. *
* Presenting a graphic character on a presentation surface requires * information on the rotation and position of character on the physical * or logical page. *
* This class proivdes font metric information for a particular font * as identified by the character set name. This information is obtained * directly from the AFP font files which must be installed in the path * specified in the afp-fonts xml definition file. *
*/ public class CharacterSet { /** Static logging instance */ protected static final Log LOG = LogFactory.getLog(CharacterSet.class.getName()); /** default codepage */ public static final String DEFAULT_CODEPAGE = "T1V10500"; /** default encoding */ public static final String DEFAULT_ENCODING = "Cp500"; private static final int MAX_NAME_LEN = 8; /** The current orientation (currently only 0 is supported by FOP) */ public static final int SUPPORTED_ORIENTATION = 0; /** The code page to which the character set relates */ protected final String codePage; /** The encoding used for the code page */ protected final String encoding; /** The characterset encoder corresponding to this encoding */ private final CharactersetEncoder encoder; /** The character set relating to the font */ protected final String name; /** The path to the installed fonts */ private final AFPResourceAccessor accessor; /** The collection of objects for each orientation */ private CharacterSetOrientation characterSetOrientation; /** The nominal vertical size (in millipoints) for bitmap fonts. 0 for outline fonts. */ private int nominalVerticalSize; /** * Constructor for the CharacterSetMetric object, the character set is used to load the font * information from the actual AFP font. * * @param codePage the code page identifier * @param encoding the encoding of the font * @param charsetType the type of the characterset * @param name the character set name * @param accessor the resource accessor to load resource with * @param eventProducer for handling AFP related events */ CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, AFPResourceAccessor accessor, AFPEventProducer eventProducer) { if (name.length() > MAX_NAME_LEN) { String msg = "Character set name '" + name + "' must be a maximum of " + MAX_NAME_LEN + " characters"; eventProducer.characterSetNameInvalid(this, msg); throw new IllegalArgumentException(msg); } // the character set name must be 8 chars long this.name = padName(name); if (codePage == null) { this.codePage = null; } else { // the code page name must be 8 chars long this.codePage = padName(codePage); } this.encoding = encoding; this.encoder = charsetType.getEncoder(encoding); this.accessor = accessor; } // right pad short names with space private String padName(String name) { return name.length() < MAX_NAME_LEN ? StringUtils.rpad(name, ' ', MAX_NAME_LEN) : name; } /** * Add character set metric information for the different orientations * * @param cso the metrics for the orientation */ public void addCharacterSetOrientation(CharacterSetOrientation cso) { if (cso.getOrientation() == SUPPORTED_ORIENTATION) { characterSetOrientation = cso; } } /** * Sets the nominal vertical size of the font in the case of bitmap fonts. * @param nominalVerticalSize the nominal vertical size (in millipoints) */ public void setNominalVerticalSize(int nominalVerticalSize) { this.nominalVerticalSize = nominalVerticalSize; } /** * Returns the nominal vertical size of the font in the case of bitmap fonts. For outline fonts, * zero is returned, because these are scalable fonts. * @return the nominal vertical size (in millipoints) for bitmap fonts, or 0 for outline fonts. */ public int getNominalVerticalSize() { return this.nominalVerticalSize; } /** * Ascender height is the distance from the character baseline to the * top of the character box. A negative ascender height signifies that * all of the graphic character is below the character baseline. For * a character rotation other than 0, ascender height loses its * meaning when the character is lying on its side or is upside down * with respect to normal viewing orientation. For the general case, * Ascender Height is the characters most positive y-axis value. * For bounded character boxes, for a given character having an * ascender, ascender height and baseline offset are equal. * * @return the ascender value in millipoints */ public int getAscender() { return getCharacterSetOrientation().getAscender(); } /** * Return the width to use for an underscore (_) character. * * @return the width of an underscore character */ public int getUnderscoreWidth() { return getCharacterSetOrientation().getUnderscoreWidth(); } /** * Return the position for an underscore (_) character. * * @return the position of an underscore character */ public int getUnderscorePosition() { return getCharacterSetOrientation().getUnderscorePosition(); } /** * Cap height is the average height of the uppercase characters in * a font. This value is specified by the designer of a font and is * usually the height of the uppercase M. * * @return the cap height value in millipoints */ public int getCapHeight() { return getCharacterSetOrientation().getCapHeight(); } /** * Descender depth is the distance from the character baseline to * the bottom of a character box. A negative descender depth signifies * that all of the graphic character is above the character baseline. * * @return the descender value in millipoints */ public int getDescender() { return getCharacterSetOrientation().getDescender(); } /** * Returns the resource accessor to load the font resources with. * @return the resource accessor to load the font resources with */ public AFPResourceAccessor getResourceAccessor() { return this.accessor; } /** * XHeight refers to the height of the lower case letters above the baseline. * * @return the typical height of characters */ public int getXHeight() { return getCharacterSetOrientation().getXHeight(); } /** * Get the width (in 1/1000ths of a point size) of the character * identified by the parameter passed. * * @param character the Unicode character from which the width will be calculated * @param size the font size * @return the width of the character */ public int getWidth(char character, int size) { return getCharacterSetOrientation().getWidth(character, size); } public Rectangle getCharacterBox(char character, int size) { return getCharacterSetOrientation().getCharacterBox(character, size); } /** * Returns the AFP character set identifier * * @return the AFP character set identifier */ public String getName() { return name; } /** * Returns the AFP character set identifier as a byte array * * @return the AFP character set identifier as a byte array */ public byte[] getNameBytes() { byte[] nameBytes = null; try { nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); } catch (UnsupportedEncodingException usee) { // @SuppressFBWarnings("DM_DEFAULT_ENCODING") nameBytes = name.getBytes(); LOG.warn( "UnsupportedEncodingException translating the name " + name); } return nameBytes; } /** * Returns the AFP code page identifier * * @return the AFP code page identifier */ public String getCodePage() { return codePage; } /** * Returns the AFP code page encoding * * @return the AFP code page encoding */ public String getEncoding() { return encoding; } /** * Helper method to return the current CharacterSetOrientation, note * that FOP does not yet implement the "reference-orientation" * attribute therefore we always use the orientation zero degrees, * Other orientation information is captured for use by a future * implementation (whenever FOP implement the mechanism). This is also * the case for landscape prints which use an orientation of 270 degrees, * in 99.9% of cases the font metrics will be the same as the 0 degrees * therefore the implementation currently will always use 0 degrees. * * @return characterSetOrentation The current orientation metrics. */ private CharacterSetOrientation getCharacterSetOrientation() { return characterSetOrientation; } /** * Indicates whether the given char in the character set. * @param c the character to check * @return true if the character is in the character set */ public boolean hasChar(char c) { if (encoder != null) { return encoder.canEncode(c); } else { //Sun Java 1.4.2 compatibility return true; } } /** * Encodes a character sequence to a byte array. * @param chars the characters * @return the encoded characters * @throws CharacterCodingException if the encoding operation fails */ public EncodedChars encodeChars(CharSequence chars) throws CharacterCodingException { return encoder.encode(chars); } /** * Map a Unicode character to a code point in the font. * The code tables are already converted to Unicode therefore * we can use the identity mapping. * * @param c the Unicode character to map * @return the mapped character */ public char mapChar(char c) { //TODO This is not strictly correct but we'll let it be for the moment return c; } /** * Returns the increment for an space. * @return the space increment */ public int getSpaceIncrement() { return getCharacterSetOrientation().getSpaceIncrement(); } /** * Returns the increment for an em space. * @return the em space increment */ public int getEmSpaceIncrement() { return getCharacterSetOrientation().getEmSpaceIncrement(); } /** * Returns the nominal character increment. * @return the nominal character increment */ public int getNominalCharIncrement() { return getCharacterSetOrientation().getNominalCharIncrement(); } }