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} 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} are
56 *   obtained from a {@link java.awt.Graphics2D Graphics2D} object.  A
57 *   {@code FontRenderContext} 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}
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} object from an
85      * optional {@link AffineTransform} and two {@code boolean}
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} and {@code false}
89      * correspond to the rendering hint values {@code ON} and
90      * {@code OFF} 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}.  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} object from an
123      * optional {@link AffineTransform} and two {@code Object}
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}.  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}.
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}
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} object
171      * measures text in a transformed render context.
172      * @return  {@code trueif this {@code FontRenderContext}
173      *          object has a non-identity AffineTransform attribute.
174      *          {@code false} 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} 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}.
209     *   @return the {@code AffineTransform} of this
210     *    {@code FontRenderContext}.
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}.
220     * Call {@link #getAntiAliasingHint() getAntiAliasingHint()}
221     * for the specific rendering hint value.
222     *   @return    {@code true}, if text is anti-aliased in this
223     *   {@code FontRenderContext}; {@code false} 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}.
236     * Call {@link #getFractionalMetricsHint() getFractionalMetricsHint()}
237     * to obtain the corresponding rendering hint value.
238     *   @return    {@code true}, if layout should be performed with
239     *   fractional metrics; {@code false} otherwise.
240     *               in this {@code FontRenderContext}.
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}.
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}.
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}.
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}.
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 trueif the specified object is equal to
295      *         this {@code FontRenderContext}; {@code false}
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} to test for equality
311      * @return {@code trueif {@code rhs} is equal to
312      *         this {@code FontRenderContext}; {@code false}
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 }
358