KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > render > java2d > Java2DFontMetrics


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: Java2DFontMetrics.java 426576 2006-07-28 15:44:37Z jeremias $ */
19  
20 package org.apache.fop.render.java2d;
21
22 // Java
23
import java.awt.Font JavaDoc;
24 import java.awt.Graphics2D JavaDoc;
25 import java.awt.geom.Rectangle2D JavaDoc;
26 import java.awt.FontMetrics JavaDoc;
27 import java.awt.font.LineMetrics JavaDoc;
28 import java.awt.font.TextAttribute JavaDoc;
29 import java.awt.font.TextLayout JavaDoc;
30 import java.util.Map JavaDoc;
31
32 /**
33  * This is a FontMetrics to be used for AWT rendering.
34  * It instanciates a font, depening on family and style
35  * values. The java.awt.FontMetrics for this font is then
36  * created to be used for the actual measurement.
37  * Since layout is word by word and since it is expected that
38  * two subsequent words often share the same style, the
39  * Font and FontMetrics is buffered and only changed if needed.
40  * <p>
41  * Since FontState and FontInfo multiply all factors by
42  * size, we assume a "standard" font of FONT_SIZE.
43  */

44 public class Java2DFontMetrics {
45
46     /**
47      * Font size standard used for metric measurements
48      */

49     public static final int FONT_SIZE = 1;
50
51     /**
52      * This factor multiplies the calculated values to scale
53      * to FOP internal measurements
54      */

55     public static final int FONT_FACTOR = (1000 * 1000) / FONT_SIZE;
56
57     /**
58      * The width of all 256 character, if requested
59      */

60     private int[] width = null;
61
62     /**
63      * The typical height of a small cap latter (often derived from "x", value in mpt)
64      */

65     private int xHeight = 0;
66     
67     /**
68      * The highest point of the font above the baseline (usually derived from "d", value in mpt)
69      */

70     private int ascender = 0;
71     
72     /**
73      * The lowest point of the font under the baseline (usually derived from "p", value in mpt)
74      */

75     private int descender = 0;
76     
77     /**
78      * Buffered font.
79      * f1 is bufferd for metric measurements during layout.
80      * fSized is buffered for display purposes
81      */

82     private Font JavaDoc f1 = null; // , fSized = null;
83

84     /**
85      * The family type of the font last used
86      */

87     private String JavaDoc family = "";
88
89     /**
90      * The style of the font last used
91      */

92     private int style = 0;
93
94     /**
95      * The size of the font last used
96      */

97     private float size = 0;
98
99     /**
100      * The FontMetrics object used to calculate character width etc.
101      */

102     private FontMetrics JavaDoc fmt = null;
103
104     /** A LineMetrics to access high-resolution metrics information. */
105     private LineMetrics JavaDoc lineMetrics;
106     
107     /**
108      * Temp graphics object needed to get the font metrics
109      */

110     private Graphics2D JavaDoc graphics;
111
112     /**
113      * Constructs a new Font-metrics.
114      * @param graphics a temp graphics object - this is needed so
115      * that we can get an instance of java.awt.FontMetrics
116      */

117     public Java2DFontMetrics(Graphics2D JavaDoc graphics) {
118         this.graphics = graphics;
119     }
120
121     /**
122      * Determines the font's maximum ascent of the Font described by the current
123      * FontMetrics object
124      * @param family font family (java name) to use
125      * @param style font style (java def.) to use
126      * @param size font size
127      * @return ascent in milliponts
128      */

129     public int getMaxAscent(String JavaDoc family, int style, int size) {
130         setFont(family, style, size);
131         return Math.round(lineMetrics.getAscent() * FONT_FACTOR);
132     }
133     
134     /**
135      * Determines the font ascent of the Font described by this
136      * FontMetrics object
137      * @param family font family (java name) to use
138      * @param style font style (java def.) to use
139      * @param size font size
140      * @return ascent in milliponts
141      */

142     public int getAscender(String JavaDoc family, int style, int size) {
143         setFont(family, style, size);
144         return ascender * 1000;
145
146         // workaround for sun bug on FontMetrics.getAscent()
147
// http://developer.java.sun.com/developer/bugParade/bugs/4399887.html
148
/*
149          * Bug 4399887 has status Closed, not a bug. The comments on the bug
150          * are:
151          * The submitter is incorrectly assuming that the string he has used
152          * is displaying characters which represent those with the maximum
153          * ascent in the font. If (for example) the unicode character
154          * Á which is the A-acute character used in many European
155          * languages is placed in the bodu of the "Wrong" string it can be
156          * seen that the JDK is exactly correct in its determination of the
157          * ascent of the font.
158          * If the bounds of a particular string are interesting then the
159          * Rectangle FontMetrics.getStringBounds(..) method can be called.
160          * The y value of the rectangle is the offset from the origin
161          * (baseline) apparently needed by the sample test program
162          *
163          * xxxxx@xxxxx 2001-05-15
164          */

165         /* I don't think this is right.
166         int realAscent = fmt.getAscent()
167                          - (fmt.getDescent() + fmt.getLeading());
168         return FONT_FACTOR * realAscent;
169         */

170     }
171
172
173     /**
174      * The size of a capital letter measured from the font's baseline
175      * @param family font family
176      * @param style font style
177      * @param size font size
178      * @return capital height in millipoints
179      */

180     public int getCapHeight(String JavaDoc family, int style, int size) {
181         // currently just gets Ascent value but maybe should use
182
// getMaxAcent() at some stage
183
return getAscender(family, style, size);
184     }
185
186     /**
187      * Determines the font descent of the Font described by this
188      * FontMetrics object
189      * @param family font family (jave name) to use
190      * @param style font style (jave def.) to use
191      * @param size font size
192      * @return descent in milliponts
193      */

194     public int getDescender(String JavaDoc family, int style, int size) {
195         setFont(family, style, size);
196         return descender * 1000;
197     }
198
199     /**
200      * Determines the typical font height of a small cap letter
201      * FontMetrics object
202      * @param family font family (jave name) to use
203      * @param style font style (jave def.) to use
204      * @param size font size
205      * @return font height in milliponts
206      */

207     public int getXHeight(String JavaDoc family, int style, int size) {
208         setFont(family, style, size);
209         return xHeight * 1000;
210     }
211
212     /**
213      * Returns width (in 1/1000ths of point size) of character at
214      * code point i
215      * @param i the character for which to get the width
216      * @param family font family (jave name) to use
217      * @param style font style (jave def.) to use
218      * @param size font size
219      * @return character width in millipoints
220      */

221     public int width(int i, String JavaDoc family, int style, int size) {
222         int w;
223         setFont(family, style, size);
224         w = internalCharWidth(i) * 1000;
225         return w;
226     }
227
228     private int internalCharWidth(int i) {
229         //w = (int)(fmt.charWidth(i) * 1000); //Not accurate enough!
230
char[] ch = {(char)i};
231         Rectangle2D JavaDoc rect = fmt.getStringBounds(ch, 0, 1, this.graphics);
232         return (int)Math.round(rect.getWidth() * 1000);
233     }
234     
235     /**
236      * Return widths (in 1/1000ths of point size) of all
237      * characters
238      * @param family font family (jave name) to use
239      * @param style font style (jave def.) to use
240      * @param size font size
241      * @return array of character widths in millipoints
242      */

243     public int[] getWidths(String JavaDoc family, int style, int size) {
244         int i;
245
246         if (width == null) {
247             width = new int[256];
248         }
249         setFont(family, style, size);
250         for (i = 0; i < 256; i++) {
251             width[i] = 1000 * internalCharWidth(i);
252         }
253         return width;
254     }
255
256     private Font JavaDoc getBaseFont(String JavaDoc family, int style, float size) {
257         Map JavaDoc atts = new java.util.HashMap JavaDoc();
258         atts.put(TextAttribute.FAMILY, family);
259         if ((style & Font.BOLD) != 0) {
260             atts.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
261         }
262         if ((style & Font.ITALIC) != 0) {
263             atts.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
264         }
265         atts.put(TextAttribute.SIZE, new Float JavaDoc(size)); //size in pt
266
return new Font JavaDoc(atts);
267     }
268     
269     /**
270      * Checks whether the font for which values are
271      * requested is the one used immediately before or
272      * whether it is a new one
273      * @param family font family (jave name) to use
274      * @param style font style (jave def.) to use
275      * @param size font size
276      * @return true if the font was changed, false otherwise
277      */

278     private boolean setFont(String JavaDoc family, int style, int size) {
279         boolean changed = false;
280         float s = size / 1000f;
281
282         if (f1 == null) {
283             f1 = getBaseFont(family, style, s);
284             fmt = graphics.getFontMetrics(f1);
285             changed = true;
286         } else {
287             if ((this.style != style) || !this.family.equals(family)
288                     || this.size != s) {
289                 if (family.equals(this.family)) {
290                     f1 = f1.deriveFont(style, s);
291                 } else {
292                     f1 = getBaseFont(family, style, s);
293                 }
294                 fmt = graphics.getFontMetrics(f1);
295                 changed = true;
296             }
297             // else the font is unchanged from last time
298
}
299         if (changed) {
300             //x-Height
301
TextLayout JavaDoc layout = new TextLayout JavaDoc("x", f1, graphics.getFontRenderContext());
302             Rectangle2D JavaDoc rect = layout.getBounds();
303             xHeight = (int)Math.round(-rect.getY() * 1000);
304             
305             //PostScript-compatible ascent
306
layout = new TextLayout JavaDoc("d", f1, graphics.getFontRenderContext());
307             rect = layout.getBounds();
308             ascender = (int)Math.round(-rect.getY() * 1000);
309             
310             //PostScript-compatible descent
311
layout = new TextLayout JavaDoc("p", f1, graphics.getFontRenderContext());
312             rect = layout.getBounds();
313             descender = (int)Math.round((rect.getY() + rect.getHeight()) * -1000);
314             
315             //Alternative way to get metrics but the ascender is again wrong for our purposes
316
lineMetrics = f1.getLineMetrics("", graphics.getFontRenderContext());
317         }
318         // save the family and style for later comparison
319
this.family = family;
320         this.style = style;
321         this.size = s;
322         return changed;
323     }
324
325
326     /**
327      * Returns a java.awt.Font instance for the desired
328      * family, style and size type.
329      * This is here, so that the font-mapping
330      * of FOP-defined fonts to java-fonts can be done
331      * in one place and does not need to occur in
332      * AWTFontRenderer.
333      * @param family font family (jave name) to use
334      * @param style font style (jave def.) to use
335      * @param size font size
336      * @return font with the desired characeristics.
337      */

338     public java.awt.Font JavaDoc getFont(String JavaDoc family, int style, int size) {
339         setFont(family, style, size);
340         return f1;
341         /*
342          * if( setFont(family,style, size) ) fSized = null;
343          * if( fSized == null || this.size != size ) {
344          * fSized = f1.deriveFont( size / 1000f );
345          * }
346          * this.size = size;
347          * return fSized;
348          */

349     }
350
351     /**
352      * Indicates whether the font contains a particular character/glyph.
353      * @param family font family (jave name) to use
354      * @param style font style (jave def.) to use
355      * @param size font size
356      * @param c the glyph to check
357      * @return true if the character is supported
358      */

359     public boolean hasChar(String JavaDoc family, int style, int size, char c) {
360         setFont(family, style, size);
361         return f1.canDisplay(c);
362     }
363
364 }
365
366
367
368
369
370
371
Popular Tags