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

com.sun.javafx.css.ParsedValueImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.css;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javafx.css.ParsedValue;
import javafx.css.StyleConverter;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;

/**
 * Implementation details behind a {@link ParsedValueImpl}. 
 */
public class ParsedValueImpl extends ParsedValue {

     /**
     * If value references another property, then the real value needs to
     * be looked up.
     */
    final private boolean lookup;
    public final boolean isLookup() { return lookup; }

    /**
     * If value is itself a ParsedValueImpl or sequence of values, and should any of
     * those values need to be looked up, then this flag is set. This
     * does not mean that this particular value needs to be looked up, but
     * that this value contains a value that needs to be looked up.
     */
    final private boolean containsLookups;
    public final boolean isContainsLookups() { return containsLookups; }

    private static boolean getContainsLookupsFlag(Object obj) {

        // Assume the value does not contain lookups
        boolean containsLookupsFlag = false;

        if (obj instanceof Size) {
            containsLookupsFlag = false;
        }

        else if(obj instanceof ParsedValueImpl) {
            ParsedValueImpl value = (ParsedValueImpl)obj;
            containsLookupsFlag = value.lookup || value.containsLookups;
        }

        else if(obj instanceof ParsedValueImpl[]) {
            ParsedValueImpl[] values = (ParsedValueImpl[])obj;
            for(int v=0;
                // Bail if value contains lookups
                // Continue iterating as long as one of the flags is false
                v converter, boolean lookup) {
        super(value, converter);
        this.lookup = lookup;
        this.containsLookups = lookup || getContainsLookupsFlag(value);
    }

    /**
     * Create an instance of ParsedValueImpl where the value type V is converted to
     * the target type T using the given Type converter. If the value needs
     * If type is null, then it is assumed that the value type V and the target
     * type T are the same (do not need converted).
     */
    public ParsedValueImpl(V value, StyleConverter type) {
        this(value, type, false);
    }

    /*
     * If this ParsedValueImpl object has lookups, then resolved is used to hold
     * the resolved lookup value. This avoids having to allocate new
     * ParsedValueImpl objects in StyleHelper.resolveLookups. The resolved value is 
     * nulled out after this ParsedValueImpl object has been converted in the 
     * StyleHelper.lookup method. 
     */
    private ParsedValueImpl resolved;

    public ParsedValueImpl getResolved() {
        return resolved;
    }

    public void setResolved(ParsedValueImpl resolved) {
        if (resolved == null) nullResolved();
        this.resolved = resolved;
    }

    /*
     * Null out the resolved field after this ParsedValueImpl object has been converted.
     * Called from StyleHelper.lookup.
     */
    private void nullResolved() {

        if (resolved == this || resolved == null) return;

        Object obj = resolved.getValue();
        if(obj instanceof ParsedValueImpl[]) {
            ParsedValueImpl[] values = (ParsedValueImpl[])obj;
            for(int v=0; v" : ""))
            .append(newline);
        indent();
        if (value != null) {
            appendValue(sbuf, value, "value");
        } else {
            appendValue(sbuf, "null", "value");
        }
        if (resolved != null && resolved != this) {
            appendValue(sbuf, resolved, "resolved");
        }
        sbuf.append(spaces())
            .append("")
            .append(converter)
            .append("")
            .append(newline);
        outdent();
        sbuf.append(spaces()).append("").append(newline);
        return sbuf.toString();
    }

    private void appendValue(StringBuilder sbuf, Object value, String tag) {
        final String newline = System.lineSeparator();
        if (value instanceof ParsedValueImpl[][]) {
            ParsedValueImpl[][] layers = (ParsedValueImpl[][])value;
            sbuf.append(spaces())
                .append('<')
                .append(tag)
                .append(" layers=\"")
                .append(layers.length)
                .append("\">")
                .append(newline);
            indent();
            for (ParsedValueImpl[] layer : layers) {
                sbuf.append(spaces())
                    .append("")
                    .append(newline);
                indent();
                if (layer == null) {
                    sbuf.append(spaces()).append("null").append(newline);
                    continue;
                }
                for(ParsedValueImpl val : layer) {
                    if (val == null) {
                        sbuf.append(spaces()).append("null").append(newline);
                    } else {
                    sbuf.append(val);
                }
            }
                outdent();
                sbuf.append(spaces())
                    .append("")
                    .append(newline);
            }
            outdent();
            sbuf.append(spaces()).append("').append(newline);

        } else if (value instanceof ParsedValueImpl[]) {
            ParsedValueImpl[] values = (ParsedValueImpl[])value;
            sbuf.append(spaces())
                .append('<')
                .append(tag)
                .append(" values=\"")
                .append(values.length)
                .append("\">")
                .append(newline);
            indent();
            for(ParsedValueImpl val : values) {
                if (val == null) {
                    sbuf.append(spaces()).append("null").append(newline);
                } else {
                sbuf.append(val);
            }
            }
            outdent();
            sbuf.append(spaces()).append("').append(newline);
        } else if (value instanceof ParsedValueImpl) {
            sbuf.append(spaces()).append('<').append(tag).append('>').append(newline);
            indent();
            sbuf.append(value);
            outdent();
            sbuf.append(spaces()).append("').append(newline);
        } else {
            sbuf.append(spaces()).append('<').append(tag).append('>');
            sbuf.append(value);
            sbuf.append("').append(newline);
        }
    }

    @Override public boolean equals(Object obj) {

        if (obj == this) return true;

        if (obj instanceof ParsedValueImpl) {

            final ParsedValueImpl other = (ParsedValueImpl)obj;
            if (this.value instanceof ParsedValueImpl[][]) {

                if (!(other.value instanceof ParsedValueImpl[][])) return false;

                final ParsedValueImpl[][] thisValues = (ParsedValueImpl[][])this.value;
                final ParsedValueImpl[][] otherValues = (ParsedValueImpl[][])other.value;

                // this.value and other.value are known to be non-null
                // due to instanceof
                if (thisValues.length != otherValues.length) return false;

                for (int i = 0; i < thisValues.length; i++) {
                    
                    // if thisValues[i] is null, then otherValues[i] must be null
                    // if thisValues[i] is not null, then otherValues[i] must 
                    // not be null
                    if ((thisValues[i] == null) && (otherValues[i] == null)) continue;
                    else if ((thisValues[i] == null) || (otherValues[i] == null)) return false;
                    
                    if (thisValues[i].length != otherValues[i].length) return false;

                    for (int j = 0; j < thisValues[i].length; j++) {

                        final ParsedValueImpl thisValue = thisValues[i][j];
                        final ParsedValueImpl otherValue = otherValues[i][j];

                        if (thisValue != null
                            ? !thisValue.equals(otherValue)
                            : otherValue != null)
                                return false;
                    }
                }
                return true;

            } else if (this.value instanceof ParsedValueImpl[]) {

                if (!(other.value instanceof ParsedValueImpl[])) return false;

                final ParsedValueImpl[] thisValues = (ParsedValueImpl[])this.value;
                final ParsedValueImpl[] otherValues = (ParsedValueImpl[])other.value;

                // this.value and other.value are known to be non-null
                // due to instanceof
                if (thisValues.length != otherValues.length) return false;

                for (int i = 0; i < thisValues.length; i++) {

                    final ParsedValueImpl thisValue = thisValues[i];
                    final ParsedValueImpl otherValue = otherValues[i];

                    if ((thisValue != null)
                        ? !thisValue.equals(otherValue)
                        : otherValue != null)
                        return false;
                }
                return true;

            } else {

                if (other.value instanceof ParsedValueImpl[][] 
                    || other.value instanceof ParsedValueImpl[]) return false;

                // we know other is not null because of the instanceof check
                return (this.value != null
                        ? this.value.equals(other.value)
                        : other.value == null);
            }
//            Converter could be null, but the values could still match.
//            It makes sense that ParsedValueImpl("abc", null) should equal
//            ParsedValueImpl("abc", StringConverter.getInstance())
//                    (converter == null ? other.converter == null : converter.equals(other.converter));
        }
        return false;
    }

    private int hc = -1;
    @Override public int hashCode() {
        if (hc == -1) {
            hc = 17;
            if (value instanceof ParsedValueImpl[][]) {
                ParsedValueImpl[][] values = (ParsedValueImpl[][])value;
                for (int i = 0; i < values.length; i++) {
                    for (int j = 0; j < values[i].length; j++) {
                        final ParsedValueImpl val = values[i][j];
                        hc = 37 * hc + ((val != null && val.value != null) ? val.value.hashCode() : 0);
                    }
                }
            } else if (value instanceof ParsedValueImpl[]) {
                ParsedValueImpl[] values = (ParsedValueImpl[])value;
                for (int i = 0; i < values.length; i++) {
                    if (values[i] == null || values[i].value == null) continue;
                    final ParsedValueImpl val = values[i];
                    hc = 37 * hc + ((val != null && val.value != null) ? val.value.hashCode() : 0);
                }
            } else {
                hc = 37 * hc + (value != null ? value.hashCode() : 0);
            }

//            Converter could be null, but the values could still match.
//            It makes sense that ParsedValueImpl("abc", null) should equal
//            ParsedValueImpl("abc", StringConverter.getInstance())
//            hc = 37 * hc + ((converter != null) ? converter.hashCode() : 1237);
        }
        return hc;
    }


    final static private byte NULL_VALUE = 0;
    final static private byte VALUE = 1;
    final static private byte VALUE_ARRAY = 2;
    final static private byte ARRAY_OF_VALUE_ARRAY = 3;
    final static private byte STRING = 4;
    final static private byte COLOR = 5;
    final static private byte ENUM = 6;
    final static private byte BOOLEAN = 7;
    final static private byte URL = 8;
    final static private byte SIZE = 9;


    public void writeBinary(DataOutputStream os, StringStore stringStore)
        throws IOException {

        os.writeBoolean(lookup);

        if (converter instanceof StyleConverterImpl) {
            os.writeBoolean(true);
            ((StyleConverterImpl)converter).writeBinary(os, stringStore);
        } else {
            os.writeBoolean(false);
            if (converter != null) {
                System.err.println("cannot writeBinary " + converter.getClass().getName());
            }
        }

        if (value instanceof ParsedValue) {
            os.writeByte(VALUE);
            final ParsedValue pv = (ParsedValue)value;
            if (pv instanceof ParsedValueImpl) {
                ((ParsedValueImpl)pv).writeBinary(os, stringStore);
            } else {
                final ParsedValueImpl impl = new ParsedValueImpl(pv.getValue(), pv.getConverter());
                impl.writeBinary(os, stringStore);
            }

        } else if (value instanceof ParsedValue[]) {
            os.writeByte(VALUE_ARRAY);
            final ParsedValue[] values = (ParsedValue[])value;
            if (values != null) {
                os.writeByte(VALUE);
            } else {
                os.writeByte(NULL_VALUE);
            }
            final int nValues = (values != null) ? values.length : 0;
            os.writeInt(nValues);
            for (int v=0; v(Color.color(r, g, b, a), converter, lookup);

        } else if (valType == ENUM) {
            final int nameIndex = is.readShort();
            final String ename = strings[nameIndex];
            ParsedValueImpl value = new ParsedValueImpl(ename, converter, lookup);
            return value;

        } else if (valType == BOOLEAN) {
            Boolean b = is.readBoolean();
            return new ParsedValueImpl(b, converter, lookup);

        } else if (valType == SIZE) {
            double val = Double.longBitsToDouble(is.readLong());
            SizeUnits units = SizeUnits.PX;
            String unitStr = strings[is.readShort()];
            try {
                units = (SizeUnits)Enum.valueOf(SizeUnits.class, unitStr);
            } catch (IllegalArgumentException iae) {
                System.err.println(iae.toString());
            } catch (NullPointerException npe) {
                System.err.println(npe.toString());
            }
            return new ParsedValueImpl(new Size(val,units), converter, lookup);

        } else if (valType == STRING) {
            String str = strings[is.readShort()];
            return new ParsedValueImpl(str, converter, lookup);

        } else if (valType == URL) {
            String str = strings[is.readShort()];
            try {
                URL url = new URL(str);
                return new ParsedValueImpl(url, converter, lookup);
            } catch (MalformedURLException malf) {
                throw new InternalError("Excpeption in Value.readBinary: " + malf);
            }

        } else if (valType == NULL_VALUE) {
            return new ParsedValueImpl(null, converter, lookup);

        } else {
            throw new InternalError("unknown type: " + valType);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy