View Javadoc
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.javascript.host.css;
16  
17  import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
18  import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
23  import org.htmlunit.cssparser.dom.CSSCharsetRuleImpl;
24  import org.htmlunit.cssparser.dom.CSSFontFaceRuleImpl;
25  import org.htmlunit.cssparser.dom.CSSImportRuleImpl;
26  import org.htmlunit.cssparser.dom.CSSMediaRuleImpl;
27  import org.htmlunit.cssparser.dom.CSSPageRuleImpl;
28  import org.htmlunit.cssparser.dom.CSSStyleRuleImpl;
29  import org.htmlunit.cssparser.dom.CSSUnknownRuleImpl;
30  import org.htmlunit.javascript.HtmlUnitScriptable;
31  import org.htmlunit.javascript.JavaScriptEngine;
32  import org.htmlunit.javascript.configuration.JsxClass;
33  import org.htmlunit.javascript.configuration.JsxConstant;
34  import org.htmlunit.javascript.configuration.JsxConstructor;
35  import org.htmlunit.javascript.configuration.JsxGetter;
36  import org.htmlunit.javascript.configuration.JsxSetter;
37  
38  /**
39   * A JavaScript object for {@code CSSRule}.
40   *
41   * @author Ahmed Ashour
42   * @author Frank Danek
43   * @author Ronald Brill
44   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRule">MDN doc</a>
45   */
46  @JsxClass
47  public class CSSRule extends HtmlUnitScriptable {
48  
49      private static final Log LOG = LogFactory.getLog(CSSRule.class);
50  
51      /**
52       * The rule is a {@code CSSUnknownRule}.
53       */
54      public static final int UNKNOWN_RULE              = org.w3c.dom.css.CSSRule.UNKNOWN_RULE;
55  
56      /**
57       * The rule is a {@code CSSStyleRule}.
58       */
59      @JsxConstant
60      public static final int STYLE_RULE                = org.w3c.dom.css.CSSRule.STYLE_RULE;
61  
62      /**
63       * The rule is a {@code CSSCharsetRule}.
64       */
65      @JsxConstant
66      public static final int CHARSET_RULE              = org.w3c.dom.css.CSSRule.CHARSET_RULE;
67  
68      /**
69       * The rule is a {@code CSSImportRule}.
70       */
71      @JsxConstant
72      public static final int IMPORT_RULE               = org.w3c.dom.css.CSSRule.IMPORT_RULE;
73  
74      /**
75       * The rule is a {@code CSSMediaRule}.
76       */
77      @JsxConstant
78      public static final int MEDIA_RULE                = org.w3c.dom.css.CSSRule.MEDIA_RULE;
79  
80      /**
81       * The rule is a {@code CSSFontFaceRule}.
82       */
83      @JsxConstant
84      public static final int FONT_FACE_RULE            = org.w3c.dom.css.CSSRule.FONT_FACE_RULE;
85  
86      /**
87       * The rule is a {@code CSSPageRule}.
88       */
89      @JsxConstant
90      public static final int PAGE_RULE                 = org.w3c.dom.css.CSSRule.PAGE_RULE;
91  
92      /**
93       * The rule is a {@code CSSKeyframesRule}.
94       */
95      @JsxConstant
96      public static final int KEYFRAMES_RULE            = 7;
97  
98      /**
99       * The rule is a {@code CSSKeyframeRule}.
100      */
101     @JsxConstant
102     public static final int KEYFRAME_RULE             = 8;
103 
104     /**
105      * The rule is a {@code CSSMerginRule}.
106      */
107     @JsxConstant({CHROME, EDGE})
108     public static final int MARGIN_RULE               = 9;
109 
110     /**
111      * The rule is a {@code CSSNamespaceRule}.
112      */
113     @JsxConstant
114     public static final int NAMESPACE_RULE           = 10;
115 
116     /**
117      * The rule is a {@code CSSCounterStyleRule}.
118      */
119     @JsxConstant
120     public static final int COUNTER_STYLE_RULE        = 11;
121 
122     /**
123      * The rule is a {@code CSSSupportsRule}.
124      */
125     @JsxConstant
126     public static final int SUPPORTS_RULE             = 12;
127 
128     /**
129      * The rule is a {@code CSSCounterStyleRule}.
130      */
131     @JsxConstant
132     public static final int FONT_FEATURE_VALUES_RULE  = 14;
133 
134     /**
135      * The rule is a {@code CSSViewportRule}.
136      */
137     public static final int VIEWPORT_RULE  = 15;
138 
139     private final CSSStyleSheet stylesheet_;
140 
141     private final AbstractCSSRuleImpl rule_;
142 
143     /**
144      * Creates a new instance.
145      */
146     public CSSRule() {
147         super();
148         stylesheet_ = null;
149         rule_ = null;
150     }
151 
152     /**
153      * Creates an instance.
154      */
155     @JsxConstructor
156     public void jsConstructor() {
157         throw JavaScriptEngine.typeErrorIllegalConstructor();
158     }
159 
160     /**
161      * Creates a CSSRule according to the specified rule type.
162      * @param stylesheet the Stylesheet of this rule
163      * @param rule the wrapped rule
164      * @return a CSSRule subclass according to the rule type
165      */
166     public static CSSRule create(final CSSStyleSheet stylesheet, final AbstractCSSRuleImpl rule) {
167         if (rule instanceof CSSStyleRuleImpl impl) {
168             return new CSSStyleRule(stylesheet, impl);
169         }
170         if (rule instanceof CSSImportRuleImpl impl) {
171             return new CSSImportRule(stylesheet, impl);
172         }
173 //        if (rule instanceof CSSCharsetRuleImpl) {
174 //            return new CSSCharsetRule(stylesheet, (CSSCharsetRuleImpl) rule);
175 //        }
176         if (rule instanceof CSSMediaRuleImpl impl) {
177             return new CSSMediaRule(stylesheet, impl);
178         }
179         if (rule instanceof CSSFontFaceRuleImpl impl) {
180             return new CSSFontFaceRule(stylesheet, impl);
181         }
182         if (rule instanceof CSSPageRuleImpl impl) {
183             return new CSSPageRule(stylesheet, impl);
184         }
185         if (rule instanceof CSSUnknownRuleImpl unknownRule) {
186             if (unknownRule.getCssText().startsWith("@keyframes")) {
187                 return new CSSKeyframesRule(stylesheet, unknownRule);
188             }
189             if (LOG.isWarnEnabled()) {
190                 LOG.warn("Unknown CSSRule " + rule.getClass().getName()
191                         + " is not yet supported; rule content: '" + rule.getCssText() + "'");
192             }
193         }
194 
195         if (LOG.isWarnEnabled()) {
196             LOG.warn("CSSRule " + rule.getClass().getName()
197                     + " is not yet supported; rule content: '" + rule.getCssText() + "'");
198         }
199 
200         return null;
201     }
202 
203     /**
204      * Creates a new instance.
205      * @param stylesheet the Stylesheet of this rule.
206      * @param rule the wrapped rule
207      */
208     protected CSSRule(final CSSStyleSheet stylesheet, final AbstractCSSRuleImpl rule) {
209         super();
210         stylesheet_ = stylesheet;
211         rule_ = rule;
212         setParentScope(stylesheet.getParentScope());
213         setPrototype(getPrototype(getClass()));
214     }
215 
216     /**
217      * Returns the type of the rule.
218      * @return the type of the rule.
219      */
220     @JsxGetter
221     public int getType() {
222         if (rule_ instanceof CSSCharsetRuleImpl) {
223             return CHARSET_RULE;
224         }
225         if (rule_ instanceof CSSFontFaceRuleImpl) {
226             return FONT_FACE_RULE;
227         }
228         if (rule_ instanceof CSSImportRuleImpl) {
229             return IMPORT_RULE;
230         }
231         if (rule_ instanceof CSSMediaRuleImpl) {
232             return MEDIA_RULE;
233         }
234         if (rule_ instanceof CSSPageRuleImpl) {
235             return PAGE_RULE;
236         }
237         if (rule_ instanceof CSSStyleRuleImpl) {
238             return STYLE_RULE;
239         }
240         if (rule_ instanceof CSSUnknownRuleImpl) {
241             return UNKNOWN_RULE;
242         }
243 
244         return UNKNOWN_RULE;
245     }
246 
247     /**
248      * Returns the parsable textual representation of the rule.
249      * This reflects the current state of the rule and not its initial value.
250      * @return the parsable textual representation of the rule.
251      */
252     @JsxGetter
253     public String getCssText() {
254         return rule_.getCssText();
255     }
256 
257     /**
258      * See <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText">
259      * https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText</a>.
260      * @param cssText ignored
261      */
262     @JsxSetter
263     public void setCssText(final String cssText) {
264         // nothing to do
265     }
266 
267     /**
268      * Returns the style sheet that contains this rule.
269      * @return the style sheet that contains this rule.
270      */
271     @JsxGetter
272     public CSSStyleSheet getParentStyleSheet() {
273         return stylesheet_;
274     }
275 
276     /**
277      * If this rule is contained inside another rule (e.g. a style rule inside a @media block),
278      * this is the containing rule. If this rule is not nested inside any other rules, this returns {@code null}.
279      * @return the parent rule
280      */
281     @JsxGetter
282     public CSSRule getParentRule() {
283         final AbstractCSSRuleImpl parentRule = rule_.getParentRule();
284         if (parentRule != null) {
285             return create(stylesheet_, parentRule);
286         }
287         return null;
288     }
289 
290     /**
291      * Returns the wrapped rule.
292      * @return the wrapped rule.
293      */
294     protected AbstractCSSRuleImpl getRule() {
295         return rule_;
296     }
297 }