diff --git a/components/script/dom/cssnesteddeclarations.rs b/components/script/dom/cssnesteddeclarations.rs new file mode 100644 index 00000000000..2f2585631e1 --- /dev/null +++ b/components/script/dom/cssnesteddeclarations.rs @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use dom_struct::dom_struct; +use servo_arc::Arc; +use style::shared_lock::{Locked, ToCssWithGuard}; +use style::stylesheets::{CssRuleType, NestedDeclarationsRule}; + +use crate::dom::bindings::codegen::Bindings::CSSNestedDeclarationsBinding::CSSNestedDeclarationsMethods; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::bindings::str::DOMString; +use crate::dom::cssrule::{CSSRule, SpecificCSSRule}; +use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner}; +use crate::dom::cssstylesheet::CSSStyleSheet; +use crate::dom::window::Window; +use crate::script_runtime::CanGc; + +#[dom_struct] +pub(crate) struct CSSNestedDeclarations { + cssrule: CSSRule, + #[ignore_malloc_size_of = "Arc"] + #[no_trace] + nesteddeclarationsrule: Arc>, + style_decl: MutNullableDom, +} + +impl CSSNestedDeclarations { + pub(crate) fn new_inherited( + parent_stylesheet: &CSSStyleSheet, + nesteddeclarationsrule: Arc>, + ) -> Self { + Self { + cssrule: CSSRule::new_inherited(parent_stylesheet), + nesteddeclarationsrule, + style_decl: Default::default(), + } + } + + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + pub(crate) fn new( + window: &Window, + parent_stylesheet: &CSSStyleSheet, + nesteddeclarationsrule: Arc>, + can_gc: CanGc, + ) -> DomRoot { + reflect_dom_object( + Box::new(Self::new_inherited( + parent_stylesheet, + nesteddeclarationsrule, + )), + window, + can_gc, + ) + } +} + +impl SpecificCSSRule for CSSNestedDeclarations { + fn ty(&self) -> CssRuleType { + CssRuleType::NestedDeclarations + } + + fn get_css(&self) -> DOMString { + let guard = self.cssrule.shared_lock().read(); + self.nesteddeclarationsrule + .read_with(&guard) + .to_css_string(&guard) + .into() + } +} + +impl CSSNestedDeclarationsMethods for CSSNestedDeclarations { + /// + fn Style(&self, can_gc: CanGc) -> DomRoot { + self.style_decl.or_init(|| { + let guard = self.cssrule.shared_lock().read(); + CSSStyleDeclaration::new( + self.global().as_window(), + CSSStyleOwner::CSSRule( + Dom::from_ref(self.upcast()), + self.nesteddeclarationsrule.read_with(&guard).block.clone(), + ), + None, + CSSModificationAccess::ReadWrite, + can_gc, + ) + }) + } +} diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index 9990be38148..172d29c26c9 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -21,6 +21,7 @@ use crate::dom::csslayerblockrule::CSSLayerBlockRule; use crate::dom::csslayerstatementrule::CSSLayerStatementRule; use crate::dom::cssmediarule::CSSMediaRule; use crate::dom::cssnamespacerule::CSSNamespaceRule; +use crate::dom::cssnesteddeclarations::CSSNestedDeclarations; use crate::dom::cssstylerule::CSSStyleRule; use crate::dom::cssstylesheet::CSSStyleSheet; use crate::dom::csssupportsrule::CSSSupportsRule; @@ -69,6 +70,8 @@ impl CSSRule { rule as &dyn SpecificCSSRule } else if let Some(rule) = self.downcast::() { rule as &dyn SpecificCSSRule + } else if let Some(rule) = self.downcast::() { + rule as &dyn SpecificCSSRule } else { unreachable!() } @@ -125,7 +128,12 @@ impl CSSRule { StyleCssRule::Scope(_) => unimplemented!(), // TODO StyleCssRule::StartingStyle(_) => unimplemented!(), // TODO StyleCssRule::PositionTry(_) => unimplemented!(), // TODO - StyleCssRule::NestedDeclarations(_) => unimplemented!(), // TODO + StyleCssRule::NestedDeclarations(s) => DomRoot::upcast(CSSNestedDeclarations::new( + window, + parent_stylesheet, + s, + can_gc, + )), } } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index a34e0b44221..40db03ed655 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -271,6 +271,7 @@ pub(crate) mod csslayerblockrule; pub(crate) mod csslayerstatementrule; pub(crate) mod cssmediarule; pub(crate) mod cssnamespacerule; +pub(crate) mod cssnesteddeclarations; pub(crate) mod cssrule; pub(crate) mod cssrulelist; pub(crate) mod cssstyledeclaration; diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index f305b74ab01..256097310bb 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -107,6 +107,10 @@ DOMInterfaces = { 'canGc': ['Media'], }, +'CSSNestedDeclarations': { + 'canGc': ['Style'], +}, + 'CSSRuleList': { 'canGc': ['Item', 'IndexedGetter'], }, diff --git a/components/script_bindings/webidls/CSSNestedDeclarations.webidl b/components/script_bindings/webidls/CSSNestedDeclarations.webidl new file mode 100644 index 00000000000..922cc61b03c --- /dev/null +++ b/components/script_bindings/webidls/CSSNestedDeclarations.webidl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * https://drafts.csswg.org/css-nesting-1/#the-cssnestrule + */ + +[Exposed=Window] +interface CSSNestedDeclarations : CSSRule { + // CSSStyleDeclaration instead of CSSStyleProperties for now, see #36260. + [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; +}; diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 960917615a8..3bab4b6e18d 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13503,7 +13503,7 @@ ] ], "interfaces.https.html": [ - "eda7cb2e00ffeb1a51e31ad42b2846d159eeb638", + "dce05a55fd33326768635c6b3cdb193d526fccdd", [ null, {} diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html index eda7cb2e00f..dce05a55fd3 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html @@ -53,6 +53,7 @@ test_interfaces([ "CSSLayerStatementRule", "CSSMediaRule", "CSSNamespaceRule", + "CSSNestedDeclarations", "CSSRule", "CSSRuleList", "CSSStyleDeclaration",