--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/font/AttributeValues.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,907 @@
+/*
+ * Portions Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ *
+ * (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; // 0f
+ private float size = 12f;
+ private float tracking; // 0f
+ private NumericShaper numericShaping; // null
+ private AffineTransform transform; // null == identity
+ private GraphicAttribute charReplacement; // null
+ private Paint foreground; // null
+ private Paint background; // null
+ private float justification = 1f;
+ private Object imHighlight; // null
+ // (can be either Attribute wrapping IMH, or IMH itself
+ private Font font; // here for completeness, don't actually use
+ private byte imUnderline = -1; // same default as underline
+ private byte superscript; // 0
+ private byte underline = -1; // arrgh, value for ON is 0
+ private byte runDirection = -2; // BIDI.DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ private byte bidiEmbedding; // 0
+ private byte kerning; // 0
+ private byte ligatures; // 0
+ private boolean strikethrough; // false
+ private boolean swapColors; // false
+
+ private AffineTransform baselineTransform; // derived from transform
+ private AffineTransform charTransform; // derived from transform
+
+ private static final AttributeValues DEFAULT = new AttributeValues();
+
+ // type-specific API
+ 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;
+ }
+
+ // key must be serializable, so use String, not Object
+ 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) { // check all...
+ ht.put(ea.att, o);
+ } else {
+ hashkey &= ~ea.mask;
+ }
+ }
+ }
+ ht.put(DEFINED_KEY, Integer.valueOf(hashkey));
+
+ return ht;
+ }
+
+ // boilerplate
+ 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) { // AffineTransform is mutable
+ result.transform = new AffineTransform(transform);
+ result.updateDerivedTransforms();
+ }
+ // if transform is null, derived transforms are null
+ // so there's nothing to do
+ return result;
+ }
+ catch (CloneNotSupportedException e) {
+ // never happens
+ 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 -1: return Integer.valueOf(runDirection);
+ case 0: return TextAttribute.RUN_DIRECTION_LTR;
+ case 1: return TextAttribute.RUN_DIRECTION_RTL;
+ default: return null;
+ }
+ } // not reachable
+ 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.
+ // Plan to remove these.
+ 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;
+ }
+
+ /**
+ * If this has an imHighlight, create copy of this with those attributes
+ * applied to it. Otherwise return this unchanged.
+ */
+ 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); // yuck
+ }
+ 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); // yuck
+ }
+ if (av != null) {
+ return av.charTransform;
+ }
+ }
+ return null;
+ }
+
+ public void updateDerivedTransforms() {
+ // this also updates the mask for the baseline transform
+ 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();
+ tx.preConcatenate(rtxi);
+ if (andTranslation) {
+ double dx = tx.getTranslateX();
+ double dy = tx.getTranslateY();
+ 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;
+ }
+}