All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.skynav.ttpe.fonts.FontFeature Maven / Gradle / Ivy

The newest version!
/*
 * 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 com.skynav.ttv.model.value.FontVariant;

public class FontFeature implements Comparable {

    public static final FontFeature     HWID            = new FontFeature("hwid");              // half width variant
    public static final FontFeature     FWID            = new FontFeature("fwid");              // full width variant
    public static final FontFeature     KERN            = new FontFeature("kern");              // kerning
    public static final FontFeature     RUBY            = new FontFeature("ruby");              // ruby variant
    public static final FontFeature     VERT            = new FontFeature("vert");              // vertical variant

    // private (non-standard) pseudo-features
    public static final FontFeature     BIDI            = new FontFeature("BIDI");              // bidi level           (Integer level)
    public static final FontFeature     COMB            = new FontFeature("COMB");              // tate-chu-yoko        (Combine combination)
    public static final FontFeature     LANG            = new FontFeature("LANG");              // resolved language    (String language)
    public static final FontFeature     MIRR            = new FontFeature("MIRR");              // mirrored glyphs      (Boolean mirrored)
    public static final FontFeature     ORNT            = new FontFeature("ORNT");              // orientation          (Orientation orientation)
    public static final FontFeature     REVS            = new FontFeature("REVS");              // reversed glyphs      (Boolean reversed)
    public static final FontFeature     SCPT            = new FontFeature("SCPT");              // resolved script      (String script)

    private final String feature;
    private final Object[] arguments;

    public FontFeature(String feature) {
        this(feature, null);
    }

    public FontFeature(String feature, Object[] arguments) {
        if ((feature == null) || feature.isEmpty())
            throw new IllegalArgumentException();
        this.feature = feature;
        if (arguments != null) {
            int na = arguments.length;
            Object[] aa = new Object[na];
            System.arraycopy(arguments, 0, aa, 0, na);
            this.arguments = aa;
        } else
            this.arguments = null;
    }

    public FontFeature parameterize(Object ... arguments) {
        return new FontFeature(this.feature, arguments);
    }

    public String getFeature() {
        return feature;
    }

    public int getArgumentCount() {
        return (arguments != null) ? arguments.length : 0;
    }

    public Object getArgument(int index) {
        if ((arguments != null) && (arguments.length > index))
            return arguments[index];
        else
            return null;
    }

    public static FontFeature fromVariant(FontVariant variant) {
        String feature;
        if (variant == FontVariant.SUPER)
            feature = "sups";
        else if (variant == FontVariant.SUB)
            feature = "subs";
        else if (variant == FontVariant.HALF)
            feature = "hwid";
        else if (variant == FontVariant.FULL)
            feature = "fwid";
        else if (variant == FontVariant.RUBY)
            feature = "ruby";
        else
            feature = null;
        return (feature != null) ? new FontFeature(feature) : null;
    }

    public int compareTo(FontFeature other) {
        int d = feature.compareTo(other.feature);
        if (d != 0)
            return d;
        return compareArguments(arguments, other.arguments);
    }

    private static int compareArguments(Object[] args1, Object[] args2) {
        if (isEmpty(args1))
            return isEmpty(args2) ? 0 : -1;
        else if (isEmpty(args2))
            return 1;
        else
            return compareArgumentsPiecewise(args1, args2);
    }

    private static boolean isEmpty(Object[] args) {
        return (args == null) || (args.length == 0);
    }

    private static int compareArgumentsPiecewise(Object[] args1, Object[] args2) {
        assert args1 != null;
        int n1 = args1.length;
        assert n1 > 0;
        assert args2 != null;
        int n2 = args2.length;
        assert n2 > 0;
        for (int i = 0, n = (n1 < n2) ? n1 : n2; i < n; ++i) {
            if (i == n1)
                return -1;
            if (i == n2)
                return 1;
            int d = compareArguments(args1[i], args2[i]);
            if (d != 0)
                return d;
        }
        return 0;
    }

    private static int compareArguments(Object a1, Object a2) {
        if (a1 == null)
            return (a2 == null) ? 0 : -1;
        else if (a2 == null)
            return 1;
        else {
            Class c1 = a1.getClass();
            Class c2 = a2.getClass();
            if (!c1.isInstance(a2) || !c2.isInstance(a1))
                return c1.getName().compareTo(c2.getName());
            else
                return compareArgumentsOfCompatibleType(a1, a2);
        }
    }

    private static int compareArgumentsOfCompatibleType(Object a1, Object a2) {
        if (a1 instanceof String) {
            if (!(a2 instanceof String))
                throw new IllegalArgumentException();
            return ((String) a1).compareTo((String) a2);
        } else if (a1 instanceof Boolean) {
            if (!(a2 instanceof Boolean))
                throw new IllegalArgumentException();
            return ((Boolean) a1).compareTo((Boolean) a2);
        } else if (a1 instanceof Integer) {
            if (!(a2 instanceof Integer))
                throw new IllegalArgumentException();
            return ((Integer) a1).compareTo((Integer) a2);
        } else if (a1 instanceof Double) {
            if (!(a2 instanceof Double))
                throw new IllegalArgumentException();
            return ((Double) a1).compareTo((Double) a2);
        } else
            return a1.toString().compareTo(a2.toString());
    }

    @Override
    public int hashCode() {
        int hc = 23;
        hc = hc * 31 + feature.hashCode();
        hc = hc * 31 + hashCode(arguments);
        return hc;
    }

    private int hashCode(Object[] arguments) {
        int hc = 23;
        if (arguments != null) {
            for (int i = 0, n = arguments.length; i < n; ++i) {
                Object a = arguments[i];
                if (a != null)
                    hc = hc * 31 + a.hashCode();
            }
        }
        return hc;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof FontFeature) {
            FontFeature other = (FontFeature) o;
            if (!feature.equals(other.feature))
                return false;
            else if (!equals(arguments, other.arguments))
                return false;
            else
                return true;
        } else
            return false;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append('[');
        sb.append('\'');
        sb.append(feature);
        sb.append('\'');
        if (arguments != null) {
            boolean first = true;
            sb.append(',');
            for (Object a : arguments) {
                if (!first)
                    sb.append(',');
                else
                    first = false;
                sb.append(a);
            }
        }
        sb.append(']');
        return sb.toString();
    }

    private boolean equals(Object[] aa1, Object[] aa2) {
        if (aa1 == null) {
            return aa2 == null;
        } else if (aa2 == null) {
            return false;
        } else if (aa1.length != aa2.length) {
            return false;
        } else {
            assert aa1.length == aa2.length;
            for (int i = 0, n = aa1.length; i < n; ++i) {
                Object a1 = aa1[i];
                Object a2 = aa2[i];
                if (a1 == null) {
                    if (a2 != null)
                        return false;
                } else if (a2 == null) {
                    return false;
                } else if (!a1.equals(a2))
                    return false;
            }
            return true;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy