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