|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
* |
|
* (C) Copyright IBM Corp. 2005 - All Rights Reserved |
|
* |
|
* The original version of this source code and documentation is |
|
* copyrighted and owned by IBM. These materials are provided |
|
* under terms of a License Agreement between IBM and Sun. |
|
* This technology is protected by multiple US and International |
|
* patents. This notice and attribution to IBM may not be removed. |
|
*/ |
|
|
|
package sun.font; |
|
|
|
import static sun.font.EAttribute.*; |
|
import static java.lang.Math.*; |
|
|
|
import java.awt.Font; |
|
import java.awt.Paint; |
|
import java.awt.Toolkit; |
|
import java.awt.font.GraphicAttribute; |
|
import java.awt.font.NumericShaper; |
|
import java.awt.font.TextAttribute; |
|
import java.awt.font.TransformAttribute; |
|
import java.awt.geom.AffineTransform; |
|
import java.awt.geom.NoninvertibleTransformException; |
|
import java.awt.geom.Point2D; |
|
import java.awt.im.InputMethodHighlight; |
|
import java.io.Serializable; |
|
import java.text.Annotation; |
|
import java.text.AttributedCharacterIterator.Attribute; |
|
import java.util.Map; |
|
import java.util.HashMap; |
|
import java.util.Hashtable; |
|
|
|
public final class AttributeValues implements Cloneable { |
|
private int defined; |
|
private int nondefault; |
|
|
|
private String family = "Default"; |
|
private float weight = 1f; |
|
private float width = 1f; |
|
private float posture; |
|
private float size = 12f; |
|
private float tracking; |
|
private NumericShaper numericShaping; |
|
private AffineTransform transform; |
|
private GraphicAttribute charReplacement; |
|
private Paint foreground; |
|
private Paint background; |
|
private float justification = 1f; |
|
private Object imHighlight; |
|
// (can be either Attribute wrapping IMH, or IMH itself |
|
private Font font; |
|
private byte imUnderline = -1; |
|
private byte superscript; |
|
private byte underline = -1; |
|
private byte runDirection = -2; |
|
private byte bidiEmbedding; |
|
private byte kerning; |
|
private byte ligatures; |
|
private boolean strikethrough; |
|
private boolean swapColors; |
|
|
|
private AffineTransform baselineTransform; |
|
private AffineTransform charTransform; |
|
|
|
private static final AttributeValues DEFAULT = new AttributeValues(); |
|
|
|
|
|
public String getFamily() { return family; } |
|
public void setFamily(String f) { this.family = f; update(EFAMILY); } |
|
|
|
public float getWeight() { return weight; } |
|
public void setWeight(float f) { this.weight = f; update(EWEIGHT); } |
|
|
|
public float getWidth() { return width; } |
|
public void setWidth(float f) { this.width = f; update(EWIDTH); } |
|
|
|
public float getPosture() { return posture; } |
|
public void setPosture(float f) { this.posture = f; update(EPOSTURE); } |
|
|
|
public float getSize() { return size; } |
|
public void setSize(float f) { this.size = f; update(ESIZE); } |
|
|
|
public AffineTransform getTransform() { return transform; } |
|
public void setTransform(AffineTransform f) { |
|
this.transform = (f == null || f.isIdentity()) |
|
? DEFAULT.transform |
|
: new AffineTransform(f); |
|
updateDerivedTransforms(); |
|
update(ETRANSFORM); |
|
} |
|
public void setTransform(TransformAttribute f) { |
|
this.transform = (f == null || f.isIdentity()) |
|
? DEFAULT.transform |
|
: f.getTransform(); |
|
updateDerivedTransforms(); |
|
update(ETRANSFORM); |
|
} |
|
|
|
public int getSuperscript() { return superscript; } |
|
public void setSuperscript(int f) { |
|
this.superscript = (byte)f; update(ESUPERSCRIPT); } |
|
|
|
public Font getFont() { return font; } |
|
public void setFont(Font f) { this.font = f; update(EFONT); } |
|
|
|
public GraphicAttribute getCharReplacement() { return charReplacement; } |
|
public void setCharReplacement(GraphicAttribute f) { |
|
this.charReplacement = f; update(ECHAR_REPLACEMENT); } |
|
|
|
public Paint getForeground() { return foreground; } |
|
public void setForeground(Paint f) { |
|
this.foreground = f; update(EFOREGROUND); } |
|
|
|
public Paint getBackground() { return background; } |
|
public void setBackground(Paint f) { |
|
this.background = f; update(EBACKGROUND); } |
|
|
|
public int getUnderline() { return underline; } |
|
public void setUnderline(int f) { |
|
this.underline = (byte)f; update(EUNDERLINE); } |
|
|
|
public boolean getStrikethrough() { return strikethrough; } |
|
public void setStrikethrough(boolean f) { |
|
this.strikethrough = f; update(ESTRIKETHROUGH); } |
|
|
|
public int getRunDirection() { return runDirection; } |
|
public void setRunDirection(int f) { |
|
this.runDirection = (byte)f; update(ERUN_DIRECTION); } |
|
|
|
public int getBidiEmbedding() { return bidiEmbedding; } |
|
public void setBidiEmbedding(int f) { |
|
this.bidiEmbedding = (byte)f; update(EBIDI_EMBEDDING); } |
|
|
|
public float getJustification() { return justification; } |
|
public void setJustification(float f) { |
|
this.justification = f; update(EJUSTIFICATION); } |
|
|
|
public Object getInputMethodHighlight() { return imHighlight; } |
|
public void setInputMethodHighlight(Annotation f) { |
|
this.imHighlight = f; update(EINPUT_METHOD_HIGHLIGHT); } |
|
public void setInputMethodHighlight(InputMethodHighlight f) { |
|
this.imHighlight = f; update(EINPUT_METHOD_HIGHLIGHT); } |
|
|
|
public int getInputMethodUnderline() { return imUnderline; } |
|
public void setInputMethodUnderline(int f) { |
|
this.imUnderline = (byte)f; update(EINPUT_METHOD_UNDERLINE); } |
|
|
|
public boolean getSwapColors() { return swapColors; } |
|
public void setSwapColors(boolean f) { |
|
this.swapColors = f; update(ESWAP_COLORS); } |
|
|
|
public NumericShaper getNumericShaping() { return numericShaping; } |
|
public void setNumericShaping(NumericShaper f) { |
|
this.numericShaping = f; update(ENUMERIC_SHAPING); } |
|
|
|
public int getKerning() { return kerning; } |
|
public void setKerning(int f) { |
|
this.kerning = (byte)f; update(EKERNING); } |
|
|
|
public float getTracking() { return tracking; } |
|
public void setTracking(float f) { |
|
this.tracking = (byte)f; update(ETRACKING); } |
|
|
|
public int getLigatures() { return ligatures; } |
|
public void setLigatures(int f) { |
|
this.ligatures = (byte)f; update(ELIGATURES); } |
|
|
|
|
|
public AffineTransform getBaselineTransform() { return baselineTransform; } |
|
public AffineTransform getCharTransform() { return charTransform; } |
|
|
|
// mask api |
|
|
|
public static int getMask(EAttribute att) { |
|
return att.mask; |
|
} |
|
|
|
public static int getMask(EAttribute ... atts) { |
|
int mask = 0; |
|
for (EAttribute a: atts) { |
|
mask |= a.mask; |
|
} |
|
return mask; |
|
} |
|
|
|
public static final int MASK_ALL = |
|
getMask(EAttribute.class.getEnumConstants()); |
|
|
|
public void unsetDefault() { |
|
defined &= nondefault; |
|
} |
|
|
|
public void defineAll(int mask) { |
|
defined |= mask; |
|
if ((defined & EBASELINE_TRANSFORM.mask) != 0) { |
|
throw new InternalError("can't define derived attribute"); |
|
} |
|
} |
|
|
|
public boolean allDefined(int mask) { |
|
return (defined & mask) == mask; |
|
} |
|
|
|
public boolean anyDefined(int mask) { |
|
return (defined & mask) != 0; |
|
} |
|
|
|
public boolean anyNonDefault(int mask) { |
|
return (nondefault & mask) != 0; |
|
} |
|
|
|
// generic EAttribute API |
|
|
|
public boolean isDefined(EAttribute a) { |
|
return (defined & a.mask) != 0; |
|
} |
|
|
|
public boolean isNonDefault(EAttribute a) { |
|
return (nondefault & a.mask) != 0; |
|
} |
|
|
|
public void setDefault(EAttribute a) { |
|
if (a.att == null) { |
|
throw new InternalError("can't set default derived attribute: " + a); |
|
} |
|
i_set(a, DEFAULT); |
|
defined |= a.mask; |
|
nondefault &= ~a.mask; |
|
} |
|
|
|
public void unset(EAttribute a) { |
|
if (a.att == null) { |
|
throw new InternalError("can't unset derived attribute: " + a); |
|
} |
|
i_set(a, DEFAULT); |
|
defined &= ~a.mask; |
|
nondefault &= ~a.mask; |
|
} |
|
|
|
public void set(EAttribute a, AttributeValues src) { |
|
if (a.att == null) { |
|
throw new InternalError("can't set derived attribute: " + a); |
|
} |
|
if (src == null || src == DEFAULT) { |
|
setDefault(a); |
|
} else { |
|
if ((src.defined & a.mask) != 0) { |
|
i_set(a, src); |
|
update(a); |
|
} |
|
} |
|
} |
|
|
|
public void set(EAttribute a, Object o) { |
|
if (a.att == null) { |
|
throw new InternalError("can't set derived attribute: " + a); |
|
} |
|
if (o != null) { |
|
try { |
|
i_set(a, o); |
|
update(a); |
|
return; |
|
} catch (Exception e) { |
|
} |
|
} |
|
setDefault(a); |
|
} |
|
|
|
public Object get(EAttribute a) { |
|
if (a.att == null) { |
|
throw new InternalError("can't get derived attribute: " + a); |
|
} |
|
if ((nondefault & a.mask) != 0) { |
|
return i_get(a); |
|
} |
|
return null; |
|
} |
|
|
|
// merging |
|
|
|
public AttributeValues merge(Map<? extends Attribute, ?>map) { |
|
return merge(map, MASK_ALL); |
|
} |
|
|
|
public AttributeValues merge(Map<? extends Attribute, ?>map, |
|
int mask) { |
|
if (map instanceof AttributeMap && |
|
((AttributeMap) map).getValues() != null) { |
|
merge(((AttributeMap)map).getValues(), mask); |
|
} else if (map != null && !map.isEmpty()) { |
|
for (Map.Entry<? extends Attribute, ?> e: map.entrySet()) { |
|
try { |
|
EAttribute ea = EAttribute.forAttribute(e.getKey()); |
|
if (ea!= null && (mask & ea.mask) != 0) { |
|
set(ea, e.getValue()); |
|
} |
|
} catch (ClassCastException cce) { |
|
// IGNORED |
|
} |
|
} |
|
} |
|
return this; |
|
} |
|
|
|
public AttributeValues merge(AttributeValues src) { |
|
return merge(src, MASK_ALL); |
|
} |
|
|
|
public AttributeValues merge(AttributeValues src, int mask) { |
|
int m = mask & src.defined; |
|
for (EAttribute ea: EAttribute.atts) { |
|
if (m == 0) { |
|
break; |
|
} |
|
if ((m & ea.mask) != 0) { |
|
m &= ~ea.mask; |
|
i_set(ea, src); |
|
update(ea); |
|
} |
|
} |
|
return this; |
|
} |
|
|
|
// creation API |
|
|
|
public static AttributeValues fromMap(Map<? extends Attribute, ?> map) { |
|
return fromMap(map, MASK_ALL); |
|
} |
|
|
|
public static AttributeValues fromMap(Map<? extends Attribute, ?> map, |
|
int mask) { |
|
return new AttributeValues().merge(map, mask); |
|
} |
|
|
|
public Map<TextAttribute, Object> toMap(Map<TextAttribute, Object> fill) { |
|
if (fill == null) { |
|
fill = new HashMap<TextAttribute, Object>(); |
|
} |
|
|
|
for (int m = defined, i = 0; m != 0; ++i) { |
|
EAttribute ea = EAttribute.atts[i]; |
|
if ((m & ea.mask) != 0) { |
|
m &= ~ea.mask; |
|
fill.put(ea.att, get(ea)); |
|
} |
|
} |
|
|
|
return fill; |
|
} |
|
|
|
|
|
private static final String DEFINED_KEY = |
|
"sun.font.attributevalues.defined_key"; |
|
|
|
public static boolean is16Hashtable(Hashtable<Object, Object> ht) { |
|
return ht.containsKey(DEFINED_KEY); |
|
} |
|
|
|
public static AttributeValues |
|
fromSerializableHashtable(Hashtable<Object, Object> ht) |
|
{ |
|
AttributeValues result = new AttributeValues(); |
|
if (ht != null && !ht.isEmpty()) { |
|
for (Map.Entry<Object, Object> e: ht.entrySet()) { |
|
Object key = e.getKey(); |
|
Object val = e.getValue(); |
|
if (key.equals(DEFINED_KEY)) { |
|
result.defineAll(((Integer)val).intValue()); |
|
} else { |
|
try { |
|
EAttribute ea = |
|
EAttribute.forAttribute((Attribute)key); |
|
if (ea != null) { |
|
result.set(ea, val); |
|
} |
|
} |
|
catch (ClassCastException ex) { |
|
} |
|
} |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
public Hashtable<Object, Object> toSerializableHashtable() { |
|
Hashtable ht = new Hashtable(); |
|
int hashkey = defined; |
|
for (int m = defined, i = 0; m != 0; ++i) { |
|
EAttribute ea = EAttribute.atts[i]; |
|
if ((m & ea.mask) != 0) { |
|
m &= ~ea.mask; |
|
Object o = get(ea); |
|
if (o == null) { |
|
// hashkey will handle it |
|
} else if (o instanceof Serializable) { |
|
ht.put(ea.att, o); |
|
} else { |
|
hashkey &= ~ea.mask; |
|
} |
|
} |
|
} |
|
ht.put(DEFINED_KEY, Integer.valueOf(hashkey)); |
|
|
|
return ht; |
|
} |
|
|
|
|
|
public int hashCode() { |
|
return defined << 8 ^ nondefault; |
|
} |
|
|
|
public boolean equals(Object rhs) { |
|
try { |
|
return equals((AttributeValues)rhs); |
|
} |
|
catch (ClassCastException e) { |
|
} |
|
return false; |
|
} |
|
|
|
public boolean equals(AttributeValues rhs) { |
|
// test in order of most likely to differ and easiest to compare |
|
// also assumes we're generally calling this only if family, |
|
// size, weight, posture are the same |
|
|
|
if (rhs == null) return false; |
|
if (rhs == this) return true; |
|
|
|
return defined == rhs.defined |
|
&& nondefault == rhs.nondefault |
|
&& underline == rhs.underline |
|
&& strikethrough == rhs.strikethrough |
|
&& superscript == rhs.superscript |
|
&& width == rhs.width |
|
&& kerning == rhs.kerning |
|
&& tracking == rhs.tracking |
|
&& ligatures == rhs.ligatures |
|
&& runDirection == rhs.runDirection |
|
&& bidiEmbedding == rhs.bidiEmbedding |
|
&& swapColors == rhs.swapColors |
|
&& equals(transform, rhs.transform) |
|
&& equals(foreground, rhs.foreground) |
|
&& equals(background, rhs.background) |
|
&& equals(numericShaping, rhs.numericShaping) |
|
&& equals(justification, rhs.justification) |
|
&& equals(charReplacement, rhs.charReplacement) |
|
&& size == rhs.size |
|
&& weight == rhs.weight |
|
&& posture == rhs.posture |
|
&& equals(family, rhs.family) |
|
&& equals(font, rhs.font) |
|
&& imUnderline == rhs.imUnderline |
|
&& equals(imHighlight, rhs.imHighlight); |
|
} |
|
|
|
public AttributeValues clone() { |
|
try { |
|
AttributeValues result = (AttributeValues)super.clone(); |
|
if (transform != null) { |
|
result.transform = new AffineTransform(transform); |
|
result.updateDerivedTransforms(); |
|
} |
|
// if transform is null, derived transforms are null |
|
|
|
return result; |
|
} |
|
catch (CloneNotSupportedException e) { |
|
|
|
return null; |
|
} |
|
} |
|
|
|
public String toString() { |
|
StringBuilder b = new StringBuilder(); |
|
b.append('{'); |
|
for (int m = defined, i = 0; m != 0; ++i) { |
|
EAttribute ea = EAttribute.atts[i]; |
|
if ((m & ea.mask) != 0) { |
|
m &= ~ea.mask; |
|
if (b.length() > 1) { |
|
b.append(", "); |
|
} |
|
b.append(ea); |
|
b.append('='); |
|
switch (ea) { |
|
case EFAMILY: b.append('"'); |
|
b.append(family); |
|
b.append('"'); break; |
|
case EWEIGHT: b.append(weight); break; |
|
case EWIDTH: b.append(width); break; |
|
case EPOSTURE: b.append(posture); break; |
|
case ESIZE: b.append(size); break; |
|
case ETRANSFORM: b.append(transform); break; |
|
case ESUPERSCRIPT: b.append(superscript); break; |
|
case EFONT: b.append(font); break; |
|
case ECHAR_REPLACEMENT: b.append(charReplacement); break; |
|
case EFOREGROUND: b.append(foreground); break; |
|
case EBACKGROUND: b.append(background); break; |
|
case EUNDERLINE: b.append(underline); break; |
|
case ESTRIKETHROUGH: b.append(strikethrough); break; |
|
case ERUN_DIRECTION: b.append(runDirection); break; |
|
case EBIDI_EMBEDDING: b.append(bidiEmbedding); break; |
|
case EJUSTIFICATION: b.append(justification); break; |
|
case EINPUT_METHOD_HIGHLIGHT: b.append(imHighlight); break; |
|
case EINPUT_METHOD_UNDERLINE: b.append(imUnderline); break; |
|
case ESWAP_COLORS: b.append(swapColors); break; |
|
case ENUMERIC_SHAPING: b.append(numericShaping); break; |
|
case EKERNING: b.append(kerning); break; |
|
case ELIGATURES: b.append(ligatures); break; |
|
case ETRACKING: b.append(tracking); break; |
|
default: throw new InternalError(); |
|
} |
|
if ((nondefault & ea.mask) == 0) { |
|
b.append('*'); |
|
} |
|
} |
|
} |
|
b.append("[btx=" + baselineTransform + ", ctx=" + charTransform + "]"); |
|
b.append('}'); |
|
return b.toString(); |
|
} |
|
|
|
// internal utilities |
|
|
|
private static boolean equals(Object lhs, Object rhs) { |
|
return lhs == null ? rhs == null : lhs.equals(rhs); |
|
} |
|
|
|
private void update(EAttribute a) { |
|
defined |= a.mask; |
|
if (i_validate(a)) { |
|
if (i_equals(a, DEFAULT)) { |
|
nondefault &= ~a.mask; |
|
} else { |
|
nondefault |= a.mask; |
|
} |
|
} else { |
|
setDefault(a); |
|
} |
|
} |
|
|
|
// dispatch |
|
|
|
private void i_set(EAttribute a, AttributeValues src) { |
|
switch (a) { |
|
case EFAMILY: family = src.family; break; |
|
case EWEIGHT: weight = src.weight; break; |
|
case EWIDTH: width = src.width; break; |
|
case EPOSTURE: posture = src.posture; break; |
|
case ESIZE: size = src.size; break; |
|
case ETRANSFORM: transform = src.transform; updateDerivedTransforms(); break; |
|
case ESUPERSCRIPT: superscript = src.superscript; break; |
|
case EFONT: font = src.font; break; |
|
case ECHAR_REPLACEMENT: charReplacement = src.charReplacement; break; |
|
case EFOREGROUND: foreground = src.foreground; break; |
|
case EBACKGROUND: background = src.background; break; |
|
case EUNDERLINE: underline = src.underline; break; |
|
case ESTRIKETHROUGH: strikethrough = src.strikethrough; break; |
|
case ERUN_DIRECTION: runDirection = src.runDirection; break; |
|
case EBIDI_EMBEDDING: bidiEmbedding = src.bidiEmbedding; break; |
|
case EJUSTIFICATION: justification = src.justification; break; |
|
case EINPUT_METHOD_HIGHLIGHT: imHighlight = src.imHighlight; break; |
|
case EINPUT_METHOD_UNDERLINE: imUnderline = src.imUnderline; break; |
|
case ESWAP_COLORS: swapColors = src.swapColors; break; |
|
case ENUMERIC_SHAPING: numericShaping = src.numericShaping; break; |
|
case EKERNING: kerning = src.kerning; break; |
|
case ELIGATURES: ligatures = src.ligatures; break; |
|
case ETRACKING: tracking = src.tracking; break; |
|
default: throw new InternalError(); |
|
} |
|
} |
|
|
|
private boolean i_equals(EAttribute a, AttributeValues src) { |
|
switch (a) { |
|
case EFAMILY: return equals(family, src.family); |
|
case EWEIGHT: return weight == src.weight; |
|
case EWIDTH: return width == src.width; |
|
case EPOSTURE: return posture == src.posture; |
|
case ESIZE: return size == src.size; |
|
case ETRANSFORM: return equals(transform, src.transform); |
|
case ESUPERSCRIPT: return superscript == src.superscript; |
|
case EFONT: return equals(font, src.font); |
|
case ECHAR_REPLACEMENT: return equals(charReplacement, src.charReplacement); |
|
case EFOREGROUND: return equals(foreground, src.foreground); |
|
case EBACKGROUND: return equals(background, src.background); |
|
case EUNDERLINE: return underline == src.underline; |
|
case ESTRIKETHROUGH: return strikethrough == src.strikethrough; |
|
case ERUN_DIRECTION: return runDirection == src.runDirection; |
|
case EBIDI_EMBEDDING: return bidiEmbedding == src.bidiEmbedding; |
|
case EJUSTIFICATION: return justification == src.justification; |
|
case EINPUT_METHOD_HIGHLIGHT: return equals(imHighlight, src.imHighlight); |
|
case EINPUT_METHOD_UNDERLINE: return imUnderline == src.imUnderline; |
|
case ESWAP_COLORS: return swapColors == src.swapColors; |
|
case ENUMERIC_SHAPING: return equals(numericShaping, src.numericShaping); |
|
case EKERNING: return kerning == src.kerning; |
|
case ELIGATURES: return ligatures == src.ligatures; |
|
case ETRACKING: return tracking == src.tracking; |
|
default: throw new InternalError(); |
|
} |
|
} |
|
|
|
private void i_set(EAttribute a, Object o) { |
|
switch (a) { |
|
case EFAMILY: family = ((String)o).trim(); break; |
|
case EWEIGHT: weight = ((Number)o).floatValue(); break; |
|
case EWIDTH: width = ((Number)o).floatValue(); break; |
|
case EPOSTURE: posture = ((Number)o).floatValue(); break; |
|
case ESIZE: size = ((Number)o).floatValue(); break; |
|
case ETRANSFORM: { |
|
if (o instanceof TransformAttribute) { |
|
TransformAttribute ta = (TransformAttribute)o; |
|
if (ta.isIdentity()) { |
|
transform = null; |
|
} else { |
|
transform = ta.getTransform(); |
|
} |
|
} else { |
|
transform = new AffineTransform((AffineTransform)o); |
|
} |
|
updateDerivedTransforms(); |
|
} break; |
|
case ESUPERSCRIPT: superscript = (byte)((Integer)o).intValue(); break; |
|
case EFONT: font = (Font)o; break; |
|
case ECHAR_REPLACEMENT: charReplacement = (GraphicAttribute)o; break; |
|
case EFOREGROUND: foreground = (Paint)o; break; |
|
case EBACKGROUND: background = (Paint)o; break; |
|
case EUNDERLINE: underline = (byte)((Integer)o).intValue(); break; |
|
case ESTRIKETHROUGH: strikethrough = ((Boolean)o).booleanValue(); break; |
|
case ERUN_DIRECTION: { |
|
if (o instanceof Boolean) { |
|
runDirection = (byte)(TextAttribute.RUN_DIRECTION_LTR.equals(o) ? 0 : 1); |
|
} else { |
|
runDirection = (byte)((Integer)o).intValue(); |
|
} |
|
} break; |
|
case EBIDI_EMBEDDING: bidiEmbedding = (byte)((Integer)o).intValue(); break; |
|
case EJUSTIFICATION: justification = ((Number)o).floatValue(); break; |
|
case EINPUT_METHOD_HIGHLIGHT: { |
|
if (o instanceof Annotation) { |
|
Annotation at = (Annotation)o; |
|
imHighlight = (InputMethodHighlight)at.getValue(); |
|
} else { |
|
imHighlight = (InputMethodHighlight)o; |
|
} |
|
} break; |
|
case EINPUT_METHOD_UNDERLINE: imUnderline = (byte)((Integer)o).intValue(); |
|
break; |
|
case ESWAP_COLORS: swapColors = ((Boolean)o).booleanValue(); break; |
|
case ENUMERIC_SHAPING: numericShaping = (NumericShaper)o; break; |
|
case EKERNING: kerning = (byte)((Integer)o).intValue(); break; |
|
case ELIGATURES: ligatures = (byte)((Integer)o).intValue(); break; |
|
case ETRACKING: tracking = ((Number)o).floatValue(); break; |
|
default: throw new InternalError(); |
|
} |
|
} |
|
|
|
private Object i_get(EAttribute a) { |
|
switch (a) { |
|
case EFAMILY: return family; |
|
case EWEIGHT: return Float.valueOf(weight); |
|
case EWIDTH: return Float.valueOf(width); |
|
case EPOSTURE: return Float.valueOf(posture); |
|
case ESIZE: return Float.valueOf(size); |
|
case ETRANSFORM: |
|
return transform == null |
|
? TransformAttribute.IDENTITY |
|
: new TransformAttribute(transform); |
|
case ESUPERSCRIPT: return Integer.valueOf(superscript); |
|
case EFONT: return font; |
|
case ECHAR_REPLACEMENT: return charReplacement; |
|
case EFOREGROUND: return foreground; |
|
case EBACKGROUND: return background; |
|
case EUNDERLINE: return Integer.valueOf(underline); |
|
case ESTRIKETHROUGH: return Boolean.valueOf(strikethrough); |
|
case ERUN_DIRECTION: { |
|
switch (runDirection) { |
|
// todo: figure out a way to indicate this value |
|
|
|
case 0: return TextAttribute.RUN_DIRECTION_LTR; |
|
case 1: return TextAttribute.RUN_DIRECTION_RTL; |
|
default: return null; |
|
} |
|
} |
|
case EBIDI_EMBEDDING: return Integer.valueOf(bidiEmbedding); |
|
case EJUSTIFICATION: return Float.valueOf(justification); |
|
case EINPUT_METHOD_HIGHLIGHT: return imHighlight; |
|
case EINPUT_METHOD_UNDERLINE: return Integer.valueOf(imUnderline); |
|
case ESWAP_COLORS: return Boolean.valueOf(swapColors); |
|
case ENUMERIC_SHAPING: return numericShaping; |
|
case EKERNING: return Integer.valueOf(kerning); |
|
case ELIGATURES: return Integer.valueOf(ligatures); |
|
case ETRACKING: return Float.valueOf(tracking); |
|
default: throw new InternalError(); |
|
} |
|
} |
|
|
|
private boolean i_validate(EAttribute a) { |
|
switch (a) { |
|
case EFAMILY: if (family == null || family.length() == 0) |
|
family = DEFAULT.family; return true; |
|
case EWEIGHT: return weight > 0 && weight < 10; |
|
case EWIDTH: return width >= .5f && width < 10; |
|
case EPOSTURE: return posture >= -1 && posture <= 1; |
|
case ESIZE: return size >= 0; |
|
case ETRANSFORM: if (transform != null && transform.isIdentity()) |
|
transform = DEFAULT.transform; return true; |
|
case ESUPERSCRIPT: return superscript >= -7 && superscript <= 7; |
|
case EFONT: return true; |
|
case ECHAR_REPLACEMENT: return true; |
|
case EFOREGROUND: return true; |
|
case EBACKGROUND: return true; |
|
case EUNDERLINE: return underline >= -1 && underline < 6; |
|
case ESTRIKETHROUGH: return true; |
|
case ERUN_DIRECTION: return runDirection >= -2 && runDirection <= 1; |
|
case EBIDI_EMBEDDING: return bidiEmbedding >= -61 && bidiEmbedding < 62; |
|
case EJUSTIFICATION: justification = max(0, min (justification, 1)); |
|
return true; |
|
case EINPUT_METHOD_HIGHLIGHT: return true; |
|
case EINPUT_METHOD_UNDERLINE: return imUnderline >= -1 && imUnderline < 6; |
|
case ESWAP_COLORS: return true; |
|
case ENUMERIC_SHAPING: return true; |
|
case EKERNING: return kerning >= 0 && kerning <= 1; |
|
case ELIGATURES: return ligatures >= 0 && ligatures <= 1; |
|
case ETRACKING: return tracking >= -1 && tracking <= 10; |
|
default: throw new InternalError("unknown attribute: " + a); |
|
} |
|
} |
|
|
|
// Until textlayout is fixed to use AttributeValues, we'll end up |
|
// creating a map from the values for it. This is a compromise between |
|
// creating the whole map and just checking a particular value. |
|
|
|
public static float getJustification(Map<?, ?> map) { |
|
if (map != null) { |
|
if (map instanceof AttributeMap && |
|
((AttributeMap) map).getValues() != null) { |
|
return ((AttributeMap)map).getValues().justification; |
|
} |
|
Object obj = map.get(TextAttribute.JUSTIFICATION); |
|
if (obj != null && obj instanceof Number) { |
|
return max(0, min(1, ((Number)obj).floatValue())); |
|
} |
|
} |
|
return DEFAULT.justification; |
|
} |
|
|
|
public static NumericShaper getNumericShaping(Map<?, ?> map) { |
|
if (map != null) { |
|
if (map instanceof AttributeMap && |
|
((AttributeMap) map).getValues() != null) { |
|
return ((AttributeMap)map).getValues().numericShaping; |
|
} |
|
Object obj = map.get(TextAttribute.NUMERIC_SHAPING); |
|
if (obj != null && obj instanceof NumericShaper) { |
|
return (NumericShaper)obj; |
|
} |
|
} |
|
return DEFAULT.numericShaping; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public AttributeValues applyIMHighlight() { |
|
if (imHighlight != null) { |
|
InputMethodHighlight hl = null; |
|
if (imHighlight instanceof InputMethodHighlight) { |
|
hl = (InputMethodHighlight)imHighlight; |
|
} else { |
|
hl = (InputMethodHighlight)((Annotation)imHighlight).getValue(); |
|
} |
|
|
|
Map imStyles = hl.getStyle(); |
|
if (imStyles == null) { |
|
Toolkit tk = Toolkit.getDefaultToolkit(); |
|
imStyles = tk.mapInputMethodHighlight(hl); |
|
} |
|
|
|
if (imStyles != null) { |
|
return clone().merge(imStyles); |
|
} |
|
} |
|
|
|
return this; |
|
} |
|
|
|
public static AffineTransform getBaselineTransform(Map<?, ?> map) { |
|
if (map != null) { |
|
AttributeValues av = null; |
|
if (map instanceof AttributeMap && |
|
((AttributeMap) map).getValues() != null) { |
|
av = ((AttributeMap)map).getValues(); |
|
} else if (map.get(TextAttribute.TRANSFORM) != null) { |
|
av = AttributeValues.fromMap((Map<Attribute, ?>)map); |
|
} |
|
if (av != null) { |
|
return av.baselineTransform; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public static AffineTransform getCharTransform(Map<?, ?> map) { |
|
if (map != null) { |
|
AttributeValues av = null; |
|
if (map instanceof AttributeMap && |
|
((AttributeMap) map).getValues() != null) { |
|
av = ((AttributeMap)map).getValues(); |
|
} else if (map.get(TextAttribute.TRANSFORM) != null) { |
|
av = AttributeValues.fromMap((Map<Attribute, ?>)map); |
|
} |
|
if (av != null) { |
|
return av.charTransform; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public void updateDerivedTransforms() { |
|
|
|
if (transform == null) { |
|
baselineTransform = null; |
|
charTransform = null; |
|
} else { |
|
charTransform = new AffineTransform(transform); |
|
baselineTransform = extractXRotation(charTransform, true); |
|
|
|
if (charTransform.isIdentity()) { |
|
charTransform = null; |
|
} |
|
|
|
if (baselineTransform.isIdentity()) { |
|
baselineTransform = null; |
|
} |
|
} |
|
|
|
if (baselineTransform == null) { |
|
nondefault &= ~EBASELINE_TRANSFORM.mask; |
|
} else { |
|
nondefault |= EBASELINE_TRANSFORM.mask; |
|
} |
|
} |
|
|
|
public static AffineTransform extractXRotation(AffineTransform tx, |
|
boolean andTranslation) { |
|
return extractRotation(new Point2D.Double(1, 0), tx, andTranslation); |
|
} |
|
|
|
public static AffineTransform extractYRotation(AffineTransform tx, |
|
boolean andTranslation) { |
|
return extractRotation(new Point2D.Double(0, 1), tx, andTranslation); |
|
} |
|
|
|
private static AffineTransform extractRotation(Point2D.Double pt, |
|
AffineTransform tx, boolean andTranslation) { |
|
|
|
tx.deltaTransform(pt, pt); |
|
AffineTransform rtx = AffineTransform.getRotateInstance(pt.x, pt.y); |
|
|
|
try { |
|
AffineTransform rtxi = rtx.createInverse(); |
|
double dx = tx.getTranslateX(); |
|
double dy = tx.getTranslateY(); |
|
tx.preConcatenate(rtxi); |
|
if (andTranslation) { |
|
if (dx != 0 || dy != 0) { |
|
tx.setTransform(tx.getScaleX(), tx.getShearY(), |
|
tx.getShearX(), tx.getScaleY(), 0, 0); |
|
rtx.setTransform(rtx.getScaleX(), rtx.getShearY(), |
|
rtx.getShearX(), rtx.getScaleY(), dx, dy); |
|
} |
|
} |
|
} |
|
catch (NoninvertibleTransformException e) { |
|
return null; |
|
} |
|
return rtx; |
|
} |
|
} |