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 java.text.AttributedCharacterIterator.Attribute;
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<? extends Attribute, ?> 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 = foreground;
bgPaint = 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();
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() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append("[");
if (fgPaint != null) sb.append("fgPaint: " + fgPaint);
if (bgPaint != null) sb.append(" bgPaint: " + bgPaint);
if (swapColors) sb.append(" swapColors: true");
if (strikethrough) sb.append(" strikethrough: true");
if (stdUnderline != null) sb.append(" stdUnderline: " + stdUnderline);
if (imUnderline != null) sb.append(" imUnderline: " + imUnderline);
sb.append("]");
return sb.toString();
}
}
}