From 23c327a988442e1df7b9b62932d540532b86de58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20W=C3=BClker?= Date: Wed, 7 May 2025 12:29:14 +0200 Subject: [PATCH] script: Serialize a custom element's "is" value as an attribute (#36888) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing: Covered by web platform tests [try run](https://github.com/simonwuelker/servo/actions/runs/14868893249) --------- Signed-off-by: Simon Wülker --- components/script/dom/servoparser/html.rs | 41 +++++++++++++------ ...tml-fragments-customized-builtins.html.ini | 6 --- 2 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 7fd0429612a..9dfbeda4030 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -16,6 +16,7 @@ use html5ever::{QualName, local_name, ns}; use markup5ever::TokenizerResult; use script_bindings::trace::CustomTraceable; use servo_url::ServoUrl; +use style::attr::AttrValue; use style::context::QuirksMode as StyleContextQuirksMode; use xml5ever::LocalName; @@ -116,18 +117,34 @@ impl Tokenizer { } } -fn start_element(node: &Element, serializer: &mut S) -> io::Result<()> { - let name = QualName::new(None, node.namespace().clone(), node.local_name().clone()); - let attrs = node - .attrs() - .iter() - .map(|attr| { - let qname = QualName::new(None, attr.namespace().clone(), attr.local_name().clone()); - let value = attr.value().clone(); - (qname, value) - }) - .collect::>(); - let attr_refs = attrs.iter().map(|(qname, value)| { +/// +fn start_element(element: &Element, serializer: &mut S) -> io::Result<()> { + let name = QualName::new( + None, + element.namespace().clone(), + element.local_name().clone(), + ); + + let mut attributes = vec![]; + + // The "is" value of an element is treated as if it was an attribute and it is serialized before all + // other attributes. If the element already has an "is" attribute then the "is" value is ignored. + if !element.has_attribute(&LocalName::from("is")) { + if let Some(is_value) = element.get_is() { + let qualified_name = QualName::new(None, ns!(), LocalName::from("is")); + + attributes.push((qualified_name, AttrValue::String(is_value.to_string()))); + } + } + + // Collect all the "normal" attributes + attributes.extend(element.attrs().iter().map(|attr| { + let qname = QualName::new(None, attr.namespace().clone(), attr.local_name().clone()); + let value = attr.value().clone(); + (qname, value) + })); + + let attr_refs = attributes.iter().map(|(qname, value)| { let ar: AttrRef = (qname, &**value); ar }); diff --git a/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini b/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini deleted file mode 100644 index 15f02f181e4..00000000000 --- a/tests/wpt/meta/custom-elements/parser/serializing-html-fragments-customized-builtins.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[serializing-html-fragments-customized-builtins.html] - ["is" value should be serialized if the custom element has no "is" content attribute] - expected: FAIL - - ["is" value should be serialized even for an undefined element] - expected: FAIL