blob: 49e7f99bab562e45eed5bc0ea582fbc2279bbf6e [file] [log] [blame]
/*
* 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.io.UnsupportedEncodingException;
import java.nio.charset.CharacterCodingException;
import java.util.HashMap;
import java.util.Map;
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.
* <p/>
* Presenting a graphic character on a presentation surface requires
* information on the rotation and position of character on the physical
* or logical page.
* <p/>
* 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.
* <p/>
*/
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 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 current orientation (currently only 0 is supported by FOP) */
private final String currentOrientation = "0";
/** The collection of objects for each orientation */
private final Map<String, CharacterSetOrientation> characterSetOrientations;
/** 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);
}
if (name.length() < MAX_NAME_LEN) {
this.name = StringUtils.rpad(name, ' ', MAX_NAME_LEN);
} else {
this.name = name;
}
this.codePage = codePage;
this.encoding = encoding;
this.encoder = charsetType.getEncoder(encoding);
this.accessor = accessor;
this.characterSetOrientations = new HashMap<String, CharacterSetOrientation>(4);
}
/**
* Add character set metric information for the different orientations
*
* @param cso the metrics for the orientation
*/
public void addCharacterSetOrientation(CharacterSetOrientation cso) {
characterSetOrientations.put(String.valueOf(cso.getOrientation()), 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();
}
/**
* 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 first character in the character set
*
* @return the first character in the character set (Unicode codepoint)
*/
public char getFirstChar() {
return getCharacterSetOrientation().getFirstChar();
}
/**
* Returns the last character in the character set
*
* @return the last character in the character set (Unicode codepoint)
*/
public char getLastChar() {
return getCharacterSetOrientation().getLastChar();
}
/**
* 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;
}
/**
* Get the width (in 1/1000ths of a point size) of all characters
*
* @return the widths of all characters
*/
public int[] getWidths() {
return getCharacterSetOrientation().getWidths();
}
/**
* 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
* @return the width of the character
*/
public int getWidth(char character) {
return getCharacterSetOrientation().getWidth(character);
}
/**
* 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) {
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() {
CharacterSetOrientation c
= characterSetOrientations.get(currentOrientation);
return c;
}
/**
* 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();
}
}