View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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) {
168             return new CSSStyleRule(stylesheet, (CSSStyleRuleImpl) rule);
169         }
170         if (rule instanceof CSSImportRuleImpl) {
171             return new CSSImportRule(stylesheet, (CSSImportRuleImpl) rule);
172         }
173 //        if (rule instanceof CSSCharsetRuleImpl) {
174 //            return new CSSCharsetRule(stylesheet, (CSSCharsetRuleImpl) rule);
175 //        }
176         if (rule instanceof CSSMediaRuleImpl) {
177             return new CSSMediaRule(stylesheet, (CSSMediaRuleImpl) rule);
178         }
179         if (rule instanceof CSSFontFaceRuleImpl) {
180             return new CSSFontFaceRule(stylesheet, (CSSFontFaceRuleImpl) rule);
181         }
182         if (rule instanceof CSSPageRuleImpl) {
183             return new CSSPageRule(stylesheet, (CSSPageRuleImpl) rule);
184         }
185         if (rule instanceof CSSUnknownRuleImpl) {
186             final CSSUnknownRuleImpl unknownRule = (CSSUnknownRuleImpl) rule;
187             if (unknownRule.getCssText().startsWith("@keyframes")) {
188                 return new CSSKeyframesRule(stylesheet, (CSSUnknownRuleImpl) rule);
189             }
190             if (LOG.isWarnEnabled()) {
191                 LOG.warn("Unknown CSSRule " + rule.getClass().getName()
192                         + " is not yet supported; rule content: '" + rule.getCssText() + "'");
193             }
194         }
195 
196         if (LOG.isWarnEnabled()) {
197             LOG.warn("CSSRule " + rule.getClass().getName()
198                     + " is not yet supported; rule content: '" + rule.getCssText() + "'");
199         }
200 
201         return null;
202     }
203 
204     /**
205      * Creates a new instance.
206      * @param stylesheet the Stylesheet of this rule.
207      * @param rule the wrapped rule
208      */
209     protected CSSRule(final CSSStyleSheet stylesheet, final AbstractCSSRuleImpl rule) {
210         super();
211         stylesheet_ = stylesheet;
212         rule_ = rule;
213         setParentScope(stylesheet);
214         setPrototype(getPrototype(getClass()));
215     }
216 
217     /**
218      * Returns the type of the rule.
219      * @return the type of the rule.
220      */
221     @JsxGetter
222     public int getType() {
223         if (rule_ instanceof CSSCharsetRuleImpl) {
224             return CHARSET_RULE;
225         }
226         if (rule_ instanceof CSSFontFaceRuleImpl) {
227             return FONT_FACE_RULE;
228         }
229         if (rule_ instanceof CSSImportRuleImpl) {
230             return IMPORT_RULE;
231         }
232         if (rule_ instanceof CSSMediaRuleImpl) {
233             return MEDIA_RULE;
234         }
235         if (rule_ instanceof CSSPageRuleImpl) {
236             return PAGE_RULE;
237         }
238         if (rule_ instanceof CSSStyleRuleImpl) {
239             return STYLE_RULE;
240         }
241         if (rule_ instanceof CSSUnknownRuleImpl) {
242             return UNKNOWN_RULE;
243         }
244 
245         return UNKNOWN_RULE;
246     }
247 
248     /**
249      * Returns the parsable textual representation of the rule.
250      * This reflects the current state of the rule and not its initial value.
251      * @return the parsable textual representation of the rule.
252      */
253     @JsxGetter
254     public String getCssText() {
255         return rule_.getCssText();
256     }
257 
258     /**
259      * See <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText">
260      * https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText</a>.
261      * @param cssText ignored
262      */
263     @JsxSetter
264     public void setCssText(final String cssText) {
265         // nothing to do
266     }
267 
268     /**
269      * Returns the style sheet that contains this rule.
270      * @return the style sheet that contains this rule.
271      */
272     @JsxGetter
273     public CSSStyleSheet getParentStyleSheet() {
274         return stylesheet_;
275     }
276 
277     /**
278      * If this rule is contained inside another rule (e.g. a style rule inside a @media block),
279      * this is the containing rule. If this rule is not nested inside any other rules, this returns {@code null}.
280      * @return the parent rule
281      */
282     @JsxGetter
283     public CSSRule getParentRule() {
284         final AbstractCSSRuleImpl parentRule = rule_.getParentRule();
285         if (parentRule != null) {
286             return create(stylesheet_, parentRule);
287         }
288         return null;
289     }
290 
291     /**
292      * Returns the wrapped rule.
293      * @return the wrapped rule.
294      */
295     protected AbstractCSSRuleImpl getRule() {
296         return rule_;
297     }
298 }