Skip to main content

script/dom/css/
css.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use cssparser::{Parser, serialize_identifier};
6use js::context::JSContext;
7use script_bindings::codegen::GenericBindings::CSSBinding::PropertyDefinition;
8use style::stylesheets::supports_rule::{Declaration, parse_condition_or_declaration};
9use style::stylesheets::{CssRuleType, UrlExtraData};
10use style::stylist::RegisterCustomPropertyResult;
11use style_traits::ParsingMode;
12
13use crate::css::css::parser_context_for_anonymous_content;
14use crate::dom::bindings::codegen::Bindings::CSSBinding::CSSMethods;
15use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
16use crate::dom::bindings::error::{Error, Fallible};
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::window::Window;
20use crate::dom::worklet::Worklet;
21
22#[expect(clippy::upper_case_acronyms)]
23pub(crate) struct CSS {}
24
25impl CSSMethods<crate::DomTypeHolder> for CSS {
26    /// <https://drafts.csswg.org/cssom/#the-css.escape()-method>
27    fn Escape(_: &Window, ident: DOMString) -> Fallible<DOMString> {
28        let mut escaped = String::new();
29        serialize_identifier(&ident.str(), &mut escaped).unwrap();
30        Ok(DOMString::from(escaped))
31    }
32
33    /// <https://drafts.csswg.org/css-conditional/#dom-css-supports>
34    fn Supports(win: &Window, property: DOMString, value: DOMString) -> bool {
35        let mut decl = String::new();
36        serialize_identifier(&property.str(), &mut decl).unwrap();
37        decl.push_str(": ");
38        decl.push_str(&value.str());
39        let decl = Declaration(decl);
40        let url_data = UrlExtraData(win.Document().url().get_arc());
41        let mut context = parser_context_for_anonymous_content(
42            CssRuleType::Style,
43            ParsingMode::DEFAULT,
44            &url_data,
45        );
46        decl.eval(&mut context)
47    }
48
49    /// <https://drafts.csswg.org/css-conditional/#dom-css-supports>
50    fn Supports_(win: &Window, condition: DOMString) -> bool {
51        let condition = condition.str();
52        let mut input = Parser::new(&condition);
53        let cond = match parse_condition_or_declaration(&mut input) {
54            Ok(c) => c,
55            Err(..) => return false,
56        };
57
58        let url_data = UrlExtraData(win.Document().url().get_arc());
59        let mut context = parser_context_for_anonymous_content(
60            CssRuleType::Style,
61            ParsingMode::DEFAULT,
62            &url_data,
63        );
64        cond.eval(&mut context)
65    }
66
67    /// <https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet>
68    fn PaintWorklet(cx: &mut JSContext, win: &Window) -> DomRoot<Worklet> {
69        win.paint_worklet(cx)
70    }
71
72    /// <https://drafts.css-houdini.org/css-properties-values-api/#the-registerproperty-function>
73    fn RegisterProperty(window: &Window, property_definition: &PropertyDefinition) -> Fallible<()> {
74        use RegisterCustomPropertyResult::*;
75        let result = window.layout_mut().stylist_mut().register_custom_property(
76            &UrlExtraData(window.get_url().get_arc()),
77            &property_definition.name.str(),
78            &property_definition.syntax.str(),
79            property_definition.inherits,
80            property_definition
81                .initialValue
82                .as_ref()
83                .map(|value| value.str())
84                .as_deref(),
85        );
86        Err(match result {
87            SuccessfullyRegistered => return Ok(()),
88            InvalidName |
89            InvalidSyntax |
90            InvalidInitialValue |
91            NoInitialValue |
92            InitialValueNotComputationallyIndependent => Error::Syntax(Some(
93                "CSS property value is not computationally independent".into(),
94            )),
95            AlreadyRegistered => {
96                Error::InvalidModification(Some("CSS property is already registered".into()))
97            },
98        })
99    }
100}