1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.css;
16
17 import java.io.Serializable;
18 import java.util.concurrent.atomic.AtomicLong;
19
20 import org.htmlunit.cssparser.parser.selector.SelectorSpecificity;
21
22 /**
23 * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
24 *
25 * Contains information about a single style element, including its name, its value, and an index which
26 * can be compared against other indices in order to determine precedence.
27 *
28 * @author Mike Bowler
29 * @author Christian Sell
30 * @author Daniel Gredler
31 * @author Chris Erskine
32 * @author Ahmed Ashour
33 * @author Rodney Gitzel
34 * @author Sudhan Moghe
35 * @author Ronald Brill
36 * @author Frank Danek
37 */
38 public class StyleElement implements Serializable {
39 /** CSS important property constant. */
40 public static final String PRIORITY_IMPORTANT = "important";
41
42 /** The current style element index. */
43 private static final AtomicLong ELEMENT_INDEX = new AtomicLong();
44
45 private final String name_;
46 private final String value_;
47 private final String priority_;
48 private final long index_;
49 private final SelectorSpecificity specificity_;
50
51 /**
52 * Creates a new instance.
53 * @param name the style element's name
54 * @param value the style element's value
55 * @param priority the style element's priority like "important"
56 * @param specificity the specificity of the rule providing this style information
57 * @param index the style element's index
58 */
59 public StyleElement(final String name, final String value, final String priority,
60 final SelectorSpecificity specificity, final long index) {
61 name_ = name;
62 value_ = value;
63 priority_ = priority;
64 specificity_ = specificity;
65 index_ = index;
66 }
67
68 /**
69 * Creates a new instance.
70 * @param name the style element's name
71 * @param value the style element's value
72 * @param priority the style element's priority like "important"
73 * @param specificity the specificity of the rule providing this style information
74 */
75 public StyleElement(final String name, final String value, final String priority,
76 final SelectorSpecificity specificity) {
77 this(name, value, priority, specificity, ELEMENT_INDEX.incrementAndGet());
78 }
79
80 /**
81 * Returns the style element's name.
82 * @return the style element's name
83 */
84 public String getName() {
85 return name_;
86 }
87
88 /**
89 * Returns the style element's value.
90 * @return the style element's value
91 */
92 public String getValue() {
93 return value_;
94 }
95
96 /**
97 * Returns the style element's priority.
98 * @return the style element's priority
99 */
100 public String getPriority() {
101 return priority_;
102 }
103
104 /**
105 * Return true if priority is 'important'.
106 *
107 * @return true if priority is 'important'
108 */
109 public boolean isImportant() {
110 return PRIORITY_IMPORTANT.equals(getPriority());
111 }
112
113 /**
114 * Returns the specificity of the rule specifying this element.
115 * @return the specificity
116 */
117 public SelectorSpecificity getSpecificity() {
118 return specificity_;
119 }
120
121 /**
122 * Returns the style element's index.
123 * @return the style element's index
124 */
125 public long getIndex() {
126 return index_;
127 }
128
129 /**
130 * {@inheritDoc}
131 */
132 @Override
133 public String toString() {
134 return "[" + index_ + "]" + name_ + "=" + value_;
135 }
136
137 /**
138 * This takes only the importance, the specificity and the index into account.
139 * The name and value properties are ignored.
140 *
141 * @param first the {@link StyleElement} to compare
142 * @param second the {@link StyleElement} to compare with
143 * @return a negative integer, zero, or a positive integer as this object
144 * is less than, equal to, or greater than the specified object.
145 */
146 public static int compareToByImportanceAndSpecificity(final StyleElement first, final StyleElement second) {
147 if (first == null) {
148 return second == null ? 0 : -1;
149 }
150
151 if (second == null) {
152 return 1;
153 }
154
155 if (first == second) {
156 return 0;
157 }
158
159 if (first.isImportant()) {
160 if (!second.isImportant()) {
161 return 1;
162 }
163 }
164 else {
165 if (second.isImportant()) {
166 return -1;
167 }
168 }
169
170 final int comp = first.getSpecificity().compareTo(second.getSpecificity());
171 if (comp == 0) {
172 return Long.compare(first.getIndex(), second.getIndex());
173 }
174 return comp;
175 }
176 }