1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.css; 27 28 import com.sun.javafx.css.Combinator; 29 30 import java.io.DataInputStream; 31 import java.io.DataOutputStream; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.List; 35 import java.util.Set; 36 37 /** 38 * Used by CSSRule to determine whether or not the selector applies to a 39 * given object. 40 * 41 * @since 9 42 */ 43 abstract public class Selector { 44 45 private static class UniversalSelector { 46 private static final Selector INSTANCE = 47 new SimpleSelector("*", null, null, null); 48 } 49 50 static Selector getUniversalSelector() { 51 return UniversalSelector.INSTANCE; 52 } 53 54 private Rule rule; 55 void setRule(Rule rule) { 56 this.rule = rule; 57 } 58 public Rule getRule() { 59 return rule; 60 } 61 62 private int ordinal = -1; 63 public void setOrdinal(int ordinal) { 64 this.ordinal = ordinal; 65 } 66 public int getOrdinal() { 67 return ordinal; 68 } 69 70 public abstract Match createMatch(); 71 72 // same as the matches method expect return true/false rather than a match 73 public abstract boolean applies(Styleable styleable); 74 75 // same as applies, but will return pseudoclass state that it finds along the way 76 public abstract boolean applies(Styleable styleable, Set<PseudoClass>[] triggerStates, int bit); 77 78 /** 79 * Determines whether the current state of the node and its parents 80 * matches the pseudo-classes defined (if any) for this selector. 81 */ 82 public abstract boolean stateMatches(Styleable styleable, Set<PseudoClass> state); 83 84 private static final int TYPE_SIMPLE = 1; 85 private static final int TYPE_COMPOUND = 2; 86 87 protected void writeBinary(DataOutputStream os, StyleConverter.StringStore stringStore) 88 throws IOException { 89 if (this instanceof SimpleSelector) { 90 os.writeByte(TYPE_SIMPLE); 91 } else { 92 os.writeByte(TYPE_COMPOUND); 93 } 94 } 95 96 static Selector readBinary(int bssVersion, DataInputStream is, String[] strings) 97 throws IOException { 98 final int type = is.readByte(); 99 if (type == TYPE_SIMPLE) 100 return SimpleSelector.readBinary(bssVersion, is,strings); 101 else 102 return CompoundSelector.readBinary(bssVersion, is,strings); 103 } 104 105 public static Selector createSelector(final String cssSelector) { 106 if (cssSelector == null || cssSelector.length() == 0) { 107 return null; // actually return a default no-match selector 108 } 109 110 // A very primitive parser 111 List<SimpleSelector> selectors = new ArrayList<SimpleSelector>(); 112 List<Combinator> combinators = new ArrayList<Combinator>(); 113 List<String> parts = new ArrayList<String>(); 114 int start = 0; 115 int end = -1; 116 char combinator = '\0'; 117 for (int i=0; i<cssSelector.length(); i++) { 118 char ch = cssSelector.charAt(i); 119 if (ch == ' ') { 120 if (combinator == '\0') { 121 combinator = ch; 122 end = i; 123 } 124 } else if (ch == '>') { 125 if (combinator == '\0') end = i; 126 combinator = ch; 127 } else if (combinator != '\0'){ 128 parts.add(cssSelector.substring(start, end)); 129 start = i; 130 combinators.add(combinator == ' ' ? Combinator.DESCENDANT : Combinator.CHILD); 131 combinator = '\0'; 132 } 133 } 134 parts.add(cssSelector.substring(start)); 135 136 for (int i=0; i<parts.size(); i++) { 137 final String part = parts.get(i); 138 if (part != null && !part.equals("")) { 139 // Now we have the parts, we can split off the pseudo classes 140 String[] pseudoClassParts = part.split(":"); 141 List<String> pseudoClasses = new ArrayList<String>(); 142 for (int j=1; j<pseudoClassParts.length; j++) { 143 if (pseudoClassParts[j] != null && !pseudoClassParts[j].equals("")) { 144 pseudoClasses.add(pseudoClassParts[j].trim()); 145 } 146 } 147 148 // Now that we've read off the pseudo classes, we can go ahead and pull 149 // apart the beginning. 150 final String selector = pseudoClassParts[0].trim(); 151 // There might be style classes, so lets peel those off next 152 String[] styleClassParts = selector.split("\\."); 153 List<String> styleClasses = new ArrayList<String>(); 154 155 // If the first one is an empty string, then it started with a pseudo class 156 // If the first one starts with a #, it was an id 157 // Otherwise, it was a name 158 for (int j=1; j<styleClassParts.length; j++) { 159 if (styleClassParts[j] != null && !styleClassParts[j].equals("")) { 160 styleClasses.add(styleClassParts[j].trim()); 161 } 162 } 163 String name = null, id = null; 164 if (styleClassParts[0].equals("")) { 165 // Do nothing! 166 } else if (styleClassParts[0].charAt(0) == '#') { 167 id = styleClassParts[0].substring(1).trim(); 168 } else { 169 name = styleClassParts[0].trim(); 170 } 171 172 selectors.add(new SimpleSelector(name, styleClasses, pseudoClasses, id)); 173 } 174 } 175 176 if (selectors.size() == 1) { 177 return selectors.get(0); 178 } else { 179 return new CompoundSelector(selectors, combinators); 180 } 181 } 182 183 }