32 * of IBM. These materials are provided under terms of a License 33 * Agreement between Taligent and Sun. This technology is protected 34 * by multiple US and International patents. 35 * 36 * This notice and attribution to Taligent may not be removed. 37 * Taligent is a registered trademark of Taligent, Inc. 38 * 39 */ 40 41 package java.awt.font; 42 43 import java.awt.Shape; 44 import java.awt.Graphics; 45 import java.awt.Rectangle; 46 import java.awt.Graphics2D; 47 import java.awt.Shape; 48 import java.awt.geom.AffineTransform; 49 import java.awt.geom.Rectangle2D; 50 51 /** 52 * The <code>ShapeGraphicAttribute</code> class is an implementation of 53 * {@link GraphicAttribute} that draws shapes in a {@link TextLayout}. 54 * @see GraphicAttribute 55 */ 56 public final class ShapeGraphicAttribute extends GraphicAttribute { 57 58 private Shape fShape; 59 private boolean fStroke; 60 61 /** 62 * A key indicating the shape should be stroked with a 1-pixel wide stroke. 63 */ 64 public static final boolean STROKE = true; 65 66 /** 67 * A key indicating the shape should be filled. 68 */ 69 public static final boolean FILL = false; 70 71 // cache shape bounds, since GeneralPath doesn't 72 private Rectangle2D fShapeBounds; 73 74 /** 75 * Constructs a <code>ShapeGraphicAttribute</code> for the specified 76 * {@link Shape}. 77 * @param shape the <code>Shape</code> to render. The 78 * <code>Shape</code> is rendered with its origin at the origin of 79 * this <code>ShapeGraphicAttribute</code> in the 80 * host <code>TextLayout</code>. This object maintains a reference to 81 * <code>shape</code>. 82 * @param alignment one of the alignments from this 83 * <code>ShapeGraphicAttribute</code>. 84 * @param stroke <code>true</code> if the <code>Shape</code> should be 85 * stroked; <code>false</code> if the <code>Shape</code> should be 86 * filled. 87 */ 88 public ShapeGraphicAttribute(Shape shape, 89 int alignment, 90 boolean stroke) { 91 92 super(alignment); 93 94 fShape = shape; 95 fStroke = stroke; 96 fShapeBounds = fShape.getBounds2D(); 97 } 98 99 /** 100 * Returns the ascent of this <code>ShapeGraphicAttribute</code>. The 101 * ascent of a <code>ShapeGraphicAttribute</code> is the positive 102 * distance from the origin of its <code>Shape</code> to the top of 103 * bounds of its <code>Shape</code>. 104 * @return the ascent of this <code>ShapeGraphicAttribute</code>. 105 */ 106 public float getAscent() { 107 108 return (float) Math.max(0, -fShapeBounds.getMinY()); 109 } 110 111 /** 112 * Returns the descent of this <code>ShapeGraphicAttribute</code>. 113 * The descent of a <code>ShapeGraphicAttribute</code> is the distance 114 * from the origin of its <code>Shape</code> to the bottom of the 115 * bounds of its <code>Shape</code>. 116 * @return the descent of this <code>ShapeGraphicAttribute</code>. 117 */ 118 public float getDescent() { 119 120 return (float) Math.max(0, fShapeBounds.getMaxY()); 121 } 122 123 /** 124 * Returns the advance of this <code>ShapeGraphicAttribute</code>. 125 * The advance of a <code>ShapeGraphicAttribute</code> is the distance 126 * from the origin of its <code>Shape</code> to the right side of the 127 * bounds of its <code>Shape</code>. 128 * @return the advance of this <code>ShapeGraphicAttribute</code>. 129 */ 130 public float getAdvance() { 131 132 return (float) Math.max(0, fShapeBounds.getMaxX()); 133 } 134 135 /** 136 * {@inheritDoc} 137 */ 138 public void draw(Graphics2D graphics, float x, float y) { 139 140 // translating graphics to draw Shape !!! 141 graphics.translate((int)x, (int)y); 142 143 try { 144 if (fStroke == STROKE) { 145 // REMIND: set stroke to correct size 146 graphics.draw(fShape); 147 } 148 else { 149 graphics.fill(fShape); 150 } 151 } 152 finally { 153 graphics.translate(-(int)x, -(int)y); 154 } 155 } 156 157 /** 158 * Returns a {@link Rectangle2D} that encloses all of the 159 * bits drawn by this <code>ShapeGraphicAttribute</code> relative to 160 * the rendering position. A graphic can be rendered beyond its 161 * origin, ascent, descent, or advance; but if it does, this method's 162 * implementation should indicate where the graphic is rendered. 163 * @return a <code>Rectangle2D</code> that encloses all of the bits 164 * rendered by this <code>ShapeGraphicAttribute</code>. 165 */ 166 public Rectangle2D getBounds() { 167 168 Rectangle2D.Float bounds = new Rectangle2D.Float(); 169 bounds.setRect(fShapeBounds); 170 171 if (fStroke == STROKE) { 172 ++bounds.width; 173 ++bounds.height; 174 } 175 176 return bounds; 177 } 178 179 /** 180 * Return a {@link java.awt.Shape} that represents the region that 181 * this <code>ShapeGraphicAttribute</code> renders. This is used when a 182 * {@link TextLayout} is requested to return the outline of the text. 183 * The (untransformed) shape must not extend outside the rectangular 184 * bounds returned by <code>getBounds</code>. 185 * @param tx an optional {@link AffineTransform} to apply to the 186 * this <code>ShapeGraphicAttribute</code>. This can be null. 187 * @return the <code>Shape</code> representing this graphic attribute, 188 * suitable for stroking or filling. 189 * @since 1.6 190 */ 191 public Shape getOutline(AffineTransform tx) { 192 return tx == null ? fShape : tx.createTransformedShape(fShape); 193 } 194 195 /** 196 * Returns a hashcode for this <code>ShapeGraphicAttribute</code>. 197 * @return a hash code value for this 198 * <code>ShapeGraphicAttribute</code>. 199 */ 200 public int hashCode() { 201 202 return fShape.hashCode(); 203 } 204 205 /** 206 * Compares this <code>ShapeGraphicAttribute</code> to the specified 207 * <code>Object</code>. 208 * @param rhs the <code>Object</code> to compare for equality 209 * @return <code>true</code> if this 210 * <code>ShapeGraphicAttribute</code> equals <code>rhs</code>; 211 * <code>false</code> otherwise. 212 */ 213 public boolean equals(Object rhs) { 214 215 try { 216 return equals((ShapeGraphicAttribute) rhs); 217 } 218 catch(ClassCastException e) { 219 return false; 220 } 221 } 222 223 /** 224 * Compares this <code>ShapeGraphicAttribute</code> to the specified 225 * <code>ShapeGraphicAttribute</code>. 226 * @param rhs the <code>ShapeGraphicAttribute</code> to compare for 227 * equality 228 * @return <code>true</code> if this 229 * <code>ShapeGraphicAttribute</code> equals <code>rhs</code>; 230 * <code>false</code> otherwise. 231 */ 232 public boolean equals(ShapeGraphicAttribute rhs) { 233 234 if (rhs == null) { 235 return false; 236 } 237 238 if (this == rhs) { 239 return true; 240 } 241 242 if (fStroke != rhs.fStroke) { 243 return false; 244 } 245 246 if (getAlignment() != rhs.getAlignment()) { 247 return false; 248 } 249 250 if (!fShape.equals(rhs.fShape)) { | 32 * of IBM. These materials are provided under terms of a License 33 * Agreement between Taligent and Sun. This technology is protected 34 * by multiple US and International patents. 35 * 36 * This notice and attribution to Taligent may not be removed. 37 * Taligent is a registered trademark of Taligent, Inc. 38 * 39 */ 40 41 package java.awt.font; 42 43 import java.awt.Shape; 44 import java.awt.Graphics; 45 import java.awt.Rectangle; 46 import java.awt.Graphics2D; 47 import java.awt.Shape; 48 import java.awt.geom.AffineTransform; 49 import java.awt.geom.Rectangle2D; 50 51 /** 52 * The {@code ShapeGraphicAttribute} class is an implementation of 53 * {@link GraphicAttribute} that draws shapes in a {@link TextLayout}. 54 * @see GraphicAttribute 55 */ 56 public final class ShapeGraphicAttribute extends GraphicAttribute { 57 58 private Shape fShape; 59 private boolean fStroke; 60 61 /** 62 * A key indicating the shape should be stroked with a 1-pixel wide stroke. 63 */ 64 public static final boolean STROKE = true; 65 66 /** 67 * A key indicating the shape should be filled. 68 */ 69 public static final boolean FILL = false; 70 71 // cache shape bounds, since GeneralPath doesn't 72 private Rectangle2D fShapeBounds; 73 74 /** 75 * Constructs a {@code ShapeGraphicAttribute} for the specified 76 * {@link Shape}. 77 * @param shape the {@code Shape} to render. The 78 * {@code Shape} is rendered with its origin at the origin of 79 * this {@code ShapeGraphicAttribute} in the 80 * host {@code TextLayout}. This object maintains a reference to 81 * {@code shape}. 82 * @param alignment one of the alignments from this 83 * {@code ShapeGraphicAttribute}. 84 * @param stroke {@code true} if the {@code Shape} should be 85 * stroked; {@code false} if the {@code Shape} should be 86 * filled. 87 */ 88 public ShapeGraphicAttribute(Shape shape, 89 int alignment, 90 boolean stroke) { 91 92 super(alignment); 93 94 fShape = shape; 95 fStroke = stroke; 96 fShapeBounds = fShape.getBounds2D(); 97 } 98 99 /** 100 * Returns the ascent of this {@code ShapeGraphicAttribute}. The 101 * ascent of a {@code ShapeGraphicAttribute} is the positive 102 * distance from the origin of its {@code Shape} to the top of 103 * bounds of its {@code Shape}. 104 * @return the ascent of this {@code ShapeGraphicAttribute}. 105 */ 106 public float getAscent() { 107 108 return (float) Math.max(0, -fShapeBounds.getMinY()); 109 } 110 111 /** 112 * Returns the descent of this {@code ShapeGraphicAttribute}. 113 * The descent of a {@code ShapeGraphicAttribute} is the distance 114 * from the origin of its {@code Shape} to the bottom of the 115 * bounds of its {@code Shape}. 116 * @return the descent of this {@code ShapeGraphicAttribute}. 117 */ 118 public float getDescent() { 119 120 return (float) Math.max(0, fShapeBounds.getMaxY()); 121 } 122 123 /** 124 * Returns the advance of this {@code ShapeGraphicAttribute}. 125 * The advance of a {@code ShapeGraphicAttribute} is the distance 126 * from the origin of its {@code Shape} to the right side of the 127 * bounds of its {@code Shape}. 128 * @return the advance of this {@code ShapeGraphicAttribute}. 129 */ 130 public float getAdvance() { 131 132 return (float) Math.max(0, fShapeBounds.getMaxX()); 133 } 134 135 /** 136 * {@inheritDoc} 137 */ 138 public void draw(Graphics2D graphics, float x, float y) { 139 140 // translating graphics to draw Shape !!! 141 graphics.translate((int)x, (int)y); 142 143 try { 144 if (fStroke == STROKE) { 145 // REMIND: set stroke to correct size 146 graphics.draw(fShape); 147 } 148 else { 149 graphics.fill(fShape); 150 } 151 } 152 finally { 153 graphics.translate(-(int)x, -(int)y); 154 } 155 } 156 157 /** 158 * Returns a {@link Rectangle2D} that encloses all of the 159 * bits drawn by this {@code ShapeGraphicAttribute} relative to 160 * the rendering position. A graphic can be rendered beyond its 161 * origin, ascent, descent, or advance; but if it does, this method's 162 * implementation should indicate where the graphic is rendered. 163 * @return a {@code Rectangle2D} that encloses all of the bits 164 * rendered by this {@code ShapeGraphicAttribute}. 165 */ 166 public Rectangle2D getBounds() { 167 168 Rectangle2D.Float bounds = new Rectangle2D.Float(); 169 bounds.setRect(fShapeBounds); 170 171 if (fStroke == STROKE) { 172 ++bounds.width; 173 ++bounds.height; 174 } 175 176 return bounds; 177 } 178 179 /** 180 * Return a {@link java.awt.Shape} that represents the region that 181 * this {@code ShapeGraphicAttribute} renders. This is used when a 182 * {@link TextLayout} is requested to return the outline of the text. 183 * The (untransformed) shape must not extend outside the rectangular 184 * bounds returned by {@code getBounds}. 185 * @param tx an optional {@link AffineTransform} to apply to the 186 * this {@code ShapeGraphicAttribute}. This can be null. 187 * @return the {@code Shape} representing this graphic attribute, 188 * suitable for stroking or filling. 189 * @since 1.6 190 */ 191 public Shape getOutline(AffineTransform tx) { 192 return tx == null ? fShape : tx.createTransformedShape(fShape); 193 } 194 195 /** 196 * Returns a hashcode for this {@code ShapeGraphicAttribute}. 197 * @return a hash code value for this 198 * {@code ShapeGraphicAttribute}. 199 */ 200 public int hashCode() { 201 202 return fShape.hashCode(); 203 } 204 205 /** 206 * Compares this {@code ShapeGraphicAttribute} to the specified 207 * {@code Object}. 208 * @param rhs the {@code Object} to compare for equality 209 * @return {@code true} if this 210 * {@code ShapeGraphicAttribute} equals {@code rhs}; 211 * {@code false} otherwise. 212 */ 213 public boolean equals(Object rhs) { 214 215 try { 216 return equals((ShapeGraphicAttribute) rhs); 217 } 218 catch(ClassCastException e) { 219 return false; 220 } 221 } 222 223 /** 224 * Compares this {@code ShapeGraphicAttribute} to the specified 225 * {@code ShapeGraphicAttribute}. 226 * @param rhs the {@code ShapeGraphicAttribute} to compare for 227 * equality 228 * @return {@code true} if this 229 * {@code ShapeGraphicAttribute} equals {@code rhs}; 230 * {@code false} otherwise. 231 */ 232 public boolean equals(ShapeGraphicAttribute rhs) { 233 234 if (rhs == null) { 235 return false; 236 } 237 238 if (this == rhs) { 239 return true; 240 } 241 242 if (fStroke != rhs.fStroke) { 243 return false; 244 } 245 246 if (getAlignment() != rhs.getAlignment()) { 247 return false; 248 } 249 250 if (!fShape.equals(rhs.fShape)) { |