1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* $Id: CharacterSet.java 1694450 2015-08-06 10:59:51Z ssteiner $ */ 19 20 package org.apache.fop.afp.fonts; 21 22 import java.awt.Rectangle; 23 import java.io.UnsupportedEncodingException; 24 import java.nio.charset.CharacterCodingException; 25 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 29 import org.apache.fop.afp.AFPConstants; 30 import org.apache.fop.afp.AFPEventProducer; 31 import org.apache.fop.afp.fonts.CharactersetEncoder.EncodedChars; 32 import org.apache.fop.afp.util.AFPResourceAccessor; 33 import org.apache.fop.afp.util.StringUtils; 34 35 /** 36 * The IBM Font Object Content Architecture (FOCA) supports presentation 37 * of character shapes by defining their characteristics, which include 38 * font description information for identifying the characters, font metric 39 * information for positioning the characters, and character shape information 40 * for presenting the character images. 41 * <br> 42 * Presenting a graphic character on a presentation surface requires 43 * information on the rotation and position of character on the physical 44 * or logical page. 45 * <br> 46 * This class proivdes font metric information for a particular font 47 * as identified by the character set name. This information is obtained 48 * directly from the AFP font files which must be installed in the path 49 * specified in the afp-fonts xml definition file. 50 * <br> 51 */ 52 public class CharacterSet { 53 54 /** Static logging instance */ 55 protected static final Log LOG = LogFactory.getLog(CharacterSet.class.getName()); 56 57 /** default codepage */ 58 public static final String DEFAULT_CODEPAGE = "T1V10500"; 59 60 /** default encoding */ 61 public static final String DEFAULT_ENCODING = "Cp500"; 62 63 private static final int MAX_NAME_LEN = 8; 64 65 /** The current orientation (currently only 0 is supported by FOP) */ 66 public static final int SUPPORTED_ORIENTATION = 0; 67 68 /** The code page to which the character set relates */ 69 protected final String codePage; 70 71 /** The encoding used for the code page */ 72 protected final String encoding; 73 74 /** The characterset encoder corresponding to this encoding */ 75 private final CharactersetEncoder encoder; 76 77 /** The character set relating to the font */ 78 protected final String name; 79 80 /** The path to the installed fonts */ 81 private final AFPResourceAccessor accessor; 82 83 /** The collection of objects for each orientation */ 84 private CharacterSetOrientation characterSetOrientation; 85 86 /** The nominal vertical size (in millipoints) for bitmap fonts. 0 for outline fonts. */ 87 private int nominalVerticalSize; 88 89 /** 90 * Constructor for the CharacterSetMetric object, the character set is used to load the font 91 * information from the actual AFP font. 92 * 93 * @param codePage the code page identifier 94 * @param encoding the encoding of the font 95 * @param charsetType the type of the characterset 96 * @param name the character set name 97 * @param accessor the resource accessor to load resource with 98 * @param eventProducer for handling AFP related events 99 */ CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, AFPResourceAccessor accessor, AFPEventProducer eventProducer)100 CharacterSet(String codePage, String encoding, CharacterSetType charsetType, String name, 101 AFPResourceAccessor accessor, AFPEventProducer eventProducer) { 102 if (name.length() > MAX_NAME_LEN) { 103 String msg = "Character set name '" + name + "' must be a maximum of " 104 + MAX_NAME_LEN + " characters"; 105 eventProducer.characterSetNameInvalid(this, msg); 106 throw new IllegalArgumentException(msg); 107 } 108 109 // the character set name must be 8 chars long 110 this.name = padName(name); 111 if (codePage == null) { 112 this.codePage = null; 113 } else { 114 // the code page name must be 8 chars long 115 this.codePage = padName(codePage); 116 } 117 118 this.encoding = encoding; 119 this.encoder = charsetType.getEncoder(encoding); 120 this.accessor = accessor; 121 } 122 123 // right pad short names with space padName(String name)124 private String padName(String name) { 125 return name.length() < MAX_NAME_LEN ? StringUtils.rpad(name, ' ', MAX_NAME_LEN) : name; 126 } 127 128 /** 129 * Add character set metric information for the different orientations 130 * 131 * @param cso the metrics for the orientation 132 */ addCharacterSetOrientation(CharacterSetOrientation cso)133 public void addCharacterSetOrientation(CharacterSetOrientation cso) { 134 if (cso.getOrientation() == SUPPORTED_ORIENTATION) { 135 characterSetOrientation = cso; 136 } 137 } 138 139 /** 140 * Sets the nominal vertical size of the font in the case of bitmap fonts. 141 * @param nominalVerticalSize the nominal vertical size (in millipoints) 142 */ setNominalVerticalSize(int nominalVerticalSize)143 public void setNominalVerticalSize(int nominalVerticalSize) { 144 this.nominalVerticalSize = nominalVerticalSize; 145 } 146 147 /** 148 * Returns the nominal vertical size of the font in the case of bitmap fonts. For outline fonts, 149 * zero is returned, because these are scalable fonts. 150 * @return the nominal vertical size (in millipoints) for bitmap fonts, or 0 for outline fonts. 151 */ getNominalVerticalSize()152 public int getNominalVerticalSize() { 153 return this.nominalVerticalSize; 154 } 155 156 /** 157 * Ascender height is the distance from the character baseline to the 158 * top of the character box. A negative ascender height signifies that 159 * all of the graphic character is below the character baseline. For 160 * a character rotation other than 0, ascender height loses its 161 * meaning when the character is lying on its side or is upside down 162 * with respect to normal viewing orientation. For the general case, 163 * Ascender Height is the characters most positive y-axis value. 164 * For bounded character boxes, for a given character having an 165 * ascender, ascender height and baseline offset are equal. 166 * 167 * @return the ascender value in millipoints 168 */ getAscender()169 public int getAscender() { 170 return getCharacterSetOrientation().getAscender(); 171 } 172 173 /** 174 * Return the width to use for an underscore (_) character. 175 * 176 * @return the width of an underscore character 177 */ getUnderscoreWidth()178 public int getUnderscoreWidth() { 179 return getCharacterSetOrientation().getUnderscoreWidth(); 180 } 181 182 /** 183 * Return the position for an underscore (_) character. 184 * 185 * @return the position of an underscore character 186 */ getUnderscorePosition()187 public int getUnderscorePosition() { 188 return getCharacterSetOrientation().getUnderscorePosition(); 189 } 190 191 /** 192 * Cap height is the average height of the uppercase characters in 193 * a font. This value is specified by the designer of a font and is 194 * usually the height of the uppercase M. 195 * 196 * @return the cap height value in millipoints 197 */ getCapHeight()198 public int getCapHeight() { 199 return getCharacterSetOrientation().getCapHeight(); 200 } 201 202 /** 203 * Descender depth is the distance from the character baseline to 204 * the bottom of a character box. A negative descender depth signifies 205 * that all of the graphic character is above the character baseline. 206 * 207 * @return the descender value in millipoints 208 */ getDescender()209 public int getDescender() { 210 211 return getCharacterSetOrientation().getDescender(); 212 } 213 214 /** 215 * Returns the resource accessor to load the font resources with. 216 * @return the resource accessor to load the font resources with 217 */ getResourceAccessor()218 public AFPResourceAccessor getResourceAccessor() { 219 return this.accessor; 220 } 221 222 /** 223 * XHeight refers to the height of the lower case letters above the baseline. 224 * 225 * @return the typical height of characters 226 */ getXHeight()227 public int getXHeight() { 228 229 return getCharacterSetOrientation().getXHeight(); 230 } 231 232 /** 233 * Get the width (in 1/1000ths of a point size) of the character 234 * identified by the parameter passed. 235 * 236 * @param character the Unicode character from which the width will be calculated 237 * @param size the font size 238 * @return the width of the character 239 */ getWidth(char character, int size)240 public int getWidth(char character, int size) { 241 return getCharacterSetOrientation().getWidth(character, size); 242 } 243 getCharacterBox(char character, int size)244 public Rectangle getCharacterBox(char character, int size) { 245 return getCharacterSetOrientation().getCharacterBox(character, size); 246 } 247 248 /** 249 * Returns the AFP character set identifier 250 * 251 * @return the AFP character set identifier 252 */ getName()253 public String getName() { 254 return name; 255 } 256 257 /** 258 * Returns the AFP character set identifier as a byte array 259 * 260 * @return the AFP character set identifier as a byte array 261 */ getNameBytes()262 public byte[] getNameBytes() { 263 byte[] nameBytes = null; 264 try { 265 nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); 266 } catch (UnsupportedEncodingException usee) { 267 // @SuppressFBWarnings("DM_DEFAULT_ENCODING") 268 nameBytes = name.getBytes(); 269 LOG.warn( 270 "UnsupportedEncodingException translating the name " + name); 271 } 272 return nameBytes; 273 } 274 275 /** 276 * Returns the AFP code page identifier 277 * 278 * @return the AFP code page identifier 279 */ getCodePage()280 public String getCodePage() { 281 return codePage; 282 } 283 284 /** 285 * Returns the AFP code page encoding 286 * 287 * @return the AFP code page encoding 288 */ getEncoding()289 public String getEncoding() { 290 return encoding; 291 } 292 293 /** 294 * Helper method to return the current CharacterSetOrientation, note 295 * that FOP does not yet implement the "reference-orientation" 296 * attribute therefore we always use the orientation zero degrees, 297 * Other orientation information is captured for use by a future 298 * implementation (whenever FOP implement the mechanism). This is also 299 * the case for landscape prints which use an orientation of 270 degrees, 300 * in 99.9% of cases the font metrics will be the same as the 0 degrees 301 * therefore the implementation currently will always use 0 degrees. 302 * 303 * @return characterSetOrentation The current orientation metrics. 304 */ getCharacterSetOrientation()305 private CharacterSetOrientation getCharacterSetOrientation() { 306 return characterSetOrientation; 307 } 308 309 /** 310 * Indicates whether the given char in the character set. 311 * @param c the character to check 312 * @return true if the character is in the character set 313 */ hasChar(char c)314 public boolean hasChar(char c) { 315 if (encoder != null) { 316 return encoder.canEncode(c); 317 } else { 318 //Sun Java 1.4.2 compatibility 319 return true; 320 } 321 } 322 323 /** 324 * Encodes a character sequence to a byte array. 325 * @param chars the characters 326 * @return the encoded characters 327 * @throws CharacterCodingException if the encoding operation fails 328 */ encodeChars(CharSequence chars)329 public EncodedChars encodeChars(CharSequence chars) throws CharacterCodingException { 330 return encoder.encode(chars); 331 } 332 333 /** 334 * Map a Unicode character to a code point in the font. 335 * The code tables are already converted to Unicode therefore 336 * we can use the identity mapping. 337 * 338 * @param c the Unicode character to map 339 * @return the mapped character 340 */ mapChar(char c)341 public char mapChar(char c) { 342 //TODO This is not strictly correct but we'll let it be for the moment 343 return c; 344 } 345 346 /** 347 * Returns the increment for an space. 348 * @return the space increment 349 */ getSpaceIncrement()350 public int getSpaceIncrement() { 351 return getCharacterSetOrientation().getSpaceIncrement(); 352 } 353 354 /** 355 * Returns the increment for an em space. 356 * @return the em space increment 357 */ getEmSpaceIncrement()358 public int getEmSpaceIncrement() { 359 return getCharacterSetOrientation().getEmSpaceIncrement(); 360 } 361 362 /** 363 * Returns the nominal character increment. 364 * @return the nominal character increment 365 */ getNominalCharIncrement()366 public int getNominalCharIncrement() { 367 return getCharacterSetOrientation().getNominalCharIncrement(); 368 } 369 370 } 371