com.adobe.xfa.text.TextMeasurement Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
package com.adobe.xfa.text;
import com.adobe.xfa.font.FontInstance;
import com.adobe.xfa.ut.UnitSpan;
/**
* @exclude from published api.
*/
public class TextMeasurement {
/**
* An absolute measurement on the document. Manifested as a UnitSpan
* value.
*/
public static final int TYPE_LENGTH = 0;
/**
* Proportional to the font em width (normally the font height). The
* value is a scale factor of type double. A value of 1 yields the em
* width.
*/
public static final int TYPE_EM = 1;
/**
* Proportional to the width of the space character, but expressed as a
* percentage in markup. A value of 1 yields the space width, but will
* appear in markup as "100%".
*/
public static final int TYPE_PERCENT = 2;
public static final int DEFAULT_PRECISION = 6;
public final static TextMeasurement ZERO = new TextMeasurement();
private final int meType;
private final UnitSpan moLength;
private final double mdScale;
/**
* Default constructor.
* The measurement is of type length, with a value of zero.
*/
public TextMeasurement () {
meType = TYPE_LENGTH;
moLength = UnitSpan.ZERO;
mdScale = 0;
}
/**
* Create a length type measurement, given a length value.
* @param oLength - Initial length value to be stored in this
* measurement.
*/
public TextMeasurement (UnitSpan oLength) {
meType = TYPE_LENGTH;
moLength = (oLength == null) ? UnitSpan.ZERO : oLength;
mdScale = 0;
}
/**
* Create a relative measurement.
* @param eType - Type of the measurement. Must be either TYPE_EM or
* TYPE_PERCENT.
* @param dScale - Scale factor for the measurement. Note that for
* percentage measurement the given value is not scaled by 100 (e.g,
* pass 1.0 to get 100%).
*/
public TextMeasurement (int eType, double dScale) {
meType = eType;
moLength = null;
mdScale = dScale;
}
/**
* Determine the absolute value of this measurement.
*
* Used at run-time, this method returns an absolute length
* corresponding to the measurement, irrespective of the measurement
* type. If the measurement is of type length, it already represents an
* absolute amount. Otherwise, the given font is used to scale the
* relative value appropriately.
* @param oFontInstance - Font instance to use to scale relative
* amounts. If this is a null reference, zero is returned. If the
* measurement type is percent and the font has no space character, the
* measurement is treated as being of type em.
* @return Resulting absolute measurement.
*/
public UnitSpan flatten (FontInstance oFontInstance) {
if (meType == TYPE_LENGTH) {
return moLength;
}
if (mdScale == 0) {
return UnitSpan.ZERO;
}
assert (oFontInstance != null);
UnitSpan oResult = oFontInstance.getSize();
// oResult = oResult.multiply (oFontInstance.getHorizontalScale()); // TODO:
if (meType == TYPE_PERCENT) {
double dWidth = oFontInstance.getDoubleCharWidth (' ', true); // TODO: vertical glyphs?
if (dWidth > 0) {
oResult = new UnitSpan (dWidth, UnitSpan.POINTS_1K);
}
}
return oResult.multiply (mdScale);
}
/**
* Determine the absolute value of this measurement in the absence of
* font information.
*
* This is a sort of poor person's Flatten() method. If the font
* information is not available, one call call this overload, typically
* with the font height. If the measurement type is relative, it
* applies the scale to the given unit span. Otherwise it simply
* returns the (absolute) length.
* @param oBaseValue - Base unit span to apply relative scales to.
* @return Resulting absolute measurement.
*/
public UnitSpan flatten (UnitSpan oBaseValue) {
return (meType == TYPE_LENGTH) ? moLength : oBaseValue.multiply (mdScale);
}
/**
* Return the type of this measurement object.
* @return Measurement type.
*/
public int getType () {
return meType;
}
/**
* Return the length value for this measurement object.
* @return Absolute length value of this measurement. Return value is
* not predictable if the measurement type is percent or em.
*/
public UnitSpan getLength () {
return moLength;
}
/**
* Return the integer value of the length.
* This is a convenience method for callers. Assuming that the
* measurement type is length, it returns the value of the length unit
* span.
* @return Integer value of the length unit span if the type is length.
* Otherwise, the return value is undefined.
*/
public int getLengthValue () {
return moLength.value();
}
/**
* Get the scale value for relative measurements.
* @return Scale value. Return value is not predictable if the
* measurement type length.
*/
public double getScale () {
return mdScale;
}
/**
* Determine whether this measurement represents a zero value.
* An absolute measurement is zero if its length is zero. A relative
* measurement is zero if its scale factor is zero.
* @return True if this measurement represents a zero value; false if it
* does not.
*/
public boolean isZero () {
return (meType == TYPE_LENGTH) ? (moLength.value() == 0) : (mdScale == 0);
}
/**
* Populate this measurement from the content of a given string.
* @param sValue - String value to use. This is essentially an
* extension of the allowable syntax for creating unit spans.
* @return True if the string was valid; false if not. If this method
* returns false, the content of the measurement is not altered.
*/
public static TextMeasurement fromString (String sValue, int eDefaultUnits, boolean bValuePerUnit) {
UnitSpan.ParseData oParseData = UnitSpan.validatingParse (sValue,
eDefaultUnits,
true,
bValuePerUnit,
true);
if (oParseData == null) {
return null;
}
if (oParseData.mbValuePerUnit) {
return null;
}
if (oParseData.meUnits != UnitSpan.UNIT_UNKNOWN) {
return new TextMeasurement (new UnitSpan (oParseData.meUnits, oParseData.mnValue));
}
int eType;
double dValue = oParseData.mnValue;
if (oParseData.mnFraction != 0) {
dValue += ((double) oParseData.mnFraction) / ((double) oParseData.mnFractionScale);
}
if (oParseData.mbPercent) {
eType = TYPE_PERCENT;
dValue /= 100;
} else {
if (oParseData.mcUnit2 != 0)
return null;
eType = TYPE_EM;
char c0 = oParseData.mcUnit0;
char c1 = oParseData.mcUnit1;
if (((c0 != 'e') && (c0 != 'E')) || ((c1 != 'm') && (c1 != 'M'))) {
return null;
}
}
return new TextMeasurement (eType, dValue);
}
public static TextMeasurement fromString (String sValue, int eDefaultUnits) {
return fromString (sValue, eDefaultUnits, false);
}
public static TextMeasurement fromString (String sValue) {
return fromString (sValue, UnitSpan.UNIT_UNKNOWN, false);
}
/**
* Generate a string from the current value of this measurement object.
* @param nPrecision - (optional) Maximum number of decimal places in
* the result. Default is six.
* @return String value. This can be persisted and subsequently passed
* to the FromString() method to populate a measurement.
*/
public String toString (int nPrecision) {
StringBuilder sResult = new StringBuilder();
switch (meType) {
case TYPE_EM:
sResult.append (Units.doubleToString (mdScale, nPrecision));
sResult.append ('e');
sResult.append ('m');
break;
case TYPE_PERCENT:
sResult.append (Units.doubleToString (mdScale * 100, nPrecision));
sResult.append ('%');
break;
default:
sResult.append (moLength.text (nPrecision, true, false));
break;
}
return sResult.toString();
}
public static boolean match (TextMeasurement m1, TextMeasurement m2) {
if (m1 == m2) {
return true;
}
if ((m1 == null) || (m2 == null)) {
return false;
}
return m1.equals (m2);
}
public String toString () {
return toString (DEFAULT_PRECISION);
}
/**
* Equality comparison.
*
* Two measurements are considered equal if they have the same type and
* the appropriate values match (length for length types, scale for
* relative types).
* @param object Measurement to compare against.
* @return True if the measurements are considered equal; false if not.
*/
public boolean equals (Object object) {
if (this == object)
return true;
// This overrides Object.equals(boolean) directly, so...
if (object == null)
return false;
if (object.getClass() != getClass())
return false;
TextMeasurement compare = (TextMeasurement) object;
if (meType != compare.meType) {
return false;
}
if (meType == TYPE_LENGTH) {
return UnitSpan.match (moLength, compare.moLength);
}
return mdScale == compare.mdScale;
}
/**
* Returns a hash code value for the object.
* @exclude from published api.
*/
public int hashCode() {
int hash = Integer.valueOf(meType).hashCode();
if (meType == TYPE_LENGTH)
hash = (hash * 31) ^ moLength.hashCode();
long bits = Double.doubleToLongBits(mdScale);
hash = (hash * 31) ^ (int) (bits ^ (bits >>> 32));
return hash;
}
public static TextMeasurement zero () {
return ZERO;
}
}