/* * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.javafx.css; import javafx.css.PseudoClass; import javafx.css.StyleOrigin; import java.util.Set; /** A marriage of pseudo-classes (potentially empty) to property and value */ public class CascadingStyle implements Comparable { /** */ private final Style style; public Style getStyle() { return style; } /** State variables, like "hover" or "pressed" */ private final Set pseudoClasses; /* specificity of the selector that matched */ private final int specificity; /* order in which this style appeared in the stylesheet */ private final int ordinal; /* * True if the property is -fx-skin. We want the skin property to * sort less than all other properties. */ private final boolean skinProp; public CascadingStyle(final Style style, Set pseudoClasses, final int specificity, final int ordinal) { this.style = style; this.pseudoClasses = pseudoClasses; this.specificity = specificity; this.ordinal = ordinal; this.skinProp = "-fx-skin".equals(style.getDeclaration().getProperty()); } // Wrapper to make StyleHelper's life a little easier public String getProperty() { return style.getDeclaration().getProperty(); } // Wrapper to make StyleHelper's life a little easier public Selector getSelector() { return style.getSelector(); } // Wrapper to make StyleHelper's life a little easier public Rule getRule() { return style.getDeclaration().getRule(); } // Wrapper to make StyleHelper's life a little easier public StyleOrigin getOrigin() { return getRule().getOrigin(); } // Wrapper to make StyleHelper's life a little easier public ParsedValueImpl getParsedValueImpl() { return style.getDeclaration().getParsedValueImpl(); } @Override public String toString() { return getProperty(); } /** * When testing equality against another Style, we only care about * the property and pseudo-classes. In other words, we only care about * where the style is applied, not what is applied. */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } CascadingStyle other = (CascadingStyle)obj; final String property = getProperty(); final String otherProperty = other.getProperty(); if (property == null ? otherProperty != null : !property.equals(otherProperty)) { return false; } // does [foo bar bang] contain all of [foo bar]? if (pseudoClasses == null ? other.pseudoClasses != null : !pseudoClasses.containsAll(other.pseudoClasses)) { return false; } return true; } /* * Hash on property and pseudoclasses since * obj1.hashCode() should equal obj2.hashCode() if obj1.equals(obj2) */ @Override public int hashCode() { int hash = 7; final String property = getProperty(); hash = 47 * hash + (property != null ? property.hashCode() : 0); hash = 47 * hash + (pseudoClasses != null ? pseudoClasses.hashCode() : 0); return hash; } /** * Implementation of Comparable such that more specific styles get * sorted before less specific ones. */ @Override public int compareTo(CascadingStyle other) { // // Important styles take the cake // Importance being equal, then specificity is considered // Specificity being equal, then the order of declaration decides. // final Declaration decl = style.getDeclaration(); final boolean important = decl != null ? decl.isImportant() : false; final Rule rule = decl != null ? decl.getRule() : null; final StyleOrigin source = rule != null ? rule.getOrigin() : null; final Declaration otherDecl = other.style.getDeclaration(); final boolean otherImportant = otherDecl != null ? otherDecl.isImportant() : false; final Rule otherRule = otherDecl != null ? otherDecl.getRule() : null; final StyleOrigin otherSource = otherRule != null ? otherRule.getOrigin() : null; int c = 0; if (this.skinProp && !other.skinProp) { c = 1; } else if (important != otherImportant) { c = important ? -1 : 1; } else if (source != otherSource) { if (source == null) c = -1; else if (otherSource == null) c = 1; else c = otherSource.compareTo(source); } else { c = other.specificity - this.specificity; }; if (c == 0) c = other.ordinal - this.ordinal; return c; } }