|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
* (C) Copyright IBM Corp. 1999-2003, All Rights Reserved |
|
* |
|
*/ |
|
|
|
package sun.font; |
|
|
|
import java.util.Map; |
|
|
|
import java.awt.BasicStroke; |
|
import java.awt.Color; |
|
import java.awt.Graphics2D; |
|
import java.awt.Paint; |
|
import java.awt.RenderingHints; |
|
import java.awt.Shape; |
|
import java.awt.Stroke; |
|
|
|
import java.awt.font.TextAttribute; |
|
|
|
import java.awt.geom.Area; |
|
import java.awt.geom.Line2D; |
|
import java.awt.geom.Rectangle2D; |
|
import java.awt.geom.GeneralPath; |
|
|
|
import static sun.font.AttributeValues.*; |
|
import static sun.font.EAttribute.*; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class Decoration { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public interface Label { |
|
CoreMetrics getCoreMetrics(); |
|
Rectangle2D getLogicalBounds(); |
|
|
|
void handleDraw(Graphics2D g2d, float x, float y); |
|
Rectangle2D handleGetCharVisualBounds(int index); |
|
Rectangle2D handleGetVisualBounds(); |
|
Shape handleGetOutline(float x, float y); |
|
} |
|
|
|
private Decoration() { |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static Decoration getPlainDecoration() { |
|
|
|
return PLAIN; |
|
} |
|
|
|
private static final int VALUES_MASK = |
|
AttributeValues.getMask(EFOREGROUND, EBACKGROUND, ESWAP_COLORS, |
|
ESTRIKETHROUGH, EUNDERLINE, EINPUT_METHOD_HIGHLIGHT, |
|
EINPUT_METHOD_UNDERLINE); |
|
|
|
public static Decoration getDecoration(AttributeValues values) { |
|
if (values == null || !values.anyDefined(VALUES_MASK)) { |
|
return PLAIN; |
|
} |
|
|
|
values = values.applyIMHighlight(); |
|
|
|
return new DecorationImpl(values.getForeground(), |
|
values.getBackground(), |
|
values.getSwapColors(), |
|
values.getStrikethrough(), |
|
Underline.getUnderline(values.getUnderline()), |
|
Underline.getUnderline(values.getInputMethodUnderline())); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static Decoration getDecoration(Map attributes) { |
|
if (attributes == null) { |
|
return PLAIN; |
|
} |
|
return getDecoration(AttributeValues.fromMap(attributes)); |
|
} |
|
|
|
public void drawTextAndDecorations(Label label, |
|
Graphics2D g2d, |
|
float x, |
|
float y) { |
|
|
|
label.handleDraw(g2d, x, y); |
|
} |
|
|
|
public Rectangle2D getVisualBounds(Label label) { |
|
|
|
return label.handleGetVisualBounds(); |
|
} |
|
|
|
public Rectangle2D getCharVisualBounds(Label label, int index) { |
|
|
|
return label.handleGetCharVisualBounds(index); |
|
} |
|
|
|
Shape getOutline(Label label, |
|
float x, |
|
float y) { |
|
|
|
return label.handleGetOutline(x, y); |
|
} |
|
|
|
private static final Decoration PLAIN = new Decoration(); |
|
|
|
private static final class DecorationImpl extends Decoration { |
|
|
|
private Paint fgPaint = null; |
|
private Paint bgPaint = null; |
|
private boolean swapColors = false; |
|
private boolean strikethrough = false; |
|
private Underline stdUnderline = null; |
|
private Underline imUnderline = null; |
|
|
|
DecorationImpl(Paint foreground, |
|
Paint background, |
|
boolean swapColors, |
|
boolean strikethrough, |
|
Underline stdUnderline, |
|
Underline imUnderline) { |
|
|
|
fgPaint = (Paint) foreground; |
|
bgPaint = (Paint) background; |
|
|
|
this.swapColors = swapColors; |
|
this.strikethrough = strikethrough; |
|
|
|
this.stdUnderline = stdUnderline; |
|
this.imUnderline = imUnderline; |
|
} |
|
|
|
private static boolean areEqual(Object lhs, Object rhs) { |
|
|
|
if (lhs == null) { |
|
return rhs == null; |
|
} |
|
else { |
|
return lhs.equals(rhs); |
|
} |
|
} |
|
|
|
public boolean equals(Object rhs) { |
|
|
|
if (rhs == this) { |
|
return true; |
|
} |
|
if (rhs == null) { |
|
return false; |
|
} |
|
|
|
DecorationImpl other = null; |
|
try { |
|
other = (DecorationImpl) rhs; |
|
} |
|
catch(ClassCastException e) { |
|
return false; |
|
} |
|
|
|
if (!(swapColors == other.swapColors && |
|
strikethrough == other.strikethrough)) { |
|
return false; |
|
} |
|
|
|
if (!areEqual(stdUnderline, other.stdUnderline)) { |
|
return false; |
|
} |
|
if (!areEqual(fgPaint, other.fgPaint)) { |
|
return false; |
|
} |
|
if (!areEqual(bgPaint, other.bgPaint)) { |
|
return false; |
|
} |
|
return areEqual(imUnderline, other.imUnderline); |
|
} |
|
|
|
public int hashCode() { |
|
|
|
int hc = 1; |
|
if (strikethrough) { |
|
hc |= 2; |
|
} |
|
if (swapColors) { |
|
hc |= 4; |
|
} |
|
if (stdUnderline != null) { |
|
hc += stdUnderline.hashCode(); |
|
} |
|
return hc; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private float getUnderlineMaxY(CoreMetrics cm) { |
|
|
|
float maxY = 0; |
|
if (stdUnderline != null) { |
|
|
|
float ulBottom = cm.underlineOffset; |
|
ulBottom += stdUnderline.getLowerDrawLimit(cm.underlineThickness); |
|
maxY = Math.max(maxY, ulBottom); |
|
} |
|
|
|
if (imUnderline != null) { |
|
|
|
float ulBottom = cm.underlineOffset; |
|
ulBottom += imUnderline.getLowerDrawLimit(cm.underlineThickness); |
|
maxY = Math.max(maxY, ulBottom); |
|
} |
|
|
|
return maxY; |
|
} |
|
|
|
private void drawTextAndEmbellishments(Label label, |
|
Graphics2D g2d, |
|
float x, |
|
float y) { |
|
|
|
label.handleDraw(g2d, x, y); |
|
|
|
if (!strikethrough && stdUnderline == null && imUnderline == null) { |
|
return; |
|
} |
|
|
|
float x1 = x; |
|
float x2 = x1 + (float)label.getLogicalBounds().getWidth(); |
|
|
|
CoreMetrics cm = label.getCoreMetrics(); |
|
if (strikethrough) { |
|
Stroke savedStroke = g2d.getStroke(); |
|
g2d.setStroke(new BasicStroke(cm.strikethroughThickness, |
|
BasicStroke.CAP_BUTT, |
|
BasicStroke.JOIN_MITER)); |
|
float strikeY = y + cm.strikethroughOffset; |
|
g2d.draw(new Line2D.Float(x1, strikeY, x2, strikeY)); |
|
g2d.setStroke(savedStroke); |
|
} |
|
|
|
float ulOffset = cm.underlineOffset; |
|
float ulThickness = cm.underlineThickness; |
|
|
|
if (stdUnderline != null) { |
|
stdUnderline.drawUnderline(g2d, ulThickness, x1, x2, y + ulOffset); |
|
} |
|
|
|
if (imUnderline != null) { |
|
imUnderline.drawUnderline(g2d, ulThickness, x1, x2, y + ulOffset); |
|
} |
|
} |
|
|
|
public void drawTextAndDecorations(Label label, |
|
Graphics2D g2d, |
|
float x, |
|
float y) { |
|
|
|
if (fgPaint == null && bgPaint == null && swapColors == false) { |
|
drawTextAndEmbellishments(label, g2d, x, y); |
|
} |
|
else { |
|
Paint savedPaint = g2d.getPaint(); |
|
Paint foreground, background; |
|
|
|
if (swapColors) { |
|
background = fgPaint==null? savedPaint : fgPaint; |
|
if (bgPaint == null) { |
|
if (background instanceof Color) { |
|
Color bg = (Color)background; |
|
|
|
int brightness = 33 * bg.getRed() |
|
+ 53 * bg.getGreen() |
|
+ 14 * bg.getBlue(); |
|
foreground = brightness > 18500 ? Color.BLACK : Color.WHITE; |
|
} else { |
|
foreground = Color.WHITE; |
|
} |
|
} else { |
|
foreground = bgPaint; |
|
} |
|
} |
|
else { |
|
foreground = fgPaint==null? savedPaint : fgPaint; |
|
background = bgPaint; |
|
} |
|
|
|
if (background != null) { |
|
|
|
Rectangle2D bgArea = label.getLogicalBounds(); |
|
bgArea = new Rectangle2D.Float(x + (float)bgArea.getX(), |
|
y + (float)bgArea.getY(), |
|
(float)bgArea.getWidth(), |
|
(float)bgArea.getHeight()); |
|
|
|
g2d.setPaint(background); |
|
g2d.fill(bgArea); |
|
} |
|
|
|
g2d.setPaint(foreground); |
|
drawTextAndEmbellishments(label, g2d, x, y); |
|
g2d.setPaint(savedPaint); |
|
} |
|
} |
|
|
|
public Rectangle2D getVisualBounds(Label label) { |
|
|
|
Rectangle2D visBounds = label.handleGetVisualBounds(); |
|
|
|
if (swapColors || bgPaint != null || strikethrough |
|
|| stdUnderline != null || imUnderline != null) { |
|
|
|
float minX = 0; |
|
Rectangle2D lb = label.getLogicalBounds(); |
|
|
|
float minY = 0, maxY = 0; |
|
|
|
if (swapColors || bgPaint != null) { |
|
|
|
minY = (float)lb.getY(); |
|
maxY = minY + (float)lb.getHeight(); |
|
} |
|
|
|
maxY = Math.max(maxY, getUnderlineMaxY(label.getCoreMetrics())); |
|
|
|
Rectangle2D ab = new Rectangle2D.Float(minX, minY, (float)lb.getWidth(), maxY-minY); |
|
visBounds.add(ab); |
|
} |
|
|
|
return visBounds; |
|
} |
|
|
|
Shape getOutline(Label label, |
|
float x, |
|
float y) { |
|
|
|
if (!strikethrough && stdUnderline == null && imUnderline == null) { |
|
return label.handleGetOutline(x, y); |
|
} |
|
|
|
CoreMetrics cm = label.getCoreMetrics(); |
|
|
|
// NOTE: The performace of the following code may |
|
|
|
float ulThickness = cm.underlineThickness; |
|
float ulOffset = cm.underlineOffset; |
|
|
|
Rectangle2D lb = label.getLogicalBounds(); |
|
float x1 = x; |
|
float x2 = x1 + (float)lb.getWidth(); |
|
|
|
Area area = null; |
|
|
|
if (stdUnderline != null) { |
|
Shape ul = stdUnderline.getUnderlineShape(ulThickness, |
|
x1, x2, y+ulOffset); |
|
area = new Area(ul); |
|
} |
|
|
|
if (strikethrough) { |
|
Stroke stStroke = new BasicStroke(cm.strikethroughThickness, |
|
BasicStroke.CAP_BUTT, |
|
BasicStroke.JOIN_MITER); |
|
float shiftY = y + cm.strikethroughOffset; |
|
Line2D line = new Line2D.Float(x1, shiftY, x2, shiftY); |
|
Area slArea = new Area(stStroke.createStrokedShape(line)); |
|
if(area == null) { |
|
area = slArea; |
|
} else { |
|
area.add(slArea); |
|
} |
|
} |
|
|
|
if (imUnderline != null) { |
|
Shape ul = imUnderline.getUnderlineShape(ulThickness, |
|
x1, x2, y+ulOffset); |
|
Area ulArea = new Area(ul); |
|
if (area == null) { |
|
area = ulArea; |
|
} |
|
else { |
|
area.add(ulArea); |
|
} |
|
} |
|
|
|
|
|
area.add(new Area(label.handleGetOutline(x, y))); |
|
|
|
return new GeneralPath(area); |
|
} |
|
|
|
|
|
public String toString() { |
|
StringBuffer buf = new StringBuffer(); |
|
buf.append(super.toString()); |
|
buf.append("["); |
|
if (fgPaint != null) buf.append("fgPaint: " + fgPaint); |
|
if (bgPaint != null) buf.append(" bgPaint: " + bgPaint); |
|
if (swapColors) buf.append(" swapColors: true"); |
|
if (strikethrough) buf.append(" strikethrough: true"); |
|
if (stdUnderline != null) buf.append(" stdUnderline: " + stdUnderline); |
|
if (imUnderline != null) buf.append(" imUnderline: " + imUnderline); |
|
buf.append("]"); |
|
return buf.toString(); |
|
} |
|
} |
|
} |