KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fonts > FontInfo


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: FontInfo.java 438923 2006-08-31 15:56:32 +0200 (Thu, 31 Aug 2006) adelmelle $ */
19
20 package org.apache.fop.fonts;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32
33 /**
34  * The FontInfo for the layout and rendering of a fo document.
35  * This stores the list of available fonts that are setup by
36  * the renderer. The font name can be retrieved for the
37  * family style and weight.
38  * <br>
39  * Currently font supported font-variant small-caps is not
40  * implemented.
41  */

42 public class FontInfo {
43     
44     /** logging instance */
45     protected static Log log = LogFactory.getLog(FontInfo.class);
46
47     /** Map containing fonts that have been used */
48     private Map JavaDoc usedFonts;
49     
50     /** look up a font-triplet to find a font-name */
51     private Map JavaDoc triplets;
52     
53     /** look up a font-name to get a font (that implements FontMetrics at least) */
54     private Map JavaDoc fonts;
55     
56     /** collection of missing fonts; used to make sure the user gets
57      * a warning for a missing font only once (not every time the font is used)
58      */

59     private Collection JavaDoc loggedFontKeys;
60
61     /** Cache for Font instances. */
62     private Map JavaDoc fontInstanceCache = new java.util.HashMap JavaDoc();
63     
64     /**
65      * Main constructor
66      */

67     public FontInfo() {
68         this.triplets = new java.util.HashMap JavaDoc();
69         this.fonts = new java.util.HashMap JavaDoc();
70         this.usedFonts = new java.util.HashMap JavaDoc();
71     }
72
73     /**
74      * Checks if the font setup is valid (At least the ultimate fallback font
75      * must be registered.)
76      * @return True if valid
77      */

78     public boolean isSetupValid() {
79         return triplets.containsKey(Font.DEFAULT_FONT);
80     }
81
82     /**
83      * Adds a new font triplet.
84      * @param name internal key
85      * @param family font family name
86      * @param style font style (normal, italic, oblique...)
87      * @param weight font weight
88      */

89     public void addFontProperties(String JavaDoc name, String JavaDoc family, String JavaDoc style, int weight) {
90         addFontProperties(name, createFontKey(family, style, weight));
91     }
92
93     /**
94      * Adds a new font triplet.
95      * @param name internal key
96      * @param triplet the font triplet to associate with the internal key
97      */

98     public void addFontProperties(String JavaDoc name, FontTriplet triplet) {
99         /*
100          * add the given family, style and weight as a lookup for the font
101          * with the given name
102          */

103         this.triplets.put(triplet, name);
104     }
105
106     /**
107      * Adds font metrics for a specific font.
108      * @param name internal key
109      * @param metrics metrics to register
110      */

111     public void addMetrics(String JavaDoc name, FontMetrics metrics) {
112         // add the given metrics as a font with the given name
113

114         this.fonts.put(name, metrics);
115     }
116
117     /**
118      * Lookup a font.
119      * <br>
120      * Locate the font name for a given family, style and weight.
121      * The font name can then be used as a key as it is unique for
122      * the associated document.
123      * This also adds the font to the list of used fonts.
124      * @param family font family
125      * @param style font style
126      * @param weight font weight
127      * @param substFont true if the font may be substituted with the
128      * default font if not found
129      * @return internal key
130      */

131     private FontTriplet fontLookup(String JavaDoc family, String JavaDoc style,
132                              int weight, boolean substFont) {
133         FontTriplet startKey = createFontKey(family, style, weight);
134         FontTriplet key = startKey;
135         // first try given parameters
136
String JavaDoc f = getInternalFontKey(key);
137         if (f == null) {
138             // then adjust weight, favouring normal or bold
139
key = findAdjustWeight(family, style, weight);
140             f = getInternalFontKey(key);
141
142             if (!substFont && f == null) {
143                 return null;
144             }
145             
146             // only if the font may be substituted
147
// fallback 1: try the same font-family and weight with default style
148
if (f == null) {
149                 key = createFontKey(family, "normal", weight);
150                 f = getInternalFontKey(key);
151             }
152             
153             // fallback 2: try the same font-family with default style and weight
154
if (f == null) {
155                 key = createFontKey(family, "normal", 400);
156                 f = getInternalFontKey(key);
157             }
158             
159             // fallback 3: try any family with orig style/weight
160
if (f == null) {
161                 key = createFontKey("any", style, weight);
162                 f = getInternalFontKey(key);
163             }
164
165             // last resort: use default
166
if (f == null) {
167                 key = Font.DEFAULT_FONT;
168                 f = getInternalFontKey(key);
169             }
170         }
171
172         if (f != null) {
173             if (key != startKey) {
174                 notifyFontReplacement(startKey, key);
175             }
176             return key;
177         } else {
178             return null;
179         }
180     }
181
182     /**
183      * Tells this class that the font with the given internal name has been used.
184      * @param internalName the internal font name (F1, F2 etc.)
185      */

186     public void useFont(String JavaDoc internalName) {
187         usedFonts.put(internalName, fonts.get(internalName));
188     }
189     
190     /**
191      * Retrieves a (possibly cached) Font instance based on a FontTriplet and a font size.
192      * @param triplet the font triplet designating the requested font
193      * @param fontSize the font size
194      * @return the requested Font instance
195      */

196     public Font getFontInstance(FontTriplet triplet, int fontSize) {
197         Map JavaDoc sizes = (Map JavaDoc)fontInstanceCache.get(triplet);
198         if (sizes == null) {
199             sizes = new java.util.HashMap JavaDoc();
200             fontInstanceCache.put(triplet, sizes);
201         }
202         Integer JavaDoc size = new Integer JavaDoc(fontSize);
203         Font font = (Font)sizes.get(size);
204         if (font == null) {
205             String JavaDoc fname = getInternalFontKey(triplet);
206             useFont(fname);
207             FontMetrics metrics = getMetricsFor(fname);
208             font = new Font(fname, triplet, metrics, fontSize);
209             sizes.put(size, font);
210         }
211         return font;
212     }
213     
214     /**
215      * Lookup a font.
216      * <br>
217      * Locate the font name for a given family, style and weight.
218      * The font name can then be used as a key as it is unique for
219      * the associated document.
220      * This also adds the font to the list of used fonts.
221      * @param family font family
222      * @param style font style
223      * @param weight font weight
224      * @return the font triplet of the font chosen
225      */

226     public FontTriplet fontLookup(String JavaDoc family, String JavaDoc style,
227                              int weight) {
228         return fontLookup(family, style, weight, true);
229     }
230     
231     /**
232      * Lookup a font.
233      * <br>
234      * Locate the font name for a given family, style and weight.
235      * The font name can then be used as a key as it is unique for
236      * the associated document.
237      * This also adds the font to the list of used fonts.
238      * @param family font family (priority list)
239      * @param style font style
240      * @param weight font weight
241      * @return font triplet of the font chosen
242      */

243     public FontTriplet fontLookup(String JavaDoc[] family, String JavaDoc style,
244                              int weight) {
245         for (int i = 0; i < family.length; i++) {
246             FontTriplet triplet = fontLookup(family[i], style, weight, (i >= family.length - 1));
247             if (triplet != null) {
248                 return triplet;
249             }
250         }
251         throw new IllegalStateException JavaDoc("fontLookup must return a key on the last call");
252     }
253     
254     private void notifyFontReplacement(FontTriplet replacedKey, FontTriplet newKey) {
255         if (loggedFontKeys == null) {
256             loggedFontKeys = new java.util.HashSet JavaDoc();
257         }
258         if (!loggedFontKeys.contains(replacedKey)) {
259             loggedFontKeys.add(replacedKey);
260             log.warn("Font '" + replacedKey + "' not found. "
261                     + "Substituting with '" + newKey + "'.");
262         }
263     }
264     
265     /**
266      * Find a font with a given family and style by trying
267      * different font weights according to the spec.
268      * @param family font family
269      * @param style font style
270      * @param weight font weight
271      * @return internal key
272      */

273     public FontTriplet findAdjustWeight(String JavaDoc family, String JavaDoc style,
274                              int weight) {
275         FontTriplet key = null;
276         String JavaDoc f = null;
277         int newWeight = weight;
278         if (newWeight < 400) {
279             while (f == null && newWeight > 0) {
280                 newWeight -= 100;
281                 key = createFontKey(family, style, newWeight);
282                 f = getInternalFontKey(key);
283             }
284         } else if (newWeight == 500) {
285             key = createFontKey(family, style, 400);
286             f = getInternalFontKey(key);
287         } else if (newWeight > 500) {
288             while (f == null && newWeight < 1000) {
289                 newWeight += 100;
290                 key = createFontKey(family, style, newWeight);
291                 f = getInternalFontKey(key);
292             }
293             newWeight = weight;
294             while (f == null && newWeight > 400) {
295                 newWeight -= 100;
296                 key = createFontKey(family, style, newWeight);
297                 f = getInternalFontKey(key);
298             }
299         }
300         if (f == null && weight != 400) {
301             key = createFontKey(family, style, 400);
302             f = getInternalFontKey(key);
303         }
304
305         if (f != null) {
306             return key;
307         } else {
308             return null;
309         }
310     }
311
312     /**
313      * Determines if a particular font is available.
314      * @param family font family
315      * @param style font style
316      * @param weight font weight
317      * @return True if available
318      */

319     public boolean hasFont(String JavaDoc family, String JavaDoc style, int weight) {
320         FontTriplet key = createFontKey(family, style, weight);
321         return this.triplets.containsKey(key);
322     }
323
324     /**
325      * Returns the internal font key (F1, F2, F3 etc.) for a given triplet.
326      * @param triplet the font triplet
327      * @return the associated internal key or null, if not found
328      */

329     public String JavaDoc getInternalFontKey(FontTriplet triplet) {
330         return (String JavaDoc)triplets.get(triplet);
331     }
332     
333     /**
334      * Creates a key from the given strings.
335      * @param family font family
336      * @param style font style
337      * @param weight font weight
338      * @return internal key
339      */

340     public static FontTriplet createFontKey(String JavaDoc family, String JavaDoc style,
341                                        int weight) {
342         return new FontTriplet(family, style, weight);
343     }
344
345     /**
346      * Gets a Map of all registred fonts.
347      * @return a read-only Map with font key/FontMetrics pairs
348      */

349     public Map JavaDoc getFonts() {
350         return java.util.Collections.unmodifiableMap(this.fonts);
351     }
352
353     /**
354      * This is used by the renderers to retrieve all the
355      * fonts used in the document.
356      * This is for embedded font or creating a list of used fonts.
357      * @return a read-only Map with font key/FontMetrics pairs
358      */

359     public Map JavaDoc getUsedFonts() {
360         return this.usedFonts;
361     }
362
363     /**
364      * Returns the FontMetrics for a particular font
365      * @param fontName internal key
366      * @return font metrics
367      */

368     public FontMetrics getMetricsFor(String JavaDoc fontName) {
369         FontMetrics metrics = (FontMetrics)fonts.get(fontName);
370         usedFonts.put(fontName, metrics);
371         return metrics;
372     }
373
374     /**
375      * Returns the first triplet matching the given font name.
376      * As there may be multiple triplets matching the font name
377      * the result set is sorted first to guarantee consistent results.
378      * @param fontName The font name we are looking for
379      * @return The first triplet for the given font name
380      */

381     public FontTriplet getTripletFor(String JavaDoc fontName) {
382         List JavaDoc foundTriplets = new ArrayList JavaDoc();
383         for (Iterator JavaDoc iter = triplets.entrySet().iterator(); iter.hasNext();) {
384             Map.Entry JavaDoc tripletEntry = (Map.Entry JavaDoc) iter.next();
385             if (fontName.equals(((String JavaDoc)tripletEntry.getValue()))) {
386                 foundTriplets.add(tripletEntry.getKey());
387             }
388         }
389         if (foundTriplets.size() > 0) {
390             Collections.sort(foundTriplets);
391             return (FontTriplet)foundTriplets.get(0);
392         }
393         return null;
394     }
395     
396     /**
397      * Returns the font style for a particular font.
398      * There may be multiple font styles matching this font. Only the first
399      * found is returned. Searching is done on a sorted list to guarantee consistent
400      * results.
401      * @param fontName internal key
402      * @return font style
403      */

404     public String JavaDoc getFontStyleFor(String JavaDoc fontName) {
405         FontTriplet triplet = getTripletFor(fontName);
406         if (triplet != null) {
407             return triplet.getStyle();
408         } else {
409             return "";
410         }
411     }
412     
413     /**
414      * Returns the font weight for a particular font.
415      * There may be multiple font weights matching this font. Only the first
416      * found is returned. Searching is done on a sorted list to guarantee consistent
417      * results.
418      * @param fontName internal key
419      * @return font weight
420      */

421     public int getFontWeightFor(String JavaDoc fontName) {
422         FontTriplet triplet = getTripletFor(fontName);
423         if (triplet != null) {
424             return triplet.getWeight();
425         } else {
426             return 0;
427         }
428     }
429     
430 }
431
432
433
434
Popular Tags