modules/graphics/src/main/java/javafx/css/SimpleSelector.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization


   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 com.sun.javafx.css;
  27 
  28 import javafx.css.PseudoClass;
  29 import javafx.css.Styleable;
  30 import javafx.geometry.NodeOrientation;
  31 import javafx.scene.Node;
  32 
  33 import java.io.DataInputStream;
  34 import java.io.DataOutputStream;
  35 import java.io.IOException;
  36 import java.util.ArrayList;
  37 import java.util.Collections;
  38 import java.util.Iterator;
  39 import java.util.List;
  40 import java.util.Set;
  41 



  42 import static javafx.geometry.NodeOrientation.INHERIT;
  43 import static javafx.geometry.NodeOrientation.LEFT_TO_RIGHT;
  44 import static javafx.geometry.NodeOrientation.RIGHT_TO_LEFT;
  45 
  46 /**
  47  * A simple selector which behaves according to the CSS standard.
  48  *

  49  */
  50 final public class SimpleSelector extends Selector {
  51     
  52     /**
  53      * If specified in the CSS file, the name of the java class to which
  54      * this selector is applied. For example, if the CSS file had:
  55      * <code><pre>
  56      *   Rectangle { }
  57      * </pre></code>
  58      * then name would be "Rectangle".
  59      */
  60     final private String name;
  61     /**
  62      * @return The name of the java class to which this selector is applied, or *.
  63      */
  64     public String getName() {
  65         return name;
  66     }
  67     
  68     /**
  69      * @return Immutable List&lt;String&gt; of style-classes of the selector
  70      */
  71     public List<String> getStyleClasses() {
  72         
  73         final List<String> names = new ArrayList<String>();
  74         
  75         Iterator<StyleClass> iter = styleClassSet.iterator();
  76         while (iter.hasNext()) {
  77             names.add(iter.next().getStyleClassName());
  78         }
  79         
  80         return Collections.unmodifiableList(names);
  81     }
  82 
  83     Set<StyleClass> getStyleClassSet() {
  84         return styleClassSet;
  85     }
  86     
  87     /** styleClasses converted to a set of bit masks */
  88     final private StyleClassSet styleClassSet;
  89     
  90     final private String id;
  91     /*
  92      * @return The value of the selector id, which may be an empty string.
  93      */
  94     public String getId() {
  95         return id;
  96     }
  97     
  98     // a mask of bits corresponding to the pseudoclasses
  99     final private PseudoClassState pseudoClassState;
 100     
 101     Set<PseudoClass> getPseudoClassStates() {
 102         return pseudoClassState;
 103     }
 104 
 105     /**
 106      * @return Immutable List&lt;String&gt; of pseudo-classes of the selector
 107      */
 108     public List<String> getPseudoclasses() {
 109         
 110         final List<String> names = new ArrayList<String>();
 111         
 112         Iterator<PseudoClass> iter = pseudoClassState.iterator();
 113         while (iter.hasNext()) {
 114             names.add(iter.next().getPseudoClassName());
 115         }
 116         
 117         if (nodeOrientation == RIGHT_TO_LEFT) {
 118             names.add("dir(rtl)");
 119         } else if (nodeOrientation == LEFT_TO_RIGHT) {
 120             names.add("dir(ltr)");
 121         }
 122                     
 123         return Collections.unmodifiableList(names);
 124     }
 125         
 126     // true if name is not a wildcard
 127     final private boolean matchOnName;
 128 
 129     // true if id given
 130     final private boolean matchOnId;
 131 
 132     // true if style class given
 133     final private boolean matchOnStyleClass;
 134 
 135     // dir(ltr) or dir(rtl), otherwise inherit
 136     final private NodeOrientation nodeOrientation;
 137     
 138     // Used in Match. If nodeOrientation is ltr or rtl, 
 139     // then count it as a pseudoclass
 140     NodeOrientation getNodeOrientation() {
 141         return nodeOrientation;
 142     }
 143     
 144     // TODO: The parser passes styleClasses as a List. Should be array?
 145     public SimpleSelector(final String name, final List<String> styleClasses,
 146             final List<String> pseudoClasses, final String id)
 147     {
 148         this.name = name == null ? "*" : name;
 149         // if name is not null and not empty or wildcard, 
 150         // then match needs to check name
 151         this.matchOnName = (name != null && !("".equals(name)) && !("*".equals(name)));
 152 
 153         this.styleClassSet = new StyleClassSet();
 154         
 155         int nMax = styleClasses != null ? styleClasses.size() : 0;
 156         for(int n=0; n<nMax; n++) { 
 157             
 158             final String styleClassName = styleClasses.get(n);
 159             if (styleClassName == null || styleClassName.isEmpty()) continue;
 160             
 161             final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
 162             this.styleClassSet.add(styleClass);
 163         }
 164         
 165         this.matchOnStyleClass = (this.styleClassSet.size() > 0);


 175             if (pclass == null || pclass.isEmpty()) continue;
 176             
 177             // TODO: This is not how we should handle functional pseudo-classes in the long-run!
 178             if ("dir(".regionMatches(true, 0, pclass, 0, 4)) {
 179                 final boolean rtl = "dir(rtl)".equalsIgnoreCase(pclass);
 180                 dir = rtl ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
 181                 continue;
 182             }
 183             
 184             final PseudoClass pseudoClass = PseudoClassState.getPseudoClass(pclass);
 185             this.pseudoClassState.add(pseudoClass);
 186         }
 187         
 188         this.nodeOrientation = dir;
 189         this.id = id == null ? "" : id;
 190         // if id is not null and not empty, then match needs to check id
 191         this.matchOnId = (id != null && !("".equals(id)));
 192 
 193     }
 194 
 195     Match createMatch() {
 196         final int idCount = (matchOnId) ? 1 : 0;
 197         int styleClassCount = styleClassSet.size();
 198         return new Match(this, pseudoClassState, idCount, styleClassCount);
 199     }
 200 
 201     @Override 
 202     public boolean applies(Styleable styleable) {
 203         
 204         // handle functional pseudo-class :dir()
 205         // INHERIT applies to both :dir(rtl) and :dir(ltr)
 206         if (nodeOrientation != INHERIT && styleable instanceof Node) {
 207             final Node node = (Node)styleable;
 208             final NodeOrientation orientation = node.getNodeOrientation();
 209 
 210             if (orientation == INHERIT
 211                     ? node.getEffectiveNodeOrientation() != nodeOrientation
 212                     : orientation != nodeOrientation)
 213             {
 214                 return false;
 215             }
 216         }
 217 
 218         // if the selector has an id,
 219         // then bail if it doesn't match the node's id
 220         // (do this first since it is potentially the cheapest check)
 221         if (matchOnId) {
 222             final String otherId = styleable.getId();


 236         if (matchOnStyleClass) {
 237             
 238             final StyleClassSet otherStyleClassSet = new StyleClassSet();
 239             final List<String> styleClasses = styleable.getStyleClass();
 240             for(int n=0, nMax = styleClasses.size(); n<nMax; n++) { 
 241 
 242                 final String styleClassName = styleClasses.get(n);
 243                 if (styleClassName == null || styleClassName.isEmpty()) continue;
 244 
 245                 final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
 246                 otherStyleClassSet.add(styleClass);
 247             }
 248             
 249             boolean styleClassMatch = matchStyleClasses(otherStyleClassSet); 
 250             if (!styleClassMatch) return false;
 251         }
 252         
 253         return true;
 254     }
 255     
 256     @Override 
 257     boolean applies(Styleable styleable, Set<PseudoClass>[] pseudoClasses, int depth) {
 258 
 259         
 260         final boolean applies = applies(styleable);
 261         
 262         //
 263         // We only need the pseudo-classes if the selector applies to the node.
 264         // 
 265         if (applies && pseudoClasses != null && depth < pseudoClasses.length) {
 266 
 267             if (pseudoClasses[depth] == null) {
 268                 pseudoClasses[depth] = new PseudoClassState();
 269             }
 270             
 271             pseudoClasses[depth].addAll(pseudoClassState);
 272             
 273         }
 274         return applies;
 275     }
 276 
 277     @Override
 278     public boolean stateMatches(final Styleable styleable, Set<PseudoClass> states) {
 279         // [foo bar] matches [foo bar bang], 
 280         // but [foo bar bang] doesn't match [foo bar]
 281         return states != null ? states.containsAll(pseudoClassState) : false;
 282     }
 283 
 284     // Are the Selector's style classes a subset of the Node's style classes?
 285     //
 286     // http://www.w3.org/TR/css3-selectors/#class-html
 287     // The following selector matches any P element whose class attribute has been
 288     // assigned a list of whitespace-separated values that includes both
 289     // pastoral and marine:
 290     //
 291     //     p.pastoral.marine { color: green }
 292     //
 293     // This selector matches when class="pastoral blue aqua marine" but does not
 294     // match for class="pastoral blue".
 295     private boolean matchStyleClasses(StyleClassSet otherStyleClasses) {
 296         return otherStyleClasses.containsAll(styleClassSet);
 297     }
 298 
 299     @Override
 300     public boolean equals(Object obj) {
 301         if (obj == null) {
 302             return false;
 303         }
 304         if (getClass() != obj.getClass()) {
 305             return false;
 306         }
 307         final SimpleSelector other = (SimpleSelector) obj;
 308         if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
 309             return false;
 310         }
 311         if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
 312             return false;
 313         }
 314         if (this.styleClassSet.equals(other.styleClassSet) == false) {
 315             return false;
 316         }
 317         if (this.pseudoClassState.equals(other.pseudoClassState) == false) {
 318             return false;
 319         } 
 320         


 340         if (name != null && name.isEmpty() == false) sbuf.append(name);
 341         else sbuf.append("*");
 342         Iterator<StyleClass> iter1 = styleClassSet.iterator();
 343         while(iter1.hasNext()) {
 344             final StyleClass styleClass = iter1.next();
 345             sbuf.append('.').append(styleClass.getStyleClassName());
 346         }
 347         if (id != null && id.isEmpty() == false) {
 348             sbuf.append('#');
 349             sbuf.append(id);
 350         }
 351         Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
 352         while(iter2.hasNext()) {
 353             final PseudoClass pseudoClass = iter2.next();
 354             sbuf.append(':').append(pseudoClass.getPseudoClassName());
 355         }
 356             
 357         return sbuf.toString();
 358     }
 359 
 360     public final void writeBinary(final DataOutputStream os, final StringStore stringStore)
 361         throws IOException
 362     {
 363         super.writeBinary(os, stringStore);
 364         os.writeShort(stringStore.addString(name));
 365         os.writeShort(styleClassSet.size());
 366         Iterator<StyleClass> iter1 = styleClassSet.iterator();
 367         while(iter1.hasNext()) {
 368             final StyleClass sc = iter1.next();
 369             os.writeShort(stringStore.addString(sc.getStyleClassName()));
 370         }
 371         os.writeShort(stringStore.addString(id));
 372         int pclassSize = pseudoClassState.size()
 373                 + (nodeOrientation == RIGHT_TO_LEFT || nodeOrientation == LEFT_TO_RIGHT ? 1 : 0);
 374         os.writeShort(pclassSize);
 375         Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
 376         while(iter2.hasNext()) {
 377             final PseudoClass pc = iter2.next();
 378             os.writeShort(stringStore.addString(pc.getPseudoClassName()));
 379         }
 380         if (nodeOrientation == RIGHT_TO_LEFT) {




   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 javafx.geometry.NodeOrientation;
  29 import javafx.scene.Node;
  30 
  31 import java.io.DataInputStream;
  32 import java.io.DataOutputStream;
  33 import java.io.IOException;
  34 import java.util.ArrayList;
  35 import java.util.Collections;
  36 import java.util.Iterator;
  37 import java.util.List;
  38 import java.util.Set;
  39 
  40 import com.sun.javafx.css.PseudoClassState;
  41 import com.sun.javafx.css.StyleClassSet;
  42 
  43 import static javafx.geometry.NodeOrientation.INHERIT;
  44 import static javafx.geometry.NodeOrientation.LEFT_TO_RIGHT;
  45 import static javafx.geometry.NodeOrientation.RIGHT_TO_LEFT;
  46 
  47 /**
  48  * A simple selector which behaves according to the CSS standard.
  49  *
  50  * @since 9
  51  */
  52 final public class SimpleSelector extends Selector {
  53     
  54     /**
  55      * If specified in the CSS file, the name of the java class to which
  56      * this selector is applied. For example, if the CSS file had:
  57      * <code><pre>
  58      *   Rectangle { }
  59      * </pre></code>
  60      * then name would be "Rectangle".
  61      */
  62     final private String name;
  63     /**
  64      * @return The name of the java class to which this selector is applied, or *.
  65      */
  66     public String getName() {
  67         return name;
  68     }
  69     
  70     /**
  71      * @return Immutable List&lt;String&gt; of style-classes of the selector
  72      */
  73     public List<String> getStyleClasses() {
  74         
  75         final List<String> names = new ArrayList<String>();
  76         
  77         Iterator<StyleClass> iter = styleClassSet.iterator();
  78         while (iter.hasNext()) {
  79             names.add(iter.next().getStyleClassName());
  80         }
  81         
  82         return Collections.unmodifiableList(names);
  83     }
  84 
  85     public Set<StyleClass> getStyleClassSet() {
  86         return styleClassSet;
  87     }
  88     
  89     /** styleClasses converted to a set of bit masks */
  90     final private StyleClassSet styleClassSet;
  91     
  92     final private String id;
  93     /*
  94      * @return The value of the selector id, which may be an empty string.
  95      */
  96     public String getId() {
  97         return id;
  98     }
  99     
 100     // a mask of bits corresponding to the pseudoclasses
 101     final private PseudoClassState pseudoClassState;
 102     
 103     Set<PseudoClass> getPseudoClassStates() {
 104         return pseudoClassState;
 105     }
 106 
 107     /**
 108      * @return Immutable List&lt;String&gt; of pseudo-classes of the selector
 109      */
 110     List<String> getPseudoclasses() {
 111         
 112         final List<String> names = new ArrayList<String>();
 113         
 114         Iterator<PseudoClass> iter = pseudoClassState.iterator();
 115         while (iter.hasNext()) {
 116             names.add(iter.next().getPseudoClassName());
 117         }
 118         
 119         if (nodeOrientation == RIGHT_TO_LEFT) {
 120             names.add("dir(rtl)");
 121         } else if (nodeOrientation == LEFT_TO_RIGHT) {
 122             names.add("dir(ltr)");
 123         }
 124                     
 125         return Collections.unmodifiableList(names);
 126     }
 127         
 128     // true if name is not a wildcard
 129     final private boolean matchOnName;
 130 
 131     // true if id given
 132     final private boolean matchOnId;
 133 
 134     // true if style class given
 135     final private boolean matchOnStyleClass;
 136 
 137     // dir(ltr) or dir(rtl), otherwise inherit
 138     final private NodeOrientation nodeOrientation;
 139     
 140     // Used in Match. If nodeOrientation is ltr or rtl, 
 141     // then count it as a pseudoclass
 142     public NodeOrientation getNodeOrientation() {
 143         return nodeOrientation;
 144     }
 145     
 146     // TODO: The parser passes styleClasses as a List. Should be array?
 147     SimpleSelector(final String name, final List<String> styleClasses,
 148             final List<String> pseudoClasses, final String id)
 149     {
 150         this.name = name == null ? "*" : name;
 151         // if name is not null and not empty or wildcard, 
 152         // then match needs to check name
 153         this.matchOnName = (name != null && !("".equals(name)) && !("*".equals(name)));
 154 
 155         this.styleClassSet = new StyleClassSet();
 156         
 157         int nMax = styleClasses != null ? styleClasses.size() : 0;
 158         for(int n=0; n<nMax; n++) { 
 159             
 160             final String styleClassName = styleClasses.get(n);
 161             if (styleClassName == null || styleClassName.isEmpty()) continue;
 162             
 163             final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
 164             this.styleClassSet.add(styleClass);
 165         }
 166         
 167         this.matchOnStyleClass = (this.styleClassSet.size() > 0);


 177             if (pclass == null || pclass.isEmpty()) continue;
 178             
 179             // TODO: This is not how we should handle functional pseudo-classes in the long-run!
 180             if ("dir(".regionMatches(true, 0, pclass, 0, 4)) {
 181                 final boolean rtl = "dir(rtl)".equalsIgnoreCase(pclass);
 182                 dir = rtl ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
 183                 continue;
 184             }
 185             
 186             final PseudoClass pseudoClass = PseudoClassState.getPseudoClass(pclass);
 187             this.pseudoClassState.add(pseudoClass);
 188         }
 189         
 190         this.nodeOrientation = dir;
 191         this.id = id == null ? "" : id;
 192         // if id is not null and not empty, then match needs to check id
 193         this.matchOnId = (id != null && !("".equals(id)));
 194 
 195     }
 196 
 197     @Override public Match createMatch() {
 198         final int idCount = (matchOnId) ? 1 : 0;
 199         int styleClassCount = styleClassSet.size();
 200         return new Match(this, pseudoClassState, idCount, styleClassCount);
 201     }
 202 
 203     @Override public boolean applies(Styleable styleable) {

 204         
 205         // handle functional pseudo-class :dir()
 206         // INHERIT applies to both :dir(rtl) and :dir(ltr)
 207         if (nodeOrientation != INHERIT && styleable instanceof Node) {
 208             final Node node = (Node)styleable;
 209             final NodeOrientation orientation = node.getNodeOrientation();
 210 
 211             if (orientation == INHERIT
 212                     ? node.getEffectiveNodeOrientation() != nodeOrientation
 213                     : orientation != nodeOrientation)
 214             {
 215                 return false;
 216             }
 217         }
 218 
 219         // if the selector has an id,
 220         // then bail if it doesn't match the node's id
 221         // (do this first since it is potentially the cheapest check)
 222         if (matchOnId) {
 223             final String otherId = styleable.getId();


 237         if (matchOnStyleClass) {
 238             
 239             final StyleClassSet otherStyleClassSet = new StyleClassSet();
 240             final List<String> styleClasses = styleable.getStyleClass();
 241             for(int n=0, nMax = styleClasses.size(); n<nMax; n++) { 
 242 
 243                 final String styleClassName = styleClasses.get(n);
 244                 if (styleClassName == null || styleClassName.isEmpty()) continue;
 245 
 246                 final StyleClass styleClass = StyleClassSet.getStyleClass(styleClassName);
 247                 otherStyleClassSet.add(styleClass);
 248             }
 249             
 250             boolean styleClassMatch = matchStyleClasses(otherStyleClassSet); 
 251             if (!styleClassMatch) return false;
 252         }
 253         
 254         return true;
 255     }
 256     
 257     @Override public boolean applies(Styleable styleable, Set<PseudoClass>[] pseudoClasses, int depth) {

 258 
 259         
 260         final boolean applies = applies(styleable);
 261         
 262         //
 263         // We only need the pseudo-classes if the selector applies to the node.
 264         // 
 265         if (applies && pseudoClasses != null && depth < pseudoClasses.length) {
 266 
 267             if (pseudoClasses[depth] == null) {
 268                 pseudoClasses[depth] = new PseudoClassState();
 269             }
 270             
 271             pseudoClasses[depth].addAll(pseudoClassState);
 272             
 273         }
 274         return applies;
 275     }
 276 
 277     @Override public boolean stateMatches(final Styleable styleable, Set<PseudoClass> states) {

 278         // [foo bar] matches [foo bar bang], 
 279         // but [foo bar bang] doesn't match [foo bar]
 280         return states != null ? states.containsAll(pseudoClassState) : false;
 281     }
 282 
 283     // Are the Selector's style classes a subset of the Node's style classes?
 284     //
 285     // http://www.w3.org/TR/css3-selectors/#class-html
 286     // The following selector matches any P element whose class attribute has been
 287     // assigned a list of whitespace-separated values that includes both
 288     // pastoral and marine:
 289     //
 290     //     p.pastoral.marine { color: green }
 291     //
 292     // This selector matches when class="pastoral blue aqua marine" but does not
 293     // match for class="pastoral blue".
 294     private boolean matchStyleClasses(StyleClassSet otherStyleClasses) {
 295         return otherStyleClasses.containsAll(styleClassSet);
 296     }
 297 
 298     @Override public boolean equals(Object obj) {

 299         if (obj == null) {
 300             return false;
 301         }
 302         if (getClass() != obj.getClass()) {
 303             return false;
 304         }
 305         final SimpleSelector other = (SimpleSelector) obj;
 306         if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
 307             return false;
 308         }
 309         if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
 310             return false;
 311         }
 312         if (this.styleClassSet.equals(other.styleClassSet) == false) {
 313             return false;
 314         }
 315         if (this.pseudoClassState.equals(other.pseudoClassState) == false) {
 316             return false;
 317         } 
 318         


 338         if (name != null && name.isEmpty() == false) sbuf.append(name);
 339         else sbuf.append("*");
 340         Iterator<StyleClass> iter1 = styleClassSet.iterator();
 341         while(iter1.hasNext()) {
 342             final StyleClass styleClass = iter1.next();
 343             sbuf.append('.').append(styleClass.getStyleClassName());
 344         }
 345         if (id != null && id.isEmpty() == false) {
 346             sbuf.append('#');
 347             sbuf.append(id);
 348         }
 349         Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
 350         while(iter2.hasNext()) {
 351             final PseudoClass pseudoClass = iter2.next();
 352             sbuf.append(':').append(pseudoClass.getPseudoClassName());
 353         }
 354             
 355         return sbuf.toString();
 356     }
 357 
 358     @Override protected final void writeBinary(final DataOutputStream os, final StyleConverter.StringStore stringStore)
 359         throws IOException
 360     {
 361         super.writeBinary(os, stringStore);
 362         os.writeShort(stringStore.addString(name));
 363         os.writeShort(styleClassSet.size());
 364         Iterator<StyleClass> iter1 = styleClassSet.iterator();
 365         while(iter1.hasNext()) {
 366             final StyleClass sc = iter1.next();
 367             os.writeShort(stringStore.addString(sc.getStyleClassName()));
 368         }
 369         os.writeShort(stringStore.addString(id));
 370         int pclassSize = pseudoClassState.size()
 371                 + (nodeOrientation == RIGHT_TO_LEFT || nodeOrientation == LEFT_TO_RIGHT ? 1 : 0);
 372         os.writeShort(pclassSize);
 373         Iterator<PseudoClass> iter2 = pseudoClassState.iterator();
 374         while(iter2.hasNext()) {
 375             final PseudoClass pc = iter2.next();
 376             os.writeShort(stringStore.addString(pc.getPseudoClassName()));
 377         }
 378         if (nodeOrientation == RIGHT_TO_LEFT) {