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, NoGC};
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::codegen::GenericBindings::AnimationBinding::AnimationMethods;
33use script_bindings::codegen::GenericBindings::KeyframeEffectBinding::KeyframeEffectMethods;
34use script_bindings::reflector::DomObject;
35use selectors::attr::CaseSensitivity;
36use selectors::matching::ElementSelectorFlags;
37use selectors::sink::Push;
38use servo_arc::Arc as ServoArc;
39use style::applicable_declarations::ApplicableDeclarationBlock;
40use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
41use style::context::QuirksMode;
42use style::invalidation::element::restyle_hints::RestyleHint;
43use style::properties::longhands::{
44 self, background_image, border_spacing, color, font_family, font_size,
45};
46use style::properties::{
47 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
48 parse_style_attribute,
49};
50use style::rule_tree::{CascadeLevel, CascadeOrigin};
51use style::selector_parser::{RestyleDamage, SelectorParser, Snapshot};
52use style::shared_lock::Locked;
53use style::stylesheets::layer_rule::LayerOrder;
54use style::stylesheets::{CssRuleType, UrlExtraData};
55use style::values::computed::Overflow;
56use style::values::generics::NonNegative;
57use style::values::generics::position::PreferredRatio;
58use style::values::generics::ratio::Ratio;
59use style::values::{AtomIdent, AtomString, CSSFloat, GenericAtomIdent, computed, specified};
60use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
61use style_traits::CSSPixel;
62use stylo_atoms::Atom;
63use stylo_dom::ElementState;
64use xml5ever::serialize::TraversalScope::{
65 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
66};
67
68use crate::conversions::Convert;
69use crate::dom::activation::Activatable;
70use crate::dom::animation::Animation;
71use crate::dom::animations::keyframeeffect::KeyframeEffect;
72use crate::dom::attr::{Attr, is_relevant_attribute};
73use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
74use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
75use crate::dom::bindings::codegen::Bindings::ElementBinding::{
76 ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
77};
78use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
79use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
80use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
81use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
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::form_controls::htmlinputelement::HTMLInputElement;
125use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
126use crate::dom::html::htmlareaelement::HTMLAreaElement;
127use crate::dom::html::htmlbodyelement::HTMLBodyElement;
128use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
129use crate::dom::html::htmlcollection::HTMLCollection;
130use crate::dom::html::htmlelement::HTMLElement;
131use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
132use crate::dom::html::htmlfontelement::HTMLFontElement;
133use crate::dom::html::htmlformelement::FormControlElementHelpers;
134use crate::dom::html::htmlhrelement::{HTMLHRElement, SizePresentationalHint};
135use crate::dom::html::htmliframeelement::HTMLIFrameElement;
136use crate::dom::html::htmlimageelement::HTMLImageElement;
137use crate::dom::html::htmllabelelement::HTMLLabelElement;
138use crate::dom::html::htmllegendelement::HTMLLegendElement;
139use crate::dom::html::htmllinkelement::HTMLLinkElement;
140use crate::dom::html::htmlobjectelement::HTMLObjectElement;
141use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
142use crate::dom::html::htmloutputelement::HTMLOutputElement;
143use crate::dom::html::htmlscriptelement::HTMLScriptElement;
144use crate::dom::html::htmlselectelement::HTMLSelectElement;
145use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
146use crate::dom::html::htmlstyleelement::HTMLStyleElement;
147use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
148use crate::dom::html::htmltablecolelement::HTMLTableColElement;
149use crate::dom::html::htmltableelement::HTMLTableElement;
150use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
151use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
152use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
153use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
154use crate::dom::html::htmlvideoelement::HTMLVideoElement;
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::svgelement::SVGElement;
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::dom::window::Window;
179use crate::layout_dom::ServoDangerousStyleElement;
180use crate::realms::enter_auto_realm;
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, no_gc: &NoGC) -> bool {
591 self.ScrollHeight() > self.ClientHeight(no_gc) ||
592 self.ScrollWidth() > self.ClientWidth(no_gc)
593 }
594
595 fn has_scrolling_box(&self, no_gc: &NoGC) -> bool {
603 self.has_css_layout_box() && self.establishes_scroll_container() && self.has_overflow(no_gc)
604 }
605
606 pub(crate) fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
607 self.rare_data()
608 .as_ref()?
609 .shadow_root
610 .as_ref()
611 .map(|sr| DomRoot::from_ref(&**sr))
612 }
613
614 pub(crate) fn is_shadow_host(&self) -> bool {
615 self.shadow_root().is_some()
616 }
617
618 #[allow(clippy::too_many_arguments)]
620 pub(crate) fn attach_shadow(
621 &self,
622 cx: &mut JSContext,
623 is_ua_widget: IsUserAgentWidget,
624 mode: ShadowRootMode,
625 clonable: bool,
626 serializable: bool,
627 delegates_focus: bool,
628 slot_assignment_mode: SlotAssignmentMode,
629 ) -> Fallible<DomRoot<ShadowRoot>> {
630 if self.namespace != ns!(html) {
633 return Err(Error::NotSupported(Some(
634 "Cannot attach shadow roots to elements with non-HTML namespaces".to_owned(),
635 )));
636 }
637
638 if !is_valid_shadow_host_name(self.local_name()) {
641 if is_ua_widget != IsUserAgentWidget::Yes {
643 let error_message = format!(
644 "Cannot attach shadow roots to <{}> elements",
645 *self.local_name()
646 );
647 return Err(Error::NotSupported(Some(error_message)));
648 }
649 }
650
651 if is_valid_custom_element_name(self.local_name()) || self.get_is().is_some() {
654 let definition = self.get_custom_element_definition();
658 if definition.is_some_and(|definition| definition.disable_shadow) {
661 let error_message = format!(
662 "The custom element constructor of <{}> disabled attachment of shadow roots",
663 self.local_name()
664 );
665 return Err(Error::NotSupported(Some(error_message)));
666 }
667 }
668
669 if let Some(current_shadow_root) = self.shadow_root() {
672 if !current_shadow_root.is_declarative() ||
676 current_shadow_root.shadow_root_mode() != mode
677 {
678 return Err(Error::NotSupported(Some(
679 "Cannot attach a second shadow root to the same element".into(),
680 )));
681 }
682
683 for child in current_shadow_root.upcast::<Node>().children() {
685 child.remove_self(cx);
686 }
687
688 current_shadow_root.set_declarative(false);
690
691 return Ok(current_shadow_root);
693 }
694
695 let shadow_root = ShadowRoot::new(
702 cx,
703 self,
704 &self.node.owner_doc(),
705 mode,
706 slot_assignment_mode,
707 clonable,
708 is_ua_widget,
709 );
710
711 let node = self.upcast::<Node>();
715 if node.is_connected() {
716 node.remove_style_and_layout_data_from_subtree(cx.no_gc());
717 }
718 shadow_root.set_delegates_focus(delegates_focus);
720
721 if matches!(
724 self.get_custom_element_state(),
725 CustomElementState::Precustomized | CustomElementState::Custom
726 ) {
727 shadow_root.set_available_to_element_internals(true);
728 }
729
730 shadow_root.set_declarative(false);
732
733 shadow_root.set_serializable(serializable);
735
736 self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
738 shadow_root
739 .upcast::<Node>()
740 .set_containing_shadow_root(Some(&shadow_root));
741
742 let bind_context = BindContext::new(self.upcast(), IsShadowTree::Yes);
743 shadow_root.bind_to_tree(cx, &bind_context);
744
745 node.dirty(NodeDamage::Other);
746
747 Ok(shadow_root)
748 }
749
750 pub(crate) fn attach_ua_shadow_root(
766 &self,
767 cx: &mut JSContext,
768 use_ua_widget_styling: bool,
769 ) -> DomRoot<ShadowRoot> {
770 let root = self
771 .attach_shadow(
772 cx,
773 IsUserAgentWidget::Yes,
774 ShadowRootMode::Closed,
775 false,
776 false,
777 false,
778 SlotAssignmentMode::Manual,
779 )
780 .expect("Attaching UA shadow root failed");
781
782 root.upcast::<Node>()
783 .set_in_ua_widget(use_ua_widget_styling);
784 root
785 }
786
787 pub(crate) fn is_translate_enabled(&self) -> bool {
789 let name = &local_name!("translate");
790 if self.has_attribute(name) {
791 let attribute = self.get_string_attribute(name);
792 match_ignore_ascii_case! { &*attribute.str(),
793 "yes" | "" => return true,
794 "no" => return false,
795 _ => {},
796 }
797 }
798 if let Some(parent) = self.upcast::<Node>().GetParentNode() &&
799 let Some(elem) = parent.downcast::<Element>()
800 {
801 return elem.is_translate_enabled();
802 }
803 true
804 }
805
806 pub(crate) fn directionality(&self) -> String {
808 self.downcast::<HTMLElement>()
809 .and_then(|html_element| html_element.directionality())
810 .unwrap_or_else(|| {
811 let node = self.upcast::<Node>();
812 node.parent_directionality()
813 })
814 }
815
816 pub(crate) fn is_root(&self) -> bool {
817 match self.node.GetParentNode() {
818 None => false,
819 Some(node) => node.is::<Document>(),
820 }
821 }
822
823 pub(crate) fn registered_intersection_observers_mut(
826 &self,
827 ) -> RefMut<'_, Vec<IntersectionObserverRegistration>> {
828 RefMut::map(self.ensure_rare_data(), |rare_data| {
829 &mut rare_data.registered_intersection_observers
830 })
831 }
832
833 pub(crate) fn registered_intersection_observers(
834 &self,
835 ) -> Option<Ref<'_, Vec<IntersectionObserverRegistration>>> {
836 let rare_data: Ref<'_, _> = self.rare_data.borrow();
837
838 if rare_data.is_none() {
839 return None;
840 }
841 Some(Ref::map(rare_data, |rare_data| {
842 &rare_data
843 .as_ref()
844 .unwrap()
845 .registered_intersection_observers
846 }))
847 }
848
849 pub(crate) fn get_intersection_observer_registration(
850 &self,
851 observer: &IntersectionObserver,
852 ) -> Option<Ref<'_, IntersectionObserverRegistration>> {
853 if let Some(registrations) = self.registered_intersection_observers() {
854 registrations
855 .iter()
856 .position(|reg_obs| reg_obs.observer == observer)
857 .map(|index| Ref::map(registrations, |registrations| ®istrations[index]))
858 } else {
859 None
860 }
861 }
862
863 pub(crate) fn add_initial_intersection_observer_registration(
865 &self,
866 observer: &IntersectionObserver,
867 ) {
868 self.ensure_rare_data()
869 .registered_intersection_observers
870 .push(IntersectionObserverRegistration::new_initial(observer));
871 }
872
873 pub(crate) fn remove_intersection_observer(&self, observer: &IntersectionObserver) {
875 self.ensure_rare_data()
876 .registered_intersection_observers
877 .retain(|reg_obs| *reg_obs.observer != *observer)
878 }
879
880 pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
883 self.owner_window()
884 .scrolling_box_query(Some(self.upcast()), flags)
885 }
886
887 pub(crate) fn scroll_into_view_with_options(
889 &self,
890 cx: &mut JSContext,
891 behavior: ScrollBehavior,
892 block: ScrollAxisState,
893 inline: ScrollAxisState,
894 container: Option<&Element>,
895 inner_target_rect: Option<Rect<Au, CSSPixel>>,
896 ) {
897 let get_target_rect = || match inner_target_rect {
898 None => self.upcast::<Node>().border_box().unwrap_or_default(),
899 Some(inner_target_rect) => inner_target_rect.translate(
900 self.upcast::<Node>()
901 .content_box()
902 .unwrap_or_default()
903 .origin
904 .to_vector(),
905 ),
906 };
907
908 let mut parent_scrolling_box = self.scrolling_box(ScrollContainerQueryFlags::empty());
911 while let Some(scrolling_box) = parent_scrolling_box {
912 parent_scrolling_box = scrolling_box.parent();
913
914 let position = scrolling_box.determine_scroll_into_view_position(
925 cx.no_gc(),
926 block,
927 inline,
928 get_target_rect(),
929 );
930
931 if position != scrolling_box.scroll_position() {
936 scrolling_box.scroll_to(cx, position, behavior);
947 }
948
949 if container.is_some_and(|container| {
953 let container_node = container.upcast::<Node>();
954 scrolling_box
955 .node()
956 .is_shadow_including_inclusive_ancestor_of(container_node)
957 }) {
958 return;
959 }
960 }
961
962 let window_proxy = self.owner_window().window_proxy();
963 let Some(frame_element) = window_proxy.frame_element() else {
964 return;
965 };
966
967 let inner_target_rect = Some(get_target_rect());
968
969 let mut realm = enter_auto_realm(cx, frame_element);
970 let cx = &mut realm;
971
972 frame_element.scroll_into_view_with_options(
973 cx,
974 behavior,
975 block,
976 inline,
977 None,
978 inner_target_rect,
979 )
980 }
981
982 pub(crate) fn ensure_contenteditable_selection_range(
983 &self,
984 cx: &mut JSContext,
985 document: &Document,
986 ) -> DomRoot<Range> {
987 self.ensure_rare_data()
988 .contenteditable_selection_range
989 .or_init(|| Range::new_with_doc(cx, document, None))
990 }
991
992 pub(crate) fn handle_scroll_event(&self) {
997 let document = self.owner_document();
999
1000 document.finish_handle_scroll_event(self.upcast());
1009 }
1010
1011 pub(crate) fn style(&self) -> Option<ServoArc<ComputedValues>> {
1012 self.owner_window().layout_reflow(QueryMsg::StyleQuery);
1013 self.style_data
1014 .borrow()
1015 .as_ref()
1016 .map(|data| data.element_data.borrow().styles.primary().clone())
1017 }
1018
1019 pub(crate) fn is_styled(&self) -> bool {
1020 self.style_data.borrow().is_some()
1021 }
1022
1023 pub(crate) fn is_display_none(&self) -> bool {
1024 self.style_data.borrow().as_ref().is_none_or(|data| {
1025 data.element_data
1026 .borrow()
1027 .styles
1028 .primary()
1029 .get_box()
1030 .display
1031 .is_none()
1032 })
1033 }
1034
1035 pub(crate) fn check_style_on_self_or_eager_pseudos(
1036 &self,
1037 check_styles_fn: impl Fn(&ComputedValues) -> bool,
1038 ) -> bool {
1039 let style_data = self.style_data.borrow();
1040 let Some(data) = style_data.as_ref().map(|data| data.element_data.borrow()) else {
1041 return false;
1042 };
1043
1044 if check_styles_fn(data.styles.primary()) {
1045 return true;
1046 }
1047
1048 let mut pseudo_styles = data.styles.pseudos.as_array().iter();
1049 pseudo_styles.any(|style| style.as_deref().is_some_and(&check_styles_fn))
1050 }
1051}
1052
1053#[inline]
1055pub(crate) fn is_valid_shadow_host_name(name: &LocalName) -> bool {
1056 if is_valid_custom_element_name(name) {
1059 return true;
1060 }
1061
1062 matches!(
1065 name,
1066 &local_name!("article") |
1067 &local_name!("aside") |
1068 &local_name!("blockquote") |
1069 &local_name!("body") |
1070 &local_name!("div") |
1071 &local_name!("footer") |
1072 &local_name!("h1") |
1073 &local_name!("h2") |
1074 &local_name!("h3") |
1075 &local_name!("h4") |
1076 &local_name!("h5") |
1077 &local_name!("h6") |
1078 &local_name!("header") |
1079 &local_name!("main") |
1080 &local_name!("nav") |
1081 &local_name!("p") |
1082 &local_name!("section") |
1083 &local_name!("span")
1084 )
1085}
1086
1087#[inline]
1088#[expect(unsafe_code)]
1089pub(crate) fn get_attr_for_layout<'dom>(
1090 elem: LayoutDom<'dom, Element>,
1091 namespace: &Namespace,
1092 name: &LocalName,
1093) -> Option<&'dom AttrValue> {
1094 let storage = unsafe { elem.unsafe_get().attrs.borrow_for_layout() };
1095 storage
1096 .iter()
1097 .find(|e: &&AttributeEntry| {
1098 name == e.local_name_for_layout() && namespace == e.namespace_for_layout()
1099 })
1100 .map(|e: &AttributeEntry| e.value_for_layout())
1101}
1102
1103impl<'dom> LayoutDom<'dom, Element> {
1104 #[inline]
1105 pub(crate) fn is_root(&self) -> bool {
1106 self.upcast::<Node>()
1107 .parent_node_ref()
1108 .is_some_and(|parent| matches!(parent.type_id_for_layout(), NodeTypeId::Document(_)))
1109 }
1110
1111 pub(crate) fn is_body_element_of_html_element_root(&self) -> bool {
1113 if self.local_name() != &local_name!("body") {
1114 return false;
1115 }
1116 let Some(parent_node) = self.upcast::<Node>().parent_node_ref() else {
1117 return false;
1118 };
1119 let Some(parent_element) = parent_node.downcast::<Element>() else {
1120 return false;
1121 };
1122 parent_element.local_name() == &local_name!("html")
1123 }
1124
1125 #[expect(unsafe_code)]
1127 #[inline]
1128 pub(crate) fn each_attr_name_for_layout<F>(self, mut callback: F)
1129 where
1130 F: FnMut(&LocalName),
1131 {
1132 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1133 for entry in storage.iter() {
1134 callback(entry.local_name_for_layout());
1135 }
1136 }
1137
1138 #[inline]
1139 pub(crate) fn has_class_or_part_for_layout(
1140 self,
1141 name: &AtomIdent,
1142 attr_name: &LocalName,
1143 case_sensitivity: CaseSensitivity,
1144 ) -> bool {
1145 get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
1146 attr.as_tokens()
1147 .iter()
1148 .any(|atom| case_sensitivity.eq_atom(atom, name))
1149 })
1150 }
1151
1152 #[inline]
1153 pub(crate) fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
1154 get_attr_for_layout(self, &ns!(), &local_name!("class")).map(|attr| attr.as_tokens())
1155 }
1156
1157 pub(crate) fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
1158 get_attr_for_layout(self, &ns!(), &local_name!("part")).map(|attr| attr.as_tokens())
1159 }
1160
1161 #[inline]
1162 #[expect(unsafe_code)]
1163 pub(crate) fn style_data(self) -> Option<&'dom StyleData> {
1164 unsafe { self.unsafe_get().style_data.borrow_for_layout().as_deref() }
1165 }
1166
1167 #[inline]
1168 #[expect(unsafe_code)]
1169 pub(crate) unsafe fn initialize_style_data(self) {
1170 let data = unsafe { self.unsafe_get().style_data.borrow_mut_for_layout() };
1171 debug_assert!(data.is_none());
1172 *data = Some(Box::default());
1173 }
1174
1175 #[inline]
1176 #[expect(unsafe_code)]
1177 pub(crate) unsafe fn clear_style_data(self) {
1178 unsafe {
1179 self.unsafe_get().style_data.borrow_mut_for_layout().take();
1180 }
1181 }
1182
1183 pub(crate) fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1184 where
1185 V: Push<ApplicableDeclarationBlock>,
1186 {
1187 let document = self.upcast::<Node>().owner_doc_for_layout();
1190 let mut property_declaration_block = None;
1191 let mut push = |declaration| {
1192 property_declaration_block
1193 .get_or_insert_with(PropertyDeclarationBlock::default)
1194 .push(declaration, Importance::Normal);
1195 };
1196
1197 if let Some(lang) = self.get_lang_attr_val_for_layout() {
1200 push(PropertyDeclaration::XLang(specified::XLang(Atom::from(
1201 lang.to_owned(),
1202 ))));
1203 }
1204
1205 let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
1206 this.get_background_color()
1207 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1208 this.get_background_color()
1209 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1210 this.get_background_color()
1211 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1212 this.get_background_color()
1213 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1214 this.get_background_color()
1215 } else {
1216 None
1217 };
1218
1219 if let Some(color) = bgcolor {
1220 push(PropertyDeclaration::BackgroundColor(
1221 specified::Color::from_absolute_color(color),
1222 ));
1223 }
1224
1225 if is_element_affected_by_legacy_background_presentational_hint(
1226 self.namespace(),
1227 self.local_name(),
1228 ) && let Some(url) = self
1229 .get_attr_for_layout(&ns!(), &local_name!("background"))
1230 .and_then(AttrValue::as_resolved_url)
1231 .cloned()
1232 {
1233 push(PropertyDeclaration::BackgroundImage(
1234 background_image::SpecifiedValue(vec![specified::Image::for_cascade(url)].into()),
1235 ));
1236 }
1237
1238 let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
1239 this.get_color()
1240 } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
1241 this.get_color()
1243 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1244 this.get_color()
1246 } else {
1247 None
1248 };
1249
1250 if let Some(color) = color {
1251 push(PropertyDeclaration::Color(
1252 longhands::color::SpecifiedValue(specified::Color::from_absolute_color(color)),
1253 ));
1254 }
1255
1256 let font_face = self
1257 .downcast::<HTMLFontElement>()
1258 .and_then(LayoutDom::get_face);
1259 if let Some(font_face) = font_face {
1260 push(PropertyDeclaration::FontFamily(
1261 font_family::SpecifiedValue::Values(computed::font::FontFamilyList {
1262 list: ArcSlice::from_iter(
1263 HTMLFontElement::parse_face_attribute(font_face).into_iter(),
1264 ),
1265 }),
1266 ));
1267 }
1268
1269 let font_size = self
1270 .downcast::<HTMLFontElement>()
1271 .and_then(LayoutDom::get_size);
1272 if let Some(font_size) = font_size {
1273 push(PropertyDeclaration::FontSize(
1274 font_size::SpecifiedValue::from_html_size(font_size as u8),
1275 ));
1276 }
1277
1278 let size = self
1284 .downcast::<HTMLInputElement>()
1285 .and_then(|input_element| {
1286 match self.get_attr_val_for_layout(&ns!(), &local_name!("type")) {
1288 Some("hidden") | Some("range") | Some("color") | Some("checkbox") |
1289 Some("radio") | Some("file") | Some("submit") | Some("image") |
1290 Some("reset") | Some("button") => None,
1291 _ => match input_element.size_for_layout() {
1293 0 => None,
1294 s => Some(s as i32),
1295 },
1296 }
1297 });
1298
1299 if let Some(size) = size {
1300 let value = specified::NoCalcLength::from_servo_character_width(size);
1301 push(PropertyDeclaration::Width(
1302 specified::Size::LengthPercentage(NonNegative(
1303 specified::LengthPercentage::Length(value),
1304 )),
1305 ));
1306 }
1307
1308 let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1309 this.get_width()
1310 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1311 this.get_width()
1312 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1313 this.get_width()
1314 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1315 this.get_width()
1316 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1317 this.get_width()
1318 } else if let Some(this) = self.downcast::<HTMLTableColElement>() {
1319 this.get_width()
1320 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1321 this.get_width()
1323 } else {
1324 LengthOrPercentageOrAuto::Auto
1325 };
1326
1327 match width {
1329 LengthOrPercentageOrAuto::Auto => {},
1330 LengthOrPercentageOrAuto::Percentage(percentage) => {
1331 let width_value = specified::Size::LengthPercentage(NonNegative(
1332 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1333 percentage,
1334 )),
1335 ));
1336 push(PropertyDeclaration::Width(width_value));
1337 },
1338 LengthOrPercentageOrAuto::Length(length) => {
1339 let width_value = specified::Size::LengthPercentage(NonNegative(
1340 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1341 length.to_f32_px(),
1342 )),
1343 ));
1344 push(PropertyDeclaration::Width(width_value));
1345 },
1346 }
1347
1348 let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1349 this.get_height()
1350 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1351 this.get_height()
1352 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1353 this.get_height()
1354 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1355 this.get_height()
1356 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1357 this.get_height()
1358 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1359 this.get_height()
1360 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1361 this.get_height()
1362 } else {
1363 LengthOrPercentageOrAuto::Auto
1364 };
1365
1366 match height {
1367 LengthOrPercentageOrAuto::Auto => {},
1368 LengthOrPercentageOrAuto::Percentage(percentage) => {
1369 let height_value = specified::Size::LengthPercentage(NonNegative(
1370 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1371 percentage,
1372 )),
1373 ));
1374 push(PropertyDeclaration::Height(height_value));
1375 },
1376 LengthOrPercentageOrAuto::Length(length) => {
1377 let height_value = specified::Size::LengthPercentage(NonNegative(
1378 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1379 length.to_f32_px(),
1380 )),
1381 ));
1382 push(PropertyDeclaration::Height(height_value));
1383 },
1384 }
1385
1386 if let Some(svg_element) = self.downcast::<SVGElement>() {
1387 svg_element.synthesize_presentational_hints(document, &mut push);
1388 }
1389
1390 if (self.is::<HTMLImageElement>() || self.is::<HTMLVideoElement>()) &&
1393 let LengthOrPercentageOrAuto::Length(width) = width &&
1394 let LengthOrPercentageOrAuto::Length(height) = height
1395 {
1396 let width_value = NonNegative(specified::Number::new(width.to_f32_px()));
1397 let height_value = NonNegative(specified::Number::new(height.to_f32_px()));
1398 let aspect_ratio = specified::position::AspectRatio {
1399 auto: true,
1400 ratio: PreferredRatio::Ratio(Ratio(width_value, height_value)),
1401 };
1402 push(PropertyDeclaration::AspectRatio(Box::new(aspect_ratio)));
1403 }
1404
1405 let cols = self
1406 .downcast::<HTMLTextAreaElement>()
1407 .map(LayoutDom::get_cols);
1408 if let Some(cols) = cols {
1409 let cols = cols as i32;
1410 if cols > 0 {
1411 let value = specified::NoCalcLength::from_servo_character_width(cols);
1417 push(PropertyDeclaration::Width(
1418 specified::Size::LengthPercentage(NonNegative(
1419 specified::LengthPercentage::Length(value),
1420 )),
1421 ));
1422 }
1423 }
1424
1425 let rows = self
1426 .downcast::<HTMLTextAreaElement>()
1427 .map(LayoutDom::get_rows);
1428 if let Some(rows) = rows {
1429 let rows = rows as i32;
1430 if rows > 0 {
1431 let value = specified::NoCalcLength::from_em(rows as CSSFloat);
1435 push(PropertyDeclaration::Height(
1436 specified::Size::LengthPercentage(NonNegative(
1437 specified::LengthPercentage::Length(value),
1438 )),
1439 ));
1440 }
1441 }
1442
1443 if let Some(table) = self.downcast::<HTMLTableElement>() {
1444 if let Some(cellspacing) = table.get_cellspacing() {
1445 let width_value = specified::Length::from_px(cellspacing as f32);
1446 push(PropertyDeclaration::BorderSpacing(
1447 border_spacing::SpecifiedValue::new(
1448 width_value.clone().into(),
1449 width_value.into(),
1450 ),
1451 ));
1452 }
1453 if let Some(border) = table.get_border() {
1454 let width_value = specified::BorderSideWidth::from_px(border as f32);
1455 push(PropertyDeclaration::BorderTopWidth(width_value.clone()));
1456 push(PropertyDeclaration::BorderLeftWidth(width_value.clone()));
1457 push(PropertyDeclaration::BorderBottomWidth(width_value.clone()));
1458 push(PropertyDeclaration::BorderRightWidth(width_value));
1459 }
1460 if document.quirks_mode() == QuirksMode::Quirks {
1461 push(PropertyDeclaration::Color(color::SpecifiedValue(
1463 specified::Color::InheritFromBodyQuirk,
1464 )));
1465 }
1466 }
1467
1468 if let Some(cellpadding) = self
1469 .downcast::<HTMLTableCellElement>()
1470 .and_then(|this| this.get_table())
1471 .and_then(|table| table.get_cellpadding())
1472 {
1473 let cellpadding = NonNegative(specified::LengthPercentage::Length(
1474 specified::NoCalcLength::from_px(cellpadding as f32),
1475 ));
1476 push(PropertyDeclaration::PaddingTop(cellpadding.clone()));
1477 push(PropertyDeclaration::PaddingLeft(cellpadding.clone()));
1478 push(PropertyDeclaration::PaddingBottom(cellpadding.clone()));
1479 push(PropertyDeclaration::PaddingRight(cellpadding));
1480 }
1481
1482 if let Some(size_info) = self
1484 .downcast::<HTMLHRElement>()
1485 .and_then(|hr_element| hr_element.get_size_info())
1486 {
1487 match size_info {
1488 SizePresentationalHint::SetHeightTo(height) => {
1489 push(PropertyDeclaration::Height(height));
1490 },
1491 SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
1492 push(PropertyDeclaration::BorderLeftWidth(border_width.clone()));
1493 push(PropertyDeclaration::BorderRightWidth(border_width.clone()));
1494 push(PropertyDeclaration::BorderTopWidth(border_width.clone()));
1495 push(PropertyDeclaration::BorderBottomWidth(border_width));
1496 },
1497 SizePresentationalHint::SetBottomBorderWidthToZero => {
1498 push(PropertyDeclaration::BorderBottomWidth(
1499 specified::border::BorderSideWidth::from_px(0.),
1500 ));
1501 },
1502 }
1503 }
1504
1505 let Some(property_declaration_block) = property_declaration_block else {
1506 return;
1507 };
1508
1509 let shared_lock = &document.shared_style_locks().author;
1510 hints.push(ApplicableDeclarationBlock::from_declarations(
1511 ServoArc::new(shared_lock.wrap(property_declaration_block)),
1512 CascadeLevel::new(CascadeOrigin::PresHints),
1513 LayerOrder::root(),
1514 ));
1515 }
1516
1517 pub(crate) fn get_span(self) -> Option<u32> {
1518 self.downcast::<HTMLTableColElement>()
1520 .and_then(|element| element.get_span())
1521 }
1522
1523 pub(crate) fn get_colspan(self) -> Option<u32> {
1524 self.downcast::<HTMLTableCellElement>()
1526 .and_then(|element| element.get_colspan())
1527 }
1528
1529 pub(crate) fn get_rowspan(self) -> Option<u32> {
1530 self.downcast::<HTMLTableCellElement>()
1532 .and_then(|element| element.get_rowspan())
1533 }
1534
1535 #[inline]
1536 pub(crate) fn is_html_element(&self) -> bool {
1537 *self.namespace() == ns!(html)
1538 }
1539
1540 #[expect(unsafe_code)]
1541 pub(crate) fn id_attribute(self) -> *const Option<Atom> {
1542 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1543 }
1544
1545 #[expect(unsafe_code)]
1546 pub(crate) fn style_attribute(
1547 self,
1548 ) -> *const Option<ServoArc<Locked<PropertyDeclarationBlock>>> {
1549 unsafe { (self.unsafe_get()).style_attribute.borrow_for_layout() }
1550 }
1551
1552 pub(crate) fn local_name(self) -> &'dom LocalName {
1553 &(self.unsafe_get()).local_name
1554 }
1555
1556 pub(crate) fn namespace(self) -> &'dom Namespace {
1557 &(self.unsafe_get()).namespace
1558 }
1559
1560 pub(crate) fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1561 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1562 return Some(attr);
1563 }
1564 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1565 return Some(attr);
1566 }
1567 None
1568 }
1569
1570 pub(crate) fn get_lang_for_layout(self) -> AtomString {
1571 let mut current_node = Some(self.upcast::<Node>());
1572 while let Some(node) = current_node {
1573 current_node = node.composed_parent_node_ref();
1574 match node.downcast::<Element>() {
1575 Some(elem) => {
1576 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1577 return AtomString::from(attr);
1578 }
1579 },
1580 None => continue,
1581 }
1582 }
1583 AtomString::default()
1586 }
1587
1588 #[inline]
1589 pub(crate) fn get_state_for_layout(self) -> ElementState {
1590 (self.unsafe_get()).state.get()
1591 }
1592
1593 #[inline]
1594 pub(crate) fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1595 debug_assert!(thread_state::get().is_layout());
1596 self.unsafe_get().insert_selector_flags(flags);
1597 }
1598
1599 #[inline]
1600 pub(crate) fn get_selector_flags(self) -> ElementSelectorFlags {
1601 self.unsafe_get().get_selector_flags()
1602 }
1603
1604 #[inline]
1605 #[expect(unsafe_code)]
1606 pub(crate) fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1607 unsafe {
1608 self.unsafe_get()
1609 .rare_data
1610 .borrow_for_layout()
1611 .as_ref()?
1612 .shadow_root
1613 .as_ref()
1614 .map(|sr| sr.to_layout())
1615 }
1616 }
1617
1618 #[inline]
1619 pub(crate) fn get_attr_for_layout(
1620 self,
1621 namespace: &Namespace,
1622 name: &LocalName,
1623 ) -> Option<&'dom AttrValue> {
1624 get_attr_for_layout(self, namespace, name)
1625 }
1626
1627 #[inline]
1628 pub(crate) fn get_attr_val_for_layout(
1629 self,
1630 namespace: &Namespace,
1631 name: &LocalName,
1632 ) -> Option<&'dom str> {
1633 get_attr_for_layout(self, namespace, name).map(|attr| &**attr)
1634 }
1635
1636 #[inline]
1637 #[expect(unsafe_code)]
1638 pub(crate) fn get_attr_vals_for_layout(
1639 self,
1640 name: &LocalName,
1641 ) -> impl Iterator<Item = &'dom AttrValue> {
1642 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1643 storage
1644 .iter()
1645 .filter(move |e: &&AttributeEntry| name == e.local_name_for_layout())
1646 .map(|e: &AttributeEntry| e.value_for_layout())
1647 }
1648
1649 #[expect(unsafe_code)]
1650 pub(crate) fn each_custom_state_for_layout(self, mut callback: impl FnMut(&AtomIdent)) {
1651 let rare_data = unsafe { self.unsafe_get().rare_data.borrow_for_layout() };
1652 let Some(rare_data) = rare_data.as_ref() else {
1653 return;
1654 };
1655 let Some(element_internals) = rare_data.element_internals.as_ref() else {
1656 return;
1657 };
1658
1659 let element_internals: LayoutDom<'_, _> = unsafe { element_internals.to_layout() };
1660 if let Some(states) = element_internals.unsafe_get().custom_states_for_layout() {
1661 for state in unsafe { states.unsafe_get().set_for_layout().iter() } {
1662 callback(&AtomIdent::from(&*state.str()));
1664 }
1665 }
1666 }
1667}
1668
1669impl Element {
1670 pub(crate) fn is_html_element(&self) -> bool {
1671 self.namespace == ns!(html)
1672 }
1673
1674 pub(crate) fn is_svg_element(&self) -> bool {
1675 self.namespace == ns!(svg)
1676 }
1677
1678 pub(crate) fn html_element_in_html_document(&self) -> bool {
1679 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1680 }
1681
1682 pub(crate) fn local_name(&self) -> &LocalName {
1683 &self.local_name
1684 }
1685
1686 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1687 if self.html_element_in_html_document() {
1688 name.make_ascii_lowercase();
1689 }
1690 LocalName::from(name)
1691 }
1692
1693 pub(crate) fn namespace(&self) -> &Namespace {
1694 &self.namespace
1695 }
1696
1697 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1698 self.prefix.borrow()
1699 }
1700
1701 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1702 *self.prefix.borrow_mut() = prefix;
1703 }
1704
1705 pub(crate) fn set_custom_element_registry(&self, registry: Option<&CustomElementRegistry>) {
1706 self.ensure_rare_data().custom_element_registry = registry.map(Dom::from_ref);
1707 }
1708
1709 pub(crate) fn custom_element_registry(&self) -> Option<DomRoot<CustomElementRegistry>> {
1710 self.rare_data()
1711 .as_ref()?
1712 .custom_element_registry
1713 .as_deref()
1714 .map(DomRoot::from_ref)
1715 }
1716
1717 pub(crate) fn attrs(&self) -> &AttributeStorage {
1718 &self.attrs
1719 }
1720
1721 pub(crate) fn dom_attrs(&self, cx: &mut JSContext) -> &AttributeStorage {
1722 let len = self.attrs.borrow().len();
1724 for i in 0..len {
1725 self.attrs.ensure_dom(cx, i, self);
1726 }
1727 &self.attrs
1728 }
1729
1730 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1732 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1733
1734 if namespace_prefix == Some(namespace_prefix!("xml")) {
1736 return ns!(xml);
1737 }
1738
1739 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1741 return ns!(xmlns);
1742 }
1743
1744 let prefix = prefix.map(LocalName::from);
1745
1746 let inclusive_ancestor_elements = self
1747 .upcast::<Node>()
1748 .inclusive_ancestors(ShadowIncluding::No)
1749 .filter_map(DomRoot::downcast::<Self>);
1750
1751 for element in inclusive_ancestor_elements {
1754 if element.namespace() != &ns!() &&
1756 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1757 {
1758 return element.namespace().clone();
1759 }
1760
1761 let found_ns = element.attrs.borrow().iter().find_map(|attr| {
1766 if attr.namespace() != &ns!(xmlns) {
1767 return None;
1768 }
1769 match (attr.prefix(), prefix.as_ref()) {
1770 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1771 if attr.local_name() == prefix {
1772 Some(Namespace::from(&**attr.value()))
1773 } else {
1774 None
1775 }
1776 },
1777 (None, None) => {
1778 if attr.local_name() == &local_name!("xmlns") {
1779 Some(Namespace::from(&**attr.value()))
1780 } else {
1781 None
1782 }
1783 },
1784 _ => None,
1785 }
1786 });
1787
1788 if let Some(ns) = found_ns {
1789 return ns;
1790 }
1791 }
1792
1793 ns!()
1794 }
1795
1796 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1797 self.rare_data().as_ref()?.name_attribute.clone()
1798 }
1799
1800 pub(crate) fn style_attribute(
1801 &self,
1802 ) -> &DomRefCell<Option<ServoArc<Locked<PropertyDeclarationBlock>>>> {
1803 &self.style_attribute
1804 }
1805
1806 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1807 self.attrs
1808 .borrow()
1809 .iter()
1810 .map(|attr| attr.summarize())
1811 .collect()
1812 }
1813
1814 pub(crate) fn is_void(&self) -> bool {
1815 if self.namespace != ns!(html) {
1816 return false;
1817 }
1818 match self.local_name {
1819 local_name!("area") |
1822 local_name!("base") |
1823 local_name!("basefont") |
1824 local_name!("bgsound") |
1825 local_name!("br") |
1826 local_name!("col") |
1827 local_name!("embed") |
1828 local_name!("frame") |
1829 local_name!("hr") |
1830 local_name!("img") |
1831 local_name!("input") |
1832 local_name!("keygen") |
1833 local_name!("link") |
1834 local_name!("meta") |
1835 local_name!("param") |
1836 local_name!("source") |
1837 local_name!("track") |
1838 local_name!("wbr") => true,
1839 _ => false,
1840 }
1841 }
1842
1843 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1844 if self.node.is_in_a_document_tree() {
1845 self.upcast::<Node>()
1846 .owner_doc()
1847 .GetDocumentElement()
1848 .unwrap()
1849 } else {
1850 self.upcast::<Node>()
1851 .inclusive_ancestors(ShadowIncluding::No)
1852 .filter_map(DomRoot::downcast)
1853 .last()
1854 .expect("We know inclusive_ancestors will return `self` which is an element")
1855 }
1856 }
1857
1858 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1860 for node in self
1861 .upcast::<Node>()
1862 .inclusive_ancestors(ShadowIncluding::No)
1863 {
1864 let element = node.downcast::<Element>()?;
1865 if *element.namespace() == namespace &&
1867 let Some(prefix) = element.GetPrefix()
1868 {
1869 return Some(prefix);
1870 }
1871
1872 for attr in element.attrs.borrow().iter() {
1874 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1875 **attr.value() == *namespace
1876 {
1877 return Some(DOMString::from(&**attr.local_name()));
1878 }
1879 }
1880 }
1881 None
1882 }
1883
1884 pub(crate) fn is_document_element(&self) -> bool {
1886 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1887 *document_element == *self
1888 } else {
1889 false
1890 }
1891 }
1892
1893 pub(crate) fn is_active_element(&self) -> bool {
1895 if let Some(active_element) = self.owner_document().GetActiveElement() {
1896 *active_element == *self
1897 } else {
1898 false
1899 }
1900 }
1901
1902 pub(crate) fn is_editing_host(&self) -> bool {
1903 self.downcast::<HTMLElement>()
1904 .is_some_and(|element| element.IsContentEditable())
1905 }
1906
1907 pub(crate) fn is_actually_disabled(&self) -> bool {
1908 let node = self.upcast::<Node>();
1909 match node.type_id() {
1910 NodeTypeId::Element(ElementTypeId::HTMLElement(
1911 HTMLElementTypeId::HTMLButtonElement,
1912 )) |
1913 NodeTypeId::Element(ElementTypeId::HTMLElement(
1914 HTMLElementTypeId::HTMLInputElement,
1915 )) |
1916 NodeTypeId::Element(ElementTypeId::HTMLElement(
1917 HTMLElementTypeId::HTMLSelectElement,
1918 )) |
1919 NodeTypeId::Element(ElementTypeId::HTMLElement(
1920 HTMLElementTypeId::HTMLTextAreaElement,
1921 )) |
1922 NodeTypeId::Element(ElementTypeId::HTMLElement(
1923 HTMLElementTypeId::HTMLOptionElement,
1924 )) => self.disabled_state(),
1925 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1926 self.downcast::<HTMLElement>()
1927 .unwrap()
1928 .is_form_associated_custom_element() &&
1929 self.disabled_state()
1930 },
1931 _ => false,
1936 }
1937 }
1938
1939 #[allow(clippy::too_many_arguments)]
1940 pub(crate) fn push_new_attribute(
1941 &self,
1942 cx: &mut JSContext,
1943 local_name: LocalName,
1944 value: AttrValue,
1945 name: LocalName,
1946 namespace: Namespace,
1947 prefix: Option<Prefix>,
1948 reason: AttributeMutationReason,
1949 ) {
1950 let data = ContentAttributeData {
1955 identifier: AttrIdentifier {
1956 local_name: GenericAtomIdent(local_name),
1957 name: GenericAtomIdent(name),
1958 namespace: GenericAtomIdent(namespace),
1959 prefix: prefix.map(GenericAtomIdent),
1960 },
1961 value,
1962 };
1963 let attr_ref = AttrRef::Raw(&data);
1964 self.will_mutate_attr(attr_ref);
1965 self.attrs.push_raw(ContentAttributeData {
1967 identifier: data.identifier.clone(),
1968 value: data.value.clone(),
1969 });
1970 self.handle_attribute_changes(cx, attr_ref, None, Some(&*attr_ref.value()), reason);
1972 }
1973
1974 fn handle_attribute_changes(
1976 &self,
1977 cx: &mut JSContext,
1978 attr: AttrRef<'_>,
1979 old_value: Option<&AttrValue>,
1980 new_value: Option<&AttrValue>,
1981 reason: AttributeMutationReason,
1982 ) {
1983 let name = attr.local_name().clone();
1986 let namespace = attr.namespace().clone();
1987 let mutation = LazyCell::new(|| Mutation::Attribute {
1988 name: name.clone(),
1989 namespace: namespace.clone(),
1990 old_value: old_value.map(|old_value| DOMString::from(&**old_value)),
1991 });
1992 MutationObserver::queue_a_mutation_record(cx, &self.node, mutation);
1993
1994 let has_new_value = new_value.is_some();
1996
1997 if self.is_custom() {
2000 let reaction = CallbackReaction::AttributeChanged(
2001 attr.local_name().clone(),
2002 old_value,
2003 new_value,
2004 attr.namespace().clone(),
2005 );
2006 ScriptThread::enqueue_callback_reaction(cx, self, reaction, None);
2007 }
2008
2009 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
2011 let attribute_mutation = if has_new_value {
2012 AttributeMutation::Set(old_value, reason)
2013 } else {
2014 AttributeMutation::Removed
2015 };
2016 vtable_for(self.upcast()).attribute_mutated(cx, attr, attribute_mutation);
2017 }
2018 }
2019
2020 pub(crate) fn change_attribute(&self, cx: &mut JSContext, attr: &Attr, mut value: AttrValue) {
2022 let old_value = &attr.value().clone();
2026 self.will_mutate_attr(AttrRef::Dom(attr));
2028 attr.swap_value(&mut value);
2029 self.handle_attribute_changes(
2033 cx,
2034 AttrRef::Dom(attr),
2035 Some(old_value),
2036 Some(&*attr.value()),
2037 AttributeMutationReason::Directly,
2038 );
2039 }
2040
2041 pub(crate) fn push_attribute(
2043 &self,
2044 cx: &mut JSContext,
2045 attr: &Attr,
2046 reason: AttributeMutationReason,
2047 ) {
2048 assert!(attr.GetOwnerElement().as_deref() == Some(self));
2052 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
2056 self.will_mutate_attr(AttrRef::Dom(attr));
2058 self.attrs.push_dom(attr);
2059 self.handle_attribute_changes(cx, AttrRef::Dom(attr), None, Some(&*attr.value()), reason);
2063 }
2064
2065 pub(crate) fn with_attribute<R, F>(
2066 &self,
2067 namespace: &Namespace,
2068 local_name: &LocalName,
2069 map_func: F,
2070 ) -> Option<R>
2071 where
2072 F: FnOnce(AttrRef<'_>) -> R,
2073 {
2074 self.attrs
2075 .borrow()
2076 .iter()
2077 .find(|attribute| {
2078 attribute.local_name() == local_name && attribute.namespace() == namespace
2079 })
2080 .map(map_func)
2081 }
2082
2083 pub(crate) fn get_attribute_with_namespace(
2089 &self,
2090 cx: &mut JSContext,
2091 namespace: &Namespace,
2092 local_name: &LocalName,
2093 ) -> Option<DomRoot<Attr>> {
2094 let idx = self
2095 .attrs
2096 .borrow()
2097 .iter()
2098 .position(|a| a.local_name() == local_name && a.namespace() == namespace)?;
2099 Some(self.attrs.ensure_dom(cx, idx, self))
2100 }
2101
2102 pub(crate) fn get_attribute_by_name(
2104 &self,
2105 cx: &mut JSContext,
2106 name: DOMString,
2107 ) -> Option<DomRoot<Attr>> {
2108 let name = &self.parsed_name(name);
2109 let idx = self.attrs.borrow().iter().position(|a| a.name() == name)?;
2110 let attr_dom = Some(self.attrs.ensure_dom(cx, idx, self));
2111 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
2112 if *name == local_name!("id") || *name == local_name!("name") {
2113 match maybe_attr {
2114 None => true,
2115 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
2116 }
2117 } else {
2118 true
2119 }
2120 }
2121 debug_assert!(id_and_name_must_be_atoms(name, &attr_dom));
2122 attr_dom
2123 }
2124
2125 pub(crate) fn set_attribute_from_parser(
2126 &self,
2127 cx: &mut JSContext,
2128 qname: QualName,
2129 value: DOMString,
2130 prefix: Option<Prefix>,
2131 ) {
2132 if self
2134 .attrs
2135 .borrow()
2136 .iter()
2137 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
2138 {
2139 return;
2140 }
2141
2142 let name = match prefix {
2143 None => qname.local.clone(),
2144 Some(ref prefix) => {
2145 let name = format!("{}:{}", &**prefix, &*qname.local);
2146 LocalName::from(name)
2147 },
2148 };
2149 let value = self.parse_attribute(&qname.ns, &qname.local, value);
2150 self.push_new_attribute(
2151 cx,
2152 qname.local,
2153 value,
2154 name,
2155 qname.ns,
2156 prefix,
2157 AttributeMutationReason::ByParser,
2158 );
2159 }
2160
2161 pub(crate) fn set_attribute(&self, cx: &mut JSContext, name: &LocalName, value: AttrValue) {
2162 debug_assert_eq!(
2163 *name,
2164 name.to_ascii_lowercase(),
2165 "All attribute accesses should use a lowercase ASCII name"
2166 );
2167 debug_assert!(!name.contains(':'));
2168
2169 self.set_first_matching_attribute(
2170 cx,
2171 name.clone(),
2172 value,
2173 name.clone(),
2174 ns!(),
2175 None,
2176 |attr| attr.local_name() == name,
2177 );
2178 }
2179
2180 pub(crate) fn set_attribute_with_namespace(
2181 &self,
2182 cx: &mut JSContext,
2183 local_name: LocalName,
2184 value: AttrValue,
2185 name: LocalName,
2186 namespace: Namespace,
2187 prefix: Option<Prefix>,
2188 ) {
2189 self.set_first_matching_attribute(
2190 cx,
2191 local_name.clone(),
2192 value,
2193 name,
2194 namespace.clone(),
2195 prefix,
2196 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
2197 );
2198 }
2199
2200 #[allow(clippy::too_many_arguments)]
2202 fn set_first_matching_attribute<F>(
2203 &self,
2204 cx: &mut JSContext,
2205 local_name: LocalName,
2206 value: AttrValue,
2207 name: LocalName,
2208 namespace: Namespace,
2209 prefix: Option<Prefix>,
2210 find: F,
2211 ) where
2212 F: Fn(AttrRef<'_>) -> bool,
2213 {
2214 let found_idx = self.attrs.borrow().iter().position(find);
2217 if let Some(idx) = found_idx {
2218 let attr = self.attrs.ensure_dom(cx, idx, self);
2219 self.will_mutate_attr(AttrRef::Dom(&attr));
2221 self.change_attribute(cx, &attr, value);
2222 } else {
2223 self.push_new_attribute(
2228 cx,
2229 local_name,
2230 value,
2231 name,
2232 namespace,
2233 prefix,
2234 AttributeMutationReason::Directly,
2235 );
2236 };
2237 }
2238
2239 pub(crate) fn parse_attribute(
2240 &self,
2241 namespace: &Namespace,
2242 local_name: &LocalName,
2243 value: DOMString,
2244 ) -> AttrValue {
2245 if is_relevant_attribute(namespace, local_name) {
2246 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2247 } else {
2248 AttrValue::String(value.into())
2249 }
2250 }
2251
2252 pub(crate) fn remove_attribute(
2253 &self,
2254 cx: &mut JSContext,
2255 namespace: &Namespace,
2256 local_name: &LocalName,
2257 ) -> Option<DomRoot<Attr>> {
2258 self.remove_first_matching_attribute(cx, |attr| {
2259 attr.namespace() == namespace && attr.local_name() == local_name
2260 })
2261 }
2262
2263 pub(crate) fn remove_attribute_by_name(
2264 &self,
2265 cx: &mut JSContext,
2266 name: &LocalName,
2267 ) -> Option<DomRoot<Attr>> {
2268 self.remove_first_matching_attribute(cx, |attr| attr.name() == name)
2269 }
2270
2271 fn remove_first_matching_attribute<F>(
2273 &self,
2274 cx: &mut JSContext,
2275 find: F,
2276 ) -> Option<DomRoot<Attr>>
2277 where
2278 F: Fn(AttrRef<'_>) -> bool,
2279 {
2280 let idx = self.attrs.borrow().iter().position(find);
2281 idx.map(|idx| {
2282 let attr = self.attrs.ensure_dom(cx, idx, self);
2283
2284 self.will_mutate_attr(AttrRef::Dom(&attr));
2286 self.attrs.remove(idx);
2287 attr.set_owner(cx, None);
2289 self.handle_attribute_changes(
2291 cx,
2292 AttrRef::Dom(&attr),
2293 Some(&attr.value()),
2294 None,
2295 AttributeMutationReason::Directly,
2296 );
2297
2298 attr
2299 })
2300 }
2301
2302 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2303 self.any_tokenlist_attribute(&local_name!("class"), |atom| {
2304 case_sensitivity.eq_atom(name, atom)
2305 })
2306 }
2307
2308 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2309 debug_assert_eq!(
2310 *local_name,
2311 local_name.to_ascii_lowercase(),
2312 "All attribute accesses should use a lowercase ASCII name"
2313 );
2314 debug_assert!(!local_name.contains(':'));
2315 self.attrs
2316 .borrow()
2317 .iter()
2318 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2319 }
2320
2321 pub(crate) fn will_mutate_attr(&self, attr: AttrRef<'_>) {
2322 let node = self.upcast::<Node>();
2323 node.owner_doc().element_attr_will_change(self, attr);
2324 }
2325
2326 fn update_style_attribute(
2328 &self,
2329 cx: &mut JSContext,
2330 attr: AttrRef<'_>,
2331 mutation: AttributeMutation,
2332 ) {
2333 let doc = self.upcast::<Node>().owner_doc();
2334 *self.style_attribute.borrow_mut() = match mutation {
2336 AttributeMutation::Set(..) => {
2337 let value = attr.as_attr().map_or_else(
2338 || attr.value(),
2339 |attribute| AttrValueRef::Borrowed(attribute.value()),
2340 );
2341
2342 Some(match &*value {
2343 AttrValue::Declaration { block, .. } => block.clone(),
2344 _ => {
2345 let win = self.owner_window();
2346 let source = &**attr.value();
2347 let global = &self.owner_global();
2348 if global
2353 .get_csp_list()
2354 .should_elements_inline_type_behavior_be_blocked(
2355 cx,
2356 global,
2357 self,
2358 InlineCheckType::StyleAttribute,
2359 source,
2360 doc.get_current_parser_line(),
2361 )
2362 {
2363 return;
2364 }
2365 ServoArc::new(doc.style_shared_author_lock().wrap(parse_style_attribute(
2366 source,
2367 &UrlExtraData(doc.base_url().get_arc()),
2368 Some(win.css_error_reporter()),
2369 doc.quirks_mode(),
2370 CssRuleType::Style,
2371 )))
2372 },
2373 })
2374 },
2375 AttributeMutation::Removed => None,
2376 };
2377 }
2378
2379 fn set_attribute_node(
2383 &self,
2384 cx: &mut JSContext,
2385 attr: &Attr,
2386 ) -> Fallible<Option<DomRoot<Attr>>> {
2387 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2391 cx,
2392 self.namespace(),
2393 self.local_name(),
2394 attr.local_name(),
2395 Some(attr.namespace()),
2396 TrustedTypeOrString::String(attr.Value()),
2397 &self.owner_global(),
2398 )?;
2399
2400 if let Some(owner) = attr.GetOwnerElement() &&
2403 &*owner != self
2404 {
2405 return Err(Error::InUseAttribute(None));
2406 }
2407
2408 let vtable = vtable_for(self.upcast());
2409
2410 attr.swap_value(
2416 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2417 );
2418
2419 let position = self.attrs.borrow().iter().position(|old_attr| {
2421 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2422 });
2423
2424 let old_attr = if let Some(position) = position {
2425 let old_attr = self.attrs.ensure_dom(cx, position, self);
2426
2427 if &*old_attr == attr {
2429 return Ok(Some(DomRoot::from_ref(attr)));
2430 }
2431
2432 self.will_mutate_attr(AttrRef::Dom(attr));
2442 self.attrs
2443 .set(position, AttributeEntry::Dom(Dom::from_ref(attr)));
2444 attr.set_owner(cx, Some(self));
2446 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2448 old_attr.set_owner(cx, None);
2450 self.handle_attribute_changes(
2452 cx,
2453 AttrRef::Dom(attr),
2454 Some(&old_attr.value()),
2455 Some(&AttrValue::String(verified_value.into())),
2456 AttributeMutationReason::Directly,
2457 );
2458
2459 Some(old_attr)
2460 } else {
2461 attr.set_owner(cx, Some(self));
2463 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2464 self.push_attribute(cx, attr, AttributeMutationReason::Directly);
2465
2466 None
2467 };
2468
2469 Ok(old_attr)
2471 }
2472
2473 pub(crate) fn update_nonce_internal_slot(&self, nonce: String) {
2475 self.ensure_rare_data().cryptographic_nonce = nonce;
2476 }
2477
2478 pub(crate) fn nonce_value(&self) -> String {
2480 match self.rare_data().as_ref() {
2481 None => String::new(),
2482 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2483 }
2484 }
2485
2486 pub(crate) fn update_nonce_post_connection(&self, cx: &mut JSContext) {
2488 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2491 return;
2492 }
2493 let global = self.owner_global();
2494 let csp_list = match global.get_csp_list() {
2496 None => return,
2497 Some(csp_list) => csp_list,
2498 };
2499 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2502 self.get_string_attribute(&local_name!("nonce")).is_empty()
2503 {
2504 return;
2505 }
2506 let nonce = self.nonce_value();
2508 self.set_string_attribute(cx, &local_name!("nonce"), "".into());
2510 self.update_nonce_internal_slot(nonce);
2512 }
2513
2514 pub(crate) fn is_nonceable(&self) -> bool {
2516 if !self.has_attribute(&local_name!("nonce")) {
2518 return false;
2519 }
2520 if self.is::<HTMLScriptElement>() {
2522 for attr in self.attrs().borrow().iter() {
2523 let attr_name = attr.name().to_ascii_lowercase();
2526 if attr_name.contains("<script") || attr_name.contains("<style") {
2527 return false;
2528 }
2529 let attr_value = attr.value().to_ascii_lowercase();
2532 if attr_value.contains("<script") || attr_value.contains("<style") {
2533 return false;
2534 }
2535 }
2536 }
2537 if self
2539 .rare_data()
2540 .as_ref()
2541 .is_some_and(|d| d.had_duplicate_attributes)
2542 {
2543 return false;
2544 }
2545 true
2547 }
2548
2549 pub(crate) fn insert_adjacent(
2551 &self,
2552 cx: &mut JSContext,
2553 where_: AdjacentPosition,
2554 node: &Node,
2555 ) -> Fallible<Option<DomRoot<Node>>> {
2556 let self_node = self.upcast::<Node>();
2557 match where_ {
2558 AdjacentPosition::BeforeBegin => {
2559 if let Some(parent) = self_node.GetParentNode() {
2560 Node::pre_insert(cx, node, &parent, Some(self_node)).map(Some)
2561 } else {
2562 Ok(None)
2563 }
2564 },
2565 AdjacentPosition::AfterBegin => {
2566 Node::pre_insert(cx, node, self_node, self_node.GetFirstChild().as_deref())
2567 .map(Some)
2568 },
2569 AdjacentPosition::BeforeEnd => Node::pre_insert(cx, node, self_node, None).map(Some),
2570 AdjacentPosition::AfterEnd => {
2571 if let Some(parent) = self_node.GetParentNode() {
2572 Node::pre_insert(cx, node, &parent, self_node.GetNextSibling().as_deref())
2573 .map(Some)
2574 } else {
2575 Ok(None)
2576 }
2577 },
2578 }
2579 }
2580
2581 pub(crate) fn scroll(&self, cx: &mut JSContext, x: f64, y: f64, behavior: ScrollBehavior) {
2586 let x = if x.is_finite() { x } else { 0.0 } as f32;
2588 let y = if y.is_finite() { y } else { 0.0 } as f32;
2589
2590 let node = self.upcast::<Node>();
2591
2592 let doc = node.owner_doc();
2594
2595 if !doc.is_fully_active() {
2597 return;
2598 }
2599
2600 let win = match doc.GetDefaultView() {
2602 None => return,
2603 Some(win) => win,
2604 };
2605
2606 if *self.root_element() == *self {
2608 if doc.quirks_mode() != QuirksMode::Quirks {
2609 win.scroll(cx, x, y, behavior);
2610 }
2611
2612 return;
2613 }
2614
2615 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2617 doc.quirks_mode() == QuirksMode::Quirks &&
2618 !self.is_potentially_scrollable_body()
2619 {
2620 win.scroll(cx, x, y, behavior);
2621 return;
2622 }
2623
2624 if !self.has_scrolling_box(cx.no_gc()) {
2626 return;
2627 }
2628
2629 win.scroll_an_element(cx, self, x, y, behavior);
2631 }
2632
2633 pub(crate) fn parse_fragment(
2635 &self,
2636 markup: DOMString,
2637 cx: &mut JSContext,
2638 ) -> Fallible<DomRoot<DocumentFragment>> {
2639 let new_children = ServoParser::parse_html_fragment(cx, self, markup, false);
2642 let context_document = {
2645 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2646 template.Content(cx).upcast::<Node>().owner_doc()
2647 } else {
2648 self.owner_document()
2649 }
2650 };
2651 let fragment = DocumentFragment::new(cx, &context_document);
2652 for child in new_children {
2654 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
2655 }
2656 Ok(fragment)
2658 }
2659
2660 pub(crate) fn fragment_parsing_context(
2663 cx: &mut JSContext,
2664 owner_doc: &Document,
2665 element: Option<&Self>,
2666 ) -> DomRoot<Self> {
2667 match element {
2669 Some(elem)
2670 if elem.local_name() != &local_name!("html") ||
2674 !elem.html_element_in_html_document() =>
2675 {
2676 DomRoot::from_ref(elem)
2677 },
2678 _ => Element::create(
2681 cx,
2682 QualName::new(None, ns!(html), local_name!("body")),
2683 None,
2684 owner_doc,
2685 ElementCreator::ScriptCreated,
2686 CustomElementCreationMode::Asynchronous,
2687 None
2688 ),
2689 }
2690 }
2691
2692 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2694 where
2695 T: DerivedFrom<Element> + DomObject,
2696 {
2697 let other = other.upcast::<Element>();
2698 self.root_element() == other.root_element()
2699 }
2700
2701 pub(crate) fn get_id(&self) -> Option<Atom> {
2702 self.id_attribute.borrow().clone()
2703 }
2704
2705 pub(crate) fn get_name(&self) -> Option<Atom> {
2706 self.rare_data().as_ref()?.name_attribute.clone()
2707 }
2708
2709 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2710 self.rare_data()
2711 .as_ref()?
2712 .element_internals
2713 .as_ref()
2714 .map(|sr| DomRoot::from_ref(&**sr))
2715 }
2716
2717 pub(crate) fn ensure_element_internals(&self, cx: &mut JSContext) -> DomRoot<ElementInternals> {
2718 let mut rare_data = self.ensure_rare_data();
2719 DomRoot::from_ref(rare_data.element_internals.get_or_insert_with(|| {
2720 let elem = self
2721 .downcast::<HTMLElement>()
2722 .expect("ensure_element_internals should only be called for an HTMLElement");
2723 Dom::from_ref(&*ElementInternals::new(cx, elem))
2724 }))
2725 }
2726
2727 pub(crate) fn outer_html(&self, cx: &mut JSContext) -> Fallible<DOMString> {
2728 match self.GetOuterHTML(cx)? {
2729 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2730 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2731 }
2732 }
2733
2734 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2735 SourcePosition {
2736 source_file: self.owner_global().get_url().to_string(),
2737 line_number: line_number + 2,
2738 column_number: 0,
2739 }
2740 }
2741
2742 pub(crate) fn explicitly_set_tab_index(&self) -> Option<i32> {
2743 if self.has_attribute(&local_name!("tabindex")) {
2744 Some(self.get_int_attribute(&local_name!("tabindex"), 0))
2745 } else {
2746 None
2747 }
2748 }
2749
2750 pub(crate) fn tab_index(&self) -> i32 {
2752 if let Some(tab_index) = self.explicitly_set_tab_index() {
2758 return tab_index;
2759 }
2760
2761 if matches!(
2767 self.upcast::<Node>().type_id(),
2768 NodeTypeId::Element(ElementTypeId::HTMLElement(
2769 HTMLElementTypeId::HTMLAnchorElement |
2770 HTMLElementTypeId::HTMLAreaElement |
2771 HTMLElementTypeId::HTMLButtonElement |
2772 HTMLElementTypeId::HTMLFrameElement |
2773 HTMLElementTypeId::HTMLIFrameElement |
2774 HTMLElementTypeId::HTMLInputElement |
2775 HTMLElementTypeId::HTMLObjectElement |
2776 HTMLElementTypeId::HTMLSelectElement |
2777 HTMLElementTypeId::HTMLTextAreaElement
2778 ))
2779 ) {
2780 return 0;
2781 }
2782 if self
2783 .downcast::<HTMLElement>()
2784 .is_some_and(|html_element| html_element.is_a_summary_for_its_parent_details())
2785 {
2786 return 0;
2787 }
2788
2789 -1
2790 }
2791
2792 #[inline]
2793 fn insert_selector_flags(&self, flags: ElementSelectorFlags) {
2794 self.selector_flags
2795 .fetch_or(flags.bits(), Ordering::Relaxed);
2796 }
2797
2798 #[inline]
2799 fn get_selector_flags(&self) -> ElementSelectorFlags {
2800 ElementSelectorFlags::from_bits_retain(self.selector_flags.load(Ordering::Relaxed))
2801 }
2802
2803 pub(crate) fn needs_preserved_style_attribute_after_change(&self) -> bool {
2808 self.owner_window().get_exists_mut_observer() ||
2815 self.get_custom_element_definition()
2816 .is_some_and(|custom_element_definition| {
2817 custom_element_definition.has_attribute_changed_callback()
2818 })
2819 }
2820
2821 pub(crate) fn register_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2822 if let Some(shadow_root) = self.containing_shadow_root() {
2823 if let Some(ref id) = *self.id_attribute.borrow() {
2824 shadow_root.register_element_id(self, id);
2825 }
2826 } else {
2827 let document = self.owner_document();
2828 if let Some(ref id) = *self.id_attribute.borrow() {
2829 document.register_element_id(cx, self, id);
2830 }
2831 if let Some(ref name) = self.name_attribute() {
2832 document.register_element_name(self, name);
2833 }
2834 }
2835 }
2836
2837 pub(crate) fn unregister_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2838 if let Some(shadow_root) = self.containing_shadow_root() {
2839 if self.upcast::<Node>().is_in_a_shadow_tree() {
2843 return;
2844 }
2845 if let Some(ref id) = *self.id_attribute.borrow() {
2846 shadow_root.unregister_element_id(id);
2847 }
2848 } else {
2849 let document = self.owner_document();
2850 if let Some(ref id) = *self.id_attribute.borrow() {
2851 document.unregister_element_id(cx, id);
2852 }
2853 if let Some(ref name) = self.name_attribute() {
2854 document.unregister_element_name(name);
2855 }
2856 }
2857 }
2858}
2859
2860impl ElementMethods<crate::DomTypeHolder> for Element {
2861 fn GetNamespaceURI(&self) -> Option<DOMString> {
2863 Node::namespace_to_string(self.namespace.clone())
2864 }
2865
2866 fn LocalName(&self) -> DOMString {
2868 DOMString::from(&*self.local_name)
2870 }
2871
2872 fn GetPrefix(&self) -> Option<DOMString> {
2874 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2875 }
2876
2877 fn TagName(&self) -> DOMString {
2879 let name = self.tag_name.or_init(|| {
2880 let qualified_name = match *self.prefix.borrow() {
2881 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2882 None => Cow::Borrowed(&*self.local_name),
2883 };
2884 if self.html_element_in_html_document() {
2885 LocalName::from(qualified_name.to_ascii_uppercase())
2886 } else {
2887 LocalName::from(qualified_name)
2888 }
2889 });
2890 DOMString::from(&*name)
2891 }
2892
2893 fn Id(&self) -> DOMString {
2897 self.get_string_attribute(&local_name!("id"))
2898 }
2899
2900 fn SetId(&self, cx: &mut JSContext, id: DOMString) {
2902 self.set_atomic_attribute(cx, &local_name!("id"), id);
2903 }
2904
2905 fn ClassName(&self) -> DOMString {
2907 self.get_string_attribute(&local_name!("class"))
2908 }
2909
2910 fn SetClassName(&self, cx: &mut JSContext, class: DOMString) {
2912 self.set_tokenlist_attribute(cx, &local_name!("class"), class);
2913 }
2914
2915 fn ClassList(&self, cx: &mut js::context::JSContext) -> DomRoot<DOMTokenList> {
2917 self.class_list
2918 .or_init(|| DOMTokenList::new(cx, self, &local_name!("class"), None))
2919 }
2920
2921 make_getter!(Slot, "slot");
2923
2924 make_setter!(SetSlot, "slot");
2926
2927 fn Attributes(&self, cx: &mut JSContext) -> DomRoot<NamedNodeMap> {
2929 self.attr_list
2930 .or_init(|| NamedNodeMap::new(cx, &self.owner_window(), self))
2931 }
2932
2933 fn HasAttributes(&self) -> bool {
2935 !self.attrs.borrow().is_empty()
2936 }
2937
2938 fn GetAttributeNames(&self) -> Vec<DOMString> {
2940 self.attrs
2941 .borrow()
2942 .iter()
2943 .map(|attr| DOMString::from(&**attr.name()))
2944 .collect()
2945 }
2946
2947 fn GetAttribute(&self, cx: &mut JSContext, name: DOMString) -> Option<DOMString> {
2949 self.GetAttributeNode(cx, name).map(|s| s.Value())
2950 }
2951
2952 fn GetAttributeNS(
2954 &self,
2955 cx: &mut JSContext,
2956 namespace: Option<DOMString>,
2957 local_name: DOMString,
2958 ) -> Option<DOMString> {
2959 self.GetAttributeNodeNS(cx, namespace, local_name)
2960 .map(|attr| attr.Value())
2961 }
2962
2963 fn GetAttributeNode(&self, cx: &mut JSContext, name: DOMString) -> Option<DomRoot<Attr>> {
2965 self.get_attribute_by_name(cx, name)
2966 }
2967
2968 fn GetAttributeNodeNS(
2970 &self,
2971 cx: &mut JSContext,
2972 namespace: Option<DOMString>,
2973 local_name: DOMString,
2974 ) -> Option<DomRoot<Attr>> {
2975 let namespace = &namespace_from_domstring(namespace);
2976 self.get_attribute_with_namespace(cx, namespace, &LocalName::from(local_name))
2977 }
2978
2979 fn ToggleAttribute(
2981 &self,
2982 cx: &mut JSContext,
2983 name: DOMString,
2984 force: Option<bool>,
2985 ) -> Fallible<bool> {
2986 if !is_valid_attribute_local_name(&name.str()) {
2989 return Err(Error::InvalidCharacter(None));
2990 }
2991
2992 let attribute = self.GetAttribute(cx, name.clone());
2994
2995 let name = self.parsed_name(name);
2997 match attribute {
2998 None => match force {
3000 None | Some(true) => {
3002 self.set_first_matching_attribute(
3003 cx,
3004 name.clone(),
3005 AttrValue::String(String::new()),
3006 name.clone(),
3007 ns!(),
3008 None,
3009 |attr| *attr.name() == name,
3010 );
3011 Ok(true)
3012 },
3013 Some(false) => Ok(false),
3015 },
3016 Some(_index) => match force {
3017 None | Some(false) => {
3019 self.remove_attribute_by_name(cx, &name);
3020 Ok(false)
3021 },
3022 Some(true) => Ok(true),
3024 },
3025 }
3026 }
3027
3028 fn SetAttribute(
3030 &self,
3031 cx: &mut JSContext,
3032 name: DOMString,
3033 value: TrustedTypeOrString,
3034 ) -> ErrorResult {
3035 if !is_valid_attribute_local_name(&name.str()) {
3038 return Err(Error::InvalidCharacter(None));
3039 }
3040
3041 let name = self.parsed_name(name);
3044
3045 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3049 cx,
3050 self.namespace(),
3051 self.local_name(),
3052 &name,
3053 None,
3054 value,
3055 &self.owner_global(),
3056 )?;
3057
3058 let value = self.parse_attribute(&ns!(), &name, value);
3063 self.set_first_matching_attribute(
3064 cx,
3065 name.clone(),
3066 value,
3067 name.clone(),
3068 ns!(),
3069 None,
3070 |attr| *attr.name() == name,
3071 );
3072 Ok(())
3073 }
3074
3075 fn SetAttributeNS(
3077 &self,
3078 cx: &mut JSContext,
3079 namespace: Option<DOMString>,
3080 qualified_name: DOMString,
3081 value: TrustedTypeOrString,
3082 ) -> ErrorResult {
3083 let (namespace, prefix, local_name) =
3085 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3086 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3089 cx,
3090 self.namespace(),
3091 self.local_name(),
3092 &local_name,
3093 Some(&namespace),
3094 value,
3095 &self.owner_global(),
3096 )?;
3097 let value = self.parse_attribute(&namespace, &local_name, value);
3099 self.set_attribute_with_namespace(
3100 cx,
3101 local_name,
3102 value,
3103 LocalName::from(qualified_name),
3104 namespace,
3105 prefix,
3106 );
3107 Ok(())
3108 }
3109
3110 fn SetAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
3112 self.set_attribute_node(cx, attr)
3113 }
3114
3115 fn SetAttributeNodeNS(
3117 &self,
3118 cx: &mut JSContext,
3119 attr: &Attr,
3120 ) -> Fallible<Option<DomRoot<Attr>>> {
3121 self.set_attribute_node(cx, attr)
3122 }
3123
3124 fn RemoveAttribute(&self, cx: &mut JSContext, name: DOMString) {
3126 let name = self.parsed_name(name);
3127 self.remove_attribute_by_name(cx, &name);
3128 }
3129
3130 fn RemoveAttributeNS(
3132 &self,
3133 cx: &mut JSContext,
3134 namespace: Option<DOMString>,
3135 local_name: DOMString,
3136 ) {
3137 let namespace = namespace_from_domstring(namespace);
3138 let local_name = LocalName::from(local_name);
3139 self.remove_attribute(cx, &namespace, &local_name);
3140 }
3141
3142 fn RemoveAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<DomRoot<Attr>> {
3144 self.remove_first_matching_attribute(cx, |a| {
3147 a.as_attr().is_some_and(|a| std::ptr::eq(a, attr))
3148 })
3149 .ok_or(Error::NotFound(None))
3150 }
3151
3152 fn HasAttribute(&self, cx: &mut JSContext, name: DOMString) -> bool {
3154 self.GetAttribute(cx, name).is_some()
3155 }
3156
3157 fn HasAttributeNS(
3159 &self,
3160 cx: &mut JSContext,
3161 namespace: Option<DOMString>,
3162 local_name: DOMString,
3163 ) -> bool {
3164 self.GetAttributeNS(cx, namespace, local_name).is_some()
3165 }
3166
3167 fn GetElementsByTagName(
3169 &self,
3170 cx: &mut JSContext,
3171 localname: DOMString,
3172 ) -> DomRoot<HTMLCollection> {
3173 let window = self.owner_window();
3174 HTMLCollection::by_qualified_name(cx, &window, self.upcast(), LocalName::from(localname))
3175 }
3176
3177 fn GetElementsByTagNameNS(
3179 &self,
3180 cx: &mut JSContext,
3181 maybe_ns: Option<DOMString>,
3182 localname: DOMString,
3183 ) -> DomRoot<HTMLCollection> {
3184 let window = self.owner_window();
3185 HTMLCollection::by_tag_name_ns(cx, &window, self.upcast(), localname, maybe_ns)
3186 }
3187
3188 fn GetElementsByClassName(
3190 &self,
3191 cx: &mut JSContext,
3192 classes: DOMString,
3193 ) -> DomRoot<HTMLCollection> {
3194 let window = self.owner_window();
3195 HTMLCollection::by_class_name(cx, &window, self.upcast(), classes)
3196 }
3197
3198 fn GetClientRects(&self, cx: &mut JSContext) -> DomRoot<DOMRectList> {
3200 let win = self.owner_window();
3201 let raw_rects = self.upcast::<Node>().border_boxes();
3202 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3203 .into_iter()
3204 .map(|rect| {
3205 DOMRect::new(
3206 cx,
3207 win.upcast(),
3208 rect.origin.x.to_f64_px(),
3209 rect.origin.y.to_f64_px(),
3210 rect.size.width.to_f64_px(),
3211 rect.size.height.to_f64_px(),
3212 )
3213 })
3214 .collect();
3215 DOMRectList::new(cx, &win, rects)
3216 }
3217
3218 fn GetBoundingClientRect(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
3220 let win = self.owner_window();
3221 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3222 debug_assert!(rect.size.width.to_f64_px() >= 0.0 && rect.size.height.to_f64_px() >= 0.0);
3223 DOMRect::new(
3224 cx,
3225 win.upcast(),
3226 rect.origin.x.to_f64_px(),
3227 rect.origin.y.to_f64_px(),
3228 rect.size.width.to_f64_px(),
3229 rect.size.height.to_f64_px(),
3230 )
3231 }
3232
3233 fn Scroll(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3235 let left = options.left.unwrap_or(self.ScrollLeft());
3237 let top = options.top.unwrap_or(self.ScrollTop());
3238 self.scroll(cx, left, top, options.parent.behavior);
3239 }
3240
3241 fn Scroll_(&self, cx: &mut JSContext, x: f64, y: f64) {
3243 self.scroll(cx, x, y, ScrollBehavior::Auto);
3244 }
3245
3246 fn ScrollTo(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3248 self.Scroll(cx, options);
3249 }
3250
3251 fn ScrollTo_(&self, cx: &mut JSContext, x: f64, y: f64) {
3253 self.Scroll_(cx, x, y);
3254 }
3255
3256 fn ScrollBy(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3258 let delta_left = options.left.unwrap_or(0.0f64);
3260 let delta_top = options.top.unwrap_or(0.0f64);
3261 let left = self.ScrollLeft();
3262 let top = self.ScrollTop();
3263 self.scroll(
3264 cx,
3265 left + delta_left,
3266 top + delta_top,
3267 options.parent.behavior,
3268 );
3269 }
3270
3271 fn ScrollBy_(&self, cx: &mut JSContext, x: f64, y: f64) {
3273 let left = self.ScrollLeft();
3274 let top = self.ScrollTop();
3275 self.scroll(cx, left + x, top + y, ScrollBehavior::Auto);
3276 }
3277
3278 fn ScrollTop(&self) -> f64 {
3280 let node = self.upcast::<Node>();
3281
3282 let doc = node.owner_doc();
3284
3285 if !doc.is_fully_active() {
3287 return 0.0;
3288 }
3289
3290 let win = match doc.GetDefaultView() {
3292 None => return 0.0,
3293 Some(win) => win,
3294 };
3295
3296 if self.is_document_element() {
3298 if doc.quirks_mode() == QuirksMode::Quirks {
3299 return 0.0;
3300 }
3301
3302 return win.ScrollY() as f64;
3304 }
3305
3306 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3308 doc.quirks_mode() == QuirksMode::Quirks &&
3309 !self.is_potentially_scrollable_body()
3310 {
3311 return win.ScrollY() as f64;
3312 }
3313
3314 if !self.has_css_layout_box() {
3316 return 0.0;
3317 }
3318
3319 let point = win.scroll_offset_query(node);
3321 point.y.abs() as f64
3322 }
3323
3324 fn SetScrollTop(&self, cx: &mut JSContext, y_: f64) {
3327 let behavior = ScrollBehavior::Auto;
3328
3329 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3331
3332 let node = self.upcast::<Node>();
3333
3334 let doc = node.owner_doc();
3336
3337 if !doc.is_fully_active() {
3339 return;
3340 }
3341
3342 let win = match doc.GetDefaultView() {
3344 None => return,
3345 Some(win) => win,
3346 };
3347
3348 if self.is_document_element() {
3350 if doc.quirks_mode() != QuirksMode::Quirks {
3351 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3352 }
3353
3354 return;
3355 }
3356
3357 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3359 doc.quirks_mode() == QuirksMode::Quirks &&
3360 !self.is_potentially_scrollable_body()
3361 {
3362 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3363 return;
3364 }
3365
3366 if !self.has_scrolling_box(cx.no_gc()) {
3368 return;
3369 }
3370
3371 win.scroll_an_element(cx, self, self.ScrollLeft() as f32, y, behavior);
3373 }
3374
3375 fn ScrollLeft(&self) -> f64 {
3377 let node = self.upcast::<Node>();
3378
3379 let doc = node.owner_doc();
3381
3382 if !doc.is_fully_active() {
3384 return 0.0;
3385 }
3386
3387 let win = match doc.GetDefaultView() {
3389 None => return 0.0,
3390 Some(win) => win,
3391 };
3392
3393 if self.is_document_element() {
3395 if doc.quirks_mode() != QuirksMode::Quirks {
3396 return win.ScrollX() as f64;
3398 }
3399
3400 return 0.0;
3401 }
3402
3403 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3405 doc.quirks_mode() == QuirksMode::Quirks &&
3406 !self.is_potentially_scrollable_body()
3407 {
3408 return win.ScrollX() as f64;
3409 }
3410
3411 if !self.has_css_layout_box() {
3413 return 0.0;
3414 }
3415
3416 let point = win.scroll_offset_query(node);
3418 point.x.abs() as f64
3419 }
3420
3421 fn SetScrollLeft(&self, cx: &mut JSContext, x: f64) {
3423 let behavior = ScrollBehavior::Auto;
3424
3425 let x = if x.is_finite() { x } else { 0.0 } as f32;
3427
3428 let node = self.upcast::<Node>();
3429
3430 let doc = node.owner_doc();
3432
3433 if !doc.is_fully_active() {
3435 return;
3436 }
3437
3438 let win = match doc.GetDefaultView() {
3440 None => return,
3441 Some(win) => win,
3442 };
3443
3444 if self.is_document_element() {
3446 if doc.quirks_mode() == QuirksMode::Quirks {
3447 return;
3448 }
3449
3450 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3451 return;
3452 }
3453
3454 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3456 doc.quirks_mode() == QuirksMode::Quirks &&
3457 !self.is_potentially_scrollable_body()
3458 {
3459 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3460 return;
3461 }
3462
3463 if !self.has_scrolling_box(cx.no_gc()) {
3465 return;
3466 }
3467
3468 win.scroll_an_element(cx, self, x, self.ScrollTop() as f32, behavior);
3470 }
3471
3472 fn ScrollIntoView(&self, cx: &mut JSContext, arg: BooleanOrScrollIntoViewOptions) {
3474 let (behavior, block, inline, container) = match arg {
3475 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3477 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3482 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3485 options.parent.behavior,
3486 options.block,
3487 options.inline,
3488 if options.container == ScrollIntoViewContainer::Nearest {
3491 Some(self)
3492 } else {
3493 None
3494 },
3495 ),
3496 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3498 ScrollBehavior::Auto,
3499 ScrollLogicalPosition::End,
3500 ScrollLogicalPosition::Nearest,
3501 None,
3502 ),
3503 };
3504
3505 if !self.has_css_layout_box() {
3508 return;
3509 }
3510
3511 self.scroll_into_view_with_options(
3513 cx,
3514 behavior,
3515 ScrollAxisState::new_always_scroll_position(block),
3516 ScrollAxisState::new_always_scroll_position(inline),
3517 container,
3518 None,
3519 );
3520
3521 }
3524
3525 fn ScrollWidth(&self) -> i32 {
3527 self.upcast::<Node>().scroll_area().size.width
3528 }
3529
3530 fn ScrollHeight(&self) -> i32 {
3532 self.upcast::<Node>().scroll_area().size.height
3533 }
3534
3535 fn ClientTop(&self, no_gc: &NoGC) -> i32 {
3537 self.client_rect(no_gc).origin.y
3538 }
3539
3540 fn ClientLeft(&self, no_gc: &NoGC) -> i32 {
3542 self.client_rect(no_gc).origin.x
3543 }
3544
3545 fn ClientWidth(&self, no_gc: &NoGC) -> i32 {
3547 self.client_rect(no_gc).size.width
3548 }
3549
3550 fn ClientHeight(&self, no_gc: &NoGC) -> i32 {
3552 self.client_rect(no_gc).size.height
3553 }
3554
3555 fn CurrentCSSZoom(&self) -> Finite<f64> {
3557 let window = self.owner_window();
3558 Finite::wrap(window.current_css_zoom_query(self.upcast::<Node>()) as f64)
3559 }
3560
3561 fn SetHTMLUnsafe(
3563 &self,
3564 cx: &mut JSContext,
3565 html: TrustedHTMLOrString,
3566 options: &SetHTMLUnsafeOptions,
3567 ) -> ErrorResult {
3568 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
3572 cx,
3573 &self.owner_global(),
3574 html,
3575 "Element setHTMLUnsafe",
3576 )?;
3577 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3579 DomRoot::upcast(template.Content(cx))
3580 } else {
3581 DomRoot::from_ref(self.upcast())
3582 };
3583
3584 Sanitizer::set_and_filter_html(cx, &target, self, compliant_html, options, false)?;
3586
3587 Ok(())
3588 }
3589
3590 fn SetHTML(
3592 &self,
3593 cx: &mut JSContext,
3594 html: DOMString,
3595 options: &SetHTMLOptions,
3596 ) -> ErrorResult {
3597 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3599 DomRoot::upcast(template.Content(cx))
3600 } else {
3601 DomRoot::from_ref(self.upcast())
3602 };
3603
3604 Sanitizer::set_and_filter_html(cx, &target, self, html, options, true)
3606 }
3607
3608 fn GetHTML(&self, cx: &mut JSContext, options: &GetHTMLOptions) -> DOMString {
3610 self.upcast::<Node>().html_serialize(
3613 cx,
3614 TraversalScope::ChildrenOnly(None),
3615 options.serializableShadowRoots,
3616 options.shadowRoots.clone(),
3617 )
3618 }
3619
3620 fn GetInnerHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3622 let qname = QualName::new(
3623 self.prefix().clone(),
3624 self.namespace().clone(),
3625 self.local_name().clone(),
3626 );
3627
3628 let result = if self.owner_document().is_html_document() {
3631 self.upcast::<Node>()
3632 .html_serialize(cx, ChildrenOnly(Some(qname)), false, vec![])
3633 } else {
3634 self.upcast::<Node>()
3635 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3636 };
3637
3638 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3639 }
3640
3641 fn SetInnerHTML(
3643 &self,
3644 cx: &mut JSContext,
3645 value: TrustedHTMLOrNullIsEmptyString,
3646 ) -> ErrorResult {
3647 let value = TrustedHTML::get_trusted_type_compliant_string(
3651 cx,
3652 &self.owner_global(),
3653 value.convert(),
3654 "Element innerHTML",
3655 )?;
3656 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3658 DomRoot::upcast(template.Content(cx))
3661 } else {
3662 DomRoot::from_ref(self.upcast())
3664 };
3665
3666 if !self.node.has_weird_parser_insertion_mode() &&
3669 value.len() < 100 &&
3670 !value
3671 .as_bytes()
3672 .iter()
3673 .any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
3674 {
3675 return Node::SetTextContent(&target, cx, Some(value));
3676 }
3677
3678 let frag = self.parse_fragment(value, cx)?;
3681
3682 Node::replace_all(cx, Some(frag.upcast()), &target);
3684 Ok(())
3685 }
3686
3687 fn GetOuterHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3689 let result = if self.owner_document().is_html_document() {
3692 self.upcast::<Node>()
3693 .html_serialize(cx, IncludeNode, false, vec![])
3694 } else {
3695 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3696 };
3697
3698 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3699 }
3700
3701 fn SetOuterHTML(
3703 &self,
3704 cx: &mut JSContext,
3705 value: TrustedHTMLOrNullIsEmptyString,
3706 ) -> ErrorResult {
3707 let value = TrustedHTML::get_trusted_type_compliant_string(
3711 cx,
3712 &self.owner_global(),
3713 value.convert(),
3714 "Element outerHTML",
3715 )?;
3716 let context_document = self.owner_document();
3717 let context_node = self.upcast::<Node>();
3718 let context_parent = match context_node.GetParentNode() {
3720 None => {
3721 return Ok(());
3724 },
3725 Some(parent) => parent,
3726 };
3727
3728 let parent = match context_parent.type_id() {
3729 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed(None)),
3731
3732 NodeTypeId::DocumentFragment(_) => {
3735 let body_elem = Element::create(
3736 cx,
3737 QualName::new(None, ns!(html), local_name!("body")),
3738 None,
3739 &context_document,
3740 ElementCreator::ScriptCreated,
3741 CustomElementCreationMode::Synchronous,
3742 None,
3743 );
3744 DomRoot::upcast(body_elem)
3745 },
3746 _ => context_node.GetParentElement().unwrap(),
3747 };
3748
3749 let frag = parent.parse_fragment(value, cx)?;
3752 context_parent.ReplaceChild(cx, frag.upcast(), context_node)?;
3754 Ok(())
3755 }
3756
3757 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3759 self.upcast::<Node>()
3760 .preceding_siblings()
3761 .find_map(DomRoot::downcast)
3762 }
3763
3764 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3766 self.upcast::<Node>()
3767 .following_siblings()
3768 .find_map(DomRoot::downcast)
3769 }
3770
3771 fn Children(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
3773 let window = self.owner_window();
3774 HTMLCollection::children(cx, &window, self.upcast())
3775 }
3776
3777 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3779 self.upcast::<Node>().child_elements().next()
3780 }
3781
3782 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3784 self.upcast::<Node>()
3785 .rev_children()
3786 .find_map(DomRoot::downcast::<Element>)
3787 }
3788
3789 fn ChildElementCount(&self) -> u32 {
3791 self.upcast::<Node>().child_elements().count() as u32
3792 }
3793
3794 fn Prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3796 self.upcast::<Node>().prepend(cx, nodes)
3797 }
3798
3799 fn Append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3801 self.upcast::<Node>().append(cx, nodes)
3802 }
3803
3804 fn ReplaceChildren(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3806 self.upcast::<Node>().replace_children(cx, nodes)
3807 }
3808
3809 fn MoveBefore(&self, cx: &mut JSContext, node: &Node, child: Option<&Node>) -> ErrorResult {
3811 self.upcast::<Node>().move_before(cx, node, child)
3812 }
3813
3814 fn QuerySelector(
3816 &self,
3817 cx: &mut JSContext,
3818 selectors: DOMString,
3819 ) -> Fallible<Option<DomRoot<Element>>> {
3820 let root = self.upcast::<Node>();
3821 root.query_selector(cx.no_gc(), selectors)
3822 }
3823
3824 fn QuerySelectorAll(
3826 &self,
3827 cx: &mut JSContext,
3828 selectors: DOMString,
3829 ) -> Fallible<DomRoot<NodeList>> {
3830 let root = self.upcast::<Node>();
3831 root.query_selector_all(cx, selectors)
3832 }
3833
3834 fn Before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3836 self.upcast::<Node>().before(cx, nodes)
3837 }
3838
3839 fn After(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3841 self.upcast::<Node>().after(cx, nodes)
3842 }
3843
3844 fn ReplaceWith(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3846 self.upcast::<Node>().replace_with(cx, nodes)
3847 }
3848
3849 fn Remove(&self, cx: &mut JSContext) {
3851 self.upcast::<Node>().remove_self(cx);
3852 }
3853
3854 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3856 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3857 let document = self.owner_document();
3858 let url = document.url();
3859 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3860 &selectors.str(),
3861 &UrlExtraData(url.get_arc()),
3862 ) {
3863 Err(_) => {
3864 return Err(Error::Syntax(
3865 format!("'{selectors}' is not a valid selector").into(),
3866 ));
3867 },
3868 Ok(selectors) => selectors,
3869 };
3870
3871 let traced_self = Dom::from_ref(self);
3873 let quirks_mode = document.quirks_mode();
3874 Ok(with_layout_state(|| {
3875 #[expect(unsafe_code)]
3876 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3877 dom_apis::element_matches(
3878 &ServoDangerousStyleElement::from(layout_element.upcast()),
3879 &selectors,
3880 quirks_mode,
3881 )
3882 }))
3883 }
3884
3885 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3887 self.Matches(selectors)
3888 }
3889
3890 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3892 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3893 let document = self.owner_document();
3894 let url = document.url();
3895 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3896 &selectors.str(),
3897 &UrlExtraData(url.get_arc()),
3898 ) {
3899 Err(_) => return Err(Error::Syntax(None)),
3900 Ok(selectors) => selectors,
3901 };
3902
3903 let traced_self = Dom::from_ref(self);
3905 let quirks_mode = document.quirks_mode();
3906 let closest_element = with_layout_state(|| {
3907 #[expect(unsafe_code)]
3908 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3909 dom_apis::element_closest(
3910 ServoDangerousStyleElement::from(layout_element.upcast()),
3911 &selectors,
3912 quirks_mode,
3913 )
3914 });
3915 Ok(closest_element.map(ServoDangerousStyleElement::rooted))
3916 }
3917
3918 fn InsertAdjacentElement(
3920 &self,
3921 cx: &mut JSContext,
3922 where_: DOMString,
3923 element: &Element,
3924 ) -> Fallible<Option<DomRoot<Element>>> {
3925 let where_ = where_.parse::<AdjacentPosition>()?;
3926 let inserted_node = self.insert_adjacent(cx, where_, element.upcast())?;
3927 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3928 }
3929
3930 fn InsertAdjacentText(
3932 &self,
3933 cx: &mut JSContext,
3934 where_: DOMString,
3935 data: DOMString,
3936 ) -> ErrorResult {
3937 let text = Text::new(cx, data, &self.owner_document());
3939
3940 let where_ = where_.parse::<AdjacentPosition>()?;
3942 self.insert_adjacent(cx, where_, text.upcast()).map(|_| ())
3943 }
3944
3945 fn InsertAdjacentHTML(
3947 &self,
3948 cx: &mut JSContext,
3949 position: DOMString,
3950 text: TrustedHTMLOrString,
3951 ) -> ErrorResult {
3952 let text = TrustedHTML::get_trusted_type_compliant_string(
3956 cx,
3957 &self.owner_global(),
3958 text,
3959 "Element insertAdjacentHTML",
3960 )?;
3961 let position = position.parse::<AdjacentPosition>()?;
3962
3963 let context = match position {
3966 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
3969 match self.upcast::<Node>().GetParentNode() {
3970 Some(ref node) if node.is::<Document>() => {
3972 return Err(Error::NoModificationAllowed(None));
3973 },
3974 None => return Err(Error::NoModificationAllowed(None)),
3975 Some(node) => node,
3977 }
3978 },
3979 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
3982 DomRoot::from_ref(self.upcast::<Node>())
3984 },
3985 };
3986
3987 let context = Element::fragment_parsing_context(
3989 cx,
3990 &context.owner_doc(),
3991 context.downcast::<Element>(),
3992 );
3993
3994 let fragment = context.parse_fragment(text, cx)?;
3997
3998 self.insert_adjacent(cx, position, fragment.upcast())
4000 .map(|_| ())
4001 }
4002
4003 fn EnterFormalActivationState(&self) -> ErrorResult {
4005 match self.as_maybe_activatable() {
4006 Some(a) => {
4007 a.enter_formal_activation_state();
4008 Ok(())
4009 },
4010 None => Err(Error::NotSupported(None)),
4011 }
4012 }
4013
4014 fn ExitFormalActivationState(&self) -> ErrorResult {
4015 match self.as_maybe_activatable() {
4016 Some(a) => {
4017 a.exit_formal_activation_state();
4018 Ok(())
4019 },
4020 None => Err(Error::NotSupported(None)),
4021 }
4022 }
4023
4024 fn RequestFullscreen(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
4026 let doc = self.owner_document();
4027 doc.enter_fullscreen(cx, self)
4028 }
4029
4030 fn SetPointerCapture(&self, pointer_id: i32) -> ErrorResult {
4032 let document = self.owner_document();
4033 let event_handler = document.event_handler();
4034
4035 if !self.upcast::<Node>().is_connected() {
4046 return Err(Error::InvalidState(Some(
4047 "Can't capture pointer on an unconnected element".into(),
4048 )));
4049 }
4050
4051 if !event_handler.is_active_pointer(pointer_id) {
4061 return Ok(());
4062 }
4063
4064 event_handler.set_pending_pointer_capture(pointer_id, self);
4067
4068 Ok(())
4069 }
4070
4071 fn ReleasePointerCapture(&self, pointer_id: i32) -> ErrorResult {
4073 let document = self.owner_document();
4074 let event_handler = document.event_handler();
4075
4076 if !event_handler.is_active_pointer(pointer_id) {
4080 return Err(Error::NotFound(Some(
4081 "Can't release a pointer that is not active".into(),
4082 )));
4083 }
4084
4085 if !event_handler.has_pointer_capture(pointer_id, self) {
4088 return Ok(());
4089 }
4090
4091 event_handler.clear_pending_pointer_capture(pointer_id);
4093
4094 Ok(())
4095 }
4096
4097 fn HasPointerCapture(&self, pointer_id: i32) -> bool {
4099 let document = self.owner_document();
4100 let event_handler = document.event_handler();
4101 event_handler.has_pointer_capture(pointer_id, self)
4102 }
4103
4104 fn AttachShadow(
4106 &self,
4107 cx: &mut JSContext,
4108 init: &ShadowRootInit,
4109 ) -> Fallible<DomRoot<ShadowRoot>> {
4110 let shadow_root = self.attach_shadow(
4113 cx,
4114 IsUserAgentWidget::No,
4115 init.mode,
4116 init.clonable,
4117 init.serializable,
4118 init.delegatesFocus,
4119 init.slotAssignment,
4120 )?;
4121
4122 Ok(shadow_root)
4124 }
4125
4126 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
4128 let shadow_or_none = self.shadow_root();
4130
4131 let shadow = shadow_or_none?;
4133 if shadow.Mode() == ShadowRootMode::Closed {
4134 return None;
4135 }
4136
4137 Some(shadow)
4139 }
4140
4141 fn GetCustomElementRegistry(&self) -> Option<DomRoot<CustomElementRegistry>> {
4143 self.custom_element_registry()
4145 }
4146
4147 fn GetRole(&self) -> Option<DOMString> {
4149 self.get_nullable_string_attribute(&local_name!("role"))
4150 }
4151
4152 fn SetRole(&self, cx: &mut JSContext, value: Option<DOMString>) {
4154 self.set_nullable_string_attribute(cx, &local_name!("role"), value);
4155 }
4156
4157 fn GetAriaAtomic(&self) -> Option<DOMString> {
4158 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
4159 }
4160
4161 fn SetAriaAtomic(&self, cx: &mut JSContext, value: Option<DOMString>) {
4162 self.set_nullable_string_attribute(cx, &local_name!("aria-atomic"), value);
4163 }
4164
4165 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
4166 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
4167 }
4168
4169 fn SetAriaAutoComplete(&self, cx: &mut JSContext, value: Option<DOMString>) {
4170 self.set_nullable_string_attribute(cx, &local_name!("aria-autocomplete"), value);
4171 }
4172
4173 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
4174 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
4175 }
4176
4177 fn SetAriaBrailleLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4178 self.set_nullable_string_attribute(cx, &local_name!("aria-braillelabel"), value);
4179 }
4180
4181 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
4182 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
4183 }
4184
4185 fn SetAriaBrailleRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4186 self.set_nullable_string_attribute(cx, &local_name!("aria-brailleroledescription"), value);
4187 }
4188
4189 fn GetAriaBusy(&self) -> Option<DOMString> {
4190 self.get_nullable_string_attribute(&local_name!("aria-busy"))
4191 }
4192
4193 fn SetAriaBusy(&self, cx: &mut JSContext, value: Option<DOMString>) {
4194 self.set_nullable_string_attribute(cx, &local_name!("aria-busy"), value);
4195 }
4196
4197 fn GetAriaChecked(&self) -> Option<DOMString> {
4198 self.get_nullable_string_attribute(&local_name!("aria-checked"))
4199 }
4200
4201 fn SetAriaChecked(&self, cx: &mut JSContext, value: Option<DOMString>) {
4202 self.set_nullable_string_attribute(cx, &local_name!("aria-checked"), value);
4203 }
4204
4205 fn GetAriaColCount(&self) -> Option<DOMString> {
4206 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
4207 }
4208
4209 fn SetAriaColCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4210 self.set_nullable_string_attribute(cx, &local_name!("aria-colcount"), value);
4211 }
4212
4213 fn GetAriaColIndex(&self) -> Option<DOMString> {
4214 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4215 }
4216
4217 fn SetAriaColIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4218 self.set_nullable_string_attribute(cx, &local_name!("aria-colindex"), value);
4219 }
4220
4221 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4222 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4223 }
4224
4225 fn SetAriaColIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4226 self.set_nullable_string_attribute(cx, &local_name!("aria-colindextext"), value);
4227 }
4228
4229 fn GetAriaColSpan(&self) -> Option<DOMString> {
4230 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4231 }
4232
4233 fn SetAriaColSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4234 self.set_nullable_string_attribute(cx, &local_name!("aria-colspan"), value);
4235 }
4236
4237 fn GetAriaCurrent(&self) -> Option<DOMString> {
4238 self.get_nullable_string_attribute(&local_name!("aria-current"))
4239 }
4240
4241 fn SetAriaCurrent(&self, cx: &mut JSContext, value: Option<DOMString>) {
4242 self.set_nullable_string_attribute(cx, &local_name!("aria-current"), value);
4243 }
4244
4245 fn GetAriaDescription(&self) -> Option<DOMString> {
4246 self.get_nullable_string_attribute(&local_name!("aria-description"))
4247 }
4248
4249 fn SetAriaDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4250 self.set_nullable_string_attribute(cx, &local_name!("aria-description"), value);
4251 }
4252
4253 fn GetAriaDisabled(&self) -> Option<DOMString> {
4254 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4255 }
4256
4257 fn SetAriaDisabled(&self, cx: &mut JSContext, value: Option<DOMString>) {
4258 self.set_nullable_string_attribute(cx, &local_name!("aria-disabled"), value);
4259 }
4260
4261 fn GetAriaExpanded(&self) -> Option<DOMString> {
4262 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4263 }
4264
4265 fn SetAriaExpanded(&self, cx: &mut JSContext, value: Option<DOMString>) {
4266 self.set_nullable_string_attribute(cx, &local_name!("aria-expanded"), value);
4267 }
4268
4269 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4270 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4271 }
4272
4273 fn SetAriaHasPopup(&self, cx: &mut JSContext, value: Option<DOMString>) {
4274 self.set_nullable_string_attribute(cx, &local_name!("aria-haspopup"), value);
4275 }
4276
4277 fn GetAriaHidden(&self) -> Option<DOMString> {
4278 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4279 }
4280
4281 fn SetAriaHidden(&self, cx: &mut JSContext, value: Option<DOMString>) {
4282 self.set_nullable_string_attribute(cx, &local_name!("aria-hidden"), value);
4283 }
4284
4285 fn GetAriaInvalid(&self) -> Option<DOMString> {
4286 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4287 }
4288
4289 fn SetAriaInvalid(&self, cx: &mut JSContext, value: Option<DOMString>) {
4290 self.set_nullable_string_attribute(cx, &local_name!("aria-invalid"), value);
4291 }
4292
4293 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4294 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4295 }
4296
4297 fn SetAriaKeyShortcuts(&self, cx: &mut JSContext, value: Option<DOMString>) {
4298 self.set_nullable_string_attribute(cx, &local_name!("aria-keyshortcuts"), value);
4299 }
4300
4301 fn GetAriaLabel(&self) -> Option<DOMString> {
4302 self.get_nullable_string_attribute(&local_name!("aria-label"))
4303 }
4304
4305 fn SetAriaLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4306 self.set_nullable_string_attribute(cx, &local_name!("aria-label"), value);
4307 }
4308
4309 fn GetAriaLevel(&self) -> Option<DOMString> {
4310 self.get_nullable_string_attribute(&local_name!("aria-level"))
4311 }
4312
4313 fn SetAriaLevel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4314 self.set_nullable_string_attribute(cx, &local_name!("aria-level"), value);
4315 }
4316
4317 fn GetAriaLive(&self) -> Option<DOMString> {
4318 self.get_nullable_string_attribute(&local_name!("aria-live"))
4319 }
4320
4321 fn SetAriaLive(&self, cx: &mut JSContext, value: Option<DOMString>) {
4322 self.set_nullable_string_attribute(cx, &local_name!("aria-live"), value);
4323 }
4324
4325 fn GetAriaModal(&self) -> Option<DOMString> {
4326 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4327 }
4328
4329 fn SetAriaModal(&self, cx: &mut JSContext, value: Option<DOMString>) {
4330 self.set_nullable_string_attribute(cx, &local_name!("aria-modal"), value);
4331 }
4332
4333 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4334 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4335 }
4336
4337 fn SetAriaMultiLine(&self, cx: &mut JSContext, value: Option<DOMString>) {
4338 self.set_nullable_string_attribute(cx, &local_name!("aria-multiline"), value);
4339 }
4340
4341 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4342 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4343 }
4344
4345 fn SetAriaMultiSelectable(&self, cx: &mut JSContext, value: Option<DOMString>) {
4346 self.set_nullable_string_attribute(cx, &local_name!("aria-multiselectable"), value);
4347 }
4348
4349 fn GetAriaOrientation(&self) -> Option<DOMString> {
4350 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4351 }
4352
4353 fn SetAriaOrientation(&self, cx: &mut JSContext, value: Option<DOMString>) {
4354 self.set_nullable_string_attribute(cx, &local_name!("aria-orientation"), value);
4355 }
4356
4357 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4358 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4359 }
4360
4361 fn SetAriaPlaceholder(&self, cx: &mut JSContext, value: Option<DOMString>) {
4362 self.set_nullable_string_attribute(cx, &local_name!("aria-placeholder"), value);
4363 }
4364
4365 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4366 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4367 }
4368
4369 fn SetAriaPosInSet(&self, cx: &mut JSContext, value: Option<DOMString>) {
4370 self.set_nullable_string_attribute(cx, &local_name!("aria-posinset"), value);
4371 }
4372
4373 fn GetAriaPressed(&self) -> Option<DOMString> {
4374 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4375 }
4376
4377 fn SetAriaPressed(&self, cx: &mut JSContext, value: Option<DOMString>) {
4378 self.set_nullable_string_attribute(cx, &local_name!("aria-pressed"), value);
4379 }
4380
4381 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4382 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4383 }
4384
4385 fn SetAriaReadOnly(&self, cx: &mut JSContext, value: Option<DOMString>) {
4386 self.set_nullable_string_attribute(cx, &local_name!("aria-readonly"), value);
4387 }
4388
4389 fn GetAriaRelevant(&self) -> Option<DOMString> {
4390 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4391 }
4392
4393 fn SetAriaRelevant(&self, cx: &mut JSContext, value: Option<DOMString>) {
4394 self.set_nullable_string_attribute(cx, &local_name!("aria-relevant"), value);
4395 }
4396
4397 fn GetAriaRequired(&self) -> Option<DOMString> {
4398 self.get_nullable_string_attribute(&local_name!("aria-required"))
4399 }
4400
4401 fn SetAriaRequired(&self, cx: &mut JSContext, value: Option<DOMString>) {
4402 self.set_nullable_string_attribute(cx, &local_name!("aria-required"), value);
4403 }
4404
4405 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4406 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4407 }
4408
4409 fn SetAriaRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4410 self.set_nullable_string_attribute(cx, &local_name!("aria-roledescription"), value);
4411 }
4412
4413 fn GetAriaRowCount(&self) -> Option<DOMString> {
4414 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4415 }
4416
4417 fn SetAriaRowCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4418 self.set_nullable_string_attribute(cx, &local_name!("aria-rowcount"), value);
4419 }
4420
4421 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4422 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4423 }
4424
4425 fn SetAriaRowIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4426 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindex"), value);
4427 }
4428
4429 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4430 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4431 }
4432
4433 fn SetAriaRowIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4434 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindextext"), value);
4435 }
4436
4437 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4438 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4439 }
4440
4441 fn SetAriaRowSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4442 self.set_nullable_string_attribute(cx, &local_name!("aria-rowspan"), value);
4443 }
4444
4445 fn GetAriaSelected(&self) -> Option<DOMString> {
4446 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4447 }
4448
4449 fn SetAriaSelected(&self, cx: &mut JSContext, value: Option<DOMString>) {
4450 self.set_nullable_string_attribute(cx, &local_name!("aria-selected"), value);
4451 }
4452
4453 fn GetAriaSetSize(&self) -> Option<DOMString> {
4454 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4455 }
4456
4457 fn SetAriaSetSize(&self, cx: &mut JSContext, value: Option<DOMString>) {
4458 self.set_nullable_string_attribute(cx, &local_name!("aria-setsize"), value);
4459 }
4460
4461 fn GetAriaSort(&self) -> Option<DOMString> {
4462 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4463 }
4464
4465 fn SetAriaSort(&self, cx: &mut JSContext, value: Option<DOMString>) {
4466 self.set_nullable_string_attribute(cx, &local_name!("aria-sort"), value);
4467 }
4468
4469 fn GetAriaValueMax(&self) -> Option<DOMString> {
4470 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4471 }
4472
4473 fn SetAriaValueMax(&self, cx: &mut JSContext, value: Option<DOMString>) {
4474 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemax"), value);
4475 }
4476
4477 fn GetAriaValueMin(&self) -> Option<DOMString> {
4478 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4479 }
4480
4481 fn SetAriaValueMin(&self, cx: &mut JSContext, value: Option<DOMString>) {
4482 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemin"), value);
4483 }
4484
4485 fn GetAriaValueNow(&self) -> Option<DOMString> {
4486 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4487 }
4488
4489 fn SetAriaValueNow(&self, cx: &mut JSContext, value: Option<DOMString>) {
4490 self.set_nullable_string_attribute(cx, &local_name!("aria-valuenow"), value);
4491 }
4492
4493 fn GetAriaValueText(&self) -> Option<DOMString> {
4494 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4495 }
4496
4497 fn SetAriaValueText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4498 self.set_nullable_string_attribute(cx, &local_name!("aria-valuetext"), value);
4499 }
4500
4501 fn GetAssignedSlot(&self, cx: &JSContext) -> Option<DomRoot<HTMLSlotElement>> {
4503 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4506 slottable.find_a_slot(true)
4507 }
4508
4509 fn Part(&self, cx: &mut JSContext) -> DomRoot<DOMTokenList> {
4511 self.ensure_rare_data()
4512 .part
4513 .or_init(|| DOMTokenList::new(cx, self, &local_name!("part"), None))
4514 }
4515
4516 fn Animate(
4518 &self,
4519 cx: &mut JSContext,
4520 keyframes: *mut JSObject,
4521 options: UnrestrictedDoubleOrKeyframeAnimationOptions,
4522 ) -> DomRoot<Animation> {
4523 let window = self.owner_window();
4524
4525 let target = self;
4527
4528 let parent_options = match options {
4536 UnrestrictedDoubleOrKeyframeAnimationOptions::UnrestrictedDouble(value) => {
4537 UnrestrictedDoubleOrKeyframeEffectOptions::UnrestrictedDouble(value)
4538 },
4539 UnrestrictedDoubleOrKeyframeAnimationOptions::KeyframeAnimationOptions(options) => {
4540 UnrestrictedDoubleOrKeyframeEffectOptions::KeyframeEffectOptions(options.parent)
4541 },
4542 };
4543 let effect =
4544 KeyframeEffect::Constructor(cx, &window, None, Some(target), keyframes, parent_options);
4545
4546 let animation = Animation::Constructor(cx, &window, None, Some(effect.upcast()));
4554
4555 animation
4562 }
4563}
4564
4565impl VirtualMethods for Element {
4566 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4567 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4568 }
4569
4570 fn attribute_affects_presentational_hints(&self, attr: AttrRef<'_>) -> bool {
4571 if attr.local_name() == &local_name!("lang") {
4573 return true;
4574 }
4575
4576 self.super_type()
4577 .unwrap()
4578 .attribute_affects_presentational_hints(attr)
4579 }
4580
4581 fn attribute_mutated(
4582 &self,
4583 cx: &mut JSContext,
4584 attr: AttrRef<'_>,
4585 mutation: AttributeMutation,
4586 ) {
4587 self.super_type()
4588 .unwrap()
4589 .attribute_mutated(cx, attr, mutation);
4590 let node = self.upcast::<Node>();
4591 let doc = node.owner_doc();
4592 match *attr.local_name() {
4593 ref name if name.starts_with("on") && EventTarget::is_content_event_handler(name) => {
4597 let evtarget = self.upcast::<EventTarget>();
4598 let event_name = &name[2..];
4599 match mutation {
4600 AttributeMutation::Set(..) => {
4602 let source = &**attr.value();
4603 let source_line = 1; evtarget.set_event_handler_uncompiled(
4605 cx,
4606 self.owner_window().get_url(),
4607 source_line,
4608 event_name,
4609 source,
4610 );
4611 },
4612 AttributeMutation::Removed => {
4614 evtarget
4615 .set_event_handler_common::<EventHandlerNonNull>(cx, event_name, None);
4616 },
4617 }
4618 },
4619 local_name!("style") => self.update_style_attribute(cx, attr, mutation),
4620 local_name!("id") => {
4621 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4623 let value = value.as_atom();
4624 if value != &atom!("") {
4625 Some(value.clone())
4627 } else {
4628 None
4630 }
4631 });
4632
4633 let containing_shadow_root = self.containing_shadow_root();
4634 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4635 let value = attr.value().as_atom().clone();
4636 match mutation {
4637 AttributeMutation::Set(old_value, _) => {
4638 if let Some(old_value) = old_value {
4639 let old_value = old_value.as_atom();
4640 if let Some(ref shadow_root) = containing_shadow_root {
4641 shadow_root.unregister_element_id(old_value);
4642 } else {
4643 doc.unregister_element_id(cx, old_value);
4644 }
4645 }
4646 if value != atom!("") {
4647 if let Some(ref shadow_root) = containing_shadow_root {
4648 shadow_root.register_element_id(self, &value);
4649 } else {
4650 doc.register_element_id(cx, self, &value);
4651 }
4652 }
4653 },
4654 AttributeMutation::Removed => {
4655 if value != atom!("") {
4656 if let Some(ref shadow_root) = containing_shadow_root {
4657 shadow_root.unregister_element_id(&value);
4658 } else {
4659 doc.unregister_element_id(cx, &value);
4660 }
4661 }
4662 },
4663 }
4664 }
4665 },
4666 local_name!("name") => {
4667 self.ensure_rare_data().name_attribute =
4669 mutation.new_value(attr).and_then(|value| {
4670 let value = value.as_atom();
4671 if value != &atom!("") {
4672 Some(value.clone())
4673 } else {
4674 None
4675 }
4676 });
4677 if node.is_connected() && node.containing_shadow_root().is_none() {
4680 let value = attr.value().as_atom().clone();
4681 match mutation {
4682 AttributeMutation::Set(old_value, _) => {
4683 if let Some(old_value) = old_value {
4684 doc.unregister_element_name(old_value.as_atom());
4685 }
4686 if value != atom!("") {
4687 doc.register_element_name(self, &value);
4688 }
4689 },
4690 AttributeMutation::Removed => {
4691 if value != atom!("") {
4692 doc.unregister_element_name(&value);
4693 }
4694 },
4695 }
4696 }
4697 },
4698 local_name!("slot") => {
4699 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4701
4702 if let Some(assigned_slot) = slottable.assigned_slot() {
4704 assigned_slot.assign_slottables(cx);
4705 }
4706 slottable.assign_a_slot(cx);
4707 },
4708 _ => {
4709 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4712 node.dirty(NodeDamage::Other);
4713 }
4714 },
4715 };
4716
4717 if self
4720 .upcast::<Node>()
4721 .get_flag(NodeFlags::USES_ATTR_IN_CONTENT_ATTRIBUTE)
4722 {
4723 node.dirty(NodeDamage::ContentOrHeritage);
4724 }
4725
4726 node.rev_version();
4730
4731 let window = self.owner_window();
4733 if window.live_devtools_updates() {
4734 let global = window.upcast::<GlobalScope>();
4735 if let Some(sender) = global.devtools_chan() {
4736 let pipeline_id = global.pipeline_id();
4737 if ScriptThread::devtools_want_updates_for_node(pipeline_id, self.upcast()) {
4738 let devtools_message = ScriptToDevtoolsControlMsg::DomMutation(
4739 pipeline_id,
4740 DomMutation::AttributeModified {
4741 node: self.upcast::<Node>().unique_id(pipeline_id),
4742 attribute_name: attr.local_name().to_string(),
4743 new_value: mutation.new_value(attr).map(|value| value.to_string()),
4744 },
4745 );
4746 sender.send(devtools_message).unwrap();
4747 }
4748 }
4749 }
4750 }
4751
4752 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4753 match *name {
4754 local_name!("id") => AttrValue::Atom(value.into()),
4755 local_name!("name") => AttrValue::Atom(value.into()),
4756 local_name!("class") | local_name!("part") => {
4757 AttrValue::from_serialized_tokenlist(value.into())
4758 },
4759 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4760 local_name!("tabindex") => AttrValue::from_i32(value.into(), -1),
4761 _ => self
4762 .super_type()
4763 .unwrap()
4764 .parse_plain_attribute(name, value),
4765 }
4766 }
4767
4768 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
4769 if let Some(s) = self.super_type() {
4770 s.bind_to_tree(cx, context);
4771 }
4772
4773 if let Some(f) = self.as_maybe_form_control() {
4774 f.bind_form_control_to_tree(cx);
4775 }
4776
4777 if let Some(ref shadow_root) = self.shadow_root() {
4778 shadow_root.bind_to_tree(cx, context);
4779 }
4780
4781 if !context.is_in_tree() {
4782 return;
4783 }
4784
4785 self.register_current_id_and_name_attribute(cx);
4786 }
4787
4788 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4789 self.super_type().unwrap().unbind_from_tree(cx, context);
4790
4791 if let Some(f) = self.as_maybe_form_control() {
4792 f.unbind_form_control_from_tree(cx);
4796 }
4797
4798 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4799 return;
4800 }
4801
4802 let doc = self.owner_document();
4803
4804 let fullscreen = doc.fullscreen_element();
4805 if fullscreen.as_deref() == Some(self) {
4806 doc.exit_fullscreen(cx);
4807 }
4808
4809 self.unregister_current_id_and_name_attribute(cx);
4810 }
4811
4812 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4813 if let Some(s) = self.super_type() {
4814 s.children_changed(cx, mutation);
4815 }
4816
4817 let flags = self.get_selector_flags();
4818 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4819 self.upcast::<Node>().dirty(NodeDamage::Other);
4821 } else {
4822 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) &&
4823 let Some(next_child) = mutation.next_child()
4824 {
4825 for child in next_child.inclusively_following_siblings_unrooted(cx.no_gc()) {
4826 if child.is::<Element>() {
4827 child.dirty(NodeDamage::Other);
4828 }
4829 }
4830 }
4831 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) &&
4832 let Some(child) = mutation.modified_edge_element(cx.no_gc())
4833 {
4834 child.dirty(NodeDamage::Other);
4835 }
4836 }
4837 }
4838
4839 fn adopting_steps(&self, cx: &mut JSContext, old_doc: &Document) {
4840 self.super_type().unwrap().adopting_steps(cx, old_doc);
4841
4842 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4843 self.tag_name.clear();
4844 }
4845 }
4846
4847 fn post_connection_steps(&self, cx: &mut JSContext) {
4848 if let Some(s) = self.super_type() {
4849 s.post_connection_steps(cx);
4850 }
4851
4852 self.update_nonce_post_connection(cx);
4853 }
4854
4855 fn cloning_steps(
4857 &self,
4858 cx: &mut JSContext,
4859 copy: &Node,
4860 maybe_doc: Option<&Document>,
4861 clone_children: CloneChildrenFlag,
4862 ) {
4863 if let Some(s) = self.super_type() {
4864 s.cloning_steps(cx, copy, maybe_doc, clone_children);
4865 }
4866 let elem = copy.downcast::<Element>().unwrap();
4867 if let Some(rare_data) = self.rare_data().as_ref() {
4868 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone());
4869 }
4870 }
4871}
4872impl Element {
4873 pub(crate) fn client_rect(&self, no_gc: &NoGC) -> Rect<i32, CSSPixel> {
4874 let doc = self.node.owner_doc();
4875
4876 if let Some(rect) = self
4877 .rare_data()
4878 .as_ref()
4879 .and_then(|data| data.client_rect.as_ref())
4880 .and_then(|rect| rect.get().ok()) &&
4881 doc.restyle_reason(no_gc).is_empty()
4882 {
4883 return rect;
4884 }
4885
4886 let mut rect = self.upcast::<Node>().client_rect();
4887 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
4888
4889 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
4890 (!in_quirks_mode && self.is_document_element())
4891 {
4892 rect.size = doc.window().viewport_details().size.round().to_i32();
4893 }
4894
4895 self.ensure_rare_data().client_rect = Some(self.owner_window().cache_layout_value(rect));
4896 rect
4897 }
4898
4899 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
4900 let element = match self.upcast::<Node>().type_id() {
4901 NodeTypeId::Element(ElementTypeId::HTMLElement(
4902 HTMLElementTypeId::HTMLInputElement,
4903 )) => {
4904 let element = self.downcast::<HTMLInputElement>().unwrap();
4905 Some(element as &dyn Activatable)
4906 },
4907 NodeTypeId::Element(ElementTypeId::HTMLElement(
4908 HTMLElementTypeId::HTMLButtonElement,
4909 )) => {
4910 let element = self.downcast::<HTMLButtonElement>().unwrap();
4911 Some(element as &dyn Activatable)
4912 },
4913 NodeTypeId::Element(ElementTypeId::HTMLElement(
4914 HTMLElementTypeId::HTMLAnchorElement,
4915 )) => {
4916 let element = self.downcast::<HTMLAnchorElement>().unwrap();
4917 Some(element as &dyn Activatable)
4918 },
4919 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
4920 let element = self.downcast::<HTMLAreaElement>().unwrap();
4921 Some(element as &dyn Activatable)
4922 },
4923 NodeTypeId::Element(ElementTypeId::HTMLElement(
4924 HTMLElementTypeId::HTMLLabelElement,
4925 )) => {
4926 let element = self.downcast::<HTMLLabelElement>().unwrap();
4927 Some(element as &dyn Activatable)
4928 },
4929 NodeTypeId::Element(ElementTypeId::HTMLElement(
4930 HTMLElementTypeId::HTMLSelectElement,
4931 )) => {
4932 let element = self.downcast::<HTMLSelectElement>().unwrap();
4933 Some(element as &dyn Activatable)
4934 },
4935 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
4936 let element = self.downcast::<HTMLElement>().unwrap();
4937 Some(element as &dyn Activatable)
4938 },
4939 _ => None,
4940 };
4941 element.and_then(|elem| {
4942 if elem.is_instance_activatable() {
4943 Some(elem)
4944 } else {
4945 None
4946 }
4947 })
4948 }
4949
4950 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
4951 if let Some(s) = self.downcast::<HTMLStyleElement>() {
4952 return Some(s as &dyn StylesheetOwner);
4953 }
4954
4955 if let Some(l) = self.downcast::<HTMLLinkElement>() {
4956 return Some(l as &dyn StylesheetOwner);
4957 }
4958
4959 None
4960 }
4961
4962 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
4964 match self.upcast::<Node>().type_id() {
4965 NodeTypeId::Element(ElementTypeId::HTMLElement(
4966 HTMLElementTypeId::HTMLInputElement,
4967 )) => {
4968 let element = self.downcast::<HTMLInputElement>().unwrap();
4969 Some(element as &dyn Validatable)
4970 },
4971 NodeTypeId::Element(ElementTypeId::HTMLElement(
4972 HTMLElementTypeId::HTMLButtonElement,
4973 )) => {
4974 let element = self.downcast::<HTMLButtonElement>().unwrap();
4975 Some(element as &dyn Validatable)
4976 },
4977 NodeTypeId::Element(ElementTypeId::HTMLElement(
4978 HTMLElementTypeId::HTMLObjectElement,
4979 )) => {
4980 let element = self.downcast::<HTMLObjectElement>().unwrap();
4981 Some(element as &dyn Validatable)
4982 },
4983 NodeTypeId::Element(ElementTypeId::HTMLElement(
4984 HTMLElementTypeId::HTMLSelectElement,
4985 )) => {
4986 let element = self.downcast::<HTMLSelectElement>().unwrap();
4987 Some(element as &dyn Validatable)
4988 },
4989 NodeTypeId::Element(ElementTypeId::HTMLElement(
4990 HTMLElementTypeId::HTMLTextAreaElement,
4991 )) => {
4992 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
4993 Some(element as &dyn Validatable)
4994 },
4995 NodeTypeId::Element(ElementTypeId::HTMLElement(
4996 HTMLElementTypeId::HTMLFieldSetElement,
4997 )) => {
4998 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
4999 Some(element as &dyn Validatable)
5000 },
5001 NodeTypeId::Element(ElementTypeId::HTMLElement(
5002 HTMLElementTypeId::HTMLOutputElement,
5003 )) => {
5004 let element = self.downcast::<HTMLOutputElement>().unwrap();
5005 Some(element as &dyn Validatable)
5006 },
5007 _ => None,
5008 }
5009 }
5010
5011 pub(crate) fn is_invalid(&self, cx: &mut JSContext, needs_update: bool) -> bool {
5012 if let Some(validatable) = self.as_maybe_validatable() {
5013 if needs_update {
5014 validatable
5015 .validity_state(cx)
5016 .perform_validation_and_update(cx, ValidationFlags::all());
5017 }
5018 return validatable.is_instance_validatable() && !validatable.satisfies_constraints(cx);
5019 }
5020
5021 if let Some(internals) = self.get_element_internals() {
5022 return internals.is_invalid(cx);
5023 }
5024 false
5025 }
5026
5027 pub(crate) fn is_instance_validatable(&self) -> bool {
5028 if let Some(validatable) = self.as_maybe_validatable() {
5029 return validatable.is_instance_validatable();
5030 }
5031 if let Some(internals) = self.get_element_internals() {
5032 return internals.is_instance_validatable();
5033 }
5034 false
5035 }
5036
5037 pub(crate) fn init_state_for_internals(&self) {
5038 self.set_enabled_state(true);
5039 self.set_state(ElementState::VALID, true);
5040 self.set_state(ElementState::INVALID, false);
5041 }
5042
5043 pub(crate) fn click_in_progress(&self) -> bool {
5044 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5045 }
5046
5047 pub(crate) fn set_click_in_progress(&self, click: bool) {
5048 self.upcast::<Node>()
5049 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5050 }
5051
5052 pub fn state(&self) -> ElementState {
5053 self.state.get()
5054 }
5055
5056 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5057 let mut state = self.state.get();
5058 let previous_state = state;
5059 if value {
5060 state.insert(which);
5061 } else {
5062 state.remove(which);
5063 }
5064
5065 if previous_state == state {
5066 return;
5068 }
5069
5070 {
5073 let document = self.owner_document();
5074 let mut entry = document.ensure_pending_restyle(self);
5075 if entry.snapshot.is_none() {
5076 entry.snapshot = Some(Snapshot::new());
5077 }
5078 let snapshot = entry.snapshot.as_mut().unwrap();
5079 if snapshot.state.is_none() {
5080 snapshot.state = Some(self.state());
5081 }
5082 }
5083
5084 self.state.set(state);
5085 }
5086
5087 pub(crate) fn set_active_state(&self, value: bool) {
5089 self.set_state(ElementState::ACTIVE, value);
5090
5091 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5092 parent.set_active_state(value);
5093 }
5094 }
5095
5096 pub(crate) fn focus_state(&self) -> bool {
5097 self.state.get().contains(ElementState::FOCUS)
5098 }
5099
5100 pub(crate) fn set_focus_state(&self, value: bool) {
5101 self.set_state(ElementState::FOCUS, value);
5102 }
5103
5104 pub(crate) fn set_hover_state(&self, value: bool) {
5105 self.set_state(ElementState::HOVER, value);
5106 }
5107
5108 pub(crate) fn enabled_state(&self) -> bool {
5109 self.state.get().contains(ElementState::ENABLED)
5110 }
5111
5112 pub(crate) fn set_enabled_state(&self, value: bool) {
5113 self.set_state(ElementState::ENABLED, value)
5114 }
5115
5116 pub(crate) fn disabled_state(&self) -> bool {
5117 self.state.get().contains(ElementState::DISABLED)
5118 }
5119
5120 pub(crate) fn set_disabled_state(&self, value: bool) {
5121 self.set_state(ElementState::DISABLED, value)
5122 }
5123
5124 pub(crate) fn read_write_state(&self) -> bool {
5125 self.state.get().contains(ElementState::READWRITE)
5126 }
5127
5128 pub(crate) fn set_read_write_state(&self, value: bool) {
5129 self.set_state(ElementState::READWRITE, value)
5130 }
5131
5132 pub(crate) fn set_open_state(&self, value: bool) {
5133 self.set_state(ElementState::OPEN, value);
5134 }
5135
5136 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5137 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5138 }
5139
5140 pub(crate) fn set_modal_state(&self, value: bool) {
5141 self.set_state(ElementState::MODAL, value);
5142 }
5143
5144 pub(crate) fn set_target_state(&self, value: bool) {
5145 self.set_state(ElementState::URLTARGET, value)
5146 }
5147
5148 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5149 self.set_state(ElementState::FULLSCREEN, value)
5150 }
5151
5152 pub(crate) fn is_connected(&self) -> bool {
5154 self.upcast::<Node>().is_connected()
5155 }
5156
5157 pub(crate) fn cannot_navigate(&self) -> bool {
5159 let document = self.owner_document();
5160
5161 !document.is_fully_active() ||
5163 (
5164 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5166 )
5167 }
5168}
5169
5170impl Element {
5171 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5172 let node = self.upcast::<Node>();
5173 if self.disabled_state() {
5174 return;
5175 }
5176 for ancestor in node.ancestors() {
5177 if !ancestor.is::<HTMLFieldSetElement>() {
5178 continue;
5179 }
5180 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5181 continue;
5182 }
5183 if ancestor.is_parent_of(node) {
5184 self.set_disabled_state(true);
5185 self.set_enabled_state(false);
5186 return;
5187 }
5188 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5189 if node.ancestors().any(|ancestor| ancestor == *legend) {
5191 continue;
5192 }
5193 }
5194 self.set_disabled_state(true);
5195 self.set_enabled_state(false);
5196 return;
5197 }
5198 }
5199
5200 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5201 if self.disabled_state() {
5202 return;
5203 }
5204 let node = self.upcast::<Node>();
5205 if let Some(ref parent) = node.GetParentNode() &&
5206 parent.is::<HTMLOptGroupElement>() &&
5207 parent.downcast::<Element>().unwrap().disabled_state()
5208 {
5209 self.set_disabled_state(true);
5210 self.set_enabled_state(false);
5211 }
5212 }
5213
5214 pub(crate) fn check_disabled_attribute(&self) {
5215 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5216 self.set_disabled_state(has_disabled_attrib);
5217 self.set_enabled_state(!has_disabled_attrib);
5218 }
5219
5220 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5221 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5222 self.set_read_write_state(has_readonly_attribute);
5223 }
5224}
5225
5226#[derive(Clone, Copy, PartialEq)]
5227pub(crate) enum AttributeMutationReason {
5228 ByCloning,
5229 ByParser,
5230 Directly,
5231}
5232
5233#[derive(Clone, Copy)]
5234pub(crate) enum AttributeMutation<'a> {
5235 Set(Option<&'a AttrValue>, AttributeMutationReason),
5238
5239 Removed,
5242}
5243
5244impl AttributeMutation<'_> {
5245 pub(crate) fn is_removal(&self) -> bool {
5246 match *self {
5247 AttributeMutation::Removed => true,
5248 AttributeMutation::Set(..) => false,
5249 }
5250 }
5251
5252 pub(crate) fn new_value<'b>(&self, attr: AttrRef<'b>) -> Option<AttrValueRef<'b>> {
5253 match *self {
5254 AttributeMutation::Set(..) => Some(attr.value()),
5255 AttributeMutation::Removed => None,
5256 }
5257 }
5258}
5259
5260#[derive(JSTraceable, MallocSizeOf)]
5264struct TagName {
5265 #[no_trace]
5266 ptr: DomRefCell<Option<LocalName>>,
5267}
5268
5269impl TagName {
5270 fn new() -> TagName {
5271 TagName {
5272 ptr: DomRefCell::new(None),
5273 }
5274 }
5275
5276 fn or_init<F>(&self, cb: F) -> LocalName
5279 where
5280 F: FnOnce() -> LocalName,
5281 {
5282 match &mut *self.ptr.borrow_mut() {
5283 &mut Some(ref name) => name.clone(),
5284 ptr => {
5285 let name = cb();
5286 *ptr = Some(name.clone());
5287 name
5288 },
5289 }
5290 }
5291
5292 fn clear(&self) {
5295 *self.ptr.borrow_mut() = None;
5296 }
5297}
5298
5299pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5301 element
5302 .get_attribute_string_value(&local_name!("crossorigin"))
5303 .map(|value| {
5304 let value = value.to_ascii_lowercase();
5305 if value == "anonymous" || value == "use-credentials" {
5306 DOMString::from(value)
5307 } else {
5308 DOMString::from("anonymous")
5309 }
5310 })
5311}
5312
5313pub(crate) fn set_cross_origin_attribute(
5314 cx: &mut JSContext,
5315 element: &Element,
5316 value: Option<DOMString>,
5317) {
5318 match value {
5319 Some(val) => element.set_string_attribute(cx, &local_name!("crossorigin"), val),
5320 None => {
5321 element.remove_attribute(cx, &ns!(), &local_name!("crossorigin"));
5322 },
5323 }
5324}
5325
5326pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5328 element
5329 .get_attribute_string_value(&local_name!("referrerpolicy"))
5330 .map(|value| {
5331 let value = value.to_ascii_lowercase();
5332 if value == "no-referrer" ||
5333 value == "no-referrer-when-downgrade" ||
5334 value == "same-origin" ||
5335 value == "origin" ||
5336 value == "strict-origin" ||
5337 value == "origin-when-cross-origin" ||
5338 value == "strict-origin-when-cross-origin" ||
5339 value == "unsafe-url"
5340 {
5341 DOMString::from(value)
5342 } else {
5343 DOMString::new()
5344 }
5345 })
5346 .unwrap_or_default()
5347}
5348
5349pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5350 element
5351 .get_attribute_string_value(&local_name!("referrerpolicy"))
5352 .map(|value| ReferrerPolicy::from(value.as_ref()))
5353 .unwrap_or(element.owner_document().get_referrer_policy())
5354}
5355
5356pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5357 element
5358 .get_attribute_string_value(&local_name!("crossorigin"))
5359 .map(|value| CorsSettings::from_enumerated_attribute(value.as_ref()))
5360}
5361
5362pub(crate) fn cors_settings_attribute_credential_mode(element: &Element) -> CredentialsMode {
5364 element
5365 .get_attribute_string_value(&local_name!("crossorigin"))
5366 .map(|value| {
5367 if value.eq_ignore_ascii_case("use-credentials") {
5368 CredentialsMode::Include
5369 } else {
5370 CredentialsMode::CredentialsSameOrigin
5372 }
5373 })
5374 .unwrap_or(CredentialsMode::CredentialsSameOrigin)
5376}
5377
5378pub(crate) fn is_element_affected_by_legacy_background_presentational_hint(
5379 namespace: &Namespace,
5380 local_name: &LocalName,
5381) -> bool {
5382 *namespace == ns!(html) &&
5383 matches!(
5384 *local_name,
5385 local_name!("body") |
5386 local_name!("table") |
5387 local_name!("thead") |
5388 local_name!("tbody") |
5389 local_name!("tfoot") |
5390 local_name!("tr") |
5391 local_name!("td") |
5392 local_name!("th")
5393 )
5394}
5395
5396impl script_bindings::callback::OwnerWindow<crate::DomTypeHolder> for Element {
5397 fn owner_window(&self) -> Option<DomRoot<Window>> {
5398 Some(NodeTraits::owner_window(self))
5399 }
5400}