--- old/modules/graphics/src/main/java/com/sun/javafx/css/CompoundSelector.java 2015-09-03 15:31:10.317970700 -0700 +++ /dev/null 2015-09-03 15:31:11.000000000 -0700 @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2008, 2014, 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 javafx.css.PseudoClass; -import javafx.css.Styleable; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * A compound selector which behaves according to the CSS standard. The selector is - * composed of one or more Selectors, along with an array of - * CompoundSelectorRelationships indicating the required relationship at each - * stage. There must be exactly one less Combinator than - * there are selectors. - *

- * For example, the parameters [selector1, selector2, selector3] - * and [Combinator.CHILD, Combinator.DESCENDANT] will match - * a component when all of the following conditions hold: - *

    - *
  1. The component itself is matched by selector3 - *
  2. The component has an ancestor which is matched by selector2 - *
  3. The ancestor matched in step 2 is a direct CHILD of a component - * matched by selector1 - *
- * In other words, the compound selector specified above is (in CSS syntax) - * selector1 > selector2 selector3. The greater-than (>) - * between selector1 and selector2 specifies a direct CHILD, whereas the - * whitespace between selector2 and selector3 corresponds to - * Combinator.DESCENDANT. - * - */ - -final public class CompoundSelector extends Selector { - - private final List selectors; - /** - * The selectors that make up this compound selector - * @return Immutable List<SimpleSelector> - */ - public List getSelectors() { - return selectors; - } - - private final List relationships; - /** - * The relationships between the selectors - * @return Immutable List<Combinator> - */ - public List getRelationships() { - return relationships; - } - - public CompoundSelector(List selectors, List relationships) - { - this.selectors = - (selectors != null) - ? Collections.unmodifiableList(selectors) - : Collections.EMPTY_LIST; - this.relationships = - (relationships != null) - ? Collections.unmodifiableList(relationships) - : Collections.EMPTY_LIST; - } - - private CompoundSelector() - { - this(null, null); - } - - Match createMatch() { - - final PseudoClassState allPseudoClasses = new PseudoClassState(); - int idCount = 0; - int styleClassCount = 0; - - for(int n=0, nMax=selectors.size(); n[] triggerStates, int depth) { - - assert (triggerStates == null || depth < triggerStates.length); - if (triggerStates != null && triggerStates.length <= depth) { - return false; - } - - // - // We only care about pseudo-class if the selector applies. But in - // the case of a compound selector, we don't know whether it applies - // until all the selectors have been checked (in the worse case). So - // the setting of pseudo-class has to be deferred until we know - // that this compound selector applies. So we'll send a new - // PseudoClassSet[] and if the compound selector applies, - // just copy the state back. - // - final Set[] tempStates = triggerStates != null - ? new PseudoClassState[triggerStates.length] : null; - - final boolean applies = applies(styleable, selectors.size()-1, tempStates, depth); - - if (applies && tempStates != null) { - - for(int n=0; n pseudoClassOut = triggerStates[n]; - final Set pseudoClassIn = tempStates[n]; - - if (pseudoClassOut != null) { - pseudoClassOut.addAll(pseudoClassIn); - } else { - triggerStates[n] = pseudoClassIn; - } - - } - } - return applies; - } - - private boolean applies(final Styleable styleable, final int index, Set[] triggerStates, int depth) { - // If the index is < 0 then we know we don't apply - if (index < 0) return false; - - // Simply check the selector associated with this index and see if it - // applies to the Node - if (! selectors.get(index).applies(styleable, triggerStates, depth)) return false; - - // If there are no more selectors to check (ie: index == 0) then we - // know we know we apply - if (index == 0) return true; - - // We have not yet checked all the selectors in this CompoundSelector, - // so now we need to find the next parent and try again. If the - // relationship between this selector and its ancestor selector is - // "CHILD" then it is required that the parent scenegraph node match - // the ancestor selector. Otherwise, we just walk up the scenegraph - // until we find an ancestor node that matches the selector. If we - // manage to walk all the way to the top without having satisfied all - // of the selectors, then we know it doesn't apply. - final Combinator relationship = relationships.get(index-1); - if (relationship == Combinator.CHILD) { - final Styleable parent = styleable.getStyleableParent(); - if (parent == null) return false; - // If this call succeeds, then all preceding selectors will have - // matched due to the recursive nature of the call - return applies(parent, index - 1, triggerStates, ++depth); - } else { - Styleable parent = styleable.getStyleableParent(); - while (parent != null) { - boolean answer = applies(parent, index - 1, triggerStates, ++depth); - // If a call to stateMatches succeeded, then we know that - // all preceding selectors will have also matched. - if (answer) return true; - // Otherwise we need to get the next parent and try again - parent = parent.getStyleableParent(); - } - } - return false; - } - - @Override - public boolean stateMatches(final Styleable styleable, Set states) { - return stateMatches(styleable, states, selectors.size()-1); - } - - private boolean stateMatches(Styleable styleable, Set states, int index) { - // If the index is < 0 then we know we don't match - if (index < 0) return false; - - // Simply check the selector associated with this index and see if it - // matches the Node and states provided. - if (! selectors.get(index).stateMatches(styleable, states)) return false; - - // If there are no more selectors to match (ie: index == 0) then we - // know we have successfully matched - if (index == 0) return true; - - // We have not yet checked all the selectors in this CompoundSelector, - // so now we need to find the next parent and try again. If the - // relationship between this selector and its ancestor selector is - // "CHILD" then it is required that the parent scenegraph node match - // the ancestor selector. Otherwise, we just walk up the scenegraph - // until we find an ancestor node that matches the selector. If we - // manage to walk all the way to the top without having satisfied all - // of the selectors, then we know it doesn't match. - final Combinator relationship = relationships.get(index - 1); - if (relationship == Combinator.CHILD) { - final Styleable parent = styleable.getStyleableParent(); - if (parent == null) return false; - if (selectors.get(index-1).applies(parent)) { - // If this call succeeds, then all preceding selectors will have - // matched due to the recursive nature of the call - Set parentStates = parent.getPseudoClassStates(); - return stateMatches(parent, parentStates, index - 1); - } - } else { - Styleable parent = styleable.getStyleableParent(); - while (parent != null) { - if (selectors.get(index-1).applies(parent)) { - Set parentStates = parent.getPseudoClassStates(); - return stateMatches(parent, parentStates, index - 1); - } - // Otherwise we need to get the next parent and try again - parent = parent.getStyleableParent(); - } - } - - return false; - } - - private int hash = -1; - - /* Hash code is used in Style's hash code and Style's hash - code is used by StyleHelper */ - @Override - public int hashCode() { - if (hash == -1) { - for (int i = 0, max=selectors.size(); i selectors = new ArrayList(); - for (int n=0; n relationships = new ArrayList(); - for (int n=0; nSelectors, along with an array of + * CompoundSelectorRelationships indicating the required relationship at each + * stage. There must be exactly one less Combinator than + * there are selectors. + *

+ * For example, the parameters [selector1, selector2, selector3] + * and [Combinator.CHILD, Combinator.DESCENDANT] will match + * a component when all of the following conditions hold: + *

    + *
  1. The component itself is matched by selector3 + *
  2. The component has an ancestor which is matched by selector2 + *
  3. The ancestor matched in step 2 is a direct CHILD of a component + * matched by selector1 + *
+ * In other words, the compound selector specified above is (in CSS syntax) + * selector1 > selector2 selector3. The greater-than (>) + * between selector1 and selector2 specifies a direct CHILD, whereas the + * whitespace between selector2 and selector3 corresponds to + * Combinator.DESCENDANT. + * + * @since 9 + */ +final public class CompoundSelector extends Selector { + + private final List selectors; + /** + * The selectors that make up this compound selector + * @return Immutable List<SimpleSelector> + */ + public List getSelectors() { + return selectors; + } + + private final List relationships; + // /** + // * The relationships between the selectors + // * @return Immutable List<Combinator> + // */ + // public List getRelationships() { + // return relationships; + // } + + /** + * Creates a CompoundSelector from a list of selectors and a + * list of Combinator relationships. There must be exactly one + * less Combinator than there are selectors. + */ + CompoundSelector(List selectors, List relationships) { + this.selectors = + (selectors != null) + ? Collections.unmodifiableList(selectors) + : Collections.EMPTY_LIST; + this.relationships = + (relationships != null) + ? Collections.unmodifiableList(relationships) + : Collections.EMPTY_LIST; + } + + private CompoundSelector() { + this(null, null); + } + + + @Override public Match createMatch() { + final PseudoClassState allPseudoClasses = new PseudoClassState(); + int idCount = 0; + int styleClassCount = 0; + + for(int n=0, nMax=selectors.size(); n[] triggerStates, int depth) { + + assert (triggerStates == null || depth < triggerStates.length); + if (triggerStates != null && triggerStates.length <= depth) { + return false; + } + + // + // We only care about pseudo-class if the selector applies. But in + // the case of a compound selector, we don't know whether it applies + // until all the selectors have been checked (in the worse case). So + // the setting of pseudo-class has to be deferred until we know + // that this compound selector applies. So we'll send a new + // PseudoClassSet[] and if the compound selector applies, + // just copy the state back. + // + final Set[] tempStates = triggerStates != null + ? new PseudoClassState[triggerStates.length] : null; + + final boolean applies = applies(styleable, selectors.size()-1, tempStates, depth); + + if (applies && tempStates != null) { + + for(int n=0; n pseudoClassOut = triggerStates[n]; + final Set pseudoClassIn = tempStates[n]; + + if (pseudoClassOut != null) { + pseudoClassOut.addAll(pseudoClassIn); + } else { + triggerStates[n] = pseudoClassIn; + } + + } + } + return applies; + } + + private boolean applies(final Styleable styleable, final int index, Set[] triggerStates, int depth) { + // If the index is < 0 then we know we don't apply + if (index < 0) return false; + + // Simply check the selector associated with this index and see if it + // applies to the Node + if (! selectors.get(index).applies(styleable, triggerStates, depth)) return false; + + // If there are no more selectors to check (ie: index == 0) then we + // know we know we apply + if (index == 0) return true; + + // We have not yet checked all the selectors in this CompoundSelector, + // so now we need to find the next parent and try again. If the + // relationship between this selector and its ancestor selector is + // "CHILD" then it is required that the parent scenegraph node match + // the ancestor selector. Otherwise, we just walk up the scenegraph + // until we find an ancestor node that matches the selector. If we + // manage to walk all the way to the top without having satisfied all + // of the selectors, then we know it doesn't apply. + final Combinator relationship = relationships.get(index-1); + if (relationship == Combinator.CHILD) { + final Styleable parent = styleable.getStyleableParent(); + if (parent == null) return false; + // If this call succeeds, then all preceding selectors will have + // matched due to the recursive nature of the call + return applies(parent, index - 1, triggerStates, ++depth); + } else { + Styleable parent = styleable.getStyleableParent(); + while (parent != null) { + boolean answer = applies(parent, index - 1, triggerStates, ++depth); + // If a call to stateMatches succeeded, then we know that + // all preceding selectors will have also matched. + if (answer) return true; + // Otherwise we need to get the next parent and try again + parent = parent.getStyleableParent(); + } + } + return false; + } + + @Override public boolean stateMatches(final Styleable styleable, Set states) { + return stateMatches(styleable, states, selectors.size()-1); + } + + private boolean stateMatches(Styleable styleable, Set states, int index) { + // If the index is < 0 then we know we don't match + if (index < 0) return false; + + // Simply check the selector associated with this index and see if it + // matches the Node and states provided. + if (! selectors.get(index).stateMatches(styleable, states)) return false; + + // If there are no more selectors to match (ie: index == 0) then we + // know we have successfully matched + if (index == 0) return true; + + // We have not yet checked all the selectors in this CompoundSelector, + // so now we need to find the next parent and try again. If the + // relationship between this selector and its ancestor selector is + // "CHILD" then it is required that the parent scenegraph node match + // the ancestor selector. Otherwise, we just walk up the scenegraph + // until we find an ancestor node that matches the selector. If we + // manage to walk all the way to the top without having satisfied all + // of the selectors, then we know it doesn't match. + final Combinator relationship = relationships.get(index - 1); + if (relationship == Combinator.CHILD) { + final Styleable parent = styleable.getStyleableParent(); + if (parent == null) return false; + if (selectors.get(index-1).applies(parent)) { + // If this call succeeds, then all preceding selectors will have + // matched due to the recursive nature of the call + Set parentStates = parent.getPseudoClassStates(); + return stateMatches(parent, parentStates, index - 1); + } + } else { + Styleable parent = styleable.getStyleableParent(); + while (parent != null) { + if (selectors.get(index-1).applies(parent)) { + Set parentStates = parent.getPseudoClassStates(); + return stateMatches(parent, parentStates, index - 1); + } + // Otherwise we need to get the next parent and try again + parent = parent.getStyleableParent(); + } + } + + return false; + } + + private int hash = -1; + + /* Hash code is used in Style's hash code and Style's hash + code is used by StyleHelper */ + @Override public int hashCode() { + if (hash == -1) { + for (int i = 0, max=selectors.size(); i selectors = new ArrayList(); + for (int n=0; n relationships = new ArrayList(); + for (int n=0; n