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 true} if 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 true} if 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 true} if {@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