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: CharacterSetOrientation.java 1805177 2017-08-16 11:02:44Z ssteiner $ */
19 
20 package org.apache.fop.afp.fonts;
21 
22 import java.awt.Rectangle;
23 
24 /**
25  * The IBM Font Object Content Architecture (FOCA) supports presentation
26  * of character shapes by defining their characteristics, which include
27  * Font-Description information for identifying the characters, Font-Metric
28  * information for positioning the characters, and Character-Shape
29  * information for presenting the character images.<br>
30  *
31  * Presenting a graphic character on a presentation surface requires
32  * that you communicate this information clearly to rotate and position
33  * characters correctly on the physical or logical page.<br>
34  *
35  * This class provides font metric information for a particular font
36  * as by the orientation.<br>
37  *
38  * This information is obtained directly from the AFP font files which must
39  * be installed in the classpath under in the location specified by the path
40  * attribute in the afp-font.xml file.
41  */
42 public class CharacterSetOrientation {
43 
44     /**
45      * The ascender height for the character set
46      */
47     private int ascender;
48 
49     /**
50      * The descender depth for the character set
51      */
52     private int descender;
53 
54     /**
55      * The height of capital letters
56      */
57     private int capHeight;
58 
59     /**
60      * The character widths in the character set (indexed using Unicode codepoints)
61      */
62     private IntegerKeyStore<CharacterMetrics> characterMetrics;
63 
64     /**
65      * The height of lowercase letters
66      */
67     private int xHeight;
68 
69     /** The character set orientation */
70     private final int orientation;
71     /** space increment */
72     private final int spaceIncrement;
73     /** em space increment */
74     private final int emSpaceIncrement;
75     /** Nominal Character Increment */
76     private final int nomCharIncrement;
77 
78     private int underscoreWidth;
79 
80     private int underscorePosition;
81 
82     /**
83      * Constructor for the CharacterSetOrientation, the orientation is
84      * expressed as the degrees rotation (i.e 0, 90, 180, 270)
85      *
86      * @param orientation   the character set orientation
87      * @param spaceIncrement    the space increment
88      * @param emSpaceIncrement  the em space increment
89      * @param nomCharIncrement  the nominal character increment
90      */
CharacterSetOrientation(int orientation, int spaceIncrement, int emSpaceIncrement, int nomCharIncrement)91     public CharacterSetOrientation(int orientation, int spaceIncrement, int emSpaceIncrement,
92             int nomCharIncrement) {
93         this.orientation = orientation;
94         this.spaceIncrement = spaceIncrement;
95         this.emSpaceIncrement = emSpaceIncrement;
96         this.nomCharIncrement = nomCharIncrement;
97         this.characterMetrics = new IntegerKeyStore<CharacterMetrics>();
98     }
99 
100     /**
101      * Ascender height is the distance from the character baseline to the
102      * top of the character box. A negative ascender height signifies that
103      * all of the graphic character is below the character baseline. For
104      * a character rotation other than 0, ascender height loses its
105      * meaning when the character is lying on its side or is upside down
106      * with respect to normal viewing orientation. For the general case,
107      * Ascender Height is the character's most positive y-axis value.
108      * For bounded character boxes, for a given character having an
109      * ascender, ascender height and baseline offset are equal.
110      * @return the ascender value in millipoints
111      */
getAscender()112     public int getAscender() {
113         return ascender;
114     }
115 
116     /**
117      * Cap height is the average height of the uppercase characters in
118      * a font. This value is specified by the designer of a font and is
119      * usually the height of the uppercase M.
120      * @return the cap height value in millipoints
121      */
getCapHeight()122     public int getCapHeight() {
123         return capHeight;
124     }
125 
126     /**
127      * Descender depth is the distance from the character baseline to
128      * the bottom of a character box. A negative descender depth signifies
129      * that all of the graphic character is above the character baseline.
130      * @return the descender value in millipoints
131      */
getDescender()132     public int getDescender() {
133         return descender;
134     }
135 
136     /**
137      *
138      * @return  the underscore width
139      */
getUnderscoreWidth()140     public int getUnderscoreWidth() {
141         return underscoreWidth;
142     }
143 
144     /**
145      *
146      * @return  the underscore position
147      */
getUnderscorePosition()148     public int getUnderscorePosition() {
149         return underscorePosition;
150     }
151 
152     /**
153      * The orientation for these metrics in the character set
154      * @return the orientation
155      */
getOrientation()156     public int getOrientation() {
157         return orientation;
158     }
159 
160     /**
161      * XHeight refers to the height of the lower case letters above
162      * the baseline.
163      * @return heightX the typical height of characters
164      */
getXHeight()165     public int getXHeight() {
166         return xHeight;
167     }
168 
169     /**
170      * Get the width (in 1/1000ths of a point size) of the character
171      * identified by the parameter passed.
172      * @param character the Unicode character to evaluate
173      * @param size  the font size
174      * @return the widths of the character
175      */
getWidth(char character, int size)176     public int getWidth(char character, int size) {
177         CharacterMetrics cm = getCharacterMetrics(character);
178         return cm == null ? -1 : size * cm.width;
179     }
180 
getCharacterMetrics(char character)181     private CharacterMetrics getCharacterMetrics(char character) {
182         return characterMetrics.get((int) character);
183     }
184 
185     /**
186      * Get the character box (rectangle with dimensions in 1/1000ths of a point size) of the character
187      * identified by the parameter passed.
188      * @param character the Unicode character to evaluate
189      * @param size  the font size
190      * @return the character box
191      */
getCharacterBox(char character, int size)192     public Rectangle getCharacterBox(char character, int size) {
193         CharacterMetrics cm = getCharacterMetrics(character);
194         return scale(cm == null ? getFallbackCharacterBox() : cm.characterBox, size);
195     }
196 
scale(Rectangle rectangle, int size)197     private static Rectangle scale(Rectangle rectangle, int size) {
198         if (rectangle == null) {
199             return null;
200         } else {
201         return new Rectangle((int) (size * rectangle.getX()), (int) (size * rectangle.getY()),
202                 (int) (size * rectangle.getWidth()), (int) (size * rectangle.getHeight()));
203         }
204     }
205 
getFallbackCharacterBox()206     private Rectangle getFallbackCharacterBox() {
207         // TODO replace with something sensible
208         return new Rectangle(0, 0, 0, 0);
209     }
210 
211     /**
212      * Ascender height is the distance from the character baseline to the
213      * top of the character box. A negative ascender height signifies that
214      * all of the graphic character is below the character baseline. For
215      * a character rotation other than 0, ascender height loses its
216      * meaning when the character is lying on its side or is upside down
217      * with respect to normal viewing orientation. For the general case,
218      * Ascender Height is the character's most positive y-axis value.
219      * For bounded character boxes, for a given character having an
220      * ascender, ascender height and baseline offset are equal.
221      * @param ascender the ascender to set
222      */
setAscender(int ascender)223     public void setAscender(int ascender) {
224         this.ascender = ascender;
225     }
226 
227     /**
228      * Cap height is the average height of the uppercase characters in
229      * a font. This value is specified by the designer of a font and is
230      * usually the height of the uppercase M.
231      * @param capHeight the cap height to set
232      */
setCapHeight(int capHeight)233     public void setCapHeight(int capHeight) {
234         this.capHeight = capHeight;
235     }
236 
237     /**
238      * Descender depth is the distance from the character baseline to
239      * the bottom of a character box. A negative descender depth signifies
240      * that all of the graphic character is above the character baseline.
241      * @param descender the descender value in millipoints
242      */
setDescender(int descender)243     public void setDescender(int descender) {
244         this.descender = descender;
245     }
246 
247     /**
248      * TODO
249      * @param underscoreWidth the underscore width value in millipoints
250      */
setUnderscoreWidth(int underscoreWidth)251     public void setUnderscoreWidth(int underscoreWidth) {
252         this.underscoreWidth = underscoreWidth;
253     }
254 
255     /**
256      * TODO
257      * @param underscorePosition the underscore position value in millipoints
258      */
setUnderscorePosition(int underscorePosition)259     public void setUnderscorePosition(int underscorePosition) {
260         this.underscorePosition = underscorePosition;
261     }
262 
263     /**
264      * Set the width (in 1/1000ths of a point size) of the character
265      * identified by the parameter passed.
266      * @param character the Unicode character for which the width is being set
267      * @param width the widths of the character
268      * @param   characterBox    the character box
269      */
setCharacterMetrics(char character, int width, Rectangle characterBox)270     public void setCharacterMetrics(char character, int width, Rectangle characterBox) {
271         characterMetrics.put((int) character, new CharacterMetrics(width, characterBox));
272     }
273 
274     /**
275      * XHeight refers to the height of the lower case letters above
276      * the baseline.
277      * @param xHeight the typical height of characters
278      */
setXHeight(int xHeight)279     public void setXHeight(int xHeight) {
280         this.xHeight = xHeight;
281     }
282 
283     /**
284      * Returns the space increment.
285      * @return the space increment
286      */
getSpaceIncrement()287     public int getSpaceIncrement() {
288         return this.spaceIncrement;
289     }
290 
291     /**
292      * Returns the em space increment.
293      * @return the em space increment
294      */
getEmSpaceIncrement()295     public int getEmSpaceIncrement() {
296         return this.emSpaceIncrement;
297     }
298 
299     /**
300      * Returns the nominal character increment.
301      * @return the nominal character increment
302      */
getNominalCharIncrement()303     public int getNominalCharIncrement() {
304         return this.nomCharIncrement;
305     }
306 
307     private static class CharacterMetrics {
308 
309         public final int width;
310 
311         public final Rectangle characterBox;
312 
CharacterMetrics(int width, Rectangle characterBox)313         public CharacterMetrics(int width, Rectangle characterBox) {
314             this.width = width;
315             this.characterBox = characterBox;
316         }
317     }
318 }
319