View Javadoc
1   /*
2    * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  /*
27   * @author Charlton Innovations, Inc.
28   */
29  
30  package java.awt.font;
31  
32  import java.awt.RenderingHints;
33  import static java.awt.RenderingHints.*;
34  import java.awt.geom.AffineTransform;
35  
36  /**
37  *   The <code>FontRenderContext</code> class is a container for the
38  *   information needed to correctly measure text.  The measurement of text
39  *   can vary because of rules that map outlines to pixels, and rendering
40  *   hints provided by an application.
41  *   <p>
42  *   One such piece of information is a transform that scales
43  *   typographical points to pixels. (A point is defined to be exactly 1/72
44  *   of an inch, which is slightly different than
45  *   the traditional mechanical measurement of a point.)  A character that
46  *   is rendered at 12pt on a 600dpi device might have a different size
47  *   than the same character rendered at 12pt on a 72dpi device because of
48  *   such factors as rounding to pixel boundaries and hints that the font
49  *   designer may have specified.
50  *   <p>
51  *   Anti-aliasing and Fractional-metrics specified by an application can also
52  *   affect the size of a character because of rounding to pixel
53  *   boundaries.
54  *   <p>
55  *   Typically, instances of <code>FontRenderContext</code> are
56  *   obtained from a {@link java.awt.Graphics2D Graphics2D} object.  A
57  *   <code>FontRenderContext</code> which is directly constructed will
58  *   most likely not represent any actual graphics device, and may lead
59  *   to unexpected or incorrect results.
60  *   @see java.awt.RenderingHints#KEY_TEXT_ANTIALIASING
61  *   @see java.awt.RenderingHints#KEY_FRACTIONALMETRICS
62  *   @see java.awt.Graphics2D#getFontRenderContext()
63  *   @see java.awt.font.LineMetrics
64  */
65  
66  public class FontRenderContext {
67      private transient AffineTransform tx;
68      private transient Object aaHintValue;
69      private transient Object fmHintValue;
70      private transient boolean defaulting;
71  
72      /**
73       * Constructs a new <code>FontRenderContext</code>
74       * object.
75       *
76       */
77      protected FontRenderContext() {
78          aaHintValue = VALUE_TEXT_ANTIALIAS_DEFAULT;
79          fmHintValue = VALUE_FRACTIONALMETRICS_DEFAULT;
80          defaulting = true;
81      }
82  
83      /**
84       * Constructs a <code>FontRenderContext</code> object from an
85       * optional {@link AffineTransform} and two <code>boolean</code>
86       * values that determine if the newly constructed object has
87       * anti-aliasing or fractional metrics.
88       * In each case the boolean values <CODE>true</CODE> and <CODE>false</CODE>
89       * correspond to the rendering hint values <CODE>ON</CODE> and
90       * <CODE>OFF</CODE> respectively.
91       * <p>
92       * To specify other hint values, use the constructor which
93       * specifies the rendering hint values as parameters :
94       * {@link #FontRenderContext(AffineTransform, Object, Object)}.
95       * @param tx the transform which is used to scale typographical points
96       * to pixels in this <code>FontRenderContext</code>.  If null, an
97       * identity transform is used.
98       * @param isAntiAliased determines if the newly constructed object
99       * has anti-aliasing.
100      * @param usesFractionalMetrics determines if the newly constructed
101      * object has fractional metrics.
102      */
103     public FontRenderContext(AffineTransform tx,
104                             boolean isAntiAliased,
105                             boolean usesFractionalMetrics) {
106         if (tx != null && !tx.isIdentity()) {
107             this.tx = new AffineTransform(tx);
108         }
109         if (isAntiAliased) {
110             aaHintValue = VALUE_TEXT_ANTIALIAS_ON;
111         } else {
112             aaHintValue = VALUE_TEXT_ANTIALIAS_OFF;
113         }
114         if (usesFractionalMetrics) {
115             fmHintValue = VALUE_FRACTIONALMETRICS_ON;
116         } else {
117             fmHintValue = VALUE_FRACTIONALMETRICS_OFF;
118         }
119     }
120 
121     /**
122      * Constructs a <code>FontRenderContext</code> object from an
123      * optional {@link AffineTransform} and two <code>Object</code>
124      * values that determine if the newly constructed object has
125      * anti-aliasing or fractional metrics.
126      * @param tx the transform which is used to scale typographical points
127      * to pixels in this <code>FontRenderContext</code>.  If null, an
128      * identity transform is used.
129      * @param aaHint - one of the text antialiasing rendering hint values
130      * defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
131      * Any other value will throw <code>IllegalArgumentException</code>.
132      * {@link java.awt.RenderingHints#VALUE_TEXT_ANTIALIAS_DEFAULT VALUE_TEXT_ANTIALIAS_DEFAULT}
133      * may be specified, in which case the mode used is implementation
134      * dependent.
135      * @param fmHint - one of the text fractional rendering hint values defined
136      * in {@link java.awt.RenderingHints java.awt.RenderingHints}.
137      * {@link java.awt.RenderingHints#VALUE_FRACTIONALMETRICS_DEFAULT VALUE_FRACTIONALMETRICS_DEFAULT}
138      * may be specified, in which case the mode used is implementation
139      * dependent.
140      * Any other value will throw <code>IllegalArgumentException</code>
141      * @throws IllegalArgumentException if the hints are not one of the
142      * legal values.
143      * @since 1.6
144      */
145     public FontRenderContext(AffineTransform tx, Object aaHint, Object fmHint){
146         if (tx != null && !tx.isIdentity()) {
147             this.tx = new AffineTransform(tx);
148         }
149         try {
150             if (KEY_TEXT_ANTIALIASING.isCompatibleValue(aaHint)) {
151                 aaHintValue = aaHint;
152             } else {
153                 throw new IllegalArgumentException("AA hint:" + aaHint);
154             }
155         } catch (Exception e) {
156             throw new IllegalArgumentException("AA hint:" +aaHint);
157         }
158         try {
159             if (KEY_FRACTIONALMETRICS.isCompatibleValue(fmHint)) {
160                 fmHintValue = fmHint;
161             } else {
162                 throw new IllegalArgumentException("FM hint:" + fmHint);
163             }
164         } catch (Exception e) {
165             throw new IllegalArgumentException("FM hint:" +fmHint);
166         }
167     }
168 
169     /**
170      * Indicates whether or not this <code>FontRenderContext</code> object
171      * measures text in a transformed render context.
172      * @return  <code>true</code> if this <code>FontRenderContext</code>
173      *          object has a non-identity AffineTransform attribute.
174      *          <code>false</code> otherwise.
175      * @see     java.awt.font.FontRenderContext#getTransform
176      * @since   1.6
177      */
178     public boolean isTransformed() {
179         if (!defaulting) {
180             return tx != null;
181         } else {
182             return !getTransform().isIdentity();
183         }
184     }
185 
186     /**
187      * Returns the integer type of the affine transform for this
188      * <code>FontRenderContext</code> as specified by
189      * {@link java.awt.geom.AffineTransform#getType()}
190      * @return the type of the transform.
191      * @see AffineTransform
192      * @since 1.6
193      */
194     public int getTransformType() {
195         if (!defaulting) {
196             if (tx == null) {
197                 return AffineTransform.TYPE_IDENTITY;
198             } else {
199                 return tx.getType();
200             }
201         } else {
202             return getTransform().getType();
203         }
204     }
205 
206     /**
207     *   Gets the transform that is used to scale typographical points
208     *   to pixels in this <code>FontRenderContext</code>.
209     *   @return the <code>AffineTransform</code> of this
210     *    <code>FontRenderContext</code>.
211     *   @see AffineTransform
212     */
213     public AffineTransform getTransform() {
214         return (tx == null) ? new AffineTransform() : new AffineTransform(tx);
215     }
216 
217     /**
218     * Returns a boolean which indicates whether or not some form of
219     * antialiasing is specified by this <code>FontRenderContext</code>.
220     * Call {@link #getAntiAliasingHint() getAntiAliasingHint()}
221     * for the specific rendering hint value.
222     *   @return    <code>true</code>, if text is anti-aliased in this
223     *   <code>FontRenderContext</code>; <code>false</code> otherwise.
224     *   @see        java.awt.RenderingHints#KEY_TEXT_ANTIALIASING
225     *   @see #FontRenderContext(AffineTransform,boolean,boolean)
226     *   @see #FontRenderContext(AffineTransform,Object,Object)
227     */
228     public boolean isAntiAliased() {
229         return !(aaHintValue == VALUE_TEXT_ANTIALIAS_OFF ||
230                  aaHintValue == VALUE_TEXT_ANTIALIAS_DEFAULT);
231     }
232 
233     /**
234     * Returns a boolean which whether text fractional metrics mode
235     * is used in this <code>FontRenderContext</code>.
236     * Call {@link #getFractionalMetricsHint() getFractionalMetricsHint()}
237     * to obtain the corresponding rendering hint value.
238     *   @return    <code>true</code>, if layout should be performed with
239     *   fractional metrics; <code>false</code> otherwise.
240     *               in this <code>FontRenderContext</code>.
241     *   @see java.awt.RenderingHints#KEY_FRACTIONALMETRICS
242     *   @see #FontRenderContext(AffineTransform,boolean,boolean)
243     *   @see #FontRenderContext(AffineTransform,Object,Object)
244     */
245     public boolean usesFractionalMetrics() {
246         return !(fmHintValue == VALUE_FRACTIONALMETRICS_OFF ||
247                  fmHintValue == VALUE_FRACTIONALMETRICS_DEFAULT);
248     }
249 
250     /**
251      * Return the text anti-aliasing rendering mode hint used in this
252      * <code>FontRenderContext</code>.
253      * This will be one of the text antialiasing rendering hint values
254      * defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
255      * @return  text anti-aliasing rendering mode hint used in this
256      * <code>FontRenderContext</code>.
257      * @since 1.6
258      */
259     public Object getAntiAliasingHint() {
260         if (defaulting) {
261             if (isAntiAliased()) {
262                  return VALUE_TEXT_ANTIALIAS_ON;
263             } else {
264                 return VALUE_TEXT_ANTIALIAS_OFF;
265             }
266         }
267         return aaHintValue;
268     }
269 
270     /**
271      * Return the text fractional metrics rendering mode hint used in this
272      * <code>FontRenderContext</code>.
273      * This will be one of the text fractional metrics rendering hint values
274      * defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
275      * @return the text fractional metrics rendering mode hint used in this
276      * <code>FontRenderContext</code>.
277      * @since 1.6
278      */
279     public Object getFractionalMetricsHint() {
280         if (defaulting) {
281             if (usesFractionalMetrics()) {
282                  return VALUE_FRACTIONALMETRICS_ON;
283             } else {
284                 return VALUE_FRACTIONALMETRICS_OFF;
285             }
286         }
287         return fmHintValue;
288     }
289 
290     /**
291      * Return true if obj is an instance of FontRenderContext and has the same
292      * transform, antialiasing, and fractional metrics values as this.
293      * @param obj the object to test for equality
294      * @return <code>true</code> if the specified object is equal to
295      *         this <code>FontRenderContext</code>; <code>false</code>
296      *         otherwise.
297      */
298     public boolean equals(Object obj) {
299         try {
300             return equals((FontRenderContext)obj);
301         }
302         catch (ClassCastException e) {
303             return false;
304         }
305     }
306 
307     /**
308      * Return true if rhs has the same transform, antialiasing,
309      * and fractional metrics values as this.
310      * @param rhs the <code>FontRenderContext</code> to test for equality
311      * @return <code>true</code> if <code>rhs</code> is equal to
312      *         this <code>FontRenderContext</code>; <code>false</code>
313      *         otherwise.
314      * @since 1.4
315      */
316     public boolean equals(FontRenderContext rhs) {
317         if (this == rhs) {
318             return true;
319         }
320         if (rhs == null) {
321             return false;
322         }
323 
324         /* if neither instance is a subclass, reference values directly. */
325         if (!rhs.defaulting && !defaulting) {
326             if (rhs.aaHintValue == aaHintValue &&
327                 rhs.fmHintValue == fmHintValue) {
328 
329                 return tx == null ? rhs.tx == null : tx.equals(rhs.tx);
330             }
331             return false;
332         } else {
333             return
334                 rhs.getAntiAliasingHint() == getAntiAliasingHint() &&
335                 rhs.getFractionalMetricsHint() == getFractionalMetricsHint() &&
336                 rhs.getTransform().equals(getTransform());
337         }
338     }
339 
340     /**
341      * Return a hashcode for this FontRenderContext.
342      */
343     public int hashCode() {
344         int hash = tx == null ? 0 : tx.hashCode();
345         /* SunHints value objects have identity hashcode, so we can rely on
346          * this to ensure that two equal FRC's have the same hashcode.
347          */
348         if (defaulting) {
349             hash += getAntiAliasingHint().hashCode();
350             hash += getFractionalMetricsHint().hashCode();
351         } else {
352             hash += aaHintValue.hashCode();
353             hash += fmHintValue.hashCode();
354         }
355         return hash;
356     }
357 }