/*
* Copyright 2014-15 Skynav, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.skynav.ttpe.fonts;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.skynav.ttpe.geometry.Axis;
import com.skynav.ttpe.geometry.Extent;
public class FontKey {
public static final List<String> DEFAULT_FAMILIES;
public static final String DEFAULT_FAMILY = "Noto Sans";
public static final Set<FontFeature> DEFAULT_FEATURES = Collections.unmodifiableSet(new java.util.HashSet<FontFeature>());
public static final FontStyle DEFAULT_STYLE = FontStyle.NORMAL;
public static final FontWeight DEFAULT_WEIGHT = FontWeight.NORMAL;
public static final Extent DEFAULT_SIZE = new Extent(24, 24);
public static final String DEFAULT_LANGUAGE = "";
public static final FontKey DEFAULT_HORIZONTAL =
new FontKey(DEFAULT_FAMILY, DEFAULT_STYLE, DEFAULT_WEIGHT, DEFAULT_LANGUAGE, Axis.HORIZONTAL, DEFAULT_SIZE, DEFAULT_FEATURES);
public static final FontKey DEFAULT_VERTICAL =
new FontKey(DEFAULT_FAMILY, DEFAULT_STYLE, DEFAULT_WEIGHT, DEFAULT_LANGUAGE, Axis.VERTICAL, DEFAULT_SIZE, DEFAULT_FEATURES);
static {
List<String> l = new java.util.ArrayList<String>();
l.add(DEFAULT_FAMILY);
DEFAULT_FAMILIES = Collections.unmodifiableList(l);
}
public String family;
public FontStyle style;
public FontWeight weight;
public String language;
public Axis axis;
public Extent size;
public Map<String,FontFeature> features;
public FontKey(FontKey key, Extent size) {
this(key.family, key.style, key.weight, key.language, key.axis, size, DEFAULT_FEATURES);
}
public FontKey(FontKey key, double s) {
this(key.family, key.style, key.weight, key.language, key.axis, key.size.scale(s), (key.features != null) ? key.features.values() : null);
}
public FontKey(String family, FontStyle style, FontWeight weight, String language, Axis axis, Extent size, Collection<FontFeature> features) {
this.family = family.toLowerCase();
this.style = style;
this.weight = weight;
this.language = language.toLowerCase();
this.axis = axis;
this.size = size;
populateFeatures(features);
}
public FontKey getScaled(double scale) {
return new FontKey(this, scale);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append('[');
sb.append(family.toUpperCase());
sb.append(',');
sb.append(style);
sb.append(',');
sb.append(weight);
sb.append(',');
sb.append(size);
sb.append(',');
sb.append(language.toUpperCase());
sb.append(',');
sb.append(axis);
sb.append(',');
if (features != null) {
boolean first = true;
sb.append('[');
for (FontFeature f : features.values()) {
if (!first)
sb.append(',');
else
first = false;
sb.append(f);
}
sb.append(']');
} else
sb.append("[]");
sb.append(']');
return sb.toString();
}
public FontSpecification getSpecification() {
return new FontSpecification(family, style, weight, language, null, null);
}
public Collection<FontFeature> getFeatures() {
return (features != null) ? features.values() : null;
}
public FontFeature getFeature(String feature) {
return (features != null) ? features.get(feature) : null;
}
public boolean isKerningEnabled() {
FontFeature f = getFeature("kern");
if (f != null) {
Object arg = f.getArgument(0);
if ((arg instanceof FontKerning) && (arg == FontKerning.NONE))
return false;
}
return true;
}
public boolean isSheared() {
FontFeature f = getFeature("oblq");
if (f != null) {
Object arg = f.getArgument(0);
if (arg instanceof Double) {
double shear = (Double) arg;
if (shear != 0)
return true;
}
}
return false;
}
public double getShear() {
FontFeature f = getFeature("oblq");
if (f != null) {
Object arg = f.getArgument(0);
if (arg instanceof Double)
return (Double) arg;
}
return 0;
}
@Override
public int hashCode() {
int hc = 23;
hc = hc * 31 + family.hashCode();
hc = hc * 31 + style.hashCode();
hc = hc * 31 + weight.hashCode();
hc = hc * 31 + language.hashCode();
hc = hc * 31 + axis.hashCode();
hc = hc * 31 + size.hashCode();
hc = hc * 31 + hashCode(features);
return hc;
}
private int hashCode(Map<String,FontFeature> features) {
int hc = 23;
if (features != null) {
for (FontFeature f : features.values())
hc = hc * 31 + f.hashCode();
}
return hc;
}
@Override
public boolean equals(Object o) {
if (o instanceof FontKey) {
FontKey other = (FontKey) o;
if (!family.equals(other.family))
return false;
else if (style != other.style)
return false;
else if (weight != other.weight)
return false;
else if (!language.equals(other.language))
return false;
else if (axis != other.axis)
return false;
else if (!size.equals(other.size))
return false;
else if (!equals(features, other.features))
return false;
else
return true;
} else
return false;
}
private boolean equals(Map<String,FontFeature> fm1, Map<String,FontFeature> fm2) {
if (fm1 == null) {
return fm2 == null;
} else if (fm2 == null) {
return false;
} else if (fm1.size() != fm2.size()) {
return false;
} else {
assert fm1 instanceof java.util.SortedMap;
FontFeature[] fa1 = fm1.values().toArray(new FontFeature[fm1.size()]);
assert fm2 instanceof java.util.SortedMap;
FontFeature[] fa2 = fm2.values().toArray(new FontFeature[fm2.size()]);
assert fa1.length == fa2.length;
for (int i = 0, n = fa1.length; i < n; ++i) {
FontFeature f1 = fa1[i];
assert f1 != null;
FontFeature f2 = fa2[i];
assert f2 != null;
if (!f1.equals(f2))
return false;
}
return true;
}
}
private void populateFeatures(Collection<FontFeature> features) {
Map<String,FontFeature> m;
if (((features != null) && !features.isEmpty()) || (axis == Axis.VERTICAL))
m = new java.util.TreeMap<String,FontFeature>();
else
m = null;
if (m != null) {
if (features != null) {
for (FontFeature f : features)
m.put(f.getFeature(), f);
}
if (axis == Axis.VERTICAL)
m.put(FontFeature.VERT.getFeature(), FontFeature.VERT);
}
this.features = m;
}
}