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: CustomFontMetricsMapper.java 1827168 2018-03-19 08:49:57Z ssteiner $ */
19 
20 package org.apache.fop.render.java2d;
21 
22 import java.awt.Font;
23 import java.awt.FontFormatException;
24 import java.awt.Rectangle;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.net.URI;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 
32 import org.apache.fop.complexscripts.fonts.Positionable;
33 import org.apache.fop.complexscripts.fonts.Substitutable;
34 import org.apache.fop.fonts.CustomFont;
35 import org.apache.fop.fonts.FontType;
36 import org.apache.fop.fonts.LazyFont;
37 import org.apache.fop.fonts.Typeface;
38 
39 /**
40  * FontMetricsMapper that delegates most methods to an underlying
41  * {@link org.apache.fop.fonts.FontMetrics} instance. This class was designed to allow
42  * the underlying {@link Font} to be loaded from a
43  * user-configured file not registered in the current graphics environment.
44  */
45 public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapper, Substitutable,
46         Positionable {
47 
48     /**
49      * Font metrics for the font this class models.
50      */
51     private Typeface typeface;
52 
53     /**
54      * The font required by the Java2D renderer.
55      */
56     private java.awt.Font font;
57 
58     /**
59      * Maintains the most recently requested size.
60      */
61     private float size = 1;
62 
63     /**
64      * Construction of this class results in the immediate construction
65      * of the underlying {@link java.awt.Font}.
66      * @param fontMetrics the metrics of the custom font
67      * @throws FontFormatException if a bad font is loaded
68      * @throws IOException if an I/O error occurs
69      */
CustomFontMetricsMapper(final CustomFont fontMetrics)70     public CustomFontMetricsMapper(final CustomFont fontMetrics)
71             throws FontFormatException, IOException {
72         this.typeface = fontMetrics;
73         initialize(fontMetrics.getInputStream());
74     }
75 
76     /**
77      * Construction of this class results in the immediate construction
78      * of the underlying {@link java.awt.Font}.
79      * @param fontMetrics the font
80      * @param fontSource the font source to access the font
81      * @throws FontFormatException if a bad font is loaded
82      * @throws IOException if an I/O error occurs
83      */
CustomFontMetricsMapper(final LazyFont fontMetrics, final InputStream fontSource)84     public CustomFontMetricsMapper(final LazyFont fontMetrics, final InputStream fontSource)
85             throws FontFormatException, IOException {
86         this.typeface = fontMetrics;
87         initialize(fontSource);
88     }
89 
90     private static final int TYPE1_FONT = 1; //Defined in Java 1.5
91 
92     /**
93      * Loads the java.awt.Font
94      * @param inStream
95      * @throws FontFormatException
96      * @throws IOException
97      */
initialize(final InputStream inStream)98     private void initialize(final InputStream inStream)
99                 throws FontFormatException, IOException {
100         int type = Font.TRUETYPE_FONT;
101         if (FontType.TYPE1.equals(typeface.getFontType())) {
102             type = TYPE1_FONT; //Font.TYPE1_FONT; only available in Java 1.5
103         }
104         this.font = Font.createFont(type, inStream);
105         inStream.close();
106     }
107 
108     /** {@inheritDoc} */
getEncodingName()109     public final String getEncodingName() {
110         return null; //Not applicable to Java2D rendering
111     }
112 
113     /** {@inheritDoc} */
hasChar(final char c)114     public final boolean hasChar(final char c) {
115         return font.canDisplay(c);
116     }
117 
118     /** {@inheritDoc} */
mapChar(final char c)119     public final char mapChar(final char c) {
120         return typeface.mapChar(c);
121     }
122 
123     /** {@inheritDoc} */
getFont(final int size)124     public final Font getFont(final int size) {
125         if (this.size == size) {
126             return font;
127         }
128 
129         this.size = size / 1000f;
130         font = font.deriveFont(this.size);
131         return font;
132     }
133 
134     /** {@inheritDoc} */
getAscender(final int size)135     public final int getAscender(final int size) {
136         return typeface.getAscender(size);
137     }
138 
139     /** {@inheritDoc} */
getCapHeight(final int size)140     public final int getCapHeight(final int size) {
141         return typeface.getCapHeight(size);
142     }
143 
144     /** {@inheritDoc} */
getDescender(final int size)145     public final int getDescender(final int size) {
146         return typeface.getDescender(size);
147     }
148 
149     /** {@inheritDoc} */
getEmbedFontName()150     public final String getEmbedFontName() {
151         return typeface.getEmbedFontName();
152     }
153 
154     /** {@inheritDoc} */
getFamilyNames()155     public final Set<String> getFamilyNames() {
156         return typeface.getFamilyNames();
157     }
158 
159     /** {@inheritDoc} */
getFontName()160     public final String getFontName() {
161         return typeface.getFontName();
162     }
163 
164     /** {@inheritDoc} */
getFontURI()165     public final URI getFontURI() {
166         return typeface.getFontURI();
167     }
168 
169     /** {@inheritDoc} */
getFontType()170     public final FontType getFontType() {
171         return typeface.getFontType();
172     }
173 
174     /** {@inheritDoc} */
getFullName()175     public final String getFullName() {
176         return typeface.getFullName();
177     }
178 
179     /** {@inheritDoc} */
getKerningInfo()180     public final Map getKerningInfo() {
181         return typeface.getKerningInfo();
182     }
183 
184     /** {@inheritDoc} */
getWidth(final int i, final int size)185     public final int getWidth(final int i, final int size) {
186         return typeface.getWidth(i, size);
187     }
188 
189     /** {@inheritDoc} */
getWidths()190     public final int[] getWidths() {
191         return typeface.getWidths();
192     }
193 
getBoundingBox(int glyphIndex, int size)194     public Rectangle getBoundingBox(int glyphIndex, int size) {
195         return typeface.getBoundingBox(glyphIndex, size);
196     }
197 
198     /** {@inheritDoc} */
getXHeight(final int size)199     public final int getXHeight(final int size) {
200         return typeface.getXHeight(size);
201     }
202 
getUnderlinePosition(int size)203     public int getUnderlinePosition(int size) {
204         return typeface.getUnderlinePosition(size);
205     }
206 
getUnderlineThickness(int size)207     public int getUnderlineThickness(int size) {
208         return typeface.getUnderlineThickness(size);
209     }
210 
getStrikeoutPosition(int size)211     public int getStrikeoutPosition(int size) {
212         return typeface.getStrikeoutPosition(size);
213     }
214 
getStrikeoutThickness(int size)215     public int getStrikeoutThickness(int size) {
216         return typeface.getStrikeoutThickness(size);
217     }
218 
219     /** {@inheritDoc} */
hasKerningInfo()220     public final boolean hasKerningInfo() {
221         return typeface.hasKerningInfo();
222     }
223 
224     /** {@inheritDoc} */
isMultiByte()225     public boolean isMultiByte() {
226         return typeface.isMultiByte();
227     }
228 
229     /**
230      * {@inheritDoc}
231      */
performsPositioning()232     public boolean performsPositioning() {
233         if (typeface instanceof Positionable) {
234             return ((Positionable) typeface).performsPositioning();
235         } else {
236             return false;
237         }
238     }
239 
240     /**
241      * {@inheritDoc}
242      */
performPositioning(CharSequence cs, String script, String language, int fontSize)243     public int[][] performPositioning(CharSequence cs, String script, String language, int fontSize) {
244         if (typeface instanceof Positionable) {
245             return ((Positionable) typeface).performPositioning(cs, script, language, fontSize);
246         } else {
247             return null;
248         }
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
performPositioning(CharSequence cs, String script, String language)254     public int[][] performPositioning(CharSequence cs, String script, String language) {
255         if (typeface instanceof Positionable) {
256             return ((Positionable) typeface).performPositioning(cs, script, language);
257         } else {
258             return null;
259         }
260     }
261 
262     /**
263      * {@inheritDoc}
264      */
performsSubstitution()265     public boolean performsSubstitution() {
266         if (typeface instanceof Substitutable) {
267             return ((Substitutable) typeface).performsSubstitution();
268         } else {
269             return false;
270         }
271     }
272 
273     /**
274      * {@inheritDoc}
275      */
performSubstitution(CharSequence cs, String script, String language, List associations, boolean retainControls)276     public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations,
277                                             boolean retainControls) {
278         if (typeface instanceof Substitutable) {
279             return ((Substitutable) typeface).performSubstitution(cs, script, language, associations, retainControls);
280         } else {
281             return cs;
282         }
283     }
284 
285     /**
286      * {@inheritDoc}
287      */
reorderCombiningMarks(CharSequence cs, int[][] gpa, String script, String language, List associations)288     public CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa,
289         String script, String language, List associations) {
290         if (typeface instanceof Substitutable) {
291             return ((Substitutable) typeface).reorderCombiningMarks(cs, gpa, script, language, associations);
292         } else {
293             return cs;
294         }
295     }
296 
getRealFont()297     public Typeface getRealFont() {
298         return typeface;
299     }
300 
301 }
302