1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell};
9use std::default::Default;
10use std::rc::Rc;
11use std::str::FromStr;
12use std::sync::atomic::{AtomicUsize, Ordering};
13use std::{fmt, mem};
14
15use app_units::Au;
16use cssparser::match_ignore_ascii_case;
17use devtools_traits::{AttrInfo, DomMutation, ScriptToDevtoolsControlMsg};
18use dom_struct::dom_struct;
19use euclid::Rect;
20use html5ever::serialize::TraversalScope;
21use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
22use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
23use js::context::JSContext;
24use js::jsapi::{Heap, JSObject};
25use js::jsval::JSVal;
26use js::realm::CurrentRealm;
27use js::rust::HandleObject;
28use layout_api::{LayoutDamage, QueryMsg, ScrollContainerQueryFlags, StyleData, with_layout_state};
29use net_traits::ReferrerPolicy;
30use net_traits::request::{CorsSettings, CredentialsMode};
31use script_bindings::cell::{DomRefCell, Ref, RefMut};
32use script_bindings::reflector::DomObject;
33use selectors::attr::CaseSensitivity;
34use selectors::matching::ElementSelectorFlags;
35use selectors::sink::Push;
36use servo_arc::Arc as ServoArc;
37use style::applicable_declarations::ApplicableDeclarationBlock;
38use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
39use style::context::QuirksMode;
40use style::invalidation::element::restyle_hints::RestyleHint;
41use style::properties::longhands::{
42 self, background_image, border_spacing, color, font_family, font_size,
43};
44use style::properties::{
45 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
46 parse_style_attribute,
47};
48use style::rule_tree::{CascadeLevel, CascadeOrigin};
49use style::selector_parser::{RestyleDamage, SelectorParser, Snapshot};
50use style::shared_lock::Locked;
51use style::stylesheets::layer_rule::LayerOrder;
52use style::stylesheets::{CssRuleType, UrlExtraData};
53use style::values::computed::Overflow;
54use style::values::generics::NonNegative;
55use style::values::generics::position::PreferredRatio;
56use style::values::generics::ratio::Ratio;
57use style::values::{AtomIdent, AtomString, CSSFloat, GenericAtomIdent, computed, specified};
58use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
59use style_traits::CSSPixel;
60use stylo_atoms::Atom;
61use stylo_dom::ElementState;
62use xml5ever::serialize::TraversalScope::{
63 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
64};
65
66use crate::conversions::Convert;
67use crate::dom::activation::Activatable;
68use crate::dom::animation::Animation;
69use crate::dom::animations::keyframeeffect::KeyframeEffect;
70use crate::dom::attr::{Attr, is_relevant_attribute};
71use crate::dom::bindings::codegen::Bindings::AnimationBinding::AnimationMethods;
72use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
73use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
74use crate::dom::bindings::codegen::Bindings::ElementBinding::{
75 ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
76};
77use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
78use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
79use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
80use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
81use crate::dom::bindings::codegen::Bindings::KeyframeEffectBinding::KeyframeEffectMethods;
82use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
83use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
84 SetHTMLOptions, SetHTMLUnsafeOptions,
85};
86use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
87 ShadowRootMethods, ShadowRootMode, SlotAssignmentMode,
88};
89use crate::dom::bindings::codegen::Bindings::WindowBinding::{
90 ScrollBehavior, ScrollToOptions, WindowMethods,
91};
92use crate::dom::bindings::codegen::UnionTypes::{
93 BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
94 TrustedHTMLOrString,
95 TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString,
96 UnrestrictedDoubleOrKeyframeAnimationOptions, UnrestrictedDoubleOrKeyframeEffectOptions,
97};
98use crate::dom::bindings::conversions::DerivedFrom;
99use crate::dom::bindings::domname::{
100 self, is_valid_attribute_local_name, namespace_from_domstring,
101};
102use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
103use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
104use crate::dom::bindings::num::Finite;
105use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
106use crate::dom::bindings::str::DOMString;
107use crate::dom::csp::{CspReporting, InlineCheckType, SourcePosition};
108use crate::dom::customelementregistry::{
109 CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementRegistry,
110 CustomElementState, is_valid_custom_element_name,
111};
112use crate::dom::document::Document;
113use crate::dom::documentfragment::DocumentFragment;
114use crate::dom::domrect::DOMRect;
115use crate::dom::domrectlist::DOMRectList;
116use crate::dom::domtokenlist::DOMTokenList;
117use crate::dom::element::attributes::storage::{
118 AttrRef, AttrValueRef, AttributeEntry, AttributeStorage, ContentAttributeData,
119};
120use crate::dom::element::create::create_element;
121use crate::dom::elementinternals::ElementInternals;
122use crate::dom::eventtarget::EventTarget;
123use crate::dom::globalscope::GlobalScope;
124use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
125use crate::dom::html::htmlareaelement::HTMLAreaElement;
126use crate::dom::html::htmlbodyelement::HTMLBodyElement;
127use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
128use crate::dom::html::htmlcollection::HTMLCollection;
129use crate::dom::html::htmlelement::HTMLElement;
130use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
131use crate::dom::html::htmlfontelement::HTMLFontElement;
132use crate::dom::html::htmlformelement::FormControlElementHelpers;
133use crate::dom::html::htmlhrelement::{HTMLHRElement, SizePresentationalHint};
134use crate::dom::html::htmliframeelement::HTMLIFrameElement;
135use crate::dom::html::htmlimageelement::HTMLImageElement;
136use crate::dom::html::htmllabelelement::HTMLLabelElement;
137use crate::dom::html::htmllegendelement::HTMLLegendElement;
138use crate::dom::html::htmllinkelement::HTMLLinkElement;
139use crate::dom::html::htmlobjectelement::HTMLObjectElement;
140use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
141use crate::dom::html::htmloutputelement::HTMLOutputElement;
142use crate::dom::html::htmlscriptelement::HTMLScriptElement;
143use crate::dom::html::htmlselectelement::HTMLSelectElement;
144use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
145use crate::dom::html::htmlstyleelement::HTMLStyleElement;
146use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
147use crate::dom::html::htmltablecolelement::HTMLTableColElement;
148use crate::dom::html::htmltableelement::HTMLTableElement;
149use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
150use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
151use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
152use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
153use crate::dom::html::htmlvideoelement::HTMLVideoElement;
154use crate::dom::input_element::HTMLInputElement;
155use crate::dom::intersectionobserver::{IntersectionObserver, IntersectionObserverRegistration};
156use crate::dom::iterators::ShadowIncluding;
157use crate::dom::mutationobserver::{Mutation, MutationObserver};
158use crate::dom::namednodemap::NamedNodeMap;
159use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
160use crate::dom::node::{
161 BindContext, ChildrenMutation, CloneChildrenFlag, IsShadowTree, Node, NodeDamage, NodeFlags,
162 NodeTraits, UnbindContext,
163};
164use crate::dom::nodelist::NodeList;
165use crate::dom::promise::Promise;
166use crate::dom::range::Range;
167use crate::dom::raredata::ElementRareData;
168use crate::dom::sanitizer::Sanitizer;
169use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
170use crate::dom::servoparser::ServoParser;
171use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
172use crate::dom::svg::svgsvgelement::SVGSVGElement;
173use crate::dom::text::Text;
174use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
175use crate::dom::trustedtypes::trustedtypepolicyfactory::TrustedTypePolicyFactory;
176use crate::dom::validation::Validatable;
177use crate::dom::validitystate::ValidationFlags;
178use crate::layout_dom::ServoDangerousStyleElement;
179use crate::realms::enter_auto_realm;
180use crate::script_runtime::CanGc;
181use crate::script_thread::ScriptThread;
182use crate::stylesheet_loader::StylesheetOwner;
183
184#[dom_struct]
190pub struct Element {
191 node: Node,
192 #[no_trace]
193 local_name: LocalName,
194 tag_name: TagName,
195 #[no_trace]
196 namespace: Namespace,
197 #[no_trace]
198 prefix: DomRefCell<Option<Prefix>>,
199 attrs: AttributeStorage,
200 #[no_trace]
201 id_attribute: DomRefCell<Option<Atom>>,
202 #[no_trace]
204 is: DomRefCell<Option<LocalName>>,
205 #[conditional_malloc_size_of]
206 #[no_trace]
207 style_attribute: DomRefCell<Option<ServoArc<Locked<PropertyDeclarationBlock>>>>,
208 attr_list: MutNullableDom<NamedNodeMap>,
209 class_list: MutNullableDom<DOMTokenList>,
210 #[no_trace]
211 state: Cell<ElementState>,
212 selector_flags: AtomicUsize,
215 rare_data: DomRefCell<Option<Box<ElementRareData>>>,
216
217 #[no_trace]
220 style_data: DomRefCell<Option<Box<StyleData>>>,
221}
222
223impl fmt::Debug for Element {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 write!(f, "<{}", self.local_name)?;
226 if let Some(ref id) = *self.id_attribute.borrow() {
227 write!(f, " id={}", id)?;
228 }
229 write!(f, ">")
230 }
231}
232
233#[derive(MallocSizeOf, PartialEq)]
234pub(crate) enum ElementCreator {
235 ParserCreated(u64),
236 ScriptCreated,
237}
238
239pub(crate) enum CustomElementCreationMode {
240 Synchronous,
241 Asynchronous,
242}
243
244impl ElementCreator {
245 pub(crate) fn is_parser_created(&self) -> bool {
246 match *self {
247 ElementCreator::ParserCreated(_) => true,
248 ElementCreator::ScriptCreated => false,
249 }
250 }
251 pub(crate) fn return_line_number(&self) -> u64 {
252 match *self {
253 ElementCreator::ParserCreated(l) => l,
254 ElementCreator::ScriptCreated => 1,
255 }
256 }
257}
258
259pub(crate) enum AdjacentPosition {
260 BeforeBegin,
261 AfterEnd,
262 AfterBegin,
263 BeforeEnd,
264}
265
266impl FromStr for AdjacentPosition {
267 type Err = Error;
268
269 fn from_str(position: &str) -> Result<Self, Self::Err> {
270 match_ignore_ascii_case! { position,
271 "beforebegin" => Ok(AdjacentPosition::BeforeBegin),
272 "afterbegin" => Ok(AdjacentPosition::AfterBegin),
273 "beforeend" => Ok(AdjacentPosition::BeforeEnd),
274 "afterend" => Ok(AdjacentPosition::AfterEnd),
275 _ => Err(Error::Syntax(None))
276 }
277 }
278}
279
280impl Element {
284 pub(crate) fn create(
285 cx: &mut JSContext,
286 name: QualName,
287 is: Option<LocalName>,
288 document: &Document,
289 creator: ElementCreator,
290 mode: CustomElementCreationMode,
291 proto: Option<HandleObject>,
292 ) -> DomRoot<Element> {
293 create_element(cx, name, is, document, creator, mode, proto)
294 }
295
296 pub(crate) fn new_inherited(
297 local_name: LocalName,
298 namespace: Namespace,
299 prefix: Option<Prefix>,
300 document: &Document,
301 ) -> Element {
302 Element::new_inherited_with_state(
303 ElementState::empty(),
304 local_name,
305 namespace,
306 prefix,
307 document,
308 )
309 }
310
311 pub(crate) fn new_inherited_with_state(
312 state: ElementState,
313 local_name: LocalName,
314 namespace: Namespace,
315 prefix: Option<Prefix>,
316 document: &Document,
317 ) -> Element {
318 Element {
319 node: Node::new_inherited(document),
320 local_name,
321 tag_name: TagName::new(),
322 namespace,
323 prefix: DomRefCell::new(prefix),
324 attrs: Default::default(),
325 id_attribute: DomRefCell::new(None),
326 is: DomRefCell::new(None),
327 style_attribute: DomRefCell::new(None),
328 attr_list: Default::default(),
329 class_list: Default::default(),
330 state: Cell::new(state),
331 selector_flags: Default::default(),
332 rare_data: Default::default(),
333 style_data: Default::default(),
334 }
335 }
336
337 pub(crate) fn set_had_duplicate_attributes(&self) {
338 self.ensure_rare_data().had_duplicate_attributes = true;
339 }
340
341 pub(crate) fn new(
342 cx: &mut JSContext,
343 local_name: LocalName,
344 namespace: Namespace,
345 prefix: Option<Prefix>,
346 document: &Document,
347 proto: Option<HandleObject>,
348 ) -> DomRoot<Element> {
349 Node::reflect_node_with_proto(
350 cx,
351 Box::new(Element::new_inherited(
352 local_name, namespace, prefix, document,
353 )),
354 document,
355 proto,
356 )
357 }
358
359 fn rare_data(&self) -> Ref<'_, Option<Box<ElementRareData>>> {
360 self.rare_data.borrow()
361 }
362
363 fn rare_data_mut(&self) -> RefMut<'_, Option<Box<ElementRareData>>> {
364 self.rare_data.borrow_mut()
365 }
366
367 pub(crate) fn ensure_rare_data(&self) -> RefMut<'_, Box<ElementRareData>> {
368 let mut rare_data = self.rare_data.borrow_mut();
369 if rare_data.is_none() {
370 *rare_data = Some(Default::default());
371 }
372 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
373 }
374
375 pub(crate) fn clean_up_style_data(&self) {
376 self.style_data.borrow_mut().take();
377 }
378
379 pub(crate) fn restyle(&self, damage: NodeDamage) {
380 let doc = self.node.owner_doc();
381 let mut restyle = doc.ensure_pending_restyle(self);
382
383 restyle.hint.insert(RestyleHint::RESTYLE_SELF);
386
387 match damage {
388 NodeDamage::Style => {},
389 NodeDamage::ContentOrHeritage => {
390 doc.note_node_with_dirty_descendants(self.upcast());
391 restyle
392 .damage
393 .insert(RestyleDamage::from(LayoutDamage::DescendantHasBoxDamage));
394 },
395 NodeDamage::Other => {
396 doc.note_node_with_dirty_descendants(self.upcast());
397 restyle.damage.insert(RestyleDamage::reconstruct());
398 },
399 }
400 }
401
402 pub(crate) fn set_is(&self, is: LocalName) {
403 *self.is.borrow_mut() = Some(is);
404 }
405
406 pub(crate) fn get_is(&self) -> Option<LocalName> {
408 self.is.borrow().clone()
409 }
410
411 pub(crate) fn set_initial_custom_element_state_to_uncustomized(&self) {
420 let mut state = self.state.get();
421 state.insert(ElementState::DEFINED);
422 self.state.set(state);
423 }
424
425 pub(crate) fn set_custom_element_state(&self, state: CustomElementState) {
427 if state != CustomElementState::Uncustomized {
429 self.ensure_rare_data().custom_element_state = state;
430 }
431
432 let in_defined_state = matches!(
433 state,
434 CustomElementState::Uncustomized | CustomElementState::Custom
435 );
436 self.set_state(ElementState::DEFINED, in_defined_state)
437 }
438
439 pub(crate) fn get_custom_element_state(&self) -> CustomElementState {
440 if let Some(rare_data) = self.rare_data().as_ref() {
441 return rare_data.custom_element_state;
442 }
443 CustomElementState::Uncustomized
444 }
445
446 pub(crate) fn is_custom(&self) -> bool {
448 self.get_custom_element_state() == CustomElementState::Custom
449 }
450
451 pub(crate) fn set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>) {
452 self.ensure_rare_data().custom_element_definition = Some(definition);
453 }
454
455 pub(crate) fn get_custom_element_definition(&self) -> Option<Rc<CustomElementDefinition>> {
456 self.rare_data().as_ref()?.custom_element_definition.clone()
457 }
458
459 pub(crate) fn clear_custom_element_definition(&self) {
460 self.ensure_rare_data().custom_element_definition = None;
461 }
462
463 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
464 pub(crate) fn push_callback_reaction(&self, function: Rc<Function>, args: Box<[Heap<JSVal>]>) {
465 self.ensure_rare_data()
466 .custom_element_reaction_queue
467 .push(CustomElementReaction::Callback(function, args));
468 }
469
470 pub(crate) fn push_upgrade_reaction(&self, definition: Rc<CustomElementDefinition>) {
471 self.ensure_rare_data()
472 .custom_element_reaction_queue
473 .push(CustomElementReaction::Upgrade(definition));
474 }
475
476 pub(crate) fn clear_reaction_queue(&self) {
477 if let Some(ref mut rare_data) = *self.rare_data_mut() {
478 rare_data.custom_element_reaction_queue.clear();
479 }
480 }
481
482 pub(crate) fn invoke_reactions(&self, cx: &mut JSContext) {
483 loop {
484 rooted_vec!(let mut reactions);
485 match *self.rare_data_mut() {
486 Some(ref mut data) => {
487 mem::swap(&mut *reactions, &mut data.custom_element_reaction_queue)
488 },
489 None => break,
490 };
491
492 if reactions.is_empty() {
493 break;
494 }
495
496 for reaction in reactions.iter() {
497 reaction.invoke(cx, self);
498 }
499
500 reactions.clear();
501 }
502 }
503
504 pub(crate) fn has_css_layout_box(&self) -> bool {
506 self.style()
507 .is_some_and(|s| !s.get_box().clone_display().is_none())
508 }
509
510 pub(crate) fn is_potentially_scrollable_body(&self) -> bool {
512 self.is_potentially_scrollable_body_shared_logic(false)
513 }
514
515 pub(crate) fn is_potentially_scrollable_body_for_scrolling_element(&self) -> bool {
517 self.is_potentially_scrollable_body_shared_logic(true)
518 }
519
520 fn is_potentially_scrollable_body_shared_logic(
522 &self,
523 treat_overflow_clip_on_parent_as_hidden: bool,
524 ) -> bool {
525 let node = self.upcast::<Node>();
526 debug_assert!(
527 node.owner_doc().GetBody().as_deref() == self.downcast::<HTMLElement>(),
528 "Called is_potentially_scrollable_body on element that is not the <body>"
529 );
530
531 if !self.has_css_layout_box() {
535 return false;
536 }
537
538 if let Some(parent) = node.GetParentElement() &&
541 let Some(style) = parent.style()
542 {
543 let mut overflow_x = style.get_box().clone_overflow_x();
544 let mut overflow_y = style.get_box().clone_overflow_y();
545
546 if treat_overflow_clip_on_parent_as_hidden {
549 if overflow_x == Overflow::Clip {
550 overflow_x = Overflow::Hidden;
551 }
552 if overflow_y == Overflow::Clip {
553 overflow_y = Overflow::Hidden;
554 }
555 }
556
557 if !overflow_x.is_scrollable() && !overflow_y.is_scrollable() {
558 return false;
559 }
560 };
561
562 if let Some(style) = self.style() &&
565 !style.get_box().clone_overflow_x().is_scrollable() &&
566 !style.get_box().clone_overflow_y().is_scrollable()
567 {
568 return false;
569 };
570
571 true
572 }
573
574 pub(crate) fn establishes_scroll_container(&self) -> bool {
577 self.upcast::<Node>()
579 .effective_overflow()
580 .is_some_and(|overflow| overflow.establishes_scroll_container())
581 }
582
583 pub(crate) fn establishes_scroll_container_without_reflow(&self) -> bool {
585 self.upcast::<Node>()
586 .effective_overflow_without_reflow()
587 .is_some_and(|overflow| overflow.establishes_scroll_container())
588 }
589
590 pub(crate) fn has_overflow(&self) -> bool {
591 self.ScrollHeight() > self.ClientHeight() || self.ScrollWidth() > self.ClientWidth()
592 }
593
594 fn has_scrolling_box(&self) -> bool {
602 self.has_css_layout_box() && self.establishes_scroll_container() && self.has_overflow()
603 }
604
605 pub(crate) fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
606 self.rare_data()
607 .as_ref()?
608 .shadow_root
609 .as_ref()
610 .map(|sr| DomRoot::from_ref(&**sr))
611 }
612
613 pub(crate) fn is_shadow_host(&self) -> bool {
614 self.shadow_root().is_some()
615 }
616
617 #[allow(clippy::too_many_arguments)]
619 pub(crate) fn attach_shadow(
620 &self,
621 cx: &mut JSContext,
622 is_ua_widget: IsUserAgentWidget,
623 mode: ShadowRootMode,
624 clonable: bool,
625 serializable: bool,
626 delegates_focus: bool,
627 slot_assignment_mode: SlotAssignmentMode,
628 ) -> Fallible<DomRoot<ShadowRoot>> {
629 if self.namespace != ns!(html) {
632 return Err(Error::NotSupported(Some(
633 "Cannot attach shadow roots to elements with non-HTML namespaces".to_owned(),
634 )));
635 }
636
637 if !is_valid_shadow_host_name(self.local_name()) {
640 if is_ua_widget != IsUserAgentWidget::Yes {
642 let error_message = format!(
643 "Cannot attach shadow roots to <{}> elements",
644 *self.local_name()
645 );
646 return Err(Error::NotSupported(Some(error_message)));
647 }
648 }
649
650 if is_valid_custom_element_name(self.local_name()) || self.get_is().is_some() {
653 let definition = self.get_custom_element_definition();
657 if definition.is_some_and(|definition| definition.disable_shadow) {
660 let error_message = format!(
661 "The custom element constructor of <{}> disabled attachment of shadow roots",
662 self.local_name()
663 );
664 return Err(Error::NotSupported(Some(error_message)));
665 }
666 }
667
668 if let Some(current_shadow_root) = self.shadow_root() {
671 if !current_shadow_root.is_declarative() ||
675 current_shadow_root.shadow_root_mode() != mode
676 {
677 return Err(Error::NotSupported(Some(
678 "Cannot attach a second shadow root to the same element".into(),
679 )));
680 }
681
682 for child in current_shadow_root.upcast::<Node>().children() {
684 child.remove_self(cx);
685 }
686
687 current_shadow_root.set_declarative(false);
689
690 return Ok(current_shadow_root);
692 }
693
694 let shadow_root = ShadowRoot::new(
701 self,
702 &self.node.owner_doc(),
703 mode,
704 slot_assignment_mode,
705 clonable,
706 is_ua_widget,
707 CanGc::from_cx(cx),
708 );
709
710 let node = self.upcast::<Node>();
714 if node.is_connected() {
715 node.remove_style_and_layout_data_from_subtree(cx.no_gc());
716 }
717 shadow_root.set_delegates_focus(delegates_focus);
719
720 if matches!(
723 self.get_custom_element_state(),
724 CustomElementState::Precustomized | CustomElementState::Custom
725 ) {
726 shadow_root.set_available_to_element_internals(true);
727 }
728
729 shadow_root.set_declarative(false);
731
732 shadow_root.set_serializable(serializable);
734
735 self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
737 shadow_root
738 .upcast::<Node>()
739 .set_containing_shadow_root(Some(&shadow_root));
740
741 let bind_context = BindContext::new(self.upcast(), IsShadowTree::Yes);
742 shadow_root.bind_to_tree(cx, &bind_context);
743
744 node.dirty(NodeDamage::Other);
745
746 Ok(shadow_root)
747 }
748
749 pub(crate) fn attach_ua_shadow_root(
765 &self,
766 cx: &mut JSContext,
767 use_ua_widget_styling: bool,
768 ) -> DomRoot<ShadowRoot> {
769 let root = self
770 .attach_shadow(
771 cx,
772 IsUserAgentWidget::Yes,
773 ShadowRootMode::Closed,
774 false,
775 false,
776 false,
777 SlotAssignmentMode::Manual,
778 )
779 .expect("Attaching UA shadow root failed");
780
781 root.upcast::<Node>()
782 .set_in_ua_widget(use_ua_widget_styling);
783 root
784 }
785
786 pub(crate) fn is_translate_enabled(&self) -> bool {
788 let name = &local_name!("translate");
789 if self.has_attribute(name) {
790 let attribute = self.get_string_attribute(name);
791 match_ignore_ascii_case! { &*attribute.str(),
792 "yes" | "" => return true,
793 "no" => return false,
794 _ => {},
795 }
796 }
797 if let Some(parent) = self.upcast::<Node>().GetParentNode() &&
798 let Some(elem) = parent.downcast::<Element>()
799 {
800 return elem.is_translate_enabled();
801 }
802 true
803 }
804
805 pub(crate) fn directionality(&self) -> String {
807 self.downcast::<HTMLElement>()
808 .and_then(|html_element| html_element.directionality())
809 .unwrap_or_else(|| {
810 let node = self.upcast::<Node>();
811 node.parent_directionality()
812 })
813 }
814
815 pub(crate) fn is_root(&self) -> bool {
816 match self.node.GetParentNode() {
817 None => false,
818 Some(node) => node.is::<Document>(),
819 }
820 }
821
822 pub(crate) fn registered_intersection_observers_mut(
825 &self,
826 ) -> RefMut<'_, Vec<IntersectionObserverRegistration>> {
827 RefMut::map(self.ensure_rare_data(), |rare_data| {
828 &mut rare_data.registered_intersection_observers
829 })
830 }
831
832 pub(crate) fn registered_intersection_observers(
833 &self,
834 ) -> Option<Ref<'_, Vec<IntersectionObserverRegistration>>> {
835 let rare_data: Ref<'_, _> = self.rare_data.borrow();
836
837 if rare_data.is_none() {
838 return None;
839 }
840 Some(Ref::map(rare_data, |rare_data| {
841 &rare_data
842 .as_ref()
843 .unwrap()
844 .registered_intersection_observers
845 }))
846 }
847
848 pub(crate) fn get_intersection_observer_registration(
849 &self,
850 observer: &IntersectionObserver,
851 ) -> Option<Ref<'_, IntersectionObserverRegistration>> {
852 if let Some(registrations) = self.registered_intersection_observers() {
853 registrations
854 .iter()
855 .position(|reg_obs| reg_obs.observer == observer)
856 .map(|index| Ref::map(registrations, |registrations| ®istrations[index]))
857 } else {
858 None
859 }
860 }
861
862 pub(crate) fn add_initial_intersection_observer_registration(
864 &self,
865 observer: &IntersectionObserver,
866 ) {
867 self.ensure_rare_data()
868 .registered_intersection_observers
869 .push(IntersectionObserverRegistration::new_initial(observer));
870 }
871
872 pub(crate) fn remove_intersection_observer(&self, observer: &IntersectionObserver) {
874 self.ensure_rare_data()
875 .registered_intersection_observers
876 .retain(|reg_obs| *reg_obs.observer != *observer)
877 }
878
879 pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
882 self.owner_window()
883 .scrolling_box_query(Some(self.upcast()), flags)
884 }
885
886 pub(crate) fn scroll_into_view_with_options(
888 &self,
889 cx: &mut JSContext,
890 behavior: ScrollBehavior,
891 block: ScrollAxisState,
892 inline: ScrollAxisState,
893 container: Option<&Element>,
894 inner_target_rect: Option<Rect<Au, CSSPixel>>,
895 ) {
896 let get_target_rect = || match inner_target_rect {
897 None => self.upcast::<Node>().border_box().unwrap_or_default(),
898 Some(inner_target_rect) => inner_target_rect.translate(
899 self.upcast::<Node>()
900 .content_box()
901 .unwrap_or_default()
902 .origin
903 .to_vector(),
904 ),
905 };
906
907 let mut parent_scrolling_box = self.scrolling_box(ScrollContainerQueryFlags::empty());
910 while let Some(scrolling_box) = parent_scrolling_box {
911 parent_scrolling_box = scrolling_box.parent();
912
913 let position =
924 scrolling_box.determine_scroll_into_view_position(block, inline, get_target_rect());
925
926 if position != scrolling_box.scroll_position() {
931 scrolling_box.scroll_to(cx, position, behavior);
942 }
943
944 if container.is_some_and(|container| {
948 let container_node = container.upcast::<Node>();
949 scrolling_box
950 .node()
951 .is_shadow_including_inclusive_ancestor_of(container_node)
952 }) {
953 return;
954 }
955 }
956
957 let window_proxy = self.owner_window().window_proxy();
958 let Some(frame_element) = window_proxy.frame_element() else {
959 return;
960 };
961
962 let inner_target_rect = Some(get_target_rect());
963
964 let mut realm = enter_auto_realm(cx, frame_element);
965 let cx = &mut realm;
966
967 frame_element.scroll_into_view_with_options(
968 cx,
969 behavior,
970 block,
971 inline,
972 None,
973 inner_target_rect,
974 )
975 }
976
977 pub(crate) fn ensure_contenteditable_selection_range(
978 &self,
979 cx: &mut JSContext,
980 document: &Document,
981 ) -> DomRoot<Range> {
982 self.ensure_rare_data()
983 .contenteditable_selection_range
984 .or_init(|| Range::new_with_doc(cx, document, None))
985 }
986
987 pub(crate) fn handle_scroll_event(&self) {
992 let document = self.owner_document();
994
995 document.finish_handle_scroll_event(self.upcast());
1004 }
1005
1006 pub(crate) fn style(&self) -> Option<ServoArc<ComputedValues>> {
1007 self.owner_window().layout_reflow(QueryMsg::StyleQuery);
1008 self.style_data
1009 .borrow()
1010 .as_ref()
1011 .map(|data| data.element_data.borrow().styles.primary().clone())
1012 }
1013
1014 pub(crate) fn is_styled(&self) -> bool {
1015 self.style_data.borrow().is_some()
1016 }
1017
1018 pub(crate) fn is_display_none(&self) -> bool {
1019 self.style_data.borrow().as_ref().is_none_or(|data| {
1020 data.element_data
1021 .borrow()
1022 .styles
1023 .primary()
1024 .get_box()
1025 .display
1026 .is_none()
1027 })
1028 }
1029
1030 pub(crate) fn check_style_on_self_or_eager_pseudos(
1031 &self,
1032 check_styles_fn: impl Fn(&ComputedValues) -> bool,
1033 ) -> bool {
1034 let style_data = self.style_data.borrow();
1035 let Some(data) = style_data.as_ref().map(|data| data.element_data.borrow()) else {
1036 return false;
1037 };
1038
1039 if check_styles_fn(data.styles.primary()) {
1040 return true;
1041 }
1042
1043 let mut pseudo_styles = data.styles.pseudos.as_array().iter();
1044 pseudo_styles.any(|style| style.as_deref().is_some_and(&check_styles_fn))
1045 }
1046}
1047
1048#[inline]
1050pub(crate) fn is_valid_shadow_host_name(name: &LocalName) -> bool {
1051 if is_valid_custom_element_name(name) {
1054 return true;
1055 }
1056
1057 matches!(
1060 name,
1061 &local_name!("article") |
1062 &local_name!("aside") |
1063 &local_name!("blockquote") |
1064 &local_name!("body") |
1065 &local_name!("div") |
1066 &local_name!("footer") |
1067 &local_name!("h1") |
1068 &local_name!("h2") |
1069 &local_name!("h3") |
1070 &local_name!("h4") |
1071 &local_name!("h5") |
1072 &local_name!("h6") |
1073 &local_name!("header") |
1074 &local_name!("main") |
1075 &local_name!("nav") |
1076 &local_name!("p") |
1077 &local_name!("section") |
1078 &local_name!("span")
1079 )
1080}
1081
1082#[inline]
1083#[expect(unsafe_code)]
1084pub(crate) fn get_attr_for_layout<'dom>(
1085 elem: LayoutDom<'dom, Element>,
1086 namespace: &Namespace,
1087 name: &LocalName,
1088) -> Option<&'dom AttrValue> {
1089 let storage = unsafe { elem.unsafe_get().attrs.borrow_for_layout() };
1090 storage
1091 .iter()
1092 .find(|e: &&AttributeEntry| {
1093 name == e.local_name_for_layout() && namespace == e.namespace_for_layout()
1094 })
1095 .map(|e: &AttributeEntry| e.value_for_layout())
1096}
1097
1098impl<'dom> LayoutDom<'dom, Element> {
1099 #[inline]
1100 pub(crate) fn is_root(&self) -> bool {
1101 self.upcast::<Node>()
1102 .parent_node_ref()
1103 .is_some_and(|parent| matches!(parent.type_id_for_layout(), NodeTypeId::Document(_)))
1104 }
1105
1106 pub(crate) fn is_body_element_of_html_element_root(&self) -> bool {
1108 if self.local_name() != &local_name!("body") {
1109 return false;
1110 }
1111 let Some(parent_node) = self.upcast::<Node>().parent_node_ref() else {
1112 return false;
1113 };
1114 let Some(parent_element) = parent_node.downcast::<Element>() else {
1115 return false;
1116 };
1117 parent_element.local_name() == &local_name!("html")
1118 }
1119
1120 #[expect(unsafe_code)]
1122 #[inline]
1123 pub(crate) fn each_attr_name_for_layout<F>(self, mut callback: F)
1124 where
1125 F: FnMut(&LocalName),
1126 {
1127 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1128 for entry in storage.iter() {
1129 callback(entry.local_name_for_layout());
1130 }
1131 }
1132
1133 #[inline]
1134 pub(crate) fn has_class_or_part_for_layout(
1135 self,
1136 name: &AtomIdent,
1137 attr_name: &LocalName,
1138 case_sensitivity: CaseSensitivity,
1139 ) -> bool {
1140 get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
1141 attr.as_tokens()
1142 .iter()
1143 .any(|atom| case_sensitivity.eq_atom(atom, name))
1144 })
1145 }
1146
1147 #[inline]
1148 pub(crate) fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
1149 get_attr_for_layout(self, &ns!(), &local_name!("class")).map(|attr| attr.as_tokens())
1150 }
1151
1152 pub(crate) fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
1153 get_attr_for_layout(self, &ns!(), &local_name!("part")).map(|attr| attr.as_tokens())
1154 }
1155
1156 #[inline]
1157 #[expect(unsafe_code)]
1158 pub(crate) fn style_data(self) -> Option<&'dom StyleData> {
1159 unsafe { self.unsafe_get().style_data.borrow_for_layout().as_deref() }
1160 }
1161
1162 #[inline]
1163 #[expect(unsafe_code)]
1164 pub(crate) unsafe fn initialize_style_data(self) {
1165 let data = unsafe { self.unsafe_get().style_data.borrow_mut_for_layout() };
1166 debug_assert!(data.is_none());
1167 *data = Some(Box::default());
1168 }
1169
1170 #[inline]
1171 #[expect(unsafe_code)]
1172 pub(crate) unsafe fn clear_style_data(self) {
1173 unsafe {
1174 self.unsafe_get().style_data.borrow_mut_for_layout().take();
1175 }
1176 }
1177
1178 pub(crate) fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1179 where
1180 V: Push<ApplicableDeclarationBlock>,
1181 {
1182 let document = self.upcast::<Node>().owner_doc_for_layout();
1183 let mut property_declaration_block = None;
1184 let mut push = |declaration| {
1185 property_declaration_block
1186 .get_or_insert_with(PropertyDeclarationBlock::default)
1187 .push(declaration, Importance::Normal);
1188 };
1189
1190 if let Some(lang) = self.get_lang_attr_val_for_layout() {
1193 push(PropertyDeclaration::XLang(specified::XLang(Atom::from(
1194 lang.to_owned(),
1195 ))));
1196 }
1197
1198 let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
1199 this.get_background_color()
1200 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1201 this.get_background_color()
1202 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1203 this.get_background_color()
1204 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1205 this.get_background_color()
1206 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1207 this.get_background_color()
1208 } else {
1209 None
1210 };
1211
1212 if let Some(color) = bgcolor {
1213 push(PropertyDeclaration::BackgroundColor(
1214 specified::Color::from_absolute_color(color),
1215 ));
1216 }
1217
1218 if is_element_affected_by_legacy_background_presentational_hint(
1219 self.namespace(),
1220 self.local_name(),
1221 ) && let Some(url) = self
1222 .get_attr_for_layout(&ns!(), &local_name!("background"))
1223 .and_then(AttrValue::as_resolved_url)
1224 .cloned()
1225 {
1226 push(PropertyDeclaration::BackgroundImage(
1227 background_image::SpecifiedValue(vec![specified::Image::for_cascade(url)].into()),
1228 ));
1229 }
1230
1231 let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
1232 this.get_color()
1233 } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
1234 this.get_color()
1236 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1237 this.get_color()
1239 } else {
1240 None
1241 };
1242
1243 if let Some(color) = color {
1244 push(PropertyDeclaration::Color(
1245 longhands::color::SpecifiedValue(specified::Color::from_absolute_color(color)),
1246 ));
1247 }
1248
1249 let font_face = self
1250 .downcast::<HTMLFontElement>()
1251 .and_then(LayoutDom::get_face);
1252 if let Some(font_face) = font_face {
1253 push(PropertyDeclaration::FontFamily(
1254 font_family::SpecifiedValue::Values(computed::font::FontFamilyList {
1255 list: ArcSlice::from_iter(
1256 HTMLFontElement::parse_face_attribute(font_face).into_iter(),
1257 ),
1258 }),
1259 ));
1260 }
1261
1262 let font_size = self
1263 .downcast::<HTMLFontElement>()
1264 .and_then(LayoutDom::get_size);
1265 if let Some(font_size) = font_size {
1266 push(PropertyDeclaration::FontSize(
1267 font_size::SpecifiedValue::from_html_size(font_size as u8),
1268 ));
1269 }
1270
1271 let size = self
1277 .downcast::<HTMLInputElement>()
1278 .and_then(|input_element| {
1279 match self.get_attr_val_for_layout(&ns!(), &local_name!("type")) {
1281 Some("hidden") | Some("range") | Some("color") | Some("checkbox") |
1282 Some("radio") | Some("file") | Some("submit") | Some("image") |
1283 Some("reset") | Some("button") => None,
1284 _ => match input_element.size_for_layout() {
1286 0 => None,
1287 s => Some(s as i32),
1288 },
1289 }
1290 });
1291
1292 if let Some(size) = size {
1293 let value = specified::NoCalcLength::from_servo_character_width(size);
1294 push(PropertyDeclaration::Width(
1295 specified::Size::LengthPercentage(NonNegative(
1296 specified::LengthPercentage::Length(value),
1297 )),
1298 ));
1299 }
1300
1301 let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1302 this.get_width()
1303 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1304 this.get_width()
1305 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1306 this.get_width()
1307 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1308 this.get_width()
1309 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1310 this.get_width()
1311 } else if let Some(this) = self.downcast::<HTMLTableColElement>() {
1312 this.get_width()
1313 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1314 this.get_width()
1316 } else {
1317 LengthOrPercentageOrAuto::Auto
1318 };
1319
1320 match width {
1322 LengthOrPercentageOrAuto::Auto => {},
1323 LengthOrPercentageOrAuto::Percentage(percentage) => {
1324 let width_value = specified::Size::LengthPercentage(NonNegative(
1325 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1326 percentage,
1327 )),
1328 ));
1329 push(PropertyDeclaration::Width(width_value));
1330 },
1331 LengthOrPercentageOrAuto::Length(length) => {
1332 let width_value = specified::Size::LengthPercentage(NonNegative(
1333 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1334 length.to_f32_px(),
1335 )),
1336 ));
1337 push(PropertyDeclaration::Width(width_value));
1338 },
1339 }
1340
1341 let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1342 this.get_height()
1343 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1344 this.get_height()
1345 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1346 this.get_height()
1347 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1348 this.get_height()
1349 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1350 this.get_height()
1351 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1352 this.get_height()
1353 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1354 this.get_height()
1355 } else {
1356 LengthOrPercentageOrAuto::Auto
1357 };
1358
1359 match height {
1360 LengthOrPercentageOrAuto::Auto => {},
1361 LengthOrPercentageOrAuto::Percentage(percentage) => {
1362 let height_value = specified::Size::LengthPercentage(NonNegative(
1363 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1364 percentage,
1365 )),
1366 ));
1367 push(PropertyDeclaration::Height(height_value));
1368 },
1369 LengthOrPercentageOrAuto::Length(length) => {
1370 let height_value = specified::Size::LengthPercentage(NonNegative(
1371 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1372 length.to_f32_px(),
1373 )),
1374 ));
1375 push(PropertyDeclaration::Height(height_value));
1376 },
1377 }
1378
1379 if let Some(this) = self.downcast::<SVGSVGElement>() {
1380 let data = this.data();
1381 if let Some(width) = data.width.and_then(AttrValue::as_length_percentage) {
1382 push(PropertyDeclaration::Width(
1383 specified::Size::LengthPercentage(NonNegative(width.clone())),
1384 ));
1385 }
1386 if let Some(height) = data.height.and_then(AttrValue::as_length_percentage) {
1387 push(PropertyDeclaration::Height(
1388 specified::Size::LengthPercentage(NonNegative(height.clone())),
1389 ));
1390 }
1391 }
1392
1393 if (self.is::<HTMLImageElement>() || self.is::<HTMLVideoElement>()) &&
1396 let LengthOrPercentageOrAuto::Length(width) = width &&
1397 let LengthOrPercentageOrAuto::Length(height) = height
1398 {
1399 let width_value = NonNegative(specified::Number::new(width.to_f32_px()));
1400 let height_value = NonNegative(specified::Number::new(height.to_f32_px()));
1401 let aspect_ratio = specified::position::AspectRatio {
1402 auto: true,
1403 ratio: PreferredRatio::Ratio(Ratio(width_value, height_value)),
1404 };
1405 push(PropertyDeclaration::AspectRatio(Box::new(aspect_ratio)));
1406 }
1407
1408 let cols = self
1409 .downcast::<HTMLTextAreaElement>()
1410 .map(LayoutDom::get_cols);
1411 if let Some(cols) = cols {
1412 let cols = cols as i32;
1413 if cols > 0 {
1414 let value = specified::NoCalcLength::from_servo_character_width(cols);
1420 push(PropertyDeclaration::Width(
1421 specified::Size::LengthPercentage(NonNegative(
1422 specified::LengthPercentage::Length(value),
1423 )),
1424 ));
1425 }
1426 }
1427
1428 let rows = self
1429 .downcast::<HTMLTextAreaElement>()
1430 .map(LayoutDom::get_rows);
1431 if let Some(rows) = rows {
1432 let rows = rows as i32;
1433 if rows > 0 {
1434 let value = specified::NoCalcLength::from_em(rows as CSSFloat);
1438 push(PropertyDeclaration::Height(
1439 specified::Size::LengthPercentage(NonNegative(
1440 specified::LengthPercentage::Length(value),
1441 )),
1442 ));
1443 }
1444 }
1445
1446 if let Some(table) = self.downcast::<HTMLTableElement>() {
1447 if let Some(cellspacing) = table.get_cellspacing() {
1448 let width_value = specified::Length::from_px(cellspacing as f32);
1449 push(PropertyDeclaration::BorderSpacing(
1450 border_spacing::SpecifiedValue::new(
1451 width_value.clone().into(),
1452 width_value.into(),
1453 ),
1454 ));
1455 }
1456 if let Some(border) = table.get_border() {
1457 let width_value = specified::BorderSideWidth::from_px(border as f32);
1458 push(PropertyDeclaration::BorderTopWidth(width_value.clone()));
1459 push(PropertyDeclaration::BorderLeftWidth(width_value.clone()));
1460 push(PropertyDeclaration::BorderBottomWidth(width_value.clone()));
1461 push(PropertyDeclaration::BorderRightWidth(width_value));
1462 }
1463 if document.quirks_mode() == QuirksMode::Quirks {
1464 push(PropertyDeclaration::Color(color::SpecifiedValue(
1466 specified::Color::InheritFromBodyQuirk,
1467 )));
1468 }
1469 }
1470
1471 if let Some(cellpadding) = self
1472 .downcast::<HTMLTableCellElement>()
1473 .and_then(|this| this.get_table())
1474 .and_then(|table| table.get_cellpadding())
1475 {
1476 let cellpadding = NonNegative(specified::LengthPercentage::Length(
1477 specified::NoCalcLength::from_px(cellpadding as f32),
1478 ));
1479 push(PropertyDeclaration::PaddingTop(cellpadding.clone()));
1480 push(PropertyDeclaration::PaddingLeft(cellpadding.clone()));
1481 push(PropertyDeclaration::PaddingBottom(cellpadding.clone()));
1482 push(PropertyDeclaration::PaddingRight(cellpadding));
1483 }
1484
1485 if let Some(size_info) = self
1487 .downcast::<HTMLHRElement>()
1488 .and_then(|hr_element| hr_element.get_size_info())
1489 {
1490 match size_info {
1491 SizePresentationalHint::SetHeightTo(height) => {
1492 push(PropertyDeclaration::Height(height));
1493 },
1494 SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
1495 push(PropertyDeclaration::BorderLeftWidth(border_width.clone()));
1496 push(PropertyDeclaration::BorderRightWidth(border_width.clone()));
1497 push(PropertyDeclaration::BorderTopWidth(border_width.clone()));
1498 push(PropertyDeclaration::BorderBottomWidth(border_width));
1499 },
1500 SizePresentationalHint::SetBottomBorderWidthToZero => {
1501 push(PropertyDeclaration::BorderBottomWidth(
1502 specified::border::BorderSideWidth::from_px(0.),
1503 ));
1504 },
1505 }
1506 }
1507
1508 let Some(property_declaration_block) = property_declaration_block else {
1509 return;
1510 };
1511
1512 let shared_lock = &document.shared_style_locks().author;
1513 hints.push(ApplicableDeclarationBlock::from_declarations(
1514 ServoArc::new(shared_lock.wrap(property_declaration_block)),
1515 CascadeLevel::new(CascadeOrigin::PresHints),
1516 LayerOrder::root(),
1517 ));
1518 }
1519
1520 pub(crate) fn get_span(self) -> Option<u32> {
1521 self.downcast::<HTMLTableColElement>()
1523 .and_then(|element| element.get_span())
1524 }
1525
1526 pub(crate) fn get_colspan(self) -> Option<u32> {
1527 self.downcast::<HTMLTableCellElement>()
1529 .and_then(|element| element.get_colspan())
1530 }
1531
1532 pub(crate) fn get_rowspan(self) -> Option<u32> {
1533 self.downcast::<HTMLTableCellElement>()
1535 .and_then(|element| element.get_rowspan())
1536 }
1537
1538 #[inline]
1539 pub(crate) fn is_html_element(&self) -> bool {
1540 *self.namespace() == ns!(html)
1541 }
1542
1543 #[expect(unsafe_code)]
1544 pub(crate) fn id_attribute(self) -> *const Option<Atom> {
1545 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1546 }
1547
1548 #[expect(unsafe_code)]
1549 pub(crate) fn style_attribute(
1550 self,
1551 ) -> *const Option<ServoArc<Locked<PropertyDeclarationBlock>>> {
1552 unsafe { (self.unsafe_get()).style_attribute.borrow_for_layout() }
1553 }
1554
1555 pub(crate) fn local_name(self) -> &'dom LocalName {
1556 &(self.unsafe_get()).local_name
1557 }
1558
1559 pub(crate) fn namespace(self) -> &'dom Namespace {
1560 &(self.unsafe_get()).namespace
1561 }
1562
1563 pub(crate) fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1564 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1565 return Some(attr);
1566 }
1567 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1568 return Some(attr);
1569 }
1570 None
1571 }
1572
1573 pub(crate) fn get_lang_for_layout(self) -> AtomString {
1574 let mut current_node = Some(self.upcast::<Node>());
1575 while let Some(node) = current_node {
1576 current_node = node.composed_parent_node_ref();
1577 match node.downcast::<Element>() {
1578 Some(elem) => {
1579 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1580 return AtomString::from(attr);
1581 }
1582 },
1583 None => continue,
1584 }
1585 }
1586 AtomString::default()
1589 }
1590
1591 #[inline]
1592 pub(crate) fn get_state_for_layout(self) -> ElementState {
1593 (self.unsafe_get()).state.get()
1594 }
1595
1596 #[inline]
1597 pub(crate) fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1598 debug_assert!(thread_state::get().is_layout());
1599 self.unsafe_get().insert_selector_flags(flags);
1600 }
1601
1602 #[inline]
1603 pub(crate) fn get_selector_flags(self) -> ElementSelectorFlags {
1604 self.unsafe_get().get_selector_flags()
1605 }
1606
1607 #[inline]
1608 #[expect(unsafe_code)]
1609 pub(crate) fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1610 unsafe {
1611 self.unsafe_get()
1612 .rare_data
1613 .borrow_for_layout()
1614 .as_ref()?
1615 .shadow_root
1616 .as_ref()
1617 .map(|sr| sr.to_layout())
1618 }
1619 }
1620
1621 #[inline]
1622 pub(crate) fn get_attr_for_layout(
1623 self,
1624 namespace: &Namespace,
1625 name: &LocalName,
1626 ) -> Option<&'dom AttrValue> {
1627 get_attr_for_layout(self, namespace, name)
1628 }
1629
1630 #[inline]
1631 pub(crate) fn get_attr_val_for_layout(
1632 self,
1633 namespace: &Namespace,
1634 name: &LocalName,
1635 ) -> Option<&'dom str> {
1636 get_attr_for_layout(self, namespace, name).map(|attr| &**attr)
1637 }
1638
1639 #[inline]
1640 #[expect(unsafe_code)]
1641 pub(crate) fn get_attr_vals_for_layout(
1642 self,
1643 name: &LocalName,
1644 ) -> impl Iterator<Item = &'dom AttrValue> {
1645 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1646 storage
1647 .iter()
1648 .filter(move |e: &&AttributeEntry| name == e.local_name_for_layout())
1649 .map(|e: &AttributeEntry| e.value_for_layout())
1650 }
1651
1652 #[expect(unsafe_code)]
1653 pub(crate) fn each_custom_state_for_layout(self, mut callback: impl FnMut(&AtomIdent)) {
1654 let rare_data = unsafe { self.unsafe_get().rare_data.borrow_for_layout() };
1655 let Some(rare_data) = rare_data.as_ref() else {
1656 return;
1657 };
1658 let Some(element_internals) = rare_data.element_internals.as_ref() else {
1659 return;
1660 };
1661
1662 let element_internals: LayoutDom<'_, _> = unsafe { element_internals.to_layout() };
1663 if let Some(states) = element_internals.unsafe_get().custom_states_for_layout() {
1664 for state in unsafe { states.unsafe_get().set_for_layout().iter() } {
1665 callback(&AtomIdent::from(&*state.str()));
1667 }
1668 }
1669 }
1670}
1671
1672impl Element {
1673 pub(crate) fn is_html_element(&self) -> bool {
1674 self.namespace == ns!(html)
1675 }
1676
1677 pub(crate) fn html_element_in_html_document(&self) -> bool {
1678 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1679 }
1680
1681 pub(crate) fn local_name(&self) -> &LocalName {
1682 &self.local_name
1683 }
1684
1685 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1686 if self.html_element_in_html_document() {
1687 name.make_ascii_lowercase();
1688 }
1689 LocalName::from(name)
1690 }
1691
1692 pub(crate) fn namespace(&self) -> &Namespace {
1693 &self.namespace
1694 }
1695
1696 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1697 self.prefix.borrow()
1698 }
1699
1700 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1701 *self.prefix.borrow_mut() = prefix;
1702 }
1703
1704 pub(crate) fn set_custom_element_registry(&self, registry: Option<&CustomElementRegistry>) {
1705 self.ensure_rare_data().custom_element_registry = registry.map(Dom::from_ref);
1706 }
1707
1708 pub(crate) fn custom_element_registry(&self) -> Option<DomRoot<CustomElementRegistry>> {
1709 self.rare_data()
1710 .as_ref()?
1711 .custom_element_registry
1712 .as_deref()
1713 .map(DomRoot::from_ref)
1714 }
1715
1716 pub(crate) fn attrs(&self) -> &AttributeStorage {
1717 &self.attrs
1718 }
1719
1720 pub(crate) fn dom_attrs(&self, cx: &mut JSContext) -> &AttributeStorage {
1721 let len = self.attrs.borrow().len();
1723 for i in 0..len {
1724 self.attrs.ensure_dom(cx, i, self);
1725 }
1726 &self.attrs
1727 }
1728
1729 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1731 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1732
1733 if namespace_prefix == Some(namespace_prefix!("xml")) {
1735 return ns!(xml);
1736 }
1737
1738 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1740 return ns!(xmlns);
1741 }
1742
1743 let prefix = prefix.map(LocalName::from);
1744
1745 let inclusive_ancestor_elements = self
1746 .upcast::<Node>()
1747 .inclusive_ancestors(ShadowIncluding::No)
1748 .filter_map(DomRoot::downcast::<Self>);
1749
1750 for element in inclusive_ancestor_elements {
1753 if element.namespace() != &ns!() &&
1755 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1756 {
1757 return element.namespace().clone();
1758 }
1759
1760 let found_ns = element.attrs.borrow().iter().find_map(|attr| {
1765 if attr.namespace() != &ns!(xmlns) {
1766 return None;
1767 }
1768 match (attr.prefix(), prefix.as_ref()) {
1769 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1770 if attr.local_name() == prefix {
1771 Some(Namespace::from(&**attr.value()))
1772 } else {
1773 None
1774 }
1775 },
1776 (None, None) => {
1777 if attr.local_name() == &local_name!("xmlns") {
1778 Some(Namespace::from(&**attr.value()))
1779 } else {
1780 None
1781 }
1782 },
1783 _ => None,
1784 }
1785 });
1786
1787 if let Some(ns) = found_ns {
1788 return ns;
1789 }
1790 }
1791
1792 ns!()
1793 }
1794
1795 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1796 self.rare_data().as_ref()?.name_attribute.clone()
1797 }
1798
1799 pub(crate) fn style_attribute(
1800 &self,
1801 ) -> &DomRefCell<Option<ServoArc<Locked<PropertyDeclarationBlock>>>> {
1802 &self.style_attribute
1803 }
1804
1805 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1806 self.attrs
1807 .borrow()
1808 .iter()
1809 .map(|attr| attr.summarize())
1810 .collect()
1811 }
1812
1813 pub(crate) fn is_void(&self) -> bool {
1814 if self.namespace != ns!(html) {
1815 return false;
1816 }
1817 match self.local_name {
1818 local_name!("area") |
1821 local_name!("base") |
1822 local_name!("basefont") |
1823 local_name!("bgsound") |
1824 local_name!("br") |
1825 local_name!("col") |
1826 local_name!("embed") |
1827 local_name!("frame") |
1828 local_name!("hr") |
1829 local_name!("img") |
1830 local_name!("input") |
1831 local_name!("keygen") |
1832 local_name!("link") |
1833 local_name!("meta") |
1834 local_name!("param") |
1835 local_name!("source") |
1836 local_name!("track") |
1837 local_name!("wbr") => true,
1838 _ => false,
1839 }
1840 }
1841
1842 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1843 if self.node.is_in_a_document_tree() {
1844 self.upcast::<Node>()
1845 .owner_doc()
1846 .GetDocumentElement()
1847 .unwrap()
1848 } else {
1849 self.upcast::<Node>()
1850 .inclusive_ancestors(ShadowIncluding::No)
1851 .filter_map(DomRoot::downcast)
1852 .last()
1853 .expect("We know inclusive_ancestors will return `self` which is an element")
1854 }
1855 }
1856
1857 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1859 for node in self
1860 .upcast::<Node>()
1861 .inclusive_ancestors(ShadowIncluding::No)
1862 {
1863 let element = node.downcast::<Element>()?;
1864 if *element.namespace() == namespace &&
1866 let Some(prefix) = element.GetPrefix()
1867 {
1868 return Some(prefix);
1869 }
1870
1871 for attr in element.attrs.borrow().iter() {
1873 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1874 **attr.value() == *namespace
1875 {
1876 return Some(DOMString::from(&**attr.local_name()));
1877 }
1878 }
1879 }
1880 None
1881 }
1882
1883 pub(crate) fn is_document_element(&self) -> bool {
1885 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1886 *document_element == *self
1887 } else {
1888 false
1889 }
1890 }
1891
1892 pub(crate) fn is_active_element(&self) -> bool {
1894 if let Some(active_element) = self.owner_document().GetActiveElement() {
1895 *active_element == *self
1896 } else {
1897 false
1898 }
1899 }
1900
1901 pub(crate) fn is_editing_host(&self) -> bool {
1902 self.downcast::<HTMLElement>()
1903 .is_some_and(|element| element.IsContentEditable())
1904 }
1905
1906 pub(crate) fn is_actually_disabled(&self) -> bool {
1907 let node = self.upcast::<Node>();
1908 match node.type_id() {
1909 NodeTypeId::Element(ElementTypeId::HTMLElement(
1910 HTMLElementTypeId::HTMLButtonElement,
1911 )) |
1912 NodeTypeId::Element(ElementTypeId::HTMLElement(
1913 HTMLElementTypeId::HTMLInputElement,
1914 )) |
1915 NodeTypeId::Element(ElementTypeId::HTMLElement(
1916 HTMLElementTypeId::HTMLSelectElement,
1917 )) |
1918 NodeTypeId::Element(ElementTypeId::HTMLElement(
1919 HTMLElementTypeId::HTMLTextAreaElement,
1920 )) |
1921 NodeTypeId::Element(ElementTypeId::HTMLElement(
1922 HTMLElementTypeId::HTMLOptionElement,
1923 )) => self.disabled_state(),
1924 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1925 self.downcast::<HTMLElement>()
1926 .unwrap()
1927 .is_form_associated_custom_element() &&
1928 self.disabled_state()
1929 },
1930 _ => false,
1935 }
1936 }
1937
1938 #[allow(clippy::too_many_arguments)]
1939 pub(crate) fn push_new_attribute(
1940 &self,
1941 cx: &mut JSContext,
1942 local_name: LocalName,
1943 value: AttrValue,
1944 name: LocalName,
1945 namespace: Namespace,
1946 prefix: Option<Prefix>,
1947 reason: AttributeMutationReason,
1948 ) {
1949 let data = ContentAttributeData {
1954 identifier: AttrIdentifier {
1955 local_name: GenericAtomIdent(local_name),
1956 name: GenericAtomIdent(name),
1957 namespace: GenericAtomIdent(namespace),
1958 prefix: prefix.map(GenericAtomIdent),
1959 },
1960 value,
1961 };
1962 let attr_ref = AttrRef::Raw(&data);
1963 self.will_mutate_attr(attr_ref);
1964 self.attrs.push_raw(ContentAttributeData {
1966 identifier: data.identifier.clone(),
1967 value: data.value.clone(),
1968 });
1969 self.handle_attribute_changes(cx, attr_ref, None, Some(&*attr_ref.value()), reason);
1971 }
1972
1973 fn handle_attribute_changes(
1975 &self,
1976 cx: &mut JSContext,
1977 attr: AttrRef<'_>,
1978 old_value: Option<&AttrValue>,
1979 new_value: Option<&AttrValue>,
1980 reason: AttributeMutationReason,
1981 ) {
1982 let name = attr.local_name().clone();
1985 let namespace = attr.namespace().clone();
1986 let mutation = LazyCell::new(|| Mutation::Attribute {
1987 name: name.clone(),
1988 namespace: namespace.clone(),
1989 old_value: old_value.map(|old_value| DOMString::from(&**old_value)),
1990 });
1991 MutationObserver::queue_a_mutation_record(&self.node, mutation);
1992
1993 let has_new_value = new_value.is_some();
1995
1996 if self.is_custom() {
1999 let reaction = CallbackReaction::AttributeChanged(
2000 attr.local_name().clone(),
2001 old_value,
2002 new_value,
2003 attr.namespace().clone(),
2004 );
2005 ScriptThread::enqueue_callback_reaction(cx, self, reaction, None);
2006 }
2007
2008 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
2010 let attribute_mutation = if has_new_value {
2011 AttributeMutation::Set(old_value, reason)
2012 } else {
2013 AttributeMutation::Removed
2014 };
2015 vtable_for(self.upcast()).attribute_mutated(cx, attr, attribute_mutation);
2016 }
2017 }
2018
2019 pub(crate) fn change_attribute(&self, cx: &mut JSContext, attr: &Attr, mut value: AttrValue) {
2021 let old_value = &attr.value().clone();
2025 self.will_mutate_attr(AttrRef::Dom(attr));
2027 attr.swap_value(&mut value);
2028 self.handle_attribute_changes(
2032 cx,
2033 AttrRef::Dom(attr),
2034 Some(old_value),
2035 Some(&*attr.value()),
2036 AttributeMutationReason::Directly,
2037 );
2038 }
2039
2040 pub(crate) fn push_attribute(
2042 &self,
2043 cx: &mut JSContext,
2044 attr: &Attr,
2045 reason: AttributeMutationReason,
2046 ) {
2047 assert!(attr.GetOwnerElement().as_deref() == Some(self));
2051 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
2055 self.will_mutate_attr(AttrRef::Dom(attr));
2057 self.attrs.push_dom(attr);
2058 self.handle_attribute_changes(cx, AttrRef::Dom(attr), None, Some(&*attr.value()), reason);
2062 }
2063
2064 pub(crate) fn with_attribute<R, F>(
2065 &self,
2066 namespace: &Namespace,
2067 local_name: &LocalName,
2068 map_func: F,
2069 ) -> Option<R>
2070 where
2071 F: FnOnce(AttrRef<'_>) -> R,
2072 {
2073 self.attrs
2074 .borrow()
2075 .iter()
2076 .find(|attribute| {
2077 attribute.local_name() == local_name && attribute.namespace() == namespace
2078 })
2079 .map(map_func)
2080 }
2081
2082 pub(crate) fn get_attribute_with_namespace(
2088 &self,
2089 cx: &mut JSContext,
2090 namespace: &Namespace,
2091 local_name: &LocalName,
2092 ) -> Option<DomRoot<Attr>> {
2093 let idx = self
2094 .attrs
2095 .borrow()
2096 .iter()
2097 .position(|a| a.local_name() == local_name && a.namespace() == namespace)?;
2098 Some(self.attrs.ensure_dom(cx, idx, self))
2099 }
2100
2101 pub(crate) fn get_attribute_by_name(
2103 &self,
2104 cx: &mut JSContext,
2105 name: DOMString,
2106 ) -> Option<DomRoot<Attr>> {
2107 let name = &self.parsed_name(name);
2108 let idx = self.attrs.borrow().iter().position(|a| a.name() == name)?;
2109 let attr_dom = Some(self.attrs.ensure_dom(cx, idx, self));
2110 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
2111 if *name == local_name!("id") || *name == local_name!("name") {
2112 match maybe_attr {
2113 None => true,
2114 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
2115 }
2116 } else {
2117 true
2118 }
2119 }
2120 debug_assert!(id_and_name_must_be_atoms(name, &attr_dom));
2121 attr_dom
2122 }
2123
2124 pub(crate) fn set_attribute_from_parser(
2125 &self,
2126 cx: &mut JSContext,
2127 qname: QualName,
2128 value: DOMString,
2129 prefix: Option<Prefix>,
2130 ) {
2131 if self
2133 .attrs
2134 .borrow()
2135 .iter()
2136 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
2137 {
2138 return;
2139 }
2140
2141 let name = match prefix {
2142 None => qname.local.clone(),
2143 Some(ref prefix) => {
2144 let name = format!("{}:{}", &**prefix, &*qname.local);
2145 LocalName::from(name)
2146 },
2147 };
2148 let value = self.parse_attribute(&qname.ns, &qname.local, value);
2149 self.push_new_attribute(
2150 cx,
2151 qname.local,
2152 value,
2153 name,
2154 qname.ns,
2155 prefix,
2156 AttributeMutationReason::ByParser,
2157 );
2158 }
2159
2160 pub(crate) fn set_attribute(&self, cx: &mut JSContext, name: &LocalName, value: AttrValue) {
2161 debug_assert_eq!(
2162 *name,
2163 name.to_ascii_lowercase(),
2164 "All attribute accesses should use a lowercase ASCII name"
2165 );
2166 debug_assert!(!name.contains(':'));
2167
2168 self.set_first_matching_attribute(
2169 cx,
2170 name.clone(),
2171 value,
2172 name.clone(),
2173 ns!(),
2174 None,
2175 |attr| attr.local_name() == name,
2176 );
2177 }
2178
2179 pub(crate) fn set_attribute_with_namespace(
2180 &self,
2181 cx: &mut JSContext,
2182 local_name: LocalName,
2183 value: AttrValue,
2184 name: LocalName,
2185 namespace: Namespace,
2186 prefix: Option<Prefix>,
2187 ) {
2188 self.set_first_matching_attribute(
2189 cx,
2190 local_name.clone(),
2191 value,
2192 name,
2193 namespace.clone(),
2194 prefix,
2195 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
2196 );
2197 }
2198
2199 #[allow(clippy::too_many_arguments)]
2201 fn set_first_matching_attribute<F>(
2202 &self,
2203 cx: &mut JSContext,
2204 local_name: LocalName,
2205 value: AttrValue,
2206 name: LocalName,
2207 namespace: Namespace,
2208 prefix: Option<Prefix>,
2209 find: F,
2210 ) where
2211 F: Fn(AttrRef<'_>) -> bool,
2212 {
2213 let found_idx = self.attrs.borrow().iter().position(find);
2216 if let Some(idx) = found_idx {
2217 let attr = self.attrs.ensure_dom(cx, idx, self);
2218 self.will_mutate_attr(AttrRef::Dom(&attr));
2220 self.change_attribute(cx, &attr, value);
2221 } else {
2222 self.push_new_attribute(
2227 cx,
2228 local_name,
2229 value,
2230 name,
2231 namespace,
2232 prefix,
2233 AttributeMutationReason::Directly,
2234 );
2235 };
2236 }
2237
2238 pub(crate) fn parse_attribute(
2239 &self,
2240 namespace: &Namespace,
2241 local_name: &LocalName,
2242 value: DOMString,
2243 ) -> AttrValue {
2244 if is_relevant_attribute(namespace, local_name) {
2245 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2246 } else {
2247 AttrValue::String(value.into())
2248 }
2249 }
2250
2251 pub(crate) fn remove_attribute(
2252 &self,
2253 cx: &mut JSContext,
2254 namespace: &Namespace,
2255 local_name: &LocalName,
2256 ) -> Option<DomRoot<Attr>> {
2257 self.remove_first_matching_attribute(cx, |attr| {
2258 attr.namespace() == namespace && attr.local_name() == local_name
2259 })
2260 }
2261
2262 pub(crate) fn remove_attribute_by_name(
2263 &self,
2264 cx: &mut JSContext,
2265 name: &LocalName,
2266 ) -> Option<DomRoot<Attr>> {
2267 self.remove_first_matching_attribute(cx, |attr| attr.name() == name)
2268 }
2269
2270 fn remove_first_matching_attribute<F>(
2272 &self,
2273 cx: &mut JSContext,
2274 find: F,
2275 ) -> Option<DomRoot<Attr>>
2276 where
2277 F: Fn(AttrRef<'_>) -> bool,
2278 {
2279 let idx = self.attrs.borrow().iter().position(find);
2280 idx.map(|idx| {
2281 let attr = self.attrs.ensure_dom(cx, idx, self);
2282
2283 self.will_mutate_attr(AttrRef::Dom(&attr));
2285 self.attrs.remove(idx);
2286 attr.set_owner(cx, None);
2288 self.handle_attribute_changes(
2290 cx,
2291 AttrRef::Dom(&attr),
2292 Some(&attr.value()),
2293 None,
2294 AttributeMutationReason::Directly,
2295 );
2296
2297 attr
2298 })
2299 }
2300
2301 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2302 self.get_tokenlist_attribute(&local_name!("class"))
2303 .iter()
2304 .any(|atom| case_sensitivity.eq_atom(name, atom))
2305 }
2306
2307 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2308 debug_assert_eq!(
2309 *local_name,
2310 local_name.to_ascii_lowercase(),
2311 "All attribute accesses should use a lowercase ASCII name"
2312 );
2313 debug_assert!(!local_name.contains(':'));
2314 self.attrs
2315 .borrow()
2316 .iter()
2317 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2318 }
2319
2320 pub(crate) fn will_mutate_attr(&self, attr: AttrRef<'_>) {
2321 let node = self.upcast::<Node>();
2322 node.owner_doc().element_attr_will_change(self, attr);
2323 }
2324
2325 fn update_style_attribute(
2327 &self,
2328 cx: &mut JSContext,
2329 attr: AttrRef<'_>,
2330 mutation: AttributeMutation,
2331 ) {
2332 let doc = self.upcast::<Node>().owner_doc();
2333 *self.style_attribute.borrow_mut() = match mutation {
2335 AttributeMutation::Set(..) => {
2336 let value = attr.as_attr().map_or_else(
2337 || attr.value(),
2338 |attribute| AttrValueRef::Borrowed(attribute.value()),
2339 );
2340
2341 Some(match &*value {
2342 AttrValue::Declaration { block, .. } => block.clone(),
2343 _ => {
2344 let win = self.owner_window();
2345 let source = &**attr.value();
2346 let global = &self.owner_global();
2347 if global
2352 .get_csp_list()
2353 .should_elements_inline_type_behavior_be_blocked(
2354 cx,
2355 global,
2356 self,
2357 InlineCheckType::StyleAttribute,
2358 source,
2359 doc.get_current_parser_line(),
2360 )
2361 {
2362 return;
2363 }
2364 ServoArc::new(doc.style_shared_author_lock().wrap(parse_style_attribute(
2365 source,
2366 &UrlExtraData(doc.base_url().get_arc()),
2367 Some(win.css_error_reporter()),
2368 doc.quirks_mode(),
2369 CssRuleType::Style,
2370 )))
2371 },
2372 })
2373 },
2374 AttributeMutation::Removed => None,
2375 };
2376 }
2377
2378 fn set_attribute_node(
2382 &self,
2383 cx: &mut JSContext,
2384 attr: &Attr,
2385 ) -> Fallible<Option<DomRoot<Attr>>> {
2386 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2390 cx,
2391 self.namespace(),
2392 self.local_name(),
2393 attr.local_name(),
2394 Some(attr.namespace()),
2395 TrustedTypeOrString::String(attr.Value()),
2396 &self.owner_global(),
2397 )?;
2398
2399 if let Some(owner) = attr.GetOwnerElement() &&
2402 &*owner != self
2403 {
2404 return Err(Error::InUseAttribute(None));
2405 }
2406
2407 let vtable = vtable_for(self.upcast());
2408
2409 attr.swap_value(
2415 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2416 );
2417
2418 let position = self.attrs.borrow().iter().position(|old_attr| {
2420 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2421 });
2422
2423 let old_attr = if let Some(position) = position {
2424 let old_attr = self.attrs.ensure_dom(cx, position, self);
2425
2426 if &*old_attr == attr {
2428 return Ok(Some(DomRoot::from_ref(attr)));
2429 }
2430
2431 self.will_mutate_attr(AttrRef::Dom(attr));
2441 self.attrs
2442 .set(position, AttributeEntry::Dom(Dom::from_ref(attr)));
2443 attr.set_owner(cx, Some(self));
2445 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2447 old_attr.set_owner(cx, None);
2449 self.handle_attribute_changes(
2451 cx,
2452 AttrRef::Dom(attr),
2453 Some(&old_attr.value()),
2454 Some(&AttrValue::String(verified_value.into())),
2455 AttributeMutationReason::Directly,
2456 );
2457
2458 Some(old_attr)
2459 } else {
2460 attr.set_owner(cx, Some(self));
2462 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2463 self.push_attribute(cx, attr, AttributeMutationReason::Directly);
2464
2465 None
2466 };
2467
2468 Ok(old_attr)
2470 }
2471
2472 pub(crate) fn update_nonce_internal_slot(&self, nonce: String) {
2474 self.ensure_rare_data().cryptographic_nonce = nonce;
2475 }
2476
2477 pub(crate) fn nonce_value(&self) -> String {
2479 match self.rare_data().as_ref() {
2480 None => String::new(),
2481 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2482 }
2483 }
2484
2485 pub(crate) fn update_nonce_post_connection(&self, cx: &mut JSContext) {
2487 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2490 return;
2491 }
2492 let global = self.owner_global();
2493 let csp_list = match global.get_csp_list() {
2495 None => return,
2496 Some(csp_list) => csp_list,
2497 };
2498 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2501 self.get_string_attribute(&local_name!("nonce")).is_empty()
2502 {
2503 return;
2504 }
2505 let nonce = self.nonce_value();
2507 self.set_string_attribute(cx, &local_name!("nonce"), "".into());
2509 self.update_nonce_internal_slot(nonce);
2511 }
2512
2513 pub(crate) fn is_nonceable(&self) -> bool {
2515 if !self.has_attribute(&local_name!("nonce")) {
2517 return false;
2518 }
2519 if self.is::<HTMLScriptElement>() {
2521 for attr in self.attrs().borrow().iter() {
2522 let attr_name = attr.name().to_ascii_lowercase();
2525 if attr_name.contains("<script") || attr_name.contains("<style") {
2526 return false;
2527 }
2528 let attr_value = attr.value().to_ascii_lowercase();
2531 if attr_value.contains("<script") || attr_value.contains("<style") {
2532 return false;
2533 }
2534 }
2535 }
2536 if self
2538 .rare_data()
2539 .as_ref()
2540 .is_some_and(|d| d.had_duplicate_attributes)
2541 {
2542 return false;
2543 }
2544 true
2546 }
2547
2548 pub(crate) fn insert_adjacent(
2550 &self,
2551 cx: &mut JSContext,
2552 where_: AdjacentPosition,
2553 node: &Node,
2554 ) -> Fallible<Option<DomRoot<Node>>> {
2555 let self_node = self.upcast::<Node>();
2556 match where_ {
2557 AdjacentPosition::BeforeBegin => {
2558 if let Some(parent) = self_node.GetParentNode() {
2559 Node::pre_insert(cx, node, &parent, Some(self_node)).map(Some)
2560 } else {
2561 Ok(None)
2562 }
2563 },
2564 AdjacentPosition::AfterBegin => {
2565 Node::pre_insert(cx, node, self_node, self_node.GetFirstChild().as_deref())
2566 .map(Some)
2567 },
2568 AdjacentPosition::BeforeEnd => Node::pre_insert(cx, node, self_node, None).map(Some),
2569 AdjacentPosition::AfterEnd => {
2570 if let Some(parent) = self_node.GetParentNode() {
2571 Node::pre_insert(cx, node, &parent, self_node.GetNextSibling().as_deref())
2572 .map(Some)
2573 } else {
2574 Ok(None)
2575 }
2576 },
2577 }
2578 }
2579
2580 pub(crate) fn scroll(&self, cx: &mut JSContext, x: f64, y: f64, behavior: ScrollBehavior) {
2585 let x = if x.is_finite() { x } else { 0.0 } as f32;
2587 let y = if y.is_finite() { y } else { 0.0 } as f32;
2588
2589 let node = self.upcast::<Node>();
2590
2591 let doc = node.owner_doc();
2593
2594 if !doc.is_fully_active() {
2596 return;
2597 }
2598
2599 let win = match doc.GetDefaultView() {
2601 None => return,
2602 Some(win) => win,
2603 };
2604
2605 if *self.root_element() == *self {
2607 if doc.quirks_mode() != QuirksMode::Quirks {
2608 win.scroll(cx, x, y, behavior);
2609 }
2610
2611 return;
2612 }
2613
2614 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2616 doc.quirks_mode() == QuirksMode::Quirks &&
2617 !self.is_potentially_scrollable_body()
2618 {
2619 win.scroll(cx, x, y, behavior);
2620 return;
2621 }
2622
2623 if !self.has_scrolling_box() {
2625 return;
2626 }
2627
2628 win.scroll_an_element(cx, self, x, y, behavior);
2630 }
2631
2632 pub(crate) fn parse_fragment(
2634 &self,
2635 markup: DOMString,
2636 cx: &mut JSContext,
2637 ) -> Fallible<DomRoot<DocumentFragment>> {
2638 let new_children = ServoParser::parse_html_fragment(cx, self, markup, false);
2641 let context_document = {
2644 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2645 template.Content(cx).upcast::<Node>().owner_doc()
2646 } else {
2647 self.owner_document()
2648 }
2649 };
2650 let fragment = DocumentFragment::new(cx, &context_document);
2651 for child in new_children {
2653 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
2654 }
2655 Ok(fragment)
2657 }
2658
2659 pub(crate) fn fragment_parsing_context(
2662 cx: &mut JSContext,
2663 owner_doc: &Document,
2664 element: Option<&Self>,
2665 ) -> DomRoot<Self> {
2666 match element {
2668 Some(elem)
2669 if elem.local_name() != &local_name!("html") ||
2673 !elem.html_element_in_html_document() =>
2674 {
2675 DomRoot::from_ref(elem)
2676 },
2677 _ => Element::create(
2680 cx,
2681 QualName::new(None, ns!(html), local_name!("body")),
2682 None,
2683 owner_doc,
2684 ElementCreator::ScriptCreated,
2685 CustomElementCreationMode::Asynchronous,
2686 None
2687 ),
2688 }
2689 }
2690
2691 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2693 where
2694 T: DerivedFrom<Element> + DomObject,
2695 {
2696 let other = other.upcast::<Element>();
2697 self.root_element() == other.root_element()
2698 }
2699
2700 pub(crate) fn get_id(&self) -> Option<Atom> {
2701 self.id_attribute.borrow().clone()
2702 }
2703
2704 pub(crate) fn get_name(&self) -> Option<Atom> {
2705 self.rare_data().as_ref()?.name_attribute.clone()
2706 }
2707
2708 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2709 self.rare_data()
2710 .as_ref()?
2711 .element_internals
2712 .as_ref()
2713 .map(|sr| DomRoot::from_ref(&**sr))
2714 }
2715
2716 pub(crate) fn ensure_element_internals(&self, can_gc: CanGc) -> DomRoot<ElementInternals> {
2717 let mut rare_data = self.ensure_rare_data();
2718 DomRoot::from_ref(rare_data.element_internals.get_or_insert_with(|| {
2719 let elem = self
2720 .downcast::<HTMLElement>()
2721 .expect("ensure_element_internals should only be called for an HTMLElement");
2722 Dom::from_ref(&*ElementInternals::new(elem, can_gc))
2723 }))
2724 }
2725
2726 pub(crate) fn outer_html(&self, cx: &mut JSContext) -> Fallible<DOMString> {
2727 match self.GetOuterHTML(cx)? {
2728 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2729 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2730 }
2731 }
2732
2733 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2734 SourcePosition {
2735 source_file: self.owner_global().get_url().to_string(),
2736 line_number: line_number + 2,
2737 column_number: 0,
2738 }
2739 }
2740
2741 pub(crate) fn explicitly_set_tab_index(&self) -> Option<i32> {
2742 if self.has_attribute(&local_name!("tabindex")) {
2743 Some(self.get_int_attribute(&local_name!("tabindex"), 0))
2744 } else {
2745 None
2746 }
2747 }
2748
2749 pub(crate) fn tab_index(&self) -> i32 {
2751 if let Some(tab_index) = self.explicitly_set_tab_index() {
2757 return tab_index;
2758 }
2759
2760 if matches!(
2766 self.upcast::<Node>().type_id(),
2767 NodeTypeId::Element(ElementTypeId::HTMLElement(
2768 HTMLElementTypeId::HTMLAnchorElement |
2769 HTMLElementTypeId::HTMLAreaElement |
2770 HTMLElementTypeId::HTMLButtonElement |
2771 HTMLElementTypeId::HTMLFrameElement |
2772 HTMLElementTypeId::HTMLIFrameElement |
2773 HTMLElementTypeId::HTMLInputElement |
2774 HTMLElementTypeId::HTMLObjectElement |
2775 HTMLElementTypeId::HTMLSelectElement |
2776 HTMLElementTypeId::HTMLTextAreaElement
2777 ))
2778 ) {
2779 return 0;
2780 }
2781 if self
2782 .downcast::<HTMLElement>()
2783 .is_some_and(|html_element| html_element.is_a_summary_for_its_parent_details())
2784 {
2785 return 0;
2786 }
2787
2788 -1
2789 }
2790
2791 #[inline]
2792 fn insert_selector_flags(&self, flags: ElementSelectorFlags) {
2793 self.selector_flags
2794 .fetch_or(flags.bits(), Ordering::Relaxed);
2795 }
2796
2797 #[inline]
2798 fn get_selector_flags(&self) -> ElementSelectorFlags {
2799 ElementSelectorFlags::from_bits_retain(self.selector_flags.load(Ordering::Relaxed))
2800 }
2801
2802 pub(crate) fn needs_preserved_style_attribute_after_change(&self) -> bool {
2807 self.owner_window().get_exists_mut_observer() ||
2814 self.get_custom_element_definition()
2815 .is_some_and(|custom_element_definition| {
2816 custom_element_definition.has_attribute_changed_callback()
2817 })
2818 }
2819
2820 pub(crate) fn register_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2821 if let Some(shadow_root) = self.containing_shadow_root() {
2822 if let Some(ref id) = *self.id_attribute.borrow() {
2823 shadow_root.register_element_id(self, id, CanGc::from_cx(cx));
2824 }
2825 } else {
2826 let document = self.owner_document();
2827 if let Some(ref id) = *self.id_attribute.borrow() {
2828 document.register_element_id(cx, self, id);
2829 }
2830 if let Some(ref name) = self.name_attribute() {
2831 document.register_element_name(self, name);
2832 }
2833 }
2834 }
2835
2836 pub(crate) fn unregister_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2837 if let Some(shadow_root) = self.containing_shadow_root() {
2838 if self.upcast::<Node>().is_in_a_shadow_tree() {
2842 return;
2843 }
2844 if let Some(ref id) = *self.id_attribute.borrow() {
2845 shadow_root.unregister_element_id(id);
2846 }
2847 } else {
2848 let document = self.owner_document();
2849 if let Some(ref id) = *self.id_attribute.borrow() {
2850 document.unregister_element_id(cx, id);
2851 }
2852 if let Some(ref name) = self.name_attribute() {
2853 document.unregister_element_name(name);
2854 }
2855 }
2856 }
2857}
2858
2859impl ElementMethods<crate::DomTypeHolder> for Element {
2860 fn GetNamespaceURI(&self) -> Option<DOMString> {
2862 Node::namespace_to_string(self.namespace.clone())
2863 }
2864
2865 fn LocalName(&self) -> DOMString {
2867 DOMString::from(&*self.local_name)
2869 }
2870
2871 fn GetPrefix(&self) -> Option<DOMString> {
2873 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2874 }
2875
2876 fn TagName(&self) -> DOMString {
2878 let name = self.tag_name.or_init(|| {
2879 let qualified_name = match *self.prefix.borrow() {
2880 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2881 None => Cow::Borrowed(&*self.local_name),
2882 };
2883 if self.html_element_in_html_document() {
2884 LocalName::from(qualified_name.to_ascii_uppercase())
2885 } else {
2886 LocalName::from(qualified_name)
2887 }
2888 });
2889 DOMString::from(&*name)
2890 }
2891
2892 fn Id(&self) -> DOMString {
2896 self.get_string_attribute(&local_name!("id"))
2897 }
2898
2899 fn SetId(&self, cx: &mut JSContext, id: DOMString) {
2901 self.set_atomic_attribute(cx, &local_name!("id"), id);
2902 }
2903
2904 fn ClassName(&self) -> DOMString {
2906 self.get_string_attribute(&local_name!("class"))
2907 }
2908
2909 fn SetClassName(&self, cx: &mut JSContext, class: DOMString) {
2911 self.set_tokenlist_attribute(cx, &local_name!("class"), class);
2912 }
2913
2914 fn ClassList(&self, cx: &mut js::context::JSContext) -> DomRoot<DOMTokenList> {
2916 self.class_list
2917 .or_init(|| DOMTokenList::new(cx, self, &local_name!("class"), None))
2918 }
2919
2920 make_getter!(Slot, "slot");
2922
2923 make_setter!(SetSlot, "slot");
2925
2926 fn Attributes(&self, can_gc: CanGc) -> DomRoot<NamedNodeMap> {
2928 self.attr_list
2929 .or_init(|| NamedNodeMap::new(&self.owner_window(), self, can_gc))
2930 }
2931
2932 fn HasAttributes(&self) -> bool {
2934 !self.attrs.borrow().is_empty()
2935 }
2936
2937 fn GetAttributeNames(&self) -> Vec<DOMString> {
2939 self.attrs
2940 .borrow()
2941 .iter()
2942 .map(|attr| DOMString::from(&**attr.name()))
2943 .collect()
2944 }
2945
2946 fn GetAttribute(&self, cx: &mut JSContext, name: DOMString) -> Option<DOMString> {
2948 self.GetAttributeNode(cx, name).map(|s| s.Value())
2949 }
2950
2951 fn GetAttributeNS(
2953 &self,
2954 cx: &mut JSContext,
2955 namespace: Option<DOMString>,
2956 local_name: DOMString,
2957 ) -> Option<DOMString> {
2958 self.GetAttributeNodeNS(cx, namespace, local_name)
2959 .map(|attr| attr.Value())
2960 }
2961
2962 fn GetAttributeNode(&self, cx: &mut JSContext, name: DOMString) -> Option<DomRoot<Attr>> {
2964 self.get_attribute_by_name(cx, name)
2965 }
2966
2967 fn GetAttributeNodeNS(
2969 &self,
2970 cx: &mut JSContext,
2971 namespace: Option<DOMString>,
2972 local_name: DOMString,
2973 ) -> Option<DomRoot<Attr>> {
2974 let namespace = &namespace_from_domstring(namespace);
2975 self.get_attribute_with_namespace(cx, namespace, &LocalName::from(local_name))
2976 }
2977
2978 fn ToggleAttribute(
2980 &self,
2981 cx: &mut JSContext,
2982 name: DOMString,
2983 force: Option<bool>,
2984 ) -> Fallible<bool> {
2985 if !is_valid_attribute_local_name(&name.str()) {
2988 return Err(Error::InvalidCharacter(None));
2989 }
2990
2991 let attribute = self.GetAttribute(cx, name.clone());
2993
2994 let name = self.parsed_name(name);
2996 match attribute {
2997 None => match force {
2999 None | Some(true) => {
3001 self.set_first_matching_attribute(
3002 cx,
3003 name.clone(),
3004 AttrValue::String(String::new()),
3005 name.clone(),
3006 ns!(),
3007 None,
3008 |attr| *attr.name() == name,
3009 );
3010 Ok(true)
3011 },
3012 Some(false) => Ok(false),
3014 },
3015 Some(_index) => match force {
3016 None | Some(false) => {
3018 self.remove_attribute_by_name(cx, &name);
3019 Ok(false)
3020 },
3021 Some(true) => Ok(true),
3023 },
3024 }
3025 }
3026
3027 fn SetAttribute(
3029 &self,
3030 cx: &mut JSContext,
3031 name: DOMString,
3032 value: TrustedTypeOrString,
3033 ) -> ErrorResult {
3034 if !is_valid_attribute_local_name(&name.str()) {
3037 return Err(Error::InvalidCharacter(None));
3038 }
3039
3040 let name = self.parsed_name(name);
3043
3044 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3048 cx,
3049 self.namespace(),
3050 self.local_name(),
3051 &name,
3052 None,
3053 value,
3054 &self.owner_global(),
3055 )?;
3056
3057 let value = self.parse_attribute(&ns!(), &name, value);
3062 self.set_first_matching_attribute(
3063 cx,
3064 name.clone(),
3065 value,
3066 name.clone(),
3067 ns!(),
3068 None,
3069 |attr| *attr.name() == name,
3070 );
3071 Ok(())
3072 }
3073
3074 fn SetAttributeNS(
3076 &self,
3077 cx: &mut JSContext,
3078 namespace: Option<DOMString>,
3079 qualified_name: DOMString,
3080 value: TrustedTypeOrString,
3081 ) -> ErrorResult {
3082 let (namespace, prefix, local_name) =
3084 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3085 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3088 cx,
3089 self.namespace(),
3090 self.local_name(),
3091 &local_name,
3092 Some(&namespace),
3093 value,
3094 &self.owner_global(),
3095 )?;
3096 let value = self.parse_attribute(&namespace, &local_name, value);
3098 self.set_attribute_with_namespace(
3099 cx,
3100 local_name,
3101 value,
3102 LocalName::from(qualified_name),
3103 namespace,
3104 prefix,
3105 );
3106 Ok(())
3107 }
3108
3109 fn SetAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
3111 self.set_attribute_node(cx, attr)
3112 }
3113
3114 fn SetAttributeNodeNS(
3116 &self,
3117 cx: &mut JSContext,
3118 attr: &Attr,
3119 ) -> Fallible<Option<DomRoot<Attr>>> {
3120 self.set_attribute_node(cx, attr)
3121 }
3122
3123 fn RemoveAttribute(&self, cx: &mut JSContext, name: DOMString) {
3125 let name = self.parsed_name(name);
3126 self.remove_attribute_by_name(cx, &name);
3127 }
3128
3129 fn RemoveAttributeNS(
3131 &self,
3132 cx: &mut JSContext,
3133 namespace: Option<DOMString>,
3134 local_name: DOMString,
3135 ) {
3136 let namespace = namespace_from_domstring(namespace);
3137 let local_name = LocalName::from(local_name);
3138 self.remove_attribute(cx, &namespace, &local_name);
3139 }
3140
3141 fn RemoveAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<DomRoot<Attr>> {
3143 self.remove_first_matching_attribute(cx, |a| {
3146 a.as_attr().is_some_and(|a| std::ptr::eq(a, attr))
3147 })
3148 .ok_or(Error::NotFound(None))
3149 }
3150
3151 fn HasAttribute(&self, cx: &mut JSContext, name: DOMString) -> bool {
3153 self.GetAttribute(cx, name).is_some()
3154 }
3155
3156 fn HasAttributeNS(
3158 &self,
3159 cx: &mut JSContext,
3160 namespace: Option<DOMString>,
3161 local_name: DOMString,
3162 ) -> bool {
3163 self.GetAttributeNS(cx, namespace, local_name).is_some()
3164 }
3165
3166 fn GetElementsByTagName(
3168 &self,
3169 cx: &mut JSContext,
3170 localname: DOMString,
3171 ) -> DomRoot<HTMLCollection> {
3172 let window = self.owner_window();
3173 HTMLCollection::by_qualified_name(cx, &window, self.upcast(), LocalName::from(localname))
3174 }
3175
3176 fn GetElementsByTagNameNS(
3178 &self,
3179 cx: &mut JSContext,
3180 maybe_ns: Option<DOMString>,
3181 localname: DOMString,
3182 ) -> DomRoot<HTMLCollection> {
3183 let window = self.owner_window();
3184 HTMLCollection::by_tag_name_ns(cx, &window, self.upcast(), localname, maybe_ns)
3185 }
3186
3187 fn GetElementsByClassName(
3189 &self,
3190 cx: &mut JSContext,
3191 classes: DOMString,
3192 ) -> DomRoot<HTMLCollection> {
3193 let window = self.owner_window();
3194 HTMLCollection::by_class_name(cx, &window, self.upcast(), classes)
3195 }
3196
3197 fn GetClientRects(&self, cx: &mut JSContext) -> DomRoot<DOMRectList> {
3199 let win = self.owner_window();
3200 let raw_rects = self.upcast::<Node>().border_boxes();
3201 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3202 .into_iter()
3203 .map(|rect| {
3204 DOMRect::new(
3205 cx,
3206 win.upcast(),
3207 rect.origin.x.to_f64_px(),
3208 rect.origin.y.to_f64_px(),
3209 rect.size.width.to_f64_px(),
3210 rect.size.height.to_f64_px(),
3211 )
3212 })
3213 .collect();
3214 DOMRectList::new(cx, &win, rects)
3215 }
3216
3217 fn GetBoundingClientRect(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
3219 let win = self.owner_window();
3220 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3221 debug_assert!(rect.size.width.to_f64_px() >= 0.0 && rect.size.height.to_f64_px() >= 0.0);
3222 DOMRect::new(
3223 cx,
3224 win.upcast(),
3225 rect.origin.x.to_f64_px(),
3226 rect.origin.y.to_f64_px(),
3227 rect.size.width.to_f64_px(),
3228 rect.size.height.to_f64_px(),
3229 )
3230 }
3231
3232 fn Scroll(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3234 let left = options.left.unwrap_or(self.ScrollLeft());
3236 let top = options.top.unwrap_or(self.ScrollTop());
3237 self.scroll(cx, left, top, options.parent.behavior);
3238 }
3239
3240 fn Scroll_(&self, cx: &mut JSContext, x: f64, y: f64) {
3242 self.scroll(cx, x, y, ScrollBehavior::Auto);
3243 }
3244
3245 fn ScrollTo(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3247 self.Scroll(cx, options);
3248 }
3249
3250 fn ScrollTo_(&self, cx: &mut JSContext, x: f64, y: f64) {
3252 self.Scroll_(cx, x, y);
3253 }
3254
3255 fn ScrollBy(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3257 let delta_left = options.left.unwrap_or(0.0f64);
3259 let delta_top = options.top.unwrap_or(0.0f64);
3260 let left = self.ScrollLeft();
3261 let top = self.ScrollTop();
3262 self.scroll(
3263 cx,
3264 left + delta_left,
3265 top + delta_top,
3266 options.parent.behavior,
3267 );
3268 }
3269
3270 fn ScrollBy_(&self, cx: &mut JSContext, x: f64, y: f64) {
3272 let left = self.ScrollLeft();
3273 let top = self.ScrollTop();
3274 self.scroll(cx, left + x, top + y, ScrollBehavior::Auto);
3275 }
3276
3277 fn ScrollTop(&self) -> f64 {
3279 let node = self.upcast::<Node>();
3280
3281 let doc = node.owner_doc();
3283
3284 if !doc.is_fully_active() {
3286 return 0.0;
3287 }
3288
3289 let win = match doc.GetDefaultView() {
3291 None => return 0.0,
3292 Some(win) => win,
3293 };
3294
3295 if self.is_document_element() {
3297 if doc.quirks_mode() == QuirksMode::Quirks {
3298 return 0.0;
3299 }
3300
3301 return win.ScrollY() as f64;
3303 }
3304
3305 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3307 doc.quirks_mode() == QuirksMode::Quirks &&
3308 !self.is_potentially_scrollable_body()
3309 {
3310 return win.ScrollY() as f64;
3311 }
3312
3313 if !self.has_css_layout_box() {
3315 return 0.0;
3316 }
3317
3318 let point = win.scroll_offset_query(node);
3320 point.y.abs() as f64
3321 }
3322
3323 fn SetScrollTop(&self, cx: &mut JSContext, y_: f64) {
3326 let behavior = ScrollBehavior::Auto;
3327
3328 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3330
3331 let node = self.upcast::<Node>();
3332
3333 let doc = node.owner_doc();
3335
3336 if !doc.is_fully_active() {
3338 return;
3339 }
3340
3341 let win = match doc.GetDefaultView() {
3343 None => return,
3344 Some(win) => win,
3345 };
3346
3347 if self.is_document_element() {
3349 if doc.quirks_mode() != QuirksMode::Quirks {
3350 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3351 }
3352
3353 return;
3354 }
3355
3356 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3358 doc.quirks_mode() == QuirksMode::Quirks &&
3359 !self.is_potentially_scrollable_body()
3360 {
3361 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3362 return;
3363 }
3364
3365 if !self.has_scrolling_box() {
3367 return;
3368 }
3369
3370 win.scroll_an_element(cx, self, self.ScrollLeft() as f32, y, behavior);
3372 }
3373
3374 fn ScrollLeft(&self) -> f64 {
3376 let node = self.upcast::<Node>();
3377
3378 let doc = node.owner_doc();
3380
3381 if !doc.is_fully_active() {
3383 return 0.0;
3384 }
3385
3386 let win = match doc.GetDefaultView() {
3388 None => return 0.0,
3389 Some(win) => win,
3390 };
3391
3392 if self.is_document_element() {
3394 if doc.quirks_mode() != QuirksMode::Quirks {
3395 return win.ScrollX() as f64;
3397 }
3398
3399 return 0.0;
3400 }
3401
3402 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3404 doc.quirks_mode() == QuirksMode::Quirks &&
3405 !self.is_potentially_scrollable_body()
3406 {
3407 return win.ScrollX() as f64;
3408 }
3409
3410 if !self.has_css_layout_box() {
3412 return 0.0;
3413 }
3414
3415 let point = win.scroll_offset_query(node);
3417 point.x.abs() as f64
3418 }
3419
3420 fn SetScrollLeft(&self, cx: &mut JSContext, x: f64) {
3422 let behavior = ScrollBehavior::Auto;
3423
3424 let x = if x.is_finite() { x } else { 0.0 } as f32;
3426
3427 let node = self.upcast::<Node>();
3428
3429 let doc = node.owner_doc();
3431
3432 if !doc.is_fully_active() {
3434 return;
3435 }
3436
3437 let win = match doc.GetDefaultView() {
3439 None => return,
3440 Some(win) => win,
3441 };
3442
3443 if self.is_document_element() {
3445 if doc.quirks_mode() == QuirksMode::Quirks {
3446 return;
3447 }
3448
3449 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3450 return;
3451 }
3452
3453 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3455 doc.quirks_mode() == QuirksMode::Quirks &&
3456 !self.is_potentially_scrollable_body()
3457 {
3458 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3459 return;
3460 }
3461
3462 if !self.has_scrolling_box() {
3464 return;
3465 }
3466
3467 win.scroll_an_element(cx, self, x, self.ScrollTop() as f32, behavior);
3469 }
3470
3471 fn ScrollIntoView(&self, cx: &mut JSContext, arg: BooleanOrScrollIntoViewOptions) {
3473 let (behavior, block, inline, container) = match arg {
3474 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3476 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3481 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3484 options.parent.behavior,
3485 options.block,
3486 options.inline,
3487 if options.container == ScrollIntoViewContainer::Nearest {
3490 Some(self)
3491 } else {
3492 None
3493 },
3494 ),
3495 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3497 ScrollBehavior::Auto,
3498 ScrollLogicalPosition::End,
3499 ScrollLogicalPosition::Nearest,
3500 None,
3501 ),
3502 };
3503
3504 if !self.has_css_layout_box() {
3507 return;
3508 }
3509
3510 self.scroll_into_view_with_options(
3512 cx,
3513 behavior,
3514 ScrollAxisState::new_always_scroll_position(block),
3515 ScrollAxisState::new_always_scroll_position(inline),
3516 container,
3517 None,
3518 );
3519
3520 }
3523
3524 fn ScrollWidth(&self) -> i32 {
3526 self.upcast::<Node>().scroll_area().size.width
3527 }
3528
3529 fn ScrollHeight(&self) -> i32 {
3531 self.upcast::<Node>().scroll_area().size.height
3532 }
3533
3534 fn ClientTop(&self) -> i32 {
3536 self.client_rect().origin.y
3537 }
3538
3539 fn ClientLeft(&self) -> i32 {
3541 self.client_rect().origin.x
3542 }
3543
3544 fn ClientWidth(&self) -> i32 {
3546 self.client_rect().size.width
3547 }
3548
3549 fn ClientHeight(&self) -> i32 {
3551 self.client_rect().size.height
3552 }
3553
3554 fn CurrentCSSZoom(&self) -> Finite<f64> {
3556 let window = self.owner_window();
3557 Finite::wrap(window.current_css_zoom_query(self.upcast::<Node>()) as f64)
3558 }
3559
3560 fn SetHTMLUnsafe(
3562 &self,
3563 cx: &mut JSContext,
3564 html: TrustedHTMLOrString,
3565 options: &SetHTMLUnsafeOptions,
3566 ) -> ErrorResult {
3567 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
3571 cx,
3572 &self.owner_global(),
3573 html,
3574 "Element setHTMLUnsafe",
3575 )?;
3576 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3578 DomRoot::upcast(template.Content(cx))
3579 } else {
3580 DomRoot::from_ref(self.upcast())
3581 };
3582
3583 Sanitizer::set_and_filter_html(cx, &target, self, compliant_html, options, false)?;
3585
3586 Ok(())
3587 }
3588
3589 fn SetHTML(
3591 &self,
3592 cx: &mut JSContext,
3593 html: DOMString,
3594 options: &SetHTMLOptions,
3595 ) -> ErrorResult {
3596 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3598 DomRoot::upcast(template.Content(cx))
3599 } else {
3600 DomRoot::from_ref(self.upcast())
3601 };
3602
3603 Sanitizer::set_and_filter_html(cx, &target, self, html, options, true)
3605 }
3606
3607 fn GetHTML(&self, cx: &mut JSContext, options: &GetHTMLOptions) -> DOMString {
3609 self.upcast::<Node>().html_serialize(
3612 cx,
3613 TraversalScope::ChildrenOnly(None),
3614 options.serializableShadowRoots,
3615 options.shadowRoots.clone(),
3616 )
3617 }
3618
3619 fn GetInnerHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3621 let qname = QualName::new(
3622 self.prefix().clone(),
3623 self.namespace().clone(),
3624 self.local_name().clone(),
3625 );
3626
3627 let result = if self.owner_document().is_html_document() {
3630 self.upcast::<Node>()
3631 .html_serialize(cx, ChildrenOnly(Some(qname)), false, vec![])
3632 } else {
3633 self.upcast::<Node>()
3634 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3635 };
3636
3637 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3638 }
3639
3640 fn SetInnerHTML(
3642 &self,
3643 cx: &mut JSContext,
3644 value: TrustedHTMLOrNullIsEmptyString,
3645 ) -> ErrorResult {
3646 let value = TrustedHTML::get_trusted_type_compliant_string(
3650 cx,
3651 &self.owner_global(),
3652 value.convert(),
3653 "Element innerHTML",
3654 )?;
3655 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3657 DomRoot::upcast(template.Content(cx))
3660 } else {
3661 DomRoot::from_ref(self.upcast())
3663 };
3664
3665 if !self.node.has_weird_parser_insertion_mode() &&
3668 value.len() < 100 &&
3669 !value
3670 .as_bytes()
3671 .iter()
3672 .any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
3673 {
3674 return Node::SetTextContent(&target, cx, Some(value));
3675 }
3676
3677 let frag = self.parse_fragment(value, cx)?;
3680
3681 Node::replace_all(cx, Some(frag.upcast()), &target);
3683 Ok(())
3684 }
3685
3686 fn GetOuterHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3688 let result = if self.owner_document().is_html_document() {
3691 self.upcast::<Node>()
3692 .html_serialize(cx, IncludeNode, false, vec![])
3693 } else {
3694 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3695 };
3696
3697 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3698 }
3699
3700 fn SetOuterHTML(
3702 &self,
3703 cx: &mut JSContext,
3704 value: TrustedHTMLOrNullIsEmptyString,
3705 ) -> ErrorResult {
3706 let value = TrustedHTML::get_trusted_type_compliant_string(
3710 cx,
3711 &self.owner_global(),
3712 value.convert(),
3713 "Element outerHTML",
3714 )?;
3715 let context_document = self.owner_document();
3716 let context_node = self.upcast::<Node>();
3717 let context_parent = match context_node.GetParentNode() {
3719 None => {
3720 return Ok(());
3723 },
3724 Some(parent) => parent,
3725 };
3726
3727 let parent = match context_parent.type_id() {
3728 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed(None)),
3730
3731 NodeTypeId::DocumentFragment(_) => {
3734 let body_elem = Element::create(
3735 cx,
3736 QualName::new(None, ns!(html), local_name!("body")),
3737 None,
3738 &context_document,
3739 ElementCreator::ScriptCreated,
3740 CustomElementCreationMode::Synchronous,
3741 None,
3742 );
3743 DomRoot::upcast(body_elem)
3744 },
3745 _ => context_node.GetParentElement().unwrap(),
3746 };
3747
3748 let frag = parent.parse_fragment(value, cx)?;
3751 context_parent.ReplaceChild(cx, frag.upcast(), context_node)?;
3753 Ok(())
3754 }
3755
3756 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3758 self.upcast::<Node>()
3759 .preceding_siblings()
3760 .find_map(DomRoot::downcast)
3761 }
3762
3763 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3765 self.upcast::<Node>()
3766 .following_siblings()
3767 .find_map(DomRoot::downcast)
3768 }
3769
3770 fn Children(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
3772 let window = self.owner_window();
3773 HTMLCollection::children(cx, &window, self.upcast())
3774 }
3775
3776 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3778 self.upcast::<Node>().child_elements().next()
3779 }
3780
3781 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3783 self.upcast::<Node>()
3784 .rev_children()
3785 .find_map(DomRoot::downcast::<Element>)
3786 }
3787
3788 fn ChildElementCount(&self) -> u32 {
3790 self.upcast::<Node>().child_elements().count() as u32
3791 }
3792
3793 fn Prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3795 self.upcast::<Node>().prepend(cx, nodes)
3796 }
3797
3798 fn Append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3800 self.upcast::<Node>().append(cx, nodes)
3801 }
3802
3803 fn ReplaceChildren(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3805 self.upcast::<Node>().replace_children(cx, nodes)
3806 }
3807
3808 fn MoveBefore(&self, cx: &mut JSContext, node: &Node, child: Option<&Node>) -> ErrorResult {
3810 self.upcast::<Node>().move_before(cx, node, child)
3811 }
3812
3813 fn QuerySelector(
3815 &self,
3816 cx: &mut JSContext,
3817 selectors: DOMString,
3818 ) -> Fallible<Option<DomRoot<Element>>> {
3819 let root = self.upcast::<Node>();
3820 root.query_selector(cx.no_gc(), selectors)
3821 }
3822
3823 fn QuerySelectorAll(
3825 &self,
3826 cx: &mut JSContext,
3827 selectors: DOMString,
3828 ) -> Fallible<DomRoot<NodeList>> {
3829 let root = self.upcast::<Node>();
3830 root.query_selector_all(cx.no_gc(), selectors)
3831 }
3832
3833 fn Before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3835 self.upcast::<Node>().before(cx, nodes)
3836 }
3837
3838 fn After(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3840 self.upcast::<Node>().after(cx, nodes)
3841 }
3842
3843 fn ReplaceWith(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3845 self.upcast::<Node>().replace_with(cx, nodes)
3846 }
3847
3848 fn Remove(&self, cx: &mut JSContext) {
3850 self.upcast::<Node>().remove_self(cx);
3851 }
3852
3853 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3855 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3856 let document = self.owner_document();
3857 let url = document.url();
3858 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3859 &selectors.str(),
3860 &UrlExtraData(url.get_arc()),
3861 ) {
3862 Err(_) => return Err(Error::Syntax(None)),
3863 Ok(selectors) => selectors,
3864 };
3865
3866 let traced_self = Dom::from_ref(self);
3868 let quirks_mode = document.quirks_mode();
3869 Ok(with_layout_state(|| {
3870 #[expect(unsafe_code)]
3871 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3872 dom_apis::element_matches(
3873 &ServoDangerousStyleElement::from(layout_element.upcast()),
3874 &selectors,
3875 quirks_mode,
3876 )
3877 }))
3878 }
3879
3880 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3882 self.Matches(selectors)
3883 }
3884
3885 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3887 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3888 let document = self.owner_document();
3889 let url = document.url();
3890 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3891 &selectors.str(),
3892 &UrlExtraData(url.get_arc()),
3893 ) {
3894 Err(_) => return Err(Error::Syntax(None)),
3895 Ok(selectors) => selectors,
3896 };
3897
3898 let traced_self = Dom::from_ref(self);
3900 let quirks_mode = document.quirks_mode();
3901 let closest_element = with_layout_state(|| {
3902 #[expect(unsafe_code)]
3903 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3904 dom_apis::element_closest(
3905 ServoDangerousStyleElement::from(layout_element.upcast()),
3906 &selectors,
3907 quirks_mode,
3908 )
3909 });
3910 Ok(closest_element.map(ServoDangerousStyleElement::rooted))
3911 }
3912
3913 fn InsertAdjacentElement(
3915 &self,
3916 cx: &mut JSContext,
3917 where_: DOMString,
3918 element: &Element,
3919 ) -> Fallible<Option<DomRoot<Element>>> {
3920 let where_ = where_.parse::<AdjacentPosition>()?;
3921 let inserted_node = self.insert_adjacent(cx, where_, element.upcast())?;
3922 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3923 }
3924
3925 fn InsertAdjacentText(
3927 &self,
3928 cx: &mut JSContext,
3929 where_: DOMString,
3930 data: DOMString,
3931 ) -> ErrorResult {
3932 let text = Text::new(cx, data, &self.owner_document());
3934
3935 let where_ = where_.parse::<AdjacentPosition>()?;
3937 self.insert_adjacent(cx, where_, text.upcast()).map(|_| ())
3938 }
3939
3940 fn InsertAdjacentHTML(
3942 &self,
3943 cx: &mut JSContext,
3944 position: DOMString,
3945 text: TrustedHTMLOrString,
3946 ) -> ErrorResult {
3947 let text = TrustedHTML::get_trusted_type_compliant_string(
3951 cx,
3952 &self.owner_global(),
3953 text,
3954 "Element insertAdjacentHTML",
3955 )?;
3956 let position = position.parse::<AdjacentPosition>()?;
3957
3958 let context = match position {
3961 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
3964 match self.upcast::<Node>().GetParentNode() {
3965 Some(ref node) if node.is::<Document>() => {
3967 return Err(Error::NoModificationAllowed(None));
3968 },
3969 None => return Err(Error::NoModificationAllowed(None)),
3970 Some(node) => node,
3972 }
3973 },
3974 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
3977 DomRoot::from_ref(self.upcast::<Node>())
3979 },
3980 };
3981
3982 let context = Element::fragment_parsing_context(
3984 cx,
3985 &context.owner_doc(),
3986 context.downcast::<Element>(),
3987 );
3988
3989 let fragment = context.parse_fragment(text, cx)?;
3992
3993 self.insert_adjacent(cx, position, fragment.upcast())
3995 .map(|_| ())
3996 }
3997
3998 fn EnterFormalActivationState(&self) -> ErrorResult {
4000 match self.as_maybe_activatable() {
4001 Some(a) => {
4002 a.enter_formal_activation_state();
4003 Ok(())
4004 },
4005 None => Err(Error::NotSupported(None)),
4006 }
4007 }
4008
4009 fn ExitFormalActivationState(&self) -> ErrorResult {
4010 match self.as_maybe_activatable() {
4011 Some(a) => {
4012 a.exit_formal_activation_state();
4013 Ok(())
4014 },
4015 None => Err(Error::NotSupported(None)),
4016 }
4017 }
4018
4019 fn RequestFullscreen(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
4021 let doc = self.owner_document();
4022 doc.enter_fullscreen(cx, self)
4023 }
4024
4025 fn SetPointerCapture(&self, pointer_id: i32) -> ErrorResult {
4027 let document = self.owner_document();
4028 let event_handler = document.event_handler();
4029
4030 if !self.upcast::<Node>().is_connected() {
4041 return Err(Error::InvalidState(Some(
4042 "Can't capture pointer on an unconnected element".into(),
4043 )));
4044 }
4045
4046 if !event_handler.is_active_pointer(pointer_id) {
4056 return Ok(());
4057 }
4058
4059 event_handler.set_pending_pointer_capture(pointer_id, self);
4062
4063 Ok(())
4064 }
4065
4066 fn ReleasePointerCapture(&self, pointer_id: i32) -> ErrorResult {
4068 let document = self.owner_document();
4069 let event_handler = document.event_handler();
4070
4071 if !event_handler.is_active_pointer(pointer_id) {
4075 return Err(Error::NotFound(Some(
4076 "Can't release a pointer that is not active".into(),
4077 )));
4078 }
4079
4080 if !event_handler.has_pointer_capture(pointer_id, self) {
4083 return Ok(());
4084 }
4085
4086 event_handler.clear_pending_pointer_capture(pointer_id);
4088
4089 Ok(())
4090 }
4091
4092 fn HasPointerCapture(&self, pointer_id: i32) -> bool {
4094 let document = self.owner_document();
4095 let event_handler = document.event_handler();
4096 event_handler.has_pointer_capture(pointer_id, self)
4097 }
4098
4099 fn AttachShadow(
4101 &self,
4102 cx: &mut JSContext,
4103 init: &ShadowRootInit,
4104 ) -> Fallible<DomRoot<ShadowRoot>> {
4105 let shadow_root = self.attach_shadow(
4108 cx,
4109 IsUserAgentWidget::No,
4110 init.mode,
4111 init.clonable,
4112 init.serializable,
4113 init.delegatesFocus,
4114 init.slotAssignment,
4115 )?;
4116
4117 Ok(shadow_root)
4119 }
4120
4121 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
4123 let shadow_or_none = self.shadow_root();
4125
4126 let shadow = shadow_or_none?;
4128 if shadow.Mode() == ShadowRootMode::Closed {
4129 return None;
4130 }
4131
4132 Some(shadow)
4134 }
4135
4136 fn GetCustomElementRegistry(&self) -> Option<DomRoot<CustomElementRegistry>> {
4138 self.custom_element_registry()
4140 }
4141
4142 fn GetRole(&self) -> Option<DOMString> {
4144 self.get_nullable_string_attribute(&local_name!("role"))
4145 }
4146
4147 fn SetRole(&self, cx: &mut JSContext, value: Option<DOMString>) {
4149 self.set_nullable_string_attribute(cx, &local_name!("role"), value);
4150 }
4151
4152 fn GetAriaAtomic(&self) -> Option<DOMString> {
4153 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
4154 }
4155
4156 fn SetAriaAtomic(&self, cx: &mut JSContext, value: Option<DOMString>) {
4157 self.set_nullable_string_attribute(cx, &local_name!("aria-atomic"), value);
4158 }
4159
4160 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
4161 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
4162 }
4163
4164 fn SetAriaAutoComplete(&self, cx: &mut JSContext, value: Option<DOMString>) {
4165 self.set_nullable_string_attribute(cx, &local_name!("aria-autocomplete"), value);
4166 }
4167
4168 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
4169 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
4170 }
4171
4172 fn SetAriaBrailleLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4173 self.set_nullable_string_attribute(cx, &local_name!("aria-braillelabel"), value);
4174 }
4175
4176 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
4177 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
4178 }
4179
4180 fn SetAriaBrailleRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4181 self.set_nullable_string_attribute(cx, &local_name!("aria-brailleroledescription"), value);
4182 }
4183
4184 fn GetAriaBusy(&self) -> Option<DOMString> {
4185 self.get_nullable_string_attribute(&local_name!("aria-busy"))
4186 }
4187
4188 fn SetAriaBusy(&self, cx: &mut JSContext, value: Option<DOMString>) {
4189 self.set_nullable_string_attribute(cx, &local_name!("aria-busy"), value);
4190 }
4191
4192 fn GetAriaChecked(&self) -> Option<DOMString> {
4193 self.get_nullable_string_attribute(&local_name!("aria-checked"))
4194 }
4195
4196 fn SetAriaChecked(&self, cx: &mut JSContext, value: Option<DOMString>) {
4197 self.set_nullable_string_attribute(cx, &local_name!("aria-checked"), value);
4198 }
4199
4200 fn GetAriaColCount(&self) -> Option<DOMString> {
4201 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
4202 }
4203
4204 fn SetAriaColCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4205 self.set_nullable_string_attribute(cx, &local_name!("aria-colcount"), value);
4206 }
4207
4208 fn GetAriaColIndex(&self) -> Option<DOMString> {
4209 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4210 }
4211
4212 fn SetAriaColIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4213 self.set_nullable_string_attribute(cx, &local_name!("aria-colindex"), value);
4214 }
4215
4216 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4217 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4218 }
4219
4220 fn SetAriaColIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4221 self.set_nullable_string_attribute(cx, &local_name!("aria-colindextext"), value);
4222 }
4223
4224 fn GetAriaColSpan(&self) -> Option<DOMString> {
4225 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4226 }
4227
4228 fn SetAriaColSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4229 self.set_nullable_string_attribute(cx, &local_name!("aria-colspan"), value);
4230 }
4231
4232 fn GetAriaCurrent(&self) -> Option<DOMString> {
4233 self.get_nullable_string_attribute(&local_name!("aria-current"))
4234 }
4235
4236 fn SetAriaCurrent(&self, cx: &mut JSContext, value: Option<DOMString>) {
4237 self.set_nullable_string_attribute(cx, &local_name!("aria-current"), value);
4238 }
4239
4240 fn GetAriaDescription(&self) -> Option<DOMString> {
4241 self.get_nullable_string_attribute(&local_name!("aria-description"))
4242 }
4243
4244 fn SetAriaDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4245 self.set_nullable_string_attribute(cx, &local_name!("aria-description"), value);
4246 }
4247
4248 fn GetAriaDisabled(&self) -> Option<DOMString> {
4249 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4250 }
4251
4252 fn SetAriaDisabled(&self, cx: &mut JSContext, value: Option<DOMString>) {
4253 self.set_nullable_string_attribute(cx, &local_name!("aria-disabled"), value);
4254 }
4255
4256 fn GetAriaExpanded(&self) -> Option<DOMString> {
4257 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4258 }
4259
4260 fn SetAriaExpanded(&self, cx: &mut JSContext, value: Option<DOMString>) {
4261 self.set_nullable_string_attribute(cx, &local_name!("aria-expanded"), value);
4262 }
4263
4264 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4265 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4266 }
4267
4268 fn SetAriaHasPopup(&self, cx: &mut JSContext, value: Option<DOMString>) {
4269 self.set_nullable_string_attribute(cx, &local_name!("aria-haspopup"), value);
4270 }
4271
4272 fn GetAriaHidden(&self) -> Option<DOMString> {
4273 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4274 }
4275
4276 fn SetAriaHidden(&self, cx: &mut JSContext, value: Option<DOMString>) {
4277 self.set_nullable_string_attribute(cx, &local_name!("aria-hidden"), value);
4278 }
4279
4280 fn GetAriaInvalid(&self) -> Option<DOMString> {
4281 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4282 }
4283
4284 fn SetAriaInvalid(&self, cx: &mut JSContext, value: Option<DOMString>) {
4285 self.set_nullable_string_attribute(cx, &local_name!("aria-invalid"), value);
4286 }
4287
4288 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4289 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4290 }
4291
4292 fn SetAriaKeyShortcuts(&self, cx: &mut JSContext, value: Option<DOMString>) {
4293 self.set_nullable_string_attribute(cx, &local_name!("aria-keyshortcuts"), value);
4294 }
4295
4296 fn GetAriaLabel(&self) -> Option<DOMString> {
4297 self.get_nullable_string_attribute(&local_name!("aria-label"))
4298 }
4299
4300 fn SetAriaLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4301 self.set_nullable_string_attribute(cx, &local_name!("aria-label"), value);
4302 }
4303
4304 fn GetAriaLevel(&self) -> Option<DOMString> {
4305 self.get_nullable_string_attribute(&local_name!("aria-level"))
4306 }
4307
4308 fn SetAriaLevel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4309 self.set_nullable_string_attribute(cx, &local_name!("aria-level"), value);
4310 }
4311
4312 fn GetAriaLive(&self) -> Option<DOMString> {
4313 self.get_nullable_string_attribute(&local_name!("aria-live"))
4314 }
4315
4316 fn SetAriaLive(&self, cx: &mut JSContext, value: Option<DOMString>) {
4317 self.set_nullable_string_attribute(cx, &local_name!("aria-live"), value);
4318 }
4319
4320 fn GetAriaModal(&self) -> Option<DOMString> {
4321 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4322 }
4323
4324 fn SetAriaModal(&self, cx: &mut JSContext, value: Option<DOMString>) {
4325 self.set_nullable_string_attribute(cx, &local_name!("aria-modal"), value);
4326 }
4327
4328 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4329 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4330 }
4331
4332 fn SetAriaMultiLine(&self, cx: &mut JSContext, value: Option<DOMString>) {
4333 self.set_nullable_string_attribute(cx, &local_name!("aria-multiline"), value);
4334 }
4335
4336 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4337 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4338 }
4339
4340 fn SetAriaMultiSelectable(&self, cx: &mut JSContext, value: Option<DOMString>) {
4341 self.set_nullable_string_attribute(cx, &local_name!("aria-multiselectable"), value);
4342 }
4343
4344 fn GetAriaOrientation(&self) -> Option<DOMString> {
4345 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4346 }
4347
4348 fn SetAriaOrientation(&self, cx: &mut JSContext, value: Option<DOMString>) {
4349 self.set_nullable_string_attribute(cx, &local_name!("aria-orientation"), value);
4350 }
4351
4352 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4353 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4354 }
4355
4356 fn SetAriaPlaceholder(&self, cx: &mut JSContext, value: Option<DOMString>) {
4357 self.set_nullable_string_attribute(cx, &local_name!("aria-placeholder"), value);
4358 }
4359
4360 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4361 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4362 }
4363
4364 fn SetAriaPosInSet(&self, cx: &mut JSContext, value: Option<DOMString>) {
4365 self.set_nullable_string_attribute(cx, &local_name!("aria-posinset"), value);
4366 }
4367
4368 fn GetAriaPressed(&self) -> Option<DOMString> {
4369 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4370 }
4371
4372 fn SetAriaPressed(&self, cx: &mut JSContext, value: Option<DOMString>) {
4373 self.set_nullable_string_attribute(cx, &local_name!("aria-pressed"), value);
4374 }
4375
4376 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4377 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4378 }
4379
4380 fn SetAriaReadOnly(&self, cx: &mut JSContext, value: Option<DOMString>) {
4381 self.set_nullable_string_attribute(cx, &local_name!("aria-readonly"), value);
4382 }
4383
4384 fn GetAriaRelevant(&self) -> Option<DOMString> {
4385 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4386 }
4387
4388 fn SetAriaRelevant(&self, cx: &mut JSContext, value: Option<DOMString>) {
4389 self.set_nullable_string_attribute(cx, &local_name!("aria-relevant"), value);
4390 }
4391
4392 fn GetAriaRequired(&self) -> Option<DOMString> {
4393 self.get_nullable_string_attribute(&local_name!("aria-required"))
4394 }
4395
4396 fn SetAriaRequired(&self, cx: &mut JSContext, value: Option<DOMString>) {
4397 self.set_nullable_string_attribute(cx, &local_name!("aria-required"), value);
4398 }
4399
4400 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4401 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4402 }
4403
4404 fn SetAriaRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4405 self.set_nullable_string_attribute(cx, &local_name!("aria-roledescription"), value);
4406 }
4407
4408 fn GetAriaRowCount(&self) -> Option<DOMString> {
4409 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4410 }
4411
4412 fn SetAriaRowCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4413 self.set_nullable_string_attribute(cx, &local_name!("aria-rowcount"), value);
4414 }
4415
4416 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4417 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4418 }
4419
4420 fn SetAriaRowIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4421 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindex"), value);
4422 }
4423
4424 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4425 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4426 }
4427
4428 fn SetAriaRowIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4429 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindextext"), value);
4430 }
4431
4432 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4433 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4434 }
4435
4436 fn SetAriaRowSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4437 self.set_nullable_string_attribute(cx, &local_name!("aria-rowspan"), value);
4438 }
4439
4440 fn GetAriaSelected(&self) -> Option<DOMString> {
4441 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4442 }
4443
4444 fn SetAriaSelected(&self, cx: &mut JSContext, value: Option<DOMString>) {
4445 self.set_nullable_string_attribute(cx, &local_name!("aria-selected"), value);
4446 }
4447
4448 fn GetAriaSetSize(&self) -> Option<DOMString> {
4449 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4450 }
4451
4452 fn SetAriaSetSize(&self, cx: &mut JSContext, value: Option<DOMString>) {
4453 self.set_nullable_string_attribute(cx, &local_name!("aria-setsize"), value);
4454 }
4455
4456 fn GetAriaSort(&self) -> Option<DOMString> {
4457 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4458 }
4459
4460 fn SetAriaSort(&self, cx: &mut JSContext, value: Option<DOMString>) {
4461 self.set_nullable_string_attribute(cx, &local_name!("aria-sort"), value);
4462 }
4463
4464 fn GetAriaValueMax(&self) -> Option<DOMString> {
4465 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4466 }
4467
4468 fn SetAriaValueMax(&self, cx: &mut JSContext, value: Option<DOMString>) {
4469 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemax"), value);
4470 }
4471
4472 fn GetAriaValueMin(&self) -> Option<DOMString> {
4473 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4474 }
4475
4476 fn SetAriaValueMin(&self, cx: &mut JSContext, value: Option<DOMString>) {
4477 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemin"), value);
4478 }
4479
4480 fn GetAriaValueNow(&self) -> Option<DOMString> {
4481 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4482 }
4483
4484 fn SetAriaValueNow(&self, cx: &mut JSContext, value: Option<DOMString>) {
4485 self.set_nullable_string_attribute(cx, &local_name!("aria-valuenow"), value);
4486 }
4487
4488 fn GetAriaValueText(&self) -> Option<DOMString> {
4489 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4490 }
4491
4492 fn SetAriaValueText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4493 self.set_nullable_string_attribute(cx, &local_name!("aria-valuetext"), value);
4494 }
4495
4496 fn GetAssignedSlot(&self, cx: &JSContext) -> Option<DomRoot<HTMLSlotElement>> {
4498 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4501 slottable.find_a_slot(true)
4502 }
4503
4504 fn Part(&self, cx: &mut JSContext) -> DomRoot<DOMTokenList> {
4506 self.ensure_rare_data()
4507 .part
4508 .or_init(|| DOMTokenList::new(cx, self, &local_name!("part"), None))
4509 }
4510
4511 fn Animate(
4513 &self,
4514 cx: &mut JSContext,
4515 keyframes: *mut JSObject,
4516 options: UnrestrictedDoubleOrKeyframeAnimationOptions,
4517 ) -> DomRoot<Animation> {
4518 let window = self.owner_window();
4519
4520 let target = self;
4522
4523 let parent_options = match options {
4531 UnrestrictedDoubleOrKeyframeAnimationOptions::UnrestrictedDouble(value) => {
4532 UnrestrictedDoubleOrKeyframeEffectOptions::UnrestrictedDouble(value)
4533 },
4534 UnrestrictedDoubleOrKeyframeAnimationOptions::KeyframeAnimationOptions(options) => {
4535 UnrestrictedDoubleOrKeyframeEffectOptions::KeyframeEffectOptions(options.parent)
4536 },
4537 };
4538 let effect =
4539 KeyframeEffect::Constructor(cx, &window, None, Some(target), keyframes, parent_options);
4540
4541 let animation = Animation::Constructor(cx, &window, None, Some(effect.upcast()));
4549
4550 animation
4557 }
4558}
4559
4560impl VirtualMethods for Element {
4561 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4562 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4563 }
4564
4565 fn attribute_affects_presentational_hints(&self, attr: AttrRef<'_>) -> bool {
4566 if attr.local_name() == &local_name!("lang") {
4568 return true;
4569 }
4570
4571 self.super_type()
4572 .unwrap()
4573 .attribute_affects_presentational_hints(attr)
4574 }
4575
4576 fn attribute_mutated(
4577 &self,
4578 cx: &mut JSContext,
4579 attr: AttrRef<'_>,
4580 mutation: AttributeMutation,
4581 ) {
4582 self.super_type()
4583 .unwrap()
4584 .attribute_mutated(cx, attr, mutation);
4585 let node = self.upcast::<Node>();
4586 let doc = node.owner_doc();
4587 match *attr.local_name() {
4588 ref name if name.starts_with("on") && EventTarget::is_content_event_handler(name) => {
4592 let evtarget = self.upcast::<EventTarget>();
4593 let event_name = &name[2..];
4594 match mutation {
4595 AttributeMutation::Set(..) => {
4597 let source = &**attr.value();
4598 let source_line = 1; evtarget.set_event_handler_uncompiled(
4600 cx,
4601 self.owner_window().get_url(),
4602 source_line,
4603 event_name,
4604 source,
4605 );
4606 },
4607 AttributeMutation::Removed => {
4609 evtarget
4610 .set_event_handler_common::<EventHandlerNonNull>(cx, event_name, None);
4611 },
4612 }
4613 },
4614 local_name!("style") => self.update_style_attribute(cx, attr, mutation),
4615 local_name!("id") => {
4616 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4618 let value = value.as_atom();
4619 if value != &atom!("") {
4620 Some(value.clone())
4622 } else {
4623 None
4625 }
4626 });
4627
4628 let containing_shadow_root = self.containing_shadow_root();
4629 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4630 let value = attr.value().as_atom().clone();
4631 match mutation {
4632 AttributeMutation::Set(old_value, _) => {
4633 if let Some(old_value) = old_value {
4634 let old_value = old_value.as_atom();
4635 if let Some(ref shadow_root) = containing_shadow_root {
4636 shadow_root.unregister_element_id(old_value);
4637 } else {
4638 doc.unregister_element_id(cx, old_value);
4639 }
4640 }
4641 if value != atom!("") {
4642 if let Some(ref shadow_root) = containing_shadow_root {
4643 shadow_root.register_element_id(
4644 self,
4645 &value,
4646 CanGc::from_cx(cx),
4647 );
4648 } else {
4649 doc.register_element_id(cx, self, &value);
4650 }
4651 }
4652 },
4653 AttributeMutation::Removed => {
4654 if value != atom!("") {
4655 if let Some(ref shadow_root) = containing_shadow_root {
4656 shadow_root.unregister_element_id(&value);
4657 } else {
4658 doc.unregister_element_id(cx, &value);
4659 }
4660 }
4661 },
4662 }
4663 }
4664 },
4665 local_name!("name") => {
4666 self.ensure_rare_data().name_attribute =
4668 mutation.new_value(attr).and_then(|value| {
4669 let value = value.as_atom();
4670 if value != &atom!("") {
4671 Some(value.clone())
4672 } else {
4673 None
4674 }
4675 });
4676 if node.is_connected() && node.containing_shadow_root().is_none() {
4679 let value = attr.value().as_atom().clone();
4680 match mutation {
4681 AttributeMutation::Set(old_value, _) => {
4682 if let Some(old_value) = old_value {
4683 doc.unregister_element_name(old_value.as_atom());
4684 }
4685 if value != atom!("") {
4686 doc.register_element_name(self, &value);
4687 }
4688 },
4689 AttributeMutation::Removed => {
4690 if value != atom!("") {
4691 doc.unregister_element_name(&value);
4692 }
4693 },
4694 }
4695 }
4696 },
4697 local_name!("slot") => {
4698 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4700
4701 if let Some(assigned_slot) = slottable.assigned_slot() {
4703 assigned_slot.assign_slottables(cx);
4704 }
4705 slottable.assign_a_slot(cx);
4706 },
4707 _ => {
4708 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4711 node.dirty(NodeDamage::Other);
4712 }
4713 },
4714 };
4715
4716 if self
4719 .upcast::<Node>()
4720 .get_flag(NodeFlags::USES_ATTR_IN_CONTENT_ATTRIBUTE)
4721 {
4722 node.dirty(NodeDamage::ContentOrHeritage);
4723 }
4724
4725 node.rev_version();
4729
4730 let window = self.owner_window();
4732 if window.live_devtools_updates() {
4733 let global = window.upcast::<GlobalScope>();
4734 if let Some(sender) = global.devtools_chan() {
4735 let pipeline_id = global.pipeline_id();
4736 if ScriptThread::devtools_want_updates_for_node(pipeline_id, self.upcast()) {
4737 let devtools_message = ScriptToDevtoolsControlMsg::DomMutation(
4738 pipeline_id,
4739 DomMutation::AttributeModified {
4740 node: self.upcast::<Node>().unique_id(pipeline_id),
4741 attribute_name: attr.local_name().to_string(),
4742 new_value: mutation.new_value(attr).map(|value| value.to_string()),
4743 },
4744 );
4745 sender.send(devtools_message).unwrap();
4746 }
4747 }
4748 }
4749 }
4750
4751 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4752 match *name {
4753 local_name!("id") => AttrValue::Atom(value.into()),
4754 local_name!("name") => AttrValue::Atom(value.into()),
4755 local_name!("class") | local_name!("part") => {
4756 AttrValue::from_serialized_tokenlist(value.into())
4757 },
4758 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4759 local_name!("tabindex") => AttrValue::from_i32(value.into(), -1),
4760 _ => self
4761 .super_type()
4762 .unwrap()
4763 .parse_plain_attribute(name, value),
4764 }
4765 }
4766
4767 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
4768 if let Some(s) = self.super_type() {
4769 s.bind_to_tree(cx, context);
4770 }
4771
4772 if let Some(f) = self.as_maybe_form_control() {
4773 f.bind_form_control_to_tree(cx);
4774 }
4775
4776 if let Some(ref shadow_root) = self.shadow_root() {
4777 shadow_root.bind_to_tree(cx, context);
4778 }
4779
4780 if !context.is_in_tree() {
4781 return;
4782 }
4783
4784 self.register_current_id_and_name_attribute(cx);
4785 }
4786
4787 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4788 self.super_type().unwrap().unbind_from_tree(cx, context);
4789
4790 if let Some(f) = self.as_maybe_form_control() {
4791 f.unbind_form_control_from_tree(cx);
4795 }
4796
4797 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4798 return;
4799 }
4800
4801 let doc = self.owner_document();
4802
4803 let fullscreen = doc.fullscreen_element();
4804 if fullscreen.as_deref() == Some(self) {
4805 doc.exit_fullscreen(cx);
4806 }
4807
4808 self.unregister_current_id_and_name_attribute(cx);
4809 }
4810
4811 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4812 if let Some(s) = self.super_type() {
4813 s.children_changed(cx, mutation);
4814 }
4815
4816 let flags = self.get_selector_flags();
4817 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4818 self.upcast::<Node>().dirty(NodeDamage::Other);
4820 } else {
4821 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) &&
4822 let Some(next_child) = mutation.next_child()
4823 {
4824 for child in next_child.inclusively_following_siblings_unrooted(cx.no_gc()) {
4825 if child.is::<Element>() {
4826 child.dirty(NodeDamage::Other);
4827 }
4828 }
4829 }
4830 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) &&
4831 let Some(child) = mutation.modified_edge_element(cx.no_gc())
4832 {
4833 child.dirty(NodeDamage::Other);
4834 }
4835 }
4836 }
4837
4838 fn adopting_steps(&self, cx: &mut JSContext, old_doc: &Document) {
4839 self.super_type().unwrap().adopting_steps(cx, old_doc);
4840
4841 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4842 self.tag_name.clear();
4843 }
4844 }
4845
4846 fn post_connection_steps(&self, cx: &mut JSContext) {
4847 if let Some(s) = self.super_type() {
4848 s.post_connection_steps(cx);
4849 }
4850
4851 self.update_nonce_post_connection(cx);
4852 }
4853
4854 fn cloning_steps(
4856 &self,
4857 cx: &mut JSContext,
4858 copy: &Node,
4859 maybe_doc: Option<&Document>,
4860 clone_children: CloneChildrenFlag,
4861 ) {
4862 if let Some(s) = self.super_type() {
4863 s.cloning_steps(cx, copy, maybe_doc, clone_children);
4864 }
4865 let elem = copy.downcast::<Element>().unwrap();
4866 if let Some(rare_data) = self.rare_data().as_ref() {
4867 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone());
4868 }
4869 }
4870}
4871impl Element {
4872 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
4873 let doc = self.node.owner_doc();
4874
4875 if let Some(rect) = self
4876 .rare_data()
4877 .as_ref()
4878 .and_then(|data| data.client_rect.as_ref())
4879 .and_then(|rect| rect.get().ok()) &&
4880 doc.restyle_reason().is_empty()
4881 {
4882 return rect;
4883 }
4884
4885 let mut rect = self.upcast::<Node>().client_rect();
4886 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
4887
4888 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
4889 (!in_quirks_mode && self.is_document_element())
4890 {
4891 rect.size = doc.window().viewport_details().size.round().to_i32();
4892 }
4893
4894 self.ensure_rare_data().client_rect = Some(self.owner_window().cache_layout_value(rect));
4895 rect
4896 }
4897
4898 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
4899 let element = match self.upcast::<Node>().type_id() {
4900 NodeTypeId::Element(ElementTypeId::HTMLElement(
4901 HTMLElementTypeId::HTMLInputElement,
4902 )) => {
4903 let element = self.downcast::<HTMLInputElement>().unwrap();
4904 Some(element as &dyn Activatable)
4905 },
4906 NodeTypeId::Element(ElementTypeId::HTMLElement(
4907 HTMLElementTypeId::HTMLButtonElement,
4908 )) => {
4909 let element = self.downcast::<HTMLButtonElement>().unwrap();
4910 Some(element as &dyn Activatable)
4911 },
4912 NodeTypeId::Element(ElementTypeId::HTMLElement(
4913 HTMLElementTypeId::HTMLAnchorElement,
4914 )) => {
4915 let element = self.downcast::<HTMLAnchorElement>().unwrap();
4916 Some(element as &dyn Activatable)
4917 },
4918 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
4919 let element = self.downcast::<HTMLAreaElement>().unwrap();
4920 Some(element as &dyn Activatable)
4921 },
4922 NodeTypeId::Element(ElementTypeId::HTMLElement(
4923 HTMLElementTypeId::HTMLLabelElement,
4924 )) => {
4925 let element = self.downcast::<HTMLLabelElement>().unwrap();
4926 Some(element as &dyn Activatable)
4927 },
4928 NodeTypeId::Element(ElementTypeId::HTMLElement(
4929 HTMLElementTypeId::HTMLSelectElement,
4930 )) => {
4931 let element = self.downcast::<HTMLSelectElement>().unwrap();
4932 Some(element as &dyn Activatable)
4933 },
4934 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
4935 let element = self.downcast::<HTMLElement>().unwrap();
4936 Some(element as &dyn Activatable)
4937 },
4938 _ => None,
4939 };
4940 element.and_then(|elem| {
4941 if elem.is_instance_activatable() {
4942 Some(elem)
4943 } else {
4944 None
4945 }
4946 })
4947 }
4948
4949 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
4950 if let Some(s) = self.downcast::<HTMLStyleElement>() {
4951 return Some(s as &dyn StylesheetOwner);
4952 }
4953
4954 if let Some(l) = self.downcast::<HTMLLinkElement>() {
4955 return Some(l as &dyn StylesheetOwner);
4956 }
4957
4958 None
4959 }
4960
4961 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
4963 match self.upcast::<Node>().type_id() {
4964 NodeTypeId::Element(ElementTypeId::HTMLElement(
4965 HTMLElementTypeId::HTMLInputElement,
4966 )) => {
4967 let element = self.downcast::<HTMLInputElement>().unwrap();
4968 Some(element as &dyn Validatable)
4969 },
4970 NodeTypeId::Element(ElementTypeId::HTMLElement(
4971 HTMLElementTypeId::HTMLButtonElement,
4972 )) => {
4973 let element = self.downcast::<HTMLButtonElement>().unwrap();
4974 Some(element as &dyn Validatable)
4975 },
4976 NodeTypeId::Element(ElementTypeId::HTMLElement(
4977 HTMLElementTypeId::HTMLObjectElement,
4978 )) => {
4979 let element = self.downcast::<HTMLObjectElement>().unwrap();
4980 Some(element as &dyn Validatable)
4981 },
4982 NodeTypeId::Element(ElementTypeId::HTMLElement(
4983 HTMLElementTypeId::HTMLSelectElement,
4984 )) => {
4985 let element = self.downcast::<HTMLSelectElement>().unwrap();
4986 Some(element as &dyn Validatable)
4987 },
4988 NodeTypeId::Element(ElementTypeId::HTMLElement(
4989 HTMLElementTypeId::HTMLTextAreaElement,
4990 )) => {
4991 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
4992 Some(element as &dyn Validatable)
4993 },
4994 NodeTypeId::Element(ElementTypeId::HTMLElement(
4995 HTMLElementTypeId::HTMLFieldSetElement,
4996 )) => {
4997 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
4998 Some(element as &dyn Validatable)
4999 },
5000 NodeTypeId::Element(ElementTypeId::HTMLElement(
5001 HTMLElementTypeId::HTMLOutputElement,
5002 )) => {
5003 let element = self.downcast::<HTMLOutputElement>().unwrap();
5004 Some(element as &dyn Validatable)
5005 },
5006 _ => None,
5007 }
5008 }
5009
5010 pub(crate) fn is_invalid(&self, cx: &mut JSContext, needs_update: bool) -> bool {
5011 if let Some(validatable) = self.as_maybe_validatable() {
5012 if needs_update {
5013 validatable
5014 .validity_state(cx)
5015 .perform_validation_and_update(cx, ValidationFlags::all());
5016 }
5017 return validatable.is_instance_validatable() && !validatable.satisfies_constraints(cx);
5018 }
5019
5020 if let Some(internals) = self.get_element_internals() {
5021 return internals.is_invalid(cx);
5022 }
5023 false
5024 }
5025
5026 pub(crate) fn is_instance_validatable(&self) -> bool {
5027 if let Some(validatable) = self.as_maybe_validatable() {
5028 return validatable.is_instance_validatable();
5029 }
5030 if let Some(internals) = self.get_element_internals() {
5031 return internals.is_instance_validatable();
5032 }
5033 false
5034 }
5035
5036 pub(crate) fn init_state_for_internals(&self) {
5037 self.set_enabled_state(true);
5038 self.set_state(ElementState::VALID, true);
5039 self.set_state(ElementState::INVALID, false);
5040 }
5041
5042 pub(crate) fn click_in_progress(&self) -> bool {
5043 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5044 }
5045
5046 pub(crate) fn set_click_in_progress(&self, click: bool) {
5047 self.upcast::<Node>()
5048 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5049 }
5050
5051 pub fn state(&self) -> ElementState {
5052 self.state.get()
5053 }
5054
5055 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5056 let mut state = self.state.get();
5057 let previous_state = state;
5058 if value {
5059 state.insert(which);
5060 } else {
5061 state.remove(which);
5062 }
5063
5064 if previous_state == state {
5065 return;
5067 }
5068
5069 {
5072 let document = self.owner_document();
5073 let mut entry = document.ensure_pending_restyle(self);
5074 if entry.snapshot.is_none() {
5075 entry.snapshot = Some(Snapshot::new());
5076 }
5077 let snapshot = entry.snapshot.as_mut().unwrap();
5078 if snapshot.state.is_none() {
5079 snapshot.state = Some(self.state());
5080 }
5081 }
5082
5083 self.state.set(state);
5084 }
5085
5086 pub(crate) fn set_active_state(&self, value: bool) {
5088 self.set_state(ElementState::ACTIVE, value);
5089
5090 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5091 parent.set_active_state(value);
5092 }
5093 }
5094
5095 pub(crate) fn focus_state(&self) -> bool {
5096 self.state.get().contains(ElementState::FOCUS)
5097 }
5098
5099 pub(crate) fn set_focus_state(&self, value: bool) {
5100 self.set_state(ElementState::FOCUS, value);
5101 }
5102
5103 pub(crate) fn set_hover_state(&self, value: bool) {
5104 self.set_state(ElementState::HOVER, value);
5105 }
5106
5107 pub(crate) fn enabled_state(&self) -> bool {
5108 self.state.get().contains(ElementState::ENABLED)
5109 }
5110
5111 pub(crate) fn set_enabled_state(&self, value: bool) {
5112 self.set_state(ElementState::ENABLED, value)
5113 }
5114
5115 pub(crate) fn disabled_state(&self) -> bool {
5116 self.state.get().contains(ElementState::DISABLED)
5117 }
5118
5119 pub(crate) fn set_disabled_state(&self, value: bool) {
5120 self.set_state(ElementState::DISABLED, value)
5121 }
5122
5123 pub(crate) fn read_write_state(&self) -> bool {
5124 self.state.get().contains(ElementState::READWRITE)
5125 }
5126
5127 pub(crate) fn set_read_write_state(&self, value: bool) {
5128 self.set_state(ElementState::READWRITE, value)
5129 }
5130
5131 pub(crate) fn set_open_state(&self, value: bool) {
5132 self.set_state(ElementState::OPEN, value);
5133 }
5134
5135 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5136 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5137 }
5138
5139 pub(crate) fn set_modal_state(&self, value: bool) {
5140 self.set_state(ElementState::MODAL, value);
5141 }
5142
5143 pub(crate) fn set_target_state(&self, value: bool) {
5144 self.set_state(ElementState::URLTARGET, value)
5145 }
5146
5147 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5148 self.set_state(ElementState::FULLSCREEN, value)
5149 }
5150
5151 pub(crate) fn is_connected(&self) -> bool {
5153 self.upcast::<Node>().is_connected()
5154 }
5155
5156 pub(crate) fn cannot_navigate(&self) -> bool {
5158 let document = self.owner_document();
5159
5160 !document.is_fully_active() ||
5162 (
5163 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5165 )
5166 }
5167}
5168
5169impl Element {
5170 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5171 let node = self.upcast::<Node>();
5172 if self.disabled_state() {
5173 return;
5174 }
5175 for ancestor in node.ancestors() {
5176 if !ancestor.is::<HTMLFieldSetElement>() {
5177 continue;
5178 }
5179 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5180 continue;
5181 }
5182 if ancestor.is_parent_of(node) {
5183 self.set_disabled_state(true);
5184 self.set_enabled_state(false);
5185 return;
5186 }
5187 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5188 if node.ancestors().any(|ancestor| ancestor == *legend) {
5190 continue;
5191 }
5192 }
5193 self.set_disabled_state(true);
5194 self.set_enabled_state(false);
5195 return;
5196 }
5197 }
5198
5199 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5200 if self.disabled_state() {
5201 return;
5202 }
5203 let node = self.upcast::<Node>();
5204 if let Some(ref parent) = node.GetParentNode() &&
5205 parent.is::<HTMLOptGroupElement>() &&
5206 parent.downcast::<Element>().unwrap().disabled_state()
5207 {
5208 self.set_disabled_state(true);
5209 self.set_enabled_state(false);
5210 }
5211 }
5212
5213 pub(crate) fn check_disabled_attribute(&self) {
5214 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5215 self.set_disabled_state(has_disabled_attrib);
5216 self.set_enabled_state(!has_disabled_attrib);
5217 }
5218
5219 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5220 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5221 self.set_read_write_state(has_readonly_attribute);
5222 }
5223}
5224
5225#[derive(Clone, Copy, PartialEq)]
5226pub(crate) enum AttributeMutationReason {
5227 ByCloning,
5228 ByParser,
5229 Directly,
5230}
5231
5232#[derive(Clone, Copy)]
5233pub(crate) enum AttributeMutation<'a> {
5234 Set(Option<&'a AttrValue>, AttributeMutationReason),
5237
5238 Removed,
5241}
5242
5243impl AttributeMutation<'_> {
5244 pub(crate) fn is_removal(&self) -> bool {
5245 match *self {
5246 AttributeMutation::Removed => true,
5247 AttributeMutation::Set(..) => false,
5248 }
5249 }
5250
5251 pub(crate) fn new_value<'b>(&self, attr: AttrRef<'b>) -> Option<AttrValueRef<'b>> {
5252 match *self {
5253 AttributeMutation::Set(..) => Some(attr.value()),
5254 AttributeMutation::Removed => None,
5255 }
5256 }
5257}
5258
5259#[derive(JSTraceable, MallocSizeOf)]
5263struct TagName {
5264 #[no_trace]
5265 ptr: DomRefCell<Option<LocalName>>,
5266}
5267
5268impl TagName {
5269 fn new() -> TagName {
5270 TagName {
5271 ptr: DomRefCell::new(None),
5272 }
5273 }
5274
5275 fn or_init<F>(&self, cb: F) -> LocalName
5278 where
5279 F: FnOnce() -> LocalName,
5280 {
5281 match &mut *self.ptr.borrow_mut() {
5282 &mut Some(ref name) => name.clone(),
5283 ptr => {
5284 let name = cb();
5285 *ptr = Some(name.clone());
5286 name
5287 },
5288 }
5289 }
5290
5291 fn clear(&self) {
5294 *self.ptr.borrow_mut() = None;
5295 }
5296}
5297
5298pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5300 element
5301 .get_attribute_string_value(&local_name!("crossorigin"))
5302 .map(|value| {
5303 let value = value.to_ascii_lowercase();
5304 if value == "anonymous" || value == "use-credentials" {
5305 DOMString::from(value)
5306 } else {
5307 DOMString::from("anonymous")
5308 }
5309 })
5310}
5311
5312pub(crate) fn set_cross_origin_attribute(
5313 cx: &mut JSContext,
5314 element: &Element,
5315 value: Option<DOMString>,
5316) {
5317 match value {
5318 Some(val) => element.set_string_attribute(cx, &local_name!("crossorigin"), val),
5319 None => {
5320 element.remove_attribute(cx, &ns!(), &local_name!("crossorigin"));
5321 },
5322 }
5323}
5324
5325pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5327 element
5328 .get_attribute_string_value(&local_name!("referrerpolicy"))
5329 .map(|value| {
5330 let value = value.to_ascii_lowercase();
5331 if value == "no-referrer" ||
5332 value == "no-referrer-when-downgrade" ||
5333 value == "same-origin" ||
5334 value == "origin" ||
5335 value == "strict-origin" ||
5336 value == "origin-when-cross-origin" ||
5337 value == "strict-origin-when-cross-origin" ||
5338 value == "unsafe-url"
5339 {
5340 DOMString::from(value)
5341 } else {
5342 DOMString::new()
5343 }
5344 })
5345 .unwrap_or_default()
5346}
5347
5348pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5349 element
5350 .get_attribute_string_value(&local_name!("referrerpolicy"))
5351 .map(|value| ReferrerPolicy::from(value.as_ref()))
5352 .unwrap_or(element.owner_document().get_referrer_policy())
5353}
5354
5355pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5356 element
5357 .get_attribute_string_value(&local_name!("crossorigin"))
5358 .map(|value| CorsSettings::from_enumerated_attribute(value.as_ref()))
5359}
5360
5361pub(crate) fn cors_settings_attribute_credential_mode(element: &Element) -> CredentialsMode {
5363 element
5364 .get_attribute_string_value(&local_name!("crossorigin"))
5365 .map(|value| {
5366 if value.eq_ignore_ascii_case("use-credentials") {
5367 CredentialsMode::Include
5368 } else {
5369 CredentialsMode::CredentialsSameOrigin
5371 }
5372 })
5373 .unwrap_or(CredentialsMode::CredentialsSameOrigin)
5375}
5376
5377pub(crate) fn is_element_affected_by_legacy_background_presentational_hint(
5378 namespace: &Namespace,
5379 local_name: &LocalName,
5380) -> bool {
5381 *namespace == ns!(html) &&
5382 matches!(
5383 *local_name,
5384 local_name!("body") |
5385 local_name!("table") |
5386 local_name!("thead") |
5387 local_name!("tbody") |
5388 local_name!("tfoot") |
5389 local_name!("tr") |
5390 local_name!("td") |
5391 local_name!("th")
5392 )
5393}