001 /*
002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 /*
027 * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
028 * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
029 *
030 * The original version of this source code and documentation is
031 * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
032 * of IBM. These materials are provided under terms of a License
033 * Agreement between Taligent and Sun. This technology is protected
034 * by multiple US and International patents.
035 *
036 * This notice and attribution to Taligent may not be removed.
037 * Taligent is a registered trademark of Taligent, Inc.
038 *
039 */
040
041 package java.awt.font;
042
043 import java.awt.Shape;
044 import java.awt.Graphics;
045 import java.awt.Rectangle;
046 import java.awt.Graphics2D;
047 import java.awt.Shape;
048 import java.awt.geom.AffineTransform;
049 import java.awt.geom.Rectangle2D;
050
051 /**
052 * The <code>ShapeGraphicAttribute</code> class is an implementation of
053 * {@link GraphicAttribute} that draws shapes in a {@link TextLayout}.
054 * @see GraphicAttribute
055 */
056 public final class ShapeGraphicAttribute extends GraphicAttribute {
057
058 private Shape fShape;
059 private boolean fStroke;
060
061 /**
062 * A key indicating the shape should be stroked with a 1-pixel wide stroke.
063 */
064 public static final boolean STROKE = true;
065
066 /**
067 * A key indicating the shape should be filled.
068 */
069 public static final boolean FILL = false;
070
071 // cache shape bounds, since GeneralPath doesn't
072 private Rectangle2D fShapeBounds;
073
074 /**
075 * Constructs a <code>ShapeGraphicAttribute</code> for the specified
076 * {@link Shape}.
077 * @param shape the <code>Shape</code> to render. The
078 * <code>Shape</code> is rendered with its origin at the origin of
079 * this <code>ShapeGraphicAttribute</code> in the
080 * host <code>TextLayout</code>. This object maintains a reference to
081 * <code>shape</code>.
082 * @param alignment one of the alignments from this
083 * <code>ShapeGraphicAttribute</code>.
084 * @param stroke <code>true</code> if the <code>Shape</code> should be
085 * stroked; <code>false</code> if the <code>Shape</code> should be
086 * filled.
087 */
088 public ShapeGraphicAttribute(Shape shape, int alignment,
089 boolean stroke) {
090
091 super (alignment);
092
093 fShape = shape;
094 fStroke = stroke;
095 fShapeBounds = fShape.getBounds2D();
096 }
097
098 /**
099 * Returns the ascent of this <code>ShapeGraphicAttribute</code>. The
100 * ascent of a <code>ShapeGraphicAttribute</code> is the positive
101 * distance from the origin of its <code>Shape</code> to the top of
102 * bounds of its <code>Shape</code>.
103 * @return the ascent of this <code>ShapeGraphicAttribute</code>.
104 */
105 public float getAscent() {
106
107 return (float) Math.max(0, -fShapeBounds.getMinY());
108 }
109
110 /**
111 * Returns the descent of this <code>ShapeGraphicAttribute</code>.
112 * The descent of a <code>ShapeGraphicAttribute</code> is the distance
113 * from the origin of its <code>Shape</code> to the bottom of the
114 * bounds of its <code>Shape</code>.
115 * @return the descent of this <code>ShapeGraphicAttribute</code>.
116 */
117 public float getDescent() {
118
119 return (float) Math.max(0, fShapeBounds.getMaxY());
120 }
121
122 /**
123 * Returns the advance of this <code>ShapeGraphicAttribute</code>.
124 * The advance of a <code>ShapeGraphicAttribute</code> is the distance
125 * from the origin of its <code>Shape</code> to the right side of the
126 * bounds of its <code>Shape</code>.
127 * @return the advance of this <code>ShapeGraphicAttribute</code>.
128 */
129 public float getAdvance() {
130
131 return (float) Math.max(0, fShapeBounds.getMaxX());
132 }
133
134 /**
135 * {@inheritDoc}
136 */
137 public void draw(Graphics2D graphics, float x, float y) {
138
139 // translating graphics to draw Shape !!!
140 graphics.translate((int) x, (int) y);
141
142 try {
143 if (fStroke == STROKE) {
144 // REMIND: set stroke to correct size
145 graphics.draw(fShape);
146 } else {
147 graphics.fill(fShape);
148 }
149 } finally {
150 graphics.translate(-(int) x, -(int) y);
151 }
152 }
153
154 /**
155 * Returns a {@link Rectangle2D} that encloses all of the
156 * bits drawn by this <code>ShapeGraphicAttribute</code> relative to
157 * the rendering position. A graphic can be rendered beyond its
158 * origin, ascent, descent, or advance; but if it does, this method's
159 * implementation should indicate where the graphic is rendered.
160 * @return a <code>Rectangle2D</code> that encloses all of the bits
161 * rendered by this <code>ShapeGraphicAttribute</code>.
162 */
163 public Rectangle2D getBounds() {
164
165 Rectangle2D.Float bounds = new Rectangle2D.Float();
166 bounds.setRect(fShapeBounds);
167
168 if (fStroke == STROKE) {
169 ++bounds.width;
170 ++bounds.height;
171 }
172
173 return bounds;
174 }
175
176 /**
177 * Return a {@link java.awt.Shape} that represents the region that
178 * this <code>ShapeGraphicAttribute</code> renders. This is used when a
179 * {@link TextLayout} is requested to return the outline of the text.
180 * The (untransformed) shape must not extend outside the rectangular
181 * bounds returned by <code>getBounds</code>.
182 * @param tx an optional {@link AffineTransform} to apply to the
183 * this <code>ShapeGraphicAttribute</code>. This can be null.
184 * @return the <code>Shape</code> representing this graphic attribute,
185 * suitable for stroking or filling.
186 * @since 1.6
187 */
188 public Shape getOutline(AffineTransform tx) {
189 return tx == null ? fShape : tx.createTransformedShape(fShape);
190 }
191
192 /**
193 * Returns a hashcode for this <code>ShapeGraphicAttribute</code>.
194 * @return a hash code value for this
195 * <code>ShapeGraphicAttribute</code>.
196 */
197 public int hashCode() {
198
199 return fShape.hashCode();
200 }
201
202 /**
203 * Compares this <code>ShapeGraphicAttribute</code> to the specified
204 * <code>Object</code>.
205 * @param rhs the <code>Object</code> to compare for equality
206 * @return <code>true</code> if this
207 * <code>ShapeGraphicAttribute</code> equals <code>rhs</code>;
208 * <code>false</code> otherwise.
209 */
210 public boolean equals(Object rhs) {
211
212 try {
213 return equals((ShapeGraphicAttribute) rhs);
214 } catch (ClassCastException e) {
215 return false;
216 }
217 }
218
219 /**
220 * Compares this <code>ShapeGraphicAttribute</code> to the specified
221 * <code>ShapeGraphicAttribute</code>.
222 * @param rhs the <code>ShapeGraphicAttribute</code> to compare for
223 * equality
224 * @return <code>true</code> if this
225 * <code>ShapeGraphicAttribute</code> equals <code>rhs</code>;
226 * <code>false</code> otherwise.
227 */
228 public boolean equals(ShapeGraphicAttribute rhs) {
229
230 if (rhs == null) {
231 return false;
232 }
233
234 if (this == rhs) {
235 return true;
236 }
237
238 if (fStroke != rhs.fStroke) {
239 return false;
240 }
241
242 if (getAlignment() != rhs.getAlignment()) {
243 return false;
244 }
245
246 if (!fShape.equals(rhs.fShape)) {
247 return false;
248 }
249
250 return true;
251 }
252 }
|