1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
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::jsapi::{Heap, JSAutoRealm};
24use js::jsval::JSVal;
25use js::rust::HandleObject;
26use layout_api::{LayoutDamage, ScrollContainerQueryFlags};
27use net_traits::ReferrerPolicy;
28use net_traits::request::CorsSettings;
29use selectors::Element as SelectorsElement;
30use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
31use selectors::bloom::{BLOOM_HASH_MASK, BloomFilter};
32use selectors::matching::{ElementSelectorFlags, MatchingContext};
33use selectors::sink::Push;
34use servo_arc::Arc;
35use style::applicable_declarations::ApplicableDeclarationBlock;
36use style::attr::{AttrValue, LengthOrPercentageOrAuto};
37use style::context::QuirksMode;
38use style::invalidation::element::restyle_hints::RestyleHint;
39use style::properties::longhands::{
40 self, background_image, border_spacing, font_family, font_size,
41};
42use style::properties::{
43 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
44 parse_style_attribute,
45};
46use style::rule_tree::CascadeLevel;
47use style::selector_parser::{
48 NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser, Snapshot,
49 extended_filtering,
50};
51use style::shared_lock::Locked;
52use style::stylesheets::layer_rule::LayerOrder;
53use style::stylesheets::{CssRuleType, UrlExtraData};
54use style::values::computed::Overflow;
55use style::values::generics::NonNegative;
56use style::values::generics::position::PreferredRatio;
57use style::values::generics::ratio::Ratio;
58use style::values::{AtomIdent, AtomString, CSSFloat, computed, specified};
59use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
60use style_traits::CSSPixel;
61use stylo_atoms::Atom;
62use stylo_dom::ElementState;
63use xml5ever::serialize::TraversalScope::{
64 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
65};
66
67use crate::conversions::Convert;
68use crate::dom::activation::Activatable;
69use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute};
70use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
71use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
72use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
73use crate::dom::bindings::codegen::Bindings::ElementBinding::{
74 ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
75};
76use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
77use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
78use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
79use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
80 ShadowRootMethods, ShadowRootMode, SlotAssignmentMode,
81};
82use crate::dom::bindings::codegen::Bindings::WindowBinding::{
83 ScrollBehavior, ScrollToOptions, WindowMethods,
84};
85use crate::dom::bindings::codegen::UnionTypes::{
86 BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
87 TrustedHTMLOrString,
88 TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString,
89 TrustedScriptURLOrUSVString,
90};
91use crate::dom::bindings::conversions::DerivedFrom;
92use crate::dom::bindings::domname::{
93 self, is_valid_attribute_local_name, namespace_from_domstring,
94};
95use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
96use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
97use crate::dom::bindings::num::Finite;
98use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
99use crate::dom::bindings::reflector::DomObject;
100use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
101use crate::dom::bindings::str::{DOMString, USVString};
102use crate::dom::bindings::xmlname::matches_name_production;
103use crate::dom::characterdata::CharacterData;
104use crate::dom::create::create_element;
105use crate::dom::csp::{CspReporting, InlineCheckType, SourcePosition};
106use crate::dom::customelementregistry::{
107 CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementRegistry,
108 CustomElementState, is_valid_custom_element_name,
109};
110use crate::dom::document::{Document, LayoutDocumentHelpers};
111use crate::dom::documentfragment::DocumentFragment;
112use crate::dom::domrect::DOMRect;
113use crate::dom::domrectlist::DOMRectList;
114use crate::dom::domtokenlist::DOMTokenList;
115use crate::dom::elementinternals::ElementInternals;
116use crate::dom::event::{EventBubbles, EventCancelable, EventComposed};
117use crate::dom::eventtarget::EventTarget;
118use crate::dom::globalscope::GlobalScope;
119use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
120use crate::dom::html::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers};
121use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
122use crate::dom::html::htmlcollection::HTMLCollection;
123use crate::dom::html::htmlelement::HTMLElement;
124use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
125use crate::dom::html::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers};
126use crate::dom::html::htmlformelement::FormControlElementHelpers;
127use crate::dom::html::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers, SizePresentationalHint};
128use crate::dom::html::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
129use crate::dom::html::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
130use crate::dom::html::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
131use crate::dom::html::htmllabelelement::HTMLLabelElement;
132use crate::dom::html::htmllegendelement::HTMLLegendElement;
133use crate::dom::html::htmllinkelement::HTMLLinkElement;
134use crate::dom::html::htmlobjectelement::HTMLObjectElement;
135use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
136use crate::dom::html::htmloutputelement::HTMLOutputElement;
137use crate::dom::html::htmlscriptelement::HTMLScriptElement;
138use crate::dom::html::htmlselectelement::HTMLSelectElement;
139use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
140use crate::dom::html::htmlstyleelement::HTMLStyleElement;
141use crate::dom::html::htmltablecellelement::{
142 HTMLTableCellElement, HTMLTableCellElementLayoutHelpers,
143};
144use crate::dom::html::htmltablecolelement::{
145 HTMLTableColElement, HTMLTableColElementLayoutHelpers,
146};
147use crate::dom::html::htmltableelement::{HTMLTableElement, HTMLTableElementLayoutHelpers};
148use crate::dom::html::htmltablerowelement::{
149 HTMLTableRowElement, HTMLTableRowElementLayoutHelpers,
150};
151use crate::dom::html::htmltablesectionelement::{
152 HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers,
153};
154use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
155use crate::dom::html::htmltextareaelement::{
156 HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers,
157};
158use crate::dom::html::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
159use crate::dom::intersectionobserver::{IntersectionObserver, IntersectionObserverRegistration};
160use crate::dom::mutationobserver::{Mutation, MutationObserver};
161use crate::dom::namednodemap::NamedNodeMap;
162use crate::dom::node::{
163 BindContext, ChildrenMutation, CloneChildrenFlag, IsShadowTree, LayoutNodeHelpers, Node,
164 NodeDamage, NodeFlags, NodeTraits, ShadowIncluding, UnbindContext,
165};
166use crate::dom::nodelist::NodeList;
167use crate::dom::promise::Promise;
168use crate::dom::raredata::ElementRareData;
169use crate::dom::scrolling_box::{ScrollAxisState, ScrollingBox};
170use crate::dom::servoparser::ServoParser;
171use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
172use crate::dom::text::Text;
173use crate::dom::trustedhtml::TrustedHTML;
174use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
175use crate::dom::validation::Validatable;
176use crate::dom::validitystate::ValidationFlags;
177use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
178use crate::script_runtime::CanGc;
179use crate::script_thread::ScriptThread;
180use crate::stylesheet_loader::StylesheetOwner;
181use crate::task::TaskOnce;
182
183#[dom_struct]
189pub struct Element {
190 node: Node,
191 #[no_trace]
192 local_name: LocalName,
193 tag_name: TagName,
194 #[no_trace]
195 namespace: Namespace,
196 #[no_trace]
197 prefix: DomRefCell<Option<Prefix>>,
198 attrs: DomRefCell<Vec<Dom<Attr>>>,
199 #[no_trace]
200 id_attribute: DomRefCell<Option<Atom>>,
201 #[no_trace]
203 is: DomRefCell<Option<LocalName>>,
204 #[conditional_malloc_size_of]
205 #[no_trace]
206 style_attribute: DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
207 attr_list: MutNullableDom<NamedNodeMap>,
208 class_list: MutNullableDom<DOMTokenList>,
209 #[no_trace]
210 state: Cell<ElementState>,
211 #[ignore_malloc_size_of = "bitflags defined in rust-selectors"]
216 #[no_trace]
217 selector_flags: Cell<ElementSelectorFlags>,
218 rare_data: DomRefCell<Option<Box<ElementRareData>>>,
219}
220
221impl fmt::Debug for Element {
222 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223 write!(f, "<{}", self.local_name)?;
224 if let Some(ref id) = *self.id_attribute.borrow() {
225 write!(f, " id={}", id)?;
226 }
227 write!(f, ">")
228 }
229}
230
231#[derive(MallocSizeOf, PartialEq)]
232pub(crate) enum ElementCreator {
233 ParserCreated(u64),
234 ScriptCreated,
235}
236
237pub(crate) enum CustomElementCreationMode {
238 Synchronous,
239 Asynchronous,
240}
241
242impl ElementCreator {
243 pub(crate) fn is_parser_created(&self) -> bool {
244 match *self {
245 ElementCreator::ParserCreated(_) => true,
246 ElementCreator::ScriptCreated => false,
247 }
248 }
249 pub(crate) fn return_line_number(&self) -> u64 {
250 match *self {
251 ElementCreator::ParserCreated(l) => l,
252 ElementCreator::ScriptCreated => 1,
253 }
254 }
255}
256
257pub(crate) enum AdjacentPosition {
258 BeforeBegin,
259 AfterEnd,
260 AfterBegin,
261 BeforeEnd,
262}
263
264impl FromStr for AdjacentPosition {
265 type Err = Error;
266
267 fn from_str(position: &str) -> Result<Self, Self::Err> {
268 match_ignore_ascii_case! { position,
269 "beforebegin" => Ok(AdjacentPosition::BeforeBegin),
270 "afterbegin" => Ok(AdjacentPosition::AfterBegin),
271 "beforeend" => Ok(AdjacentPosition::BeforeEnd),
272 "afterend" => Ok(AdjacentPosition::AfterEnd),
273 _ => Err(Error::Syntax(None))
274 }
275 }
276}
277
278impl Element {
282 pub(crate) fn create(
283 name: QualName,
284 is: Option<LocalName>,
285 document: &Document,
286 creator: ElementCreator,
287 mode: CustomElementCreationMode,
288 proto: Option<HandleObject>,
289 can_gc: CanGc,
290 ) -> DomRoot<Element> {
291 create_element(name, is, document, creator, mode, proto, can_gc)
292 }
293
294 pub(crate) fn new_inherited(
295 local_name: LocalName,
296 namespace: Namespace,
297 prefix: Option<Prefix>,
298 document: &Document,
299 ) -> Element {
300 Element::new_inherited_with_state(
301 ElementState::empty(),
302 local_name,
303 namespace,
304 prefix,
305 document,
306 )
307 }
308
309 pub(crate) fn new_inherited_with_state(
310 state: ElementState,
311 local_name: LocalName,
312 namespace: Namespace,
313 prefix: Option<Prefix>,
314 document: &Document,
315 ) -> Element {
316 Element {
317 node: Node::new_inherited(document),
318 local_name,
319 tag_name: TagName::new(),
320 namespace,
321 prefix: DomRefCell::new(prefix),
322 attrs: DomRefCell::new(vec![]),
323 id_attribute: DomRefCell::new(None),
324 is: DomRefCell::new(None),
325 style_attribute: DomRefCell::new(None),
326 attr_list: Default::default(),
327 class_list: Default::default(),
328 state: Cell::new(state),
329 selector_flags: Cell::new(ElementSelectorFlags::empty()),
330 rare_data: Default::default(),
331 }
332 }
333
334 pub(crate) fn new(
335 local_name: LocalName,
336 namespace: Namespace,
337 prefix: Option<Prefix>,
338 document: &Document,
339 proto: Option<HandleObject>,
340 can_gc: CanGc,
341 ) -> DomRoot<Element> {
342 Node::reflect_node_with_proto(
343 Box::new(Element::new_inherited(
344 local_name, namespace, prefix, document,
345 )),
346 document,
347 proto,
348 can_gc,
349 )
350 }
351
352 fn rare_data(&self) -> Ref<'_, Option<Box<ElementRareData>>> {
353 self.rare_data.borrow()
354 }
355
356 fn rare_data_mut(&self) -> RefMut<'_, Option<Box<ElementRareData>>> {
357 self.rare_data.borrow_mut()
358 }
359
360 fn ensure_rare_data(&self) -> RefMut<'_, Box<ElementRareData>> {
361 let mut rare_data = self.rare_data.borrow_mut();
362 if rare_data.is_none() {
363 *rare_data = Some(Default::default());
364 }
365 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
366 }
367
368 pub(crate) fn restyle(&self, damage: NodeDamage) {
369 let doc = self.node.owner_doc();
370 let mut restyle = doc.ensure_pending_restyle(self);
371
372 restyle.hint.insert(RestyleHint::RESTYLE_SELF);
375
376 match damage {
377 NodeDamage::Style => {},
378 NodeDamage::ContentOrHeritage => {
379 doc.note_node_with_dirty_descendants(self.upcast());
380 restyle
381 .damage
382 .insert(LayoutDamage::descendant_has_box_damage());
383 },
384 NodeDamage::Other => {
385 doc.note_node_with_dirty_descendants(self.upcast());
386 restyle.damage.insert(RestyleDamage::reconstruct());
387 },
388 }
389 }
390
391 pub(crate) fn set_is(&self, is: LocalName) {
392 *self.is.borrow_mut() = Some(is);
393 }
394
395 pub(crate) fn get_is(&self) -> Option<LocalName> {
397 self.is.borrow().clone()
398 }
399
400 pub(crate) fn set_initial_custom_element_state_to_uncustomized(&self) {
409 let mut state = self.state.get();
410 state.insert(ElementState::DEFINED);
411 self.state.set(state);
412 }
413
414 pub(crate) fn set_custom_element_state(&self, state: CustomElementState) {
416 if state != CustomElementState::Uncustomized {
418 self.ensure_rare_data().custom_element_state = state;
419 }
420
421 let in_defined_state = matches!(
422 state,
423 CustomElementState::Uncustomized | CustomElementState::Custom
424 );
425 self.set_state(ElementState::DEFINED, in_defined_state)
426 }
427
428 pub(crate) fn get_custom_element_state(&self) -> CustomElementState {
429 if let Some(rare_data) = self.rare_data().as_ref() {
430 return rare_data.custom_element_state;
431 }
432 CustomElementState::Uncustomized
433 }
434
435 pub(crate) fn is_custom(&self) -> bool {
437 self.get_custom_element_state() == CustomElementState::Custom
438 }
439
440 pub(crate) fn set_custom_element_definition(&self, definition: Rc<CustomElementDefinition>) {
441 self.ensure_rare_data().custom_element_definition = Some(definition);
442 }
443
444 pub(crate) fn get_custom_element_definition(&self) -> Option<Rc<CustomElementDefinition>> {
445 self.rare_data().as_ref()?.custom_element_definition.clone()
446 }
447
448 pub(crate) fn clear_custom_element_definition(&self) {
449 self.ensure_rare_data().custom_element_definition = None;
450 }
451
452 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
453 pub(crate) fn push_callback_reaction(&self, function: Rc<Function>, args: Box<[Heap<JSVal>]>) {
454 self.ensure_rare_data()
455 .custom_element_reaction_queue
456 .push(CustomElementReaction::Callback(function, args));
457 }
458
459 pub(crate) fn push_upgrade_reaction(&self, definition: Rc<CustomElementDefinition>) {
460 self.ensure_rare_data()
461 .custom_element_reaction_queue
462 .push(CustomElementReaction::Upgrade(definition));
463 }
464
465 pub(crate) fn clear_reaction_queue(&self) {
466 if let Some(ref mut rare_data) = *self.rare_data_mut() {
467 rare_data.custom_element_reaction_queue.clear();
468 }
469 }
470
471 pub(crate) fn invoke_reactions(&self, can_gc: CanGc) {
472 loop {
473 rooted_vec!(let mut reactions);
474 match *self.rare_data_mut() {
475 Some(ref mut data) => {
476 mem::swap(&mut *reactions, &mut data.custom_element_reaction_queue)
477 },
478 None => break,
479 };
480
481 if reactions.is_empty() {
482 break;
483 }
484
485 for reaction in reactions.iter() {
486 reaction.invoke(self, can_gc);
487 }
488
489 reactions.clear();
490 }
491 }
492
493 pub(crate) fn style(&self) -> Option<Arc<ComputedValues>> {
496 self.upcast::<Node>().style()
497 }
498
499 pub(crate) fn has_css_layout_box(&self) -> bool {
501 self.style()
502 .is_some_and(|s| !s.get_box().clone_display().is_none())
503 }
504
505 pub(crate) fn is_potentially_scrollable_body(&self) -> bool {
507 self.is_potentially_scrollable_body_shared_logic(false)
508 }
509
510 pub(crate) fn is_potentially_scrollable_body_for_scrolling_element(&self) -> bool {
512 self.is_potentially_scrollable_body_shared_logic(true)
513 }
514
515 fn is_potentially_scrollable_body_shared_logic(
517 &self,
518 treat_overflow_clip_on_parent_as_hidden: bool,
519 ) -> bool {
520 let node = self.upcast::<Node>();
521 debug_assert!(
522 node.owner_doc().GetBody().as_deref() == self.downcast::<HTMLElement>(),
523 "Called is_potentially_scrollable_body on element that is not the <body>"
524 );
525
526 if !self.has_css_layout_box() {
530 return false;
531 }
532
533 if let Some(parent) = node.GetParentElement() {
536 if let Some(style) = parent.style() {
537 let mut overflow_x = style.get_box().clone_overflow_x();
538 let mut overflow_y = style.get_box().clone_overflow_y();
539
540 if treat_overflow_clip_on_parent_as_hidden {
543 if overflow_x == Overflow::Clip {
544 overflow_x = Overflow::Hidden;
545 }
546 if overflow_y == Overflow::Clip {
547 overflow_y = Overflow::Hidden;
548 }
549 }
550
551 if !overflow_x.is_scrollable() && !overflow_y.is_scrollable() {
552 return false;
553 }
554 };
555 }
556
557 if let Some(style) = self.style() {
560 if !style.get_box().clone_overflow_x().is_scrollable() &&
561 !style.get_box().clone_overflow_y().is_scrollable()
562 {
563 return false;
564 }
565 };
566
567 true
568 }
569
570 fn has_scrolling_box(&self) -> bool {
572 self.style().is_some_and(|style| {
575 style.get_box().clone_overflow_x().is_scrollable() ||
576 style.get_box().clone_overflow_y().is_scrollable()
577 })
578 }
579
580 fn has_overflow(&self) -> bool {
581 self.ScrollHeight() > self.ClientHeight() || self.ScrollWidth() > self.ClientWidth()
582 }
583
584 pub(crate) fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
585 self.rare_data()
586 .as_ref()?
587 .shadow_root
588 .as_ref()
589 .map(|sr| DomRoot::from_ref(&**sr))
590 }
591
592 pub(crate) fn is_shadow_host(&self) -> bool {
593 self.shadow_root().is_some()
594 }
595
596 #[allow(clippy::too_many_arguments)]
598 pub(crate) fn attach_shadow(
599 &self,
600 is_ua_widget: IsUserAgentWidget,
601 mode: ShadowRootMode,
602 clonable: bool,
603 serializable: bool,
604 delegates_focus: bool,
605 slot_assignment_mode: SlotAssignmentMode,
606 can_gc: CanGc,
607 ) -> Fallible<DomRoot<ShadowRoot>> {
608 if self.namespace != ns!(html) {
611 return Err(Error::NotSupported(Some(
612 "Cannot attach shadow roots to elements with non-HTML namespaces".to_owned(),
613 )));
614 }
615
616 if !is_valid_shadow_host_name(self.local_name()) {
619 if is_ua_widget != IsUserAgentWidget::Yes {
621 let error_message = format!(
622 "Cannot attach shadow roots to <{}> elements",
623 *self.local_name()
624 );
625 return Err(Error::NotSupported(Some(error_message)));
626 }
627 }
628
629 if is_valid_custom_element_name(self.local_name()) || self.get_is().is_some() {
632 let definition = self.get_custom_element_definition();
636 if definition.is_some_and(|definition| definition.disable_shadow) {
639 let error_message = format!(
640 "The custom element constructor of <{}> disabled attachment of shadow roots",
641 self.local_name()
642 );
643 return Err(Error::NotSupported(Some(error_message)));
644 }
645 }
646
647 if let Some(current_shadow_root) = self.shadow_root() {
650 if !current_shadow_root.is_declarative() ||
654 current_shadow_root.shadow_root_mode() != mode
655 {
656 return Err(Error::NotSupported(Some(
657 "Cannot attach a second shadow root to the same element".into(),
658 )));
659 }
660
661 for child in current_shadow_root.upcast::<Node>().children() {
663 child.remove_self(can_gc);
664 }
665
666 current_shadow_root.set_declarative(false);
668
669 return Ok(current_shadow_root);
671 }
672
673 let shadow_root = ShadowRoot::new(
680 self,
681 &self.node.owner_doc(),
682 mode,
683 slot_assignment_mode,
684 clonable,
685 is_ua_widget,
686 can_gc,
687 );
688
689 let node = self.upcast::<Node>();
693 node.remove_layout_boxes_from_subtree();
694
695 shadow_root.set_delegates_focus(delegates_focus);
697
698 if matches!(
701 self.get_custom_element_state(),
702 CustomElementState::Precustomized | CustomElementState::Custom
703 ) {
704 shadow_root.set_available_to_element_internals(true);
705 }
706
707 shadow_root.set_declarative(false);
709
710 shadow_root.set_serializable(serializable);
712
713 self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
715 shadow_root
716 .upcast::<Node>()
717 .set_containing_shadow_root(Some(&shadow_root));
718
719 let bind_context = BindContext::new(self.upcast(), IsShadowTree::Yes);
720 shadow_root.bind_to_tree(&bind_context, can_gc);
721
722 node.dirty(NodeDamage::Other);
723
724 Ok(shadow_root)
725 }
726
727 pub(crate) fn attach_ua_shadow_root(
743 &self,
744 use_ua_widget_styling: bool,
745 can_gc: CanGc,
746 ) -> DomRoot<ShadowRoot> {
747 let root = self
748 .attach_shadow(
749 IsUserAgentWidget::Yes,
750 ShadowRootMode::Closed,
751 false,
752 false,
753 false,
754 SlotAssignmentMode::Manual,
755 can_gc,
756 )
757 .expect("Attaching UA shadow root failed");
758
759 root.upcast::<Node>()
760 .set_in_ua_widget(use_ua_widget_styling);
761 root
762 }
763
764 pub(crate) fn is_translate_enabled(&self) -> bool {
766 let name = &local_name!("translate");
767 if self.has_attribute(name) {
768 let attribute = self.get_string_attribute(name);
769 match_ignore_ascii_case! { &*attribute.str(),
770 "yes" | "" => return true,
771 "no" => return false,
772 _ => {},
773 }
774 }
775 if let Some(parent) = self.upcast::<Node>().GetParentNode() {
776 if let Some(elem) = parent.downcast::<Element>() {
777 return elem.is_translate_enabled();
778 }
779 }
780 true
781 }
782
783 pub(crate) fn directionality(&self) -> String {
785 self.downcast::<HTMLElement>()
786 .and_then(|html_element| html_element.directionality())
787 .unwrap_or_else(|| {
788 let node = self.upcast::<Node>();
789 node.parent_directionality()
790 })
791 }
792
793 pub(crate) fn is_root(&self) -> bool {
794 match self.node.GetParentNode() {
795 None => false,
796 Some(node) => node.is::<Document>(),
797 }
798 }
799
800 pub(crate) fn registered_intersection_observers_mut(
803 &self,
804 ) -> RefMut<'_, Vec<IntersectionObserverRegistration>> {
805 RefMut::map(self.ensure_rare_data(), |rare_data| {
806 &mut rare_data.registered_intersection_observers
807 })
808 }
809
810 pub(crate) fn registered_intersection_observers(
811 &self,
812 ) -> Option<Ref<'_, Vec<IntersectionObserverRegistration>>> {
813 let rare_data: Ref<'_, _> = self.rare_data.borrow();
814
815 if rare_data.is_none() {
816 return None;
817 }
818 Some(Ref::map(rare_data, |rare_data| {
819 &rare_data
820 .as_ref()
821 .unwrap()
822 .registered_intersection_observers
823 }))
824 }
825
826 pub(crate) fn get_intersection_observer_registration(
827 &self,
828 observer: &IntersectionObserver,
829 ) -> Option<Ref<'_, IntersectionObserverRegistration>> {
830 if let Some(registrations) = self.registered_intersection_observers() {
831 registrations
832 .iter()
833 .position(|reg_obs| reg_obs.observer == observer)
834 .map(|index| Ref::map(registrations, |registrations| ®istrations[index]))
835 } else {
836 None
837 }
838 }
839
840 pub(crate) fn add_initial_intersection_observer_registration(
842 &self,
843 observer: &IntersectionObserver,
844 ) {
845 self.ensure_rare_data()
846 .registered_intersection_observers
847 .push(IntersectionObserverRegistration::new_initial(observer));
848 }
849
850 pub(crate) fn remove_intersection_observer(&self, observer: &IntersectionObserver) {
852 self.ensure_rare_data()
853 .registered_intersection_observers
854 .retain(|reg_obs| *reg_obs.observer != *observer)
855 }
856
857 pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
860 self.owner_window()
861 .scrolling_box_query(Some(self.upcast()), flags)
862 }
863
864 pub(crate) fn scroll_into_view_with_options(
866 &self,
867 behavior: ScrollBehavior,
868 block: ScrollAxisState,
869 inline: ScrollAxisState,
870 container: Option<&Element>,
871 inner_target_rect: Option<Rect<Au, CSSPixel>>,
872 ) {
873 let get_target_rect = || match inner_target_rect {
874 None => self.upcast::<Node>().border_box().unwrap_or_default(),
875 Some(inner_target_rect) => inner_target_rect.translate(
876 self.upcast::<Node>()
877 .content_box()
878 .unwrap_or_default()
879 .origin
880 .to_vector(),
881 ),
882 };
883
884 let mut parent_scrolling_box = self.scrolling_box(ScrollContainerQueryFlags::empty());
887 while let Some(scrolling_box) = parent_scrolling_box {
888 parent_scrolling_box = scrolling_box.parent();
889
890 let position =
901 scrolling_box.determine_scroll_into_view_position(block, inline, get_target_rect());
902
903 if position != scrolling_box.scroll_position() {
908 scrolling_box.scroll_to(position, behavior);
919 }
920
921 if container.is_some_and(|container| {
925 let container_node = container.upcast::<Node>();
926 scrolling_box
927 .node()
928 .is_shadow_including_inclusive_ancestor_of(container_node)
929 }) {
930 return;
931 }
932 }
933
934 let window_proxy = self.owner_window().window_proxy();
935 let Some(frame_element) = window_proxy.frame_element() else {
936 return;
937 };
938
939 let inner_target_rect = Some(get_target_rect());
940 let parent_window = frame_element.owner_window();
941 let cx = GlobalScope::get_cx();
942 let _ac = JSAutoRealm::new(*cx, *parent_window.reflector().get_jsobject());
943 frame_element.scroll_into_view_with_options(
944 behavior,
945 block,
946 inline,
947 None,
948 inner_target_rect,
949 )
950 }
951}
952
953#[inline]
955pub(crate) fn is_valid_shadow_host_name(name: &LocalName) -> bool {
956 if is_valid_custom_element_name(name) {
959 return true;
960 }
961
962 matches!(
965 name,
966 &local_name!("article") |
967 &local_name!("aside") |
968 &local_name!("blockquote") |
969 &local_name!("body") |
970 &local_name!("div") |
971 &local_name!("footer") |
972 &local_name!("h1") |
973 &local_name!("h2") |
974 &local_name!("h3") |
975 &local_name!("h4") |
976 &local_name!("h5") |
977 &local_name!("h6") |
978 &local_name!("header") |
979 &local_name!("main") |
980 &local_name!("nav") |
981 &local_name!("p") |
982 &local_name!("section") |
983 &local_name!("span")
984 )
985}
986
987#[inline]
988pub(crate) fn get_attr_for_layout<'dom>(
989 elem: LayoutDom<'dom, Element>,
990 namespace: &Namespace,
991 name: &LocalName,
992) -> Option<&'dom AttrValue> {
993 elem.attrs()
994 .iter()
995 .find(|attr| name == attr.local_name() && namespace == attr.namespace())
996 .map(|attr| attr.value())
997}
998
999pub(crate) trait LayoutElementHelpers<'dom> {
1000 fn attrs(self) -> &'dom [LayoutDom<'dom, Attr>];
1001 fn has_class_or_part_for_layout(
1002 self,
1003 name: &AtomIdent,
1004 attr_name: &LocalName,
1005 case_sensitivity: CaseSensitivity,
1006 ) -> bool;
1007 fn get_classes_for_layout(self) -> Option<&'dom [Atom]>;
1008 fn get_parts_for_layout(self) -> Option<&'dom [Atom]>;
1009
1010 fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1011 where
1012 V: Push<ApplicableDeclarationBlock>;
1013 fn get_span(self) -> Option<u32>;
1014 fn get_colspan(self) -> Option<u32>;
1015 fn get_rowspan(self) -> Option<u32>;
1016 fn is_html_element(&self) -> bool;
1017 fn id_attribute(self) -> *const Option<Atom>;
1018 fn style_attribute(self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
1019 fn local_name(self) -> &'dom LocalName;
1020 fn namespace(self) -> &'dom Namespace;
1021 fn get_lang_attr_val_for_layout(self) -> Option<&'dom str>;
1022 fn get_lang_for_layout(self) -> String;
1023 fn get_state_for_layout(self) -> ElementState;
1024 fn insert_selector_flags(self, flags: ElementSelectorFlags);
1025 fn get_selector_flags(self) -> ElementSelectorFlags;
1026 fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>>;
1028 fn get_attr_for_layout(
1029 self,
1030 namespace: &Namespace,
1031 name: &LocalName,
1032 ) -> Option<&'dom AttrValue>;
1033 fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str>;
1034 fn get_attr_vals_for_layout(self, name: &LocalName) -> impl Iterator<Item = &'dom AttrValue>;
1035 fn each_custom_state_for_layout(self, allback: impl FnMut(&AtomIdent));
1036}
1037
1038impl LayoutDom<'_, Element> {
1039 pub(super) fn focus_state(self) -> bool {
1040 self.unsafe_get().state.get().contains(ElementState::FOCUS)
1041 }
1042}
1043
1044impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
1045 #[expect(unsafe_code)]
1046 #[inline]
1047 fn attrs(self) -> &'dom [LayoutDom<'dom, Attr>] {
1048 unsafe { LayoutDom::to_layout_slice(self.unsafe_get().attrs.borrow_for_layout()) }
1049 }
1050
1051 #[inline]
1052 fn has_class_or_part_for_layout(
1053 self,
1054 name: &AtomIdent,
1055 attr_name: &LocalName,
1056 case_sensitivity: CaseSensitivity,
1057 ) -> bool {
1058 get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
1059 attr.as_tokens()
1060 .iter()
1061 .any(|atom| case_sensitivity.eq_atom(atom, name))
1062 })
1063 }
1064
1065 #[inline]
1066 fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
1067 get_attr_for_layout(self, &ns!(), &local_name!("class")).map(|attr| attr.as_tokens())
1068 }
1069
1070 fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
1071 get_attr_for_layout(self, &ns!(), &local_name!("part")).map(|attr| attr.as_tokens())
1072 }
1073
1074 fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1075 where
1076 V: Push<ApplicableDeclarationBlock>,
1077 {
1078 let mut property_declaration_block = None;
1079 let mut push = |declaration| {
1080 property_declaration_block
1081 .get_or_insert_with(PropertyDeclarationBlock::default)
1082 .push(declaration, Importance::Normal);
1083 };
1084
1085 if let Some(lang) = self.get_lang_attr_val_for_layout() {
1088 push(PropertyDeclaration::XLang(specified::XLang(Atom::from(
1089 lang.to_owned(),
1090 ))));
1091 }
1092
1093 let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
1094 this.get_background_color()
1095 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1096 this.get_background_color()
1097 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1098 this.get_background_color()
1099 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1100 this.get_background_color()
1101 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1102 this.get_background_color()
1103 } else {
1104 None
1105 };
1106
1107 if let Some(color) = bgcolor {
1108 push(PropertyDeclaration::BackgroundColor(
1109 specified::Color::from_absolute_color(color),
1110 ));
1111 }
1112
1113 if is_element_affected_by_legacy_background_presentational_hint(
1114 self.namespace(),
1115 self.local_name(),
1116 ) {
1117 if let Some(url) = self
1118 .get_attr_for_layout(&ns!(), &local_name!("background"))
1119 .and_then(AttrValue::as_resolved_url)
1120 .cloned()
1121 {
1122 push(PropertyDeclaration::BackgroundImage(
1123 background_image::SpecifiedValue(
1124 vec![specified::Image::for_cascade(url)].into(),
1125 ),
1126 ));
1127 }
1128 }
1129
1130 let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
1131 this.get_color()
1132 } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
1133 this.get_color()
1135 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1136 this.get_color()
1138 } else {
1139 None
1140 };
1141
1142 if let Some(color) = color {
1143 push(PropertyDeclaration::Color(
1144 longhands::color::SpecifiedValue(specified::Color::from_absolute_color(color)),
1145 ));
1146 }
1147
1148 let font_face = self
1149 .downcast::<HTMLFontElement>()
1150 .and_then(HTMLFontElementLayoutHelpers::get_face);
1151 if let Some(font_face) = font_face {
1152 push(PropertyDeclaration::FontFamily(
1153 font_family::SpecifiedValue::Values(computed::font::FontFamilyList {
1154 list: ArcSlice::from_iter(
1155 HTMLFontElement::parse_face_attribute(font_face).into_iter(),
1156 ),
1157 }),
1158 ));
1159 }
1160
1161 let font_size = self
1162 .downcast::<HTMLFontElement>()
1163 .and_then(HTMLFontElementLayoutHelpers::get_size);
1164 if let Some(font_size) = font_size {
1165 push(PropertyDeclaration::FontSize(
1166 font_size::SpecifiedValue::from_html_size(font_size as u8),
1167 ));
1168 }
1169
1170 let cellspacing = self
1171 .downcast::<HTMLTableElement>()
1172 .and_then(HTMLTableElementLayoutHelpers::get_cellspacing);
1173 if let Some(cellspacing) = cellspacing {
1174 let width_value = specified::Length::from_px(cellspacing as f32);
1175 push(PropertyDeclaration::BorderSpacing(Box::new(
1176 border_spacing::SpecifiedValue::new(width_value.clone().into(), width_value.into()),
1177 )));
1178 }
1179
1180 let size = self
1186 .downcast::<HTMLInputElement>()
1187 .and_then(|input_element| {
1188 match self.get_attr_val_for_layout(&ns!(), &local_name!("type")) {
1190 Some("hidden") | Some("range") | Some("color") | Some("checkbox") |
1191 Some("radio") | Some("file") | Some("submit") | Some("image") |
1192 Some("reset") | Some("button") => None,
1193 _ => match input_element.size_for_layout() {
1195 0 => None,
1196 s => Some(s as i32),
1197 },
1198 }
1199 });
1200
1201 if let Some(size) = size {
1202 let value =
1203 specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size));
1204 push(PropertyDeclaration::Width(
1205 specified::Size::LengthPercentage(NonNegative(
1206 specified::LengthPercentage::Length(value),
1207 )),
1208 ));
1209 }
1210
1211 let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1212 this.get_width()
1213 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1214 this.get_width()
1215 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1216 this.get_width()
1217 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1218 this.get_width()
1219 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1220 this.get_width()
1221 } else if let Some(this) = self.downcast::<HTMLTableColElement>() {
1222 this.get_width()
1223 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1224 this.get_width()
1226 } else {
1227 LengthOrPercentageOrAuto::Auto
1228 };
1229
1230 match width {
1232 LengthOrPercentageOrAuto::Auto => {},
1233 LengthOrPercentageOrAuto::Percentage(percentage) => {
1234 let width_value = specified::Size::LengthPercentage(NonNegative(
1235 specified::LengthPercentage::Percentage(computed::Percentage(percentage)),
1236 ));
1237 push(PropertyDeclaration::Width(width_value));
1238 },
1239 LengthOrPercentageOrAuto::Length(length) => {
1240 let width_value = specified::Size::LengthPercentage(NonNegative(
1241 specified::LengthPercentage::Length(specified::NoCalcLength::Absolute(
1242 specified::AbsoluteLength::Px(length.to_f32_px()),
1243 )),
1244 ));
1245 push(PropertyDeclaration::Width(width_value));
1246 },
1247 }
1248
1249 let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1250 this.get_height()
1251 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1252 this.get_height()
1253 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1254 this.get_height()
1255 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1256 this.get_height()
1257 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1258 this.get_height()
1259 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1260 this.get_height()
1261 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1262 this.get_height()
1263 } else {
1264 LengthOrPercentageOrAuto::Auto
1265 };
1266
1267 match height {
1268 LengthOrPercentageOrAuto::Auto => {},
1269 LengthOrPercentageOrAuto::Percentage(percentage) => {
1270 let height_value = specified::Size::LengthPercentage(NonNegative(
1271 specified::LengthPercentage::Percentage(computed::Percentage(percentage)),
1272 ));
1273 push(PropertyDeclaration::Height(height_value));
1274 },
1275 LengthOrPercentageOrAuto::Length(length) => {
1276 let height_value = specified::Size::LengthPercentage(NonNegative(
1277 specified::LengthPercentage::Length(specified::NoCalcLength::Absolute(
1278 specified::AbsoluteLength::Px(length.to_f32_px()),
1279 )),
1280 ));
1281 push(PropertyDeclaration::Height(height_value));
1282 },
1283 }
1284
1285 if self.downcast::<HTMLImageElement>().is_some() ||
1288 self.downcast::<HTMLVideoElement>().is_some()
1289 {
1290 if let LengthOrPercentageOrAuto::Length(width) = width {
1291 if let LengthOrPercentageOrAuto::Length(height) = height {
1292 let width_value = NonNegative(specified::Number::new(width.to_f32_px()));
1293 let height_value = NonNegative(specified::Number::new(height.to_f32_px()));
1294 let aspect_ratio = specified::position::AspectRatio {
1295 auto: true,
1296 ratio: PreferredRatio::Ratio(Ratio(width_value, height_value)),
1297 };
1298 push(PropertyDeclaration::AspectRatio(aspect_ratio));
1299 }
1300 }
1301 }
1302
1303 let cols = self
1304 .downcast::<HTMLTextAreaElement>()
1305 .map(LayoutHTMLTextAreaElementHelpers::get_cols);
1306 if let Some(cols) = cols {
1307 let cols = cols as i32;
1308 if cols > 0 {
1309 let value =
1315 specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols));
1316 push(PropertyDeclaration::Width(
1317 specified::Size::LengthPercentage(NonNegative(
1318 specified::LengthPercentage::Length(value),
1319 )),
1320 ));
1321 }
1322 }
1323
1324 let rows = self
1325 .downcast::<HTMLTextAreaElement>()
1326 .map(LayoutHTMLTextAreaElementHelpers::get_rows);
1327 if let Some(rows) = rows {
1328 let rows = rows as i32;
1329 if rows > 0 {
1330 let value = specified::NoCalcLength::FontRelative(
1334 specified::FontRelativeLength::Em(rows as CSSFloat),
1335 );
1336 push(PropertyDeclaration::Height(
1337 specified::Size::LengthPercentage(NonNegative(
1338 specified::LengthPercentage::Length(value),
1339 )),
1340 ));
1341 }
1342 }
1343
1344 let border = self
1345 .downcast::<HTMLTableElement>()
1346 .and_then(|table| table.get_border());
1347 if let Some(border) = border {
1348 let width_value = specified::BorderSideWidth::from_px(border as f32);
1349 push(PropertyDeclaration::BorderTopWidth(width_value.clone()));
1350 push(PropertyDeclaration::BorderLeftWidth(width_value.clone()));
1351 push(PropertyDeclaration::BorderBottomWidth(width_value.clone()));
1352 push(PropertyDeclaration::BorderRightWidth(width_value));
1353 }
1354
1355 if let Some(cellpadding) = self
1356 .downcast::<HTMLTableCellElement>()
1357 .and_then(|this| this.get_table())
1358 .and_then(|table| table.get_cellpadding())
1359 {
1360 let cellpadding = NonNegative(specified::LengthPercentage::Length(
1361 specified::NoCalcLength::from_px(cellpadding as f32),
1362 ));
1363 push(PropertyDeclaration::PaddingTop(cellpadding.clone()));
1364 push(PropertyDeclaration::PaddingLeft(cellpadding.clone()));
1365 push(PropertyDeclaration::PaddingBottom(cellpadding.clone()));
1366 push(PropertyDeclaration::PaddingRight(cellpadding));
1367 }
1368
1369 if let Some(size_info) = self
1371 .downcast::<HTMLHRElement>()
1372 .and_then(|hr_element| hr_element.get_size_info())
1373 {
1374 match size_info {
1375 SizePresentationalHint::SetHeightTo(height) => {
1376 push(PropertyDeclaration::Height(height));
1377 },
1378 SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
1379 push(PropertyDeclaration::BorderLeftWidth(border_width.clone()));
1380 push(PropertyDeclaration::BorderRightWidth(border_width.clone()));
1381 push(PropertyDeclaration::BorderTopWidth(border_width.clone()));
1382 push(PropertyDeclaration::BorderBottomWidth(border_width));
1383 },
1384 SizePresentationalHint::SetBottomBorderWidthToZero => {
1385 push(PropertyDeclaration::BorderBottomWidth(
1386 specified::border::BorderSideWidth::from_px(0.),
1387 ));
1388 },
1389 }
1390 }
1391
1392 let Some(property_declaration_block) = property_declaration_block else {
1393 return;
1394 };
1395
1396 let document = self.upcast::<Node>().owner_doc_for_layout();
1397 let shared_lock = document.style_shared_lock();
1398 hints.push(ApplicableDeclarationBlock::from_declarations(
1399 Arc::new(shared_lock.wrap(property_declaration_block)),
1400 CascadeLevel::PresHints,
1401 LayerOrder::root(),
1402 ));
1403 }
1404
1405 fn get_span(self) -> Option<u32> {
1406 self.downcast::<HTMLTableColElement>()
1408 .and_then(|element| element.get_span())
1409 }
1410
1411 fn get_colspan(self) -> Option<u32> {
1412 self.downcast::<HTMLTableCellElement>()
1414 .and_then(|element| element.get_colspan())
1415 }
1416
1417 fn get_rowspan(self) -> Option<u32> {
1418 self.downcast::<HTMLTableCellElement>()
1420 .and_then(|element| element.get_rowspan())
1421 }
1422
1423 #[inline]
1424 fn is_html_element(&self) -> bool {
1425 *self.namespace() == ns!(html)
1426 }
1427
1428 #[expect(unsafe_code)]
1429 fn id_attribute(self) -> *const Option<Atom> {
1430 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1431 }
1432
1433 #[expect(unsafe_code)]
1434 fn style_attribute(self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
1435 unsafe { (self.unsafe_get()).style_attribute.borrow_for_layout() }
1436 }
1437
1438 fn local_name(self) -> &'dom LocalName {
1439 &(self.unsafe_get()).local_name
1440 }
1441
1442 fn namespace(self) -> &'dom Namespace {
1443 &(self.unsafe_get()).namespace
1444 }
1445
1446 fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1447 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1448 return Some(attr);
1449 }
1450 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1451 return Some(attr);
1452 }
1453 None
1454 }
1455
1456 fn get_lang_for_layout(self) -> String {
1457 let mut current_node = Some(self.upcast::<Node>());
1458 while let Some(node) = current_node {
1459 current_node = node.composed_parent_node_ref();
1460 match node.downcast::<Element>() {
1461 Some(elem) => {
1462 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1463 return attr.to_owned();
1464 }
1465 },
1466 None => continue,
1467 }
1468 }
1469 String::new()
1472 }
1473
1474 #[inline]
1475 fn get_state_for_layout(self) -> ElementState {
1476 (self.unsafe_get()).state.get()
1477 }
1478
1479 #[inline]
1480 fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1481 debug_assert!(thread_state::get().is_layout());
1482 let f = &(self.unsafe_get()).selector_flags;
1483 f.set(f.get() | flags);
1484 }
1485
1486 #[inline]
1487 fn get_selector_flags(self) -> ElementSelectorFlags {
1488 self.unsafe_get().selector_flags.get()
1489 }
1490
1491 #[inline]
1492 #[expect(unsafe_code)]
1493 fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1494 unsafe {
1495 self.unsafe_get()
1496 .rare_data
1497 .borrow_for_layout()
1498 .as_ref()?
1499 .shadow_root
1500 .as_ref()
1501 .map(|sr| sr.to_layout())
1502 }
1503 }
1504
1505 #[inline]
1506 fn get_attr_for_layout(
1507 self,
1508 namespace: &Namespace,
1509 name: &LocalName,
1510 ) -> Option<&'dom AttrValue> {
1511 get_attr_for_layout(self, namespace, name)
1512 }
1513
1514 #[inline]
1515 fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str> {
1516 get_attr_for_layout(self, namespace, name).map(|attr| &**attr)
1517 }
1518
1519 #[inline]
1520 fn get_attr_vals_for_layout(self, name: &LocalName) -> impl Iterator<Item = &'dom AttrValue> {
1521 self.attrs().iter().filter_map(move |attr| {
1522 if name == attr.local_name() {
1523 Some(attr.value())
1524 } else {
1525 None
1526 }
1527 })
1528 }
1529
1530 #[expect(unsafe_code)]
1531 fn each_custom_state_for_layout(self, mut callback: impl FnMut(&AtomIdent)) {
1532 let rare_data = self.unsafe_get().rare_data();
1533 let Some(rare_data) = rare_data.as_ref() else {
1534 return;
1535 };
1536 let Some(element_internals) = rare_data.element_internals.as_ref() else {
1537 return;
1538 };
1539
1540 let element_internals = unsafe { element_internals.to_layout() };
1541 if let Some(states) = element_internals.unsafe_get().custom_states_for_layout() {
1542 for state in states.unsafe_get().set().iter() {
1543 callback(&AtomIdent::from(&*state.str()));
1545 }
1546 }
1547 }
1548}
1549
1550impl Element {
1551 pub(crate) fn is_html_element(&self) -> bool {
1552 self.namespace == ns!(html)
1553 }
1554
1555 pub(crate) fn html_element_in_html_document(&self) -> bool {
1556 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1557 }
1558
1559 pub(crate) fn local_name(&self) -> &LocalName {
1560 &self.local_name
1561 }
1562
1563 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1564 if self.html_element_in_html_document() {
1565 name.make_ascii_lowercase();
1566 }
1567 LocalName::from(name)
1568 }
1569
1570 pub(crate) fn namespace(&self) -> &Namespace {
1571 &self.namespace
1572 }
1573
1574 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1575 self.prefix.borrow()
1576 }
1577
1578 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1579 *self.prefix.borrow_mut() = prefix;
1580 }
1581
1582 pub(crate) fn set_custom_element_registry(
1583 &self,
1584 registry: Option<DomRoot<CustomElementRegistry>>,
1585 ) {
1586 self.ensure_rare_data().custom_element_registry = registry.as_deref().map(Dom::from_ref);
1587 }
1588
1589 pub(crate) fn custom_element_registry(&self) -> Option<DomRoot<CustomElementRegistry>> {
1590 self.rare_data()
1591 .as_ref()?
1592 .custom_element_registry
1593 .as_deref()
1594 .map(DomRoot::from_ref)
1595 }
1596
1597 pub(crate) fn attrs(&self) -> Ref<'_, [Dom<Attr>]> {
1598 Ref::map(self.attrs.borrow(), |attrs| &**attrs)
1599 }
1600
1601 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1603 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1604
1605 if namespace_prefix == Some(namespace_prefix!("xml")) {
1607 return ns!(xml);
1608 }
1609
1610 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1612 return ns!(xmlns);
1613 }
1614
1615 let prefix = prefix.map(LocalName::from);
1616
1617 let inclusive_ancestor_elements = self
1618 .upcast::<Node>()
1619 .inclusive_ancestors(ShadowIncluding::No)
1620 .filter_map(DomRoot::downcast::<Self>);
1621
1622 for element in inclusive_ancestor_elements {
1625 if element.namespace() != &ns!() &&
1627 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1628 {
1629 return element.namespace().clone();
1630 }
1631
1632 let attr = Ref::filter_map(self.attrs(), |attrs| {
1637 attrs.iter().find(|attr| {
1638 if attr.namespace() != &ns!(xmlns) {
1639 return false;
1640 }
1641 match (attr.prefix(), prefix.as_ref()) {
1642 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1643 attr.local_name() == prefix
1644 },
1645 (None, None) => attr.local_name() == &local_name!("xmlns"),
1646 _ => false,
1647 }
1648 })
1649 })
1650 .ok();
1651
1652 if let Some(attr) = attr {
1653 return (**attr.value()).into();
1654 }
1655 }
1656
1657 ns!()
1658 }
1659
1660 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1661 self.rare_data().as_ref()?.name_attribute.clone()
1662 }
1663
1664 pub(crate) fn style_attribute(
1665 &self,
1666 ) -> &DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
1667 &self.style_attribute
1668 }
1669
1670 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1671 self.attrs
1672 .borrow()
1673 .iter()
1674 .map(|attr| attr.summarize())
1675 .collect()
1676 }
1677
1678 pub(crate) fn is_void(&self) -> bool {
1679 if self.namespace != ns!(html) {
1680 return false;
1681 }
1682 match self.local_name {
1683 local_name!("area") |
1686 local_name!("base") |
1687 local_name!("basefont") |
1688 local_name!("bgsound") |
1689 local_name!("br") |
1690 local_name!("col") |
1691 local_name!("embed") |
1692 local_name!("frame") |
1693 local_name!("hr") |
1694 local_name!("img") |
1695 local_name!("input") |
1696 local_name!("keygen") |
1697 local_name!("link") |
1698 local_name!("meta") |
1699 local_name!("param") |
1700 local_name!("source") |
1701 local_name!("track") |
1702 local_name!("wbr") => true,
1703 _ => false,
1704 }
1705 }
1706
1707 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1708 if self.node.is_in_a_document_tree() {
1709 self.upcast::<Node>()
1710 .owner_doc()
1711 .GetDocumentElement()
1712 .unwrap()
1713 } else {
1714 self.upcast::<Node>()
1715 .inclusive_ancestors(ShadowIncluding::No)
1716 .filter_map(DomRoot::downcast)
1717 .last()
1718 .expect("We know inclusive_ancestors will return `self` which is an element")
1719 }
1720 }
1721
1722 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1724 for node in self
1725 .upcast::<Node>()
1726 .inclusive_ancestors(ShadowIncluding::No)
1727 {
1728 let element = node.downcast::<Element>()?;
1729 if *element.namespace() == namespace {
1731 if let Some(prefix) = element.GetPrefix() {
1732 return Some(prefix);
1733 }
1734 }
1735
1736 for attr in element.attrs.borrow().iter() {
1738 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1739 **attr.value() == *namespace
1740 {
1741 return Some(attr.LocalName());
1742 }
1743 }
1744 }
1745 None
1746 }
1747
1748 pub(crate) fn is_document_element(&self) -> bool {
1750 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1751 *document_element == *self
1752 } else {
1753 false
1754 }
1755 }
1756
1757 pub(crate) fn is_active_element(&self) -> bool {
1759 if let Some(active_element) = self.owner_document().GetActiveElement() {
1760 *active_element == *self
1761 } else {
1762 false
1763 }
1764 }
1765
1766 pub(crate) fn is_focusable_area(&self) -> bool {
1767 if self.is_actually_disabled() {
1768 return false;
1769 }
1770 let node = self.upcast::<Node>();
1771 if node.get_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE) {
1772 return true;
1773 }
1774
1775 matches!(
1777 node.type_id(),
1778 NodeTypeId::Element(ElementTypeId::HTMLElement(
1779 HTMLElementTypeId::HTMLAnchorElement,
1780 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1781 HTMLElementTypeId::HTMLInputElement,
1782 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1783 HTMLElementTypeId::HTMLSelectElement,
1784 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1785 HTMLElementTypeId::HTMLTextAreaElement,
1786 ))
1787 )
1788 }
1789
1790 pub(crate) fn find_focusable_shadow_host_if_necessary(&self) -> Option<DomRoot<Element>> {
1795 if self.is_focusable_area() {
1796 return Some(DomRoot::from_ref(self));
1797 }
1798
1799 if self.upcast::<Node>().implemented_pseudo_element() ==
1800 Some(PseudoElement::ServoTextControlInnerEditor)
1801 {
1802 let containing_shadow_host = self
1804 .containing_shadow_root()
1805 .map(|root| root.Host())
1806 .expect("Text control inner shadow DOM should always have a shadow host.");
1807 if !containing_shadow_host.is_focusable_area() {
1808 return None;
1809 }
1810 return Some(containing_shadow_host);
1811 }
1812
1813 None
1814 }
1815
1816 pub(crate) fn is_actually_disabled(&self) -> bool {
1817 let node = self.upcast::<Node>();
1818 match node.type_id() {
1819 NodeTypeId::Element(ElementTypeId::HTMLElement(
1820 HTMLElementTypeId::HTMLButtonElement,
1821 )) |
1822 NodeTypeId::Element(ElementTypeId::HTMLElement(
1823 HTMLElementTypeId::HTMLInputElement,
1824 )) |
1825 NodeTypeId::Element(ElementTypeId::HTMLElement(
1826 HTMLElementTypeId::HTMLSelectElement,
1827 )) |
1828 NodeTypeId::Element(ElementTypeId::HTMLElement(
1829 HTMLElementTypeId::HTMLTextAreaElement,
1830 )) |
1831 NodeTypeId::Element(ElementTypeId::HTMLElement(
1832 HTMLElementTypeId::HTMLOptionElement,
1833 )) => self.disabled_state(),
1834 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1835 self.downcast::<HTMLElement>()
1836 .unwrap()
1837 .is_form_associated_custom_element() &&
1838 self.disabled_state()
1839 },
1840 _ => false,
1845 }
1846 }
1847
1848 #[allow(clippy::too_many_arguments)]
1849 pub(crate) fn push_new_attribute(
1850 &self,
1851 local_name: LocalName,
1852 value: AttrValue,
1853 name: LocalName,
1854 namespace: Namespace,
1855 prefix: Option<Prefix>,
1856 reason: AttributeMutationReason,
1857 can_gc: CanGc,
1858 ) {
1859 let attr = Attr::new(
1860 &self.node.owner_doc(),
1861 local_name,
1862 value,
1863 name,
1864 namespace,
1865 prefix,
1866 Some(self),
1867 can_gc,
1868 );
1869 self.push_attribute(&attr, reason, can_gc);
1870 }
1871
1872 fn handle_attribute_changes(
1874 &self,
1875 attr: &Attr,
1876 old_value: Option<&AttrValue>,
1877 new_value: Option<DOMString>,
1878 reason: AttributeMutationReason,
1879 can_gc: CanGc,
1880 ) {
1881 let old_value_string = old_value.map(|old_value| DOMString::from(&**old_value));
1882 let name = attr.local_name().clone();
1885 let namespace = attr.namespace().clone();
1886 let mutation = LazyCell::new(|| Mutation::Attribute {
1887 name: name.clone(),
1888 namespace: namespace.clone(),
1889 old_value: old_value_string.clone(),
1890 });
1891 MutationObserver::queue_a_mutation_record(&self.node, mutation);
1892
1893 let has_new_value = new_value.is_some();
1895
1896 if self.is_custom() {
1899 let reaction = CallbackReaction::AttributeChanged(
1900 attr.local_name().clone(),
1901 old_value_string,
1902 new_value,
1903 attr.namespace().clone(),
1904 );
1905 ScriptThread::enqueue_callback_reaction(self, reaction, None);
1906 }
1907
1908 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
1910 let attribute_mutation = if has_new_value {
1911 AttributeMutation::Set(old_value, reason)
1912 } else {
1913 AttributeMutation::Removed
1914 };
1915 vtable_for(self.upcast()).attribute_mutated(attr, attribute_mutation, can_gc);
1916 }
1917 }
1918
1919 pub(crate) fn change_attribute(&self, attr: &Attr, mut value: AttrValue, can_gc: CanGc) {
1921 let old_value = &attr.value().clone();
1925 self.will_mutate_attr(attr);
1927 attr.swap_value(&mut value);
1928 let new_value = DOMString::from(&**attr.value());
1932 self.handle_attribute_changes(
1933 attr,
1934 Some(old_value),
1935 Some(new_value),
1936 AttributeMutationReason::Directly,
1937 can_gc,
1938 );
1939 }
1940
1941 pub(crate) fn push_attribute(
1943 &self,
1944 attr: &Attr,
1945 reason: AttributeMutationReason,
1946 can_gc: CanGc,
1947 ) {
1948 assert!(attr.GetOwnerElement().as_deref() == Some(self));
1952 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
1956 self.will_mutate_attr(attr);
1958 self.attrs.borrow_mut().push(Dom::from_ref(attr));
1959 let new_value = DOMString::from(&**attr.value());
1963 self.handle_attribute_changes(attr, None, Some(new_value), reason, can_gc);
1964 }
1965
1966 pub(crate) fn get_attribute(
1967 &self,
1968 namespace: &Namespace,
1969 local_name: &LocalName,
1970 ) -> Option<DomRoot<Attr>> {
1971 self.attrs
1972 .borrow()
1973 .iter()
1974 .find(|attr| attr.local_name() == local_name && attr.namespace() == namespace)
1975 .map(|js| DomRoot::from_ref(&**js))
1976 }
1977
1978 pub(crate) fn get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>> {
1980 let name = &self.parsed_name(name);
1981 let maybe_attribute = self
1982 .attrs
1983 .borrow()
1984 .iter()
1985 .find(|a| a.name() == name)
1986 .map(|js| DomRoot::from_ref(&**js));
1987 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
1988 if *name == local_name!("id") || *name == local_name!("name") {
1989 match maybe_attr {
1990 None => true,
1991 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
1992 }
1993 } else {
1994 true
1995 }
1996 }
1997 debug_assert!(id_and_name_must_be_atoms(name, &maybe_attribute));
1998 maybe_attribute
1999 }
2000
2001 pub(crate) fn set_attribute_from_parser(
2002 &self,
2003 qname: QualName,
2004 value: DOMString,
2005 prefix: Option<Prefix>,
2006 can_gc: CanGc,
2007 ) {
2008 if self
2010 .attrs
2011 .borrow()
2012 .iter()
2013 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
2014 {
2015 return;
2016 }
2017
2018 let name = match prefix {
2019 None => qname.local.clone(),
2020 Some(ref prefix) => {
2021 let name = format!("{}:{}", &**prefix, &*qname.local);
2022 LocalName::from(name)
2023 },
2024 };
2025 let value = self.parse_attribute(&qname.ns, &qname.local, value);
2026 self.push_new_attribute(
2027 qname.local,
2028 value,
2029 name,
2030 qname.ns,
2031 prefix,
2032 AttributeMutationReason::ByParser,
2033 can_gc,
2034 );
2035 }
2036
2037 pub(crate) fn set_attribute(&self, name: &LocalName, value: AttrValue, can_gc: CanGc) {
2038 assert!(name == &name.to_ascii_lowercase());
2039 assert!(!name.contains(':'));
2040
2041 self.set_first_matching_attribute(
2042 name.clone(),
2043 value,
2044 name.clone(),
2045 ns!(),
2046 None,
2047 |attr| attr.local_name() == name,
2048 can_gc,
2049 );
2050 }
2051
2052 pub(crate) fn set_custom_attribute(
2054 &self,
2055 name: DOMString,
2056 value: DOMString,
2057 can_gc: CanGc,
2058 ) -> ErrorResult {
2059 if !matches_name_production(&name.str()) {
2061 return Err(Error::InvalidCharacter(None));
2062 }
2063
2064 let name = LocalName::from(name);
2066 let value = self.parse_attribute(&ns!(), &name, value);
2067 self.set_first_matching_attribute(
2068 name.clone(),
2069 value,
2070 name.clone(),
2071 ns!(),
2072 None,
2073 |attr| *attr.name() == name && *attr.namespace() == ns!(),
2074 can_gc,
2075 );
2076 Ok(())
2077 }
2078
2079 #[allow(clippy::too_many_arguments)]
2081 fn set_first_matching_attribute<F>(
2082 &self,
2083 local_name: LocalName,
2084 value: AttrValue,
2085 name: LocalName,
2086 namespace: Namespace,
2087 prefix: Option<Prefix>,
2088 find: F,
2089 can_gc: CanGc,
2090 ) where
2091 F: Fn(&Attr) -> bool,
2092 {
2093 let attr = self
2095 .attrs
2096 .borrow()
2097 .iter()
2098 .find(|attr| find(attr))
2099 .map(|js| DomRoot::from_ref(&**js));
2100 if let Some(attr) = attr {
2101 self.will_mutate_attr(&attr);
2103 self.change_attribute(&attr, value, can_gc);
2104 } else {
2105 self.push_new_attribute(
2110 local_name,
2111 value,
2112 name,
2113 namespace,
2114 prefix,
2115 AttributeMutationReason::Directly,
2116 can_gc,
2117 );
2118 };
2119 }
2120
2121 pub(crate) fn parse_attribute(
2122 &self,
2123 namespace: &Namespace,
2124 local_name: &LocalName,
2125 value: DOMString,
2126 ) -> AttrValue {
2127 if is_relevant_attribute(namespace, local_name) {
2128 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2129 } else {
2130 AttrValue::String(value.into())
2131 }
2132 }
2133
2134 pub(crate) fn remove_attribute(
2135 &self,
2136 namespace: &Namespace,
2137 local_name: &LocalName,
2138 can_gc: CanGc,
2139 ) -> Option<DomRoot<Attr>> {
2140 self.remove_first_matching_attribute(
2141 |attr| attr.namespace() == namespace && attr.local_name() == local_name,
2142 can_gc,
2143 )
2144 }
2145
2146 pub(crate) fn remove_attribute_by_name(
2147 &self,
2148 name: &LocalName,
2149 can_gc: CanGc,
2150 ) -> Option<DomRoot<Attr>> {
2151 self.remove_first_matching_attribute(|attr| attr.name() == name, can_gc)
2152 }
2153
2154 fn remove_first_matching_attribute<F>(&self, find: F, can_gc: CanGc) -> Option<DomRoot<Attr>>
2156 where
2157 F: Fn(&Attr) -> bool,
2158 {
2159 let idx = self.attrs.borrow().iter().position(|attr| find(attr));
2160 idx.map(|idx| {
2161 let attr = DomRoot::from_ref(&*(*self.attrs.borrow())[idx]);
2162
2163 self.will_mutate_attr(&attr);
2165 self.attrs.borrow_mut().remove(idx);
2166 attr.set_owner(None);
2168 self.handle_attribute_changes(
2170 &attr,
2171 Some(&attr.value()),
2172 None,
2173 AttributeMutationReason::Directly,
2174 can_gc,
2175 );
2176
2177 attr
2178 })
2179 }
2180
2181 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2182 self.get_attribute(&ns!(), &local_name!("class"))
2183 .is_some_and(|attr| {
2184 attr.value()
2185 .as_tokens()
2186 .iter()
2187 .any(|atom| case_sensitivity.eq_atom(name, atom))
2188 })
2189 }
2190
2191 pub(crate) fn is_part(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2192 self.get_attribute(&ns!(), &LocalName::from("part"))
2193 .is_some_and(|attr| {
2194 attr.value()
2195 .as_tokens()
2196 .iter()
2197 .any(|atom| case_sensitivity.eq_atom(name, atom))
2198 })
2199 }
2200
2201 pub(crate) fn set_atomic_attribute(
2202 &self,
2203 local_name: &LocalName,
2204 value: DOMString,
2205 can_gc: CanGc,
2206 ) {
2207 assert!(*local_name == local_name.to_ascii_lowercase());
2208 let value = AttrValue::from_atomic(value.into());
2209 self.set_attribute(local_name, value, can_gc);
2210 }
2211
2212 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2213 assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b));
2214 self.attrs
2215 .borrow()
2216 .iter()
2217 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2218 }
2219
2220 pub(crate) fn set_bool_attribute(&self, local_name: &LocalName, value: bool, can_gc: CanGc) {
2221 if self.has_attribute(local_name) == value {
2222 return;
2223 }
2224 if value {
2225 self.set_string_attribute(local_name, DOMString::new(), can_gc);
2226 } else {
2227 self.remove_attribute(&ns!(), local_name, can_gc);
2228 }
2229 }
2230
2231 pub(crate) fn get_url_attribute(&self, local_name: &LocalName) -> USVString {
2232 assert!(*local_name == local_name.to_ascii_lowercase());
2233 let attr = match self.get_attribute(&ns!(), local_name) {
2234 Some(attr) => attr,
2235 None => return USVString::default(),
2236 };
2237 let value = &**attr.value();
2238 self.owner_document()
2240 .base_url()
2241 .join(value)
2242 .map(|parsed| USVString(parsed.into_string()))
2243 .unwrap_or_else(|_| USVString(value.to_owned()))
2244 }
2245
2246 pub(crate) fn set_url_attribute(
2247 &self,
2248 local_name: &LocalName,
2249 value: USVString,
2250 can_gc: CanGc,
2251 ) {
2252 assert!(*local_name == local_name.to_ascii_lowercase());
2253 self.set_attribute(local_name, AttrValue::String(value.to_string()), can_gc);
2254 }
2255
2256 pub(crate) fn get_trusted_type_url_attribute(
2257 &self,
2258 local_name: &LocalName,
2259 ) -> TrustedScriptURLOrUSVString {
2260 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2261 let attr = match self.get_attribute(&ns!(), local_name) {
2262 Some(attr) => attr,
2263 None => return TrustedScriptURLOrUSVString::USVString(USVString::default()),
2264 };
2265 let value = &**attr.value();
2266 self.owner_document()
2268 .base_url()
2269 .join(value)
2270 .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
2271 .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
2272 }
2273
2274 pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
2275 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2276 let value = match self.get_attribute(&ns!(), local_name) {
2277 Some(attr) => (&**attr.value()).into(),
2278 None => "".into(),
2279 };
2280 TrustedHTMLOrString::String(value)
2281 }
2282
2283 pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
2284 match self.get_attribute(&ns!(), local_name) {
2285 Some(x) => x.Value(),
2286 None => DOMString::new(),
2287 }
2288 }
2289
2290 pub(crate) fn set_string_attribute(
2291 &self,
2292 local_name: &LocalName,
2293 value: DOMString,
2294 can_gc: CanGc,
2295 ) {
2296 assert!(*local_name == local_name.to_ascii_lowercase());
2297 self.set_attribute(local_name, AttrValue::String(value.into()), can_gc);
2298 }
2299
2300 fn get_nullable_string_attribute(&self, local_name: &LocalName) -> Option<DOMString> {
2303 if self.has_attribute(local_name) {
2304 Some(self.get_string_attribute(local_name))
2305 } else {
2306 None
2307 }
2308 }
2309
2310 fn set_nullable_string_attribute(
2313 &self,
2314 local_name: &LocalName,
2315 value: Option<DOMString>,
2316 can_gc: CanGc,
2317 ) {
2318 match value {
2319 Some(val) => {
2320 self.set_string_attribute(local_name, val, can_gc);
2321 },
2322 None => {
2323 self.remove_attribute(&ns!(), local_name, can_gc);
2324 },
2325 }
2326 }
2327
2328 pub(crate) fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
2329 self.get_attribute(&ns!(), local_name)
2330 .map(|attr| attr.value().as_tokens().to_vec())
2331 .unwrap_or_default()
2332 }
2333
2334 pub(crate) fn set_tokenlist_attribute(
2335 &self,
2336 local_name: &LocalName,
2337 value: DOMString,
2338 can_gc: CanGc,
2339 ) {
2340 assert!(*local_name == local_name.to_ascii_lowercase());
2341 self.set_attribute(
2342 local_name,
2343 AttrValue::from_serialized_tokenlist(value.into()),
2344 can_gc,
2345 );
2346 }
2347
2348 pub(crate) fn set_atomic_tokenlist_attribute(
2349 &self,
2350 local_name: &LocalName,
2351 tokens: Vec<Atom>,
2352 can_gc: CanGc,
2353 ) {
2354 assert!(*local_name == local_name.to_ascii_lowercase());
2355 self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens), can_gc);
2356 }
2357
2358 pub(crate) fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
2359 assert!(
2361 local_name
2362 .chars()
2363 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2364 );
2365 let attribute = self.get_attribute(&ns!(), local_name);
2366
2367 match attribute {
2368 Some(ref attribute) => match *attribute.value() {
2369 AttrValue::Int(_, value) => value,
2370 _ => panic!(
2371 "Expected an AttrValue::Int: \
2372 implement parse_plain_attribute"
2373 ),
2374 },
2375 None => default,
2376 }
2377 }
2378
2379 pub(crate) fn set_int_attribute(&self, local_name: &LocalName, value: i32, can_gc: CanGc) {
2380 assert!(*local_name == local_name.to_ascii_lowercase());
2381 self.set_attribute(local_name, AttrValue::Int(value.to_string(), value), can_gc);
2382 }
2383
2384 pub(crate) fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
2385 assert!(
2386 local_name
2387 .chars()
2388 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2389 );
2390 let attribute = self.get_attribute(&ns!(), local_name);
2391 match attribute {
2392 Some(ref attribute) => match *attribute.value() {
2393 AttrValue::UInt(_, value) => value,
2394 _ => panic!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
2395 },
2396 None => default,
2397 }
2398 }
2399 pub(crate) fn set_uint_attribute(&self, local_name: &LocalName, value: u32, can_gc: CanGc) {
2400 assert!(*local_name == local_name.to_ascii_lowercase());
2401 self.set_attribute(
2402 local_name,
2403 AttrValue::UInt(value.to_string(), value),
2404 can_gc,
2405 );
2406 }
2407
2408 pub(crate) fn will_mutate_attr(&self, attr: &Attr) {
2409 let node = self.upcast::<Node>();
2410 node.owner_doc().element_attr_will_change(self, attr);
2411 }
2412
2413 fn update_style_attribute(&self, attr: &Attr, mutation: AttributeMutation) {
2415 let doc = self.upcast::<Node>().owner_doc();
2416 *self.style_attribute.borrow_mut() = match mutation {
2418 AttributeMutation::Set(..) => {
2419 let is_declaration = matches!(*attr.value(), AttrValue::Declaration(..));
2425
2426 let block = if is_declaration {
2427 let mut value = AttrValue::String(String::new());
2428 attr.swap_value(&mut value);
2429 let (serialization, block) = match value {
2430 AttrValue::Declaration(s, b) => (s, b),
2431 _ => unreachable!(),
2432 };
2433 let mut value = AttrValue::String(serialization);
2434 attr.swap_value(&mut value);
2435 block
2436 } else {
2437 let win = self.owner_window();
2438 let source = &**attr.value();
2439 let global = &self.owner_global();
2440 if global
2445 .get_csp_list()
2446 .should_elements_inline_type_behavior_be_blocked(
2447 global,
2448 self,
2449 InlineCheckType::StyleAttribute,
2450 source,
2451 doc.get_current_parser_line(),
2452 )
2453 {
2454 return;
2455 }
2456 Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
2457 source,
2458 &UrlExtraData(doc.base_url().get_arc()),
2459 Some(win.css_error_reporter()),
2460 doc.quirks_mode(),
2461 CssRuleType::Style,
2462 )))
2463 };
2464
2465 Some(block)
2466 },
2467 AttributeMutation::Removed => None,
2468 };
2469 }
2470
2471 fn set_attribute_node(
2475 &self,
2476 cx: &mut js::context::JSContext,
2477 attr: &Attr,
2478 ) -> Fallible<Option<DomRoot<Attr>>> {
2479 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2483 self.namespace(),
2484 self.local_name(),
2485 attr.local_name(),
2486 Some(attr.namespace()),
2487 TrustedTypeOrString::String(attr.Value()),
2488 &self.owner_global(),
2489 CanGc::from_cx(cx),
2490 )?;
2491
2492 if let Some(owner) = attr.GetOwnerElement() {
2495 if &*owner != self {
2496 return Err(Error::InUseAttribute(None));
2497 }
2498 }
2499
2500 let vtable = vtable_for(self.upcast());
2501
2502 attr.swap_value(
2508 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2509 );
2510
2511 let position = self.attrs.borrow().iter().position(|old_attr| {
2513 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2514 });
2515
2516 let old_attr = if let Some(position) = position {
2517 let old_attr = DomRoot::from_ref(&*self.attrs.borrow()[position]);
2518
2519 if &*old_attr == attr {
2521 return Ok(Some(DomRoot::from_ref(attr)));
2522 }
2523
2524 self.will_mutate_attr(attr);
2534 self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
2535 attr.set_owner(Some(self));
2537 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2539 old_attr.set_owner(None);
2541 self.handle_attribute_changes(
2543 attr,
2544 Some(&old_attr.value()),
2545 Some(verified_value),
2546 AttributeMutationReason::Directly,
2547 CanGc::from_cx(cx),
2548 );
2549
2550 Some(old_attr)
2551 } else {
2552 attr.set_owner(Some(self));
2554 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2555 self.push_attribute(attr, AttributeMutationReason::Directly, CanGc::from_cx(cx));
2556
2557 None
2558 };
2559
2560 Ok(old_attr)
2562 }
2563
2564 pub(crate) fn update_nonce_internal_slot(&self, nonce: String) {
2566 self.ensure_rare_data().cryptographic_nonce = nonce;
2567 }
2568
2569 pub(crate) fn nonce_value(&self) -> String {
2571 match self.rare_data().as_ref() {
2572 None => String::new(),
2573 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2574 }
2575 }
2576
2577 pub(crate) fn update_nonce_post_connection(&self) {
2579 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2582 return;
2583 }
2584 let global = self.owner_global();
2585 let csp_list = match global.get_csp_list() {
2587 None => return,
2588 Some(csp_list) => csp_list,
2589 };
2590 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2593 self.get_string_attribute(&local_name!("nonce")).is_empty()
2594 {
2595 return;
2596 }
2597 let nonce = self.nonce_value();
2599 self.set_string_attribute(&local_name!("nonce"), "".into(), CanGc::note());
2601 self.update_nonce_internal_slot(nonce);
2603 }
2604
2605 pub(crate) fn nonce_value_if_nonceable(&self) -> Option<String> {
2607 if !self.has_attribute(&local_name!("nonce")) {
2609 return None;
2610 }
2611 if self.downcast::<HTMLScriptElement>().is_some() {
2613 for attr in self.attrs().iter() {
2614 let attr_name = attr.name().to_ascii_lowercase();
2617 if attr_name.contains("<script") || attr_name.contains("<style") {
2618 return None;
2619 }
2620 let attr_value = attr.value().to_ascii_lowercase();
2623 if attr_value.contains("<script") || attr_value.contains("<style") {
2624 return None;
2625 }
2626 }
2627 }
2628 Some(self.nonce_value().trim().to_owned())
2633 }
2634
2635 pub(crate) fn insert_adjacent(
2637 &self,
2638 where_: AdjacentPosition,
2639 node: &Node,
2640 can_gc: CanGc,
2641 ) -> Fallible<Option<DomRoot<Node>>> {
2642 let self_node = self.upcast::<Node>();
2643 match where_ {
2644 AdjacentPosition::BeforeBegin => {
2645 if let Some(parent) = self_node.GetParentNode() {
2646 Node::pre_insert(node, &parent, Some(self_node), can_gc).map(Some)
2647 } else {
2648 Ok(None)
2649 }
2650 },
2651 AdjacentPosition::AfterBegin => Node::pre_insert(
2652 node,
2653 self_node,
2654 self_node.GetFirstChild().as_deref(),
2655 can_gc,
2656 )
2657 .map(Some),
2658 AdjacentPosition::BeforeEnd => {
2659 Node::pre_insert(node, self_node, None, can_gc).map(Some)
2660 },
2661 AdjacentPosition::AfterEnd => {
2662 if let Some(parent) = self_node.GetParentNode() {
2663 Node::pre_insert(node, &parent, self_node.GetNextSibling().as_deref(), can_gc)
2664 .map(Some)
2665 } else {
2666 Ok(None)
2667 }
2668 },
2669 }
2670 }
2671
2672 pub(crate) fn scroll(&self, x: f64, y: f64, behavior: ScrollBehavior) {
2677 let x = if x.is_finite() { x } else { 0.0 } as f32;
2679 let y = if y.is_finite() { y } else { 0.0 } as f32;
2680
2681 let node = self.upcast::<Node>();
2682
2683 let doc = node.owner_doc();
2685
2686 if !doc.is_fully_active() {
2688 return;
2689 }
2690
2691 let win = match doc.GetDefaultView() {
2693 None => return,
2694 Some(win) => win,
2695 };
2696
2697 if *self.root_element() == *self {
2699 if doc.quirks_mode() != QuirksMode::Quirks {
2700 win.scroll(x, y, behavior);
2701 }
2702
2703 return;
2704 }
2705
2706 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2708 doc.quirks_mode() == QuirksMode::Quirks &&
2709 !self.is_potentially_scrollable_body()
2710 {
2711 win.scroll(x, y, behavior);
2712 return;
2713 }
2714
2715 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
2717 return;
2718 }
2719
2720 win.scroll_an_element(self, x, y, behavior);
2722 }
2723
2724 pub(crate) fn parse_fragment(
2726 &self,
2727 markup: DOMString,
2728 can_gc: CanGc,
2729 ) -> Fallible<DomRoot<DocumentFragment>> {
2730 let new_children = ServoParser::parse_html_fragment(self, markup, false, can_gc);
2733 let context_document = {
2736 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2737 template.Content(can_gc).upcast::<Node>().owner_doc()
2738 } else {
2739 self.owner_document()
2740 }
2741 };
2742 let fragment = DocumentFragment::new(&context_document, can_gc);
2743 for child in new_children {
2745 fragment
2746 .upcast::<Node>()
2747 .AppendChild(&child, can_gc)
2748 .unwrap();
2749 }
2750 Ok(fragment)
2752 }
2753
2754 pub(crate) fn fragment_parsing_context(
2757 owner_doc: &Document,
2758 element: Option<&Self>,
2759 can_gc: CanGc,
2760 ) -> DomRoot<Self> {
2761 match element {
2763 Some(elem)
2764 if elem.local_name() != &local_name!("html") ||
2768 !elem.html_element_in_html_document() =>
2769 {
2770 DomRoot::from_ref(elem)
2771 },
2772 _ => Element::create(
2775 QualName::new(None, ns!(html), local_name!("body")),
2776 None,
2777 owner_doc,
2778 ElementCreator::ScriptCreated,
2779 CustomElementCreationMode::Asynchronous,
2780 None,
2781 can_gc,
2782 ),
2783 }
2784 }
2785
2786 pub(crate) fn fullscreen_element_ready_check(&self) -> bool {
2788 if !self.is_connected() {
2789 return false;
2790 }
2791 self.owner_document().get_allow_fullscreen()
2792 }
2793
2794 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2796 where
2797 T: DerivedFrom<Element> + DomObject,
2798 {
2799 let other = other.upcast::<Element>();
2800 self.root_element() == other.root_element()
2801 }
2802
2803 pub(crate) fn get_id(&self) -> Option<Atom> {
2804 self.id_attribute.borrow().clone()
2805 }
2806
2807 pub(crate) fn get_name(&self) -> Option<Atom> {
2808 self.rare_data().as_ref()?.name_attribute.clone()
2809 }
2810
2811 fn is_sequentially_focusable(&self) -> bool {
2812 let element = self.upcast::<Element>();
2813 let node = self.upcast::<Node>();
2814 if !node.is_connected() {
2815 return false;
2816 }
2817
2818 if element.has_attribute(&local_name!("hidden")) {
2819 return false;
2820 }
2821
2822 if self.disabled_state() {
2823 return false;
2824 }
2825
2826 if element.has_attribute(&local_name!("tabindex")) {
2827 return true;
2828 }
2829
2830 match node.type_id() {
2831 NodeTypeId::Element(ElementTypeId::HTMLElement(
2833 HTMLElementTypeId::HTMLButtonElement,
2834 )) |
2835 NodeTypeId::Element(ElementTypeId::HTMLElement(
2836 HTMLElementTypeId::HTMLSelectElement,
2837 )) |
2838 NodeTypeId::Element(ElementTypeId::HTMLElement(
2839 HTMLElementTypeId::HTMLIFrameElement,
2840 )) |
2841 NodeTypeId::Element(ElementTypeId::HTMLElement(
2842 HTMLElementTypeId::HTMLTextAreaElement,
2843 )) => true,
2844
2845 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) |
2847 NodeTypeId::Element(ElementTypeId::HTMLElement(
2848 HTMLElementTypeId::HTMLAnchorElement,
2849 )) => element.has_attribute(&local_name!("href")),
2850
2851 _ => {
2854 element.get_string_attribute(&local_name!("draggable")) == "true"
2856 },
2857 }
2858 }
2859
2860 pub(crate) fn update_sequentially_focusable_status(&self, can_gc: CanGc) {
2861 let node = self.upcast::<Node>();
2862 let is_sequentially_focusable = self.is_sequentially_focusable();
2863 node.set_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE, is_sequentially_focusable);
2864
2865 if !is_sequentially_focusable {
2867 self.owner_document().perform_focus_fixup_rule(self, can_gc);
2868 }
2869 }
2870
2871 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2872 self.rare_data()
2873 .as_ref()?
2874 .element_internals
2875 .as_ref()
2876 .map(|sr| DomRoot::from_ref(&**sr))
2877 }
2878
2879 pub(crate) fn ensure_element_internals(&self, can_gc: CanGc) -> DomRoot<ElementInternals> {
2880 let mut rare_data = self.ensure_rare_data();
2881 DomRoot::from_ref(rare_data.element_internals.get_or_insert_with(|| {
2882 let elem = self
2883 .downcast::<HTMLElement>()
2884 .expect("ensure_element_internals should only be called for an HTMLElement");
2885 Dom::from_ref(&*ElementInternals::new(elem, can_gc))
2886 }))
2887 }
2888
2889 pub(crate) fn outer_html(&self, can_gc: CanGc) -> Fallible<DOMString> {
2890 match self.GetOuterHTML(can_gc)? {
2891 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2892 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2893 }
2894 }
2895
2896 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2897 SourcePosition {
2898 source_file: self.owner_global().get_url().to_string(),
2899 line_number: line_number + 2,
2900 column_number: 0,
2901 }
2902 }
2903}
2904
2905impl ElementMethods<crate::DomTypeHolder> for Element {
2906 fn GetNamespaceURI(&self) -> Option<DOMString> {
2908 Node::namespace_to_string(self.namespace.clone())
2909 }
2910
2911 fn LocalName(&self) -> DOMString {
2913 DOMString::from(&*self.local_name)
2915 }
2916
2917 fn GetPrefix(&self) -> Option<DOMString> {
2919 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2920 }
2921
2922 fn TagName(&self) -> DOMString {
2924 let name = self.tag_name.or_init(|| {
2925 let qualified_name = match *self.prefix.borrow() {
2926 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2927 None => Cow::Borrowed(&*self.local_name),
2928 };
2929 if self.html_element_in_html_document() {
2930 LocalName::from(qualified_name.to_ascii_uppercase())
2931 } else {
2932 LocalName::from(qualified_name)
2933 }
2934 });
2935 DOMString::from(&*name)
2936 }
2937
2938 fn Id(&self) -> DOMString {
2942 self.get_string_attribute(&local_name!("id"))
2943 }
2944
2945 fn SetId(&self, id: DOMString, can_gc: CanGc) {
2947 self.set_atomic_attribute(&local_name!("id"), id, can_gc);
2948 }
2949
2950 fn ClassName(&self) -> DOMString {
2952 self.get_string_attribute(&local_name!("class"))
2953 }
2954
2955 fn SetClassName(&self, class: DOMString, can_gc: CanGc) {
2957 self.set_tokenlist_attribute(&local_name!("class"), class, can_gc);
2958 }
2959
2960 fn ClassList(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
2962 self.class_list
2963 .or_init(|| DOMTokenList::new(self, &local_name!("class"), None, can_gc))
2964 }
2965
2966 make_getter!(Slot, "slot");
2968
2969 make_setter!(SetSlot, "slot");
2971
2972 fn Attributes(&self, can_gc: CanGc) -> DomRoot<NamedNodeMap> {
2974 self.attr_list
2975 .or_init(|| NamedNodeMap::new(&self.owner_window(), self, can_gc))
2976 }
2977
2978 fn HasAttributes(&self) -> bool {
2980 !self.attrs.borrow().is_empty()
2981 }
2982
2983 fn GetAttributeNames(&self) -> Vec<DOMString> {
2985 self.attrs.borrow().iter().map(|attr| attr.Name()).collect()
2986 }
2987
2988 fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
2990 self.GetAttributeNode(name).map(|s| s.Value())
2991 }
2992
2993 fn GetAttributeNS(
2995 &self,
2996 namespace: Option<DOMString>,
2997 local_name: DOMString,
2998 ) -> Option<DOMString> {
2999 self.GetAttributeNodeNS(namespace, local_name)
3000 .map(|attr| attr.Value())
3001 }
3002
3003 fn GetAttributeNode(&self, name: DOMString) -> Option<DomRoot<Attr>> {
3005 self.get_attribute_by_name(name)
3006 }
3007
3008 fn GetAttributeNodeNS(
3010 &self,
3011 namespace: Option<DOMString>,
3012 local_name: DOMString,
3013 ) -> Option<DomRoot<Attr>> {
3014 let namespace = &namespace_from_domstring(namespace);
3015 self.get_attribute(namespace, &LocalName::from(local_name))
3016 }
3017
3018 fn ToggleAttribute(
3020 &self,
3021 cx: &mut js::context::JSContext,
3022 name: DOMString,
3023 force: Option<bool>,
3024 ) -> Fallible<bool> {
3025 if !is_valid_attribute_local_name(&name.str()) {
3028 return Err(Error::InvalidCharacter(None));
3029 }
3030
3031 let attribute = self.GetAttribute(name.clone());
3033
3034 let name = self.parsed_name(name);
3036 match attribute {
3037 None => match force {
3039 None | Some(true) => {
3041 self.set_first_matching_attribute(
3042 name.clone(),
3043 AttrValue::String(String::new()),
3044 name.clone(),
3045 ns!(),
3046 None,
3047 |attr| *attr.name() == name,
3048 CanGc::from_cx(cx),
3049 );
3050 Ok(true)
3051 },
3052 Some(false) => Ok(false),
3054 },
3055 Some(_index) => match force {
3056 None | Some(false) => {
3058 self.remove_attribute_by_name(&name, CanGc::from_cx(cx));
3059 Ok(false)
3060 },
3061 Some(true) => Ok(true),
3063 },
3064 }
3065 }
3066
3067 fn SetAttribute(
3069 &self,
3070 cx: &mut js::context::JSContext,
3071 name: DOMString,
3072 value: TrustedTypeOrString,
3073 ) -> ErrorResult {
3074 if !is_valid_attribute_local_name(&name.str()) {
3077 return Err(Error::InvalidCharacter(None));
3078 }
3079
3080 let name = self.parsed_name(name);
3083
3084 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3088 self.namespace(),
3089 self.local_name(),
3090 &name,
3091 None,
3092 value,
3093 &self.owner_global(),
3094 CanGc::from_cx(cx),
3095 )?;
3096
3097 let value = self.parse_attribute(&ns!(), &name, value);
3102 self.set_first_matching_attribute(
3103 name.clone(),
3104 value,
3105 name.clone(),
3106 ns!(),
3107 None,
3108 |attr| *attr.name() == name,
3109 CanGc::from_cx(cx),
3110 );
3111 Ok(())
3112 }
3113
3114 fn SetAttributeNS(
3116 &self,
3117 cx: &mut js::context::JSContext,
3118 namespace: Option<DOMString>,
3119 qualified_name: DOMString,
3120 value: TrustedTypeOrString,
3121 ) -> ErrorResult {
3122 let (namespace, prefix, local_name) =
3124 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3125 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3128 self.namespace(),
3129 self.local_name(),
3130 &local_name,
3131 Some(&namespace),
3132 value,
3133 &self.owner_global(),
3134 CanGc::from_cx(cx),
3135 )?;
3136 let value = self.parse_attribute(&namespace, &local_name, value);
3138 self.set_first_matching_attribute(
3139 local_name.clone(),
3140 value,
3141 LocalName::from(qualified_name),
3142 namespace.clone(),
3143 prefix,
3144 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
3145 CanGc::from_cx(cx),
3146 );
3147 Ok(())
3148 }
3149
3150 fn SetAttributeNode(
3152 &self,
3153 cx: &mut js::context::JSContext,
3154 attr: &Attr,
3155 ) -> Fallible<Option<DomRoot<Attr>>> {
3156 self.set_attribute_node(cx, attr)
3157 }
3158
3159 fn SetAttributeNodeNS(
3161 &self,
3162 cx: &mut js::context::JSContext,
3163 attr: &Attr,
3164 ) -> Fallible<Option<DomRoot<Attr>>> {
3165 self.set_attribute_node(cx, attr)
3166 }
3167
3168 fn RemoveAttribute(&self, name: DOMString, can_gc: CanGc) {
3170 let name = self.parsed_name(name);
3171 self.remove_attribute_by_name(&name, can_gc);
3172 }
3173
3174 fn RemoveAttributeNS(
3176 &self,
3177 cx: &mut js::context::JSContext,
3178 namespace: Option<DOMString>,
3179 local_name: DOMString,
3180 ) {
3181 let namespace = namespace_from_domstring(namespace);
3182 let local_name = LocalName::from(local_name);
3183 self.remove_attribute(&namespace, &local_name, CanGc::from_cx(cx));
3184 }
3185
3186 fn RemoveAttributeNode(
3188 &self,
3189 cx: &mut js::context::JSContext,
3190 attr: &Attr,
3191 ) -> Fallible<DomRoot<Attr>> {
3192 self.remove_first_matching_attribute(|a| a == attr, CanGc::from_cx(cx))
3193 .ok_or(Error::NotFound(None))
3194 }
3195
3196 fn HasAttribute(&self, name: DOMString) -> bool {
3198 self.GetAttribute(name).is_some()
3199 }
3200
3201 fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
3203 self.GetAttributeNS(namespace, local_name).is_some()
3204 }
3205
3206 fn GetElementsByTagName(&self, localname: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3208 let window = self.owner_window();
3209 HTMLCollection::by_qualified_name(
3210 &window,
3211 self.upcast(),
3212 LocalName::from(localname),
3213 can_gc,
3214 )
3215 }
3216
3217 fn GetElementsByTagNameNS(
3219 &self,
3220 maybe_ns: Option<DOMString>,
3221 localname: DOMString,
3222 can_gc: CanGc,
3223 ) -> DomRoot<HTMLCollection> {
3224 let window = self.owner_window();
3225 HTMLCollection::by_tag_name_ns(&window, self.upcast(), localname, maybe_ns, can_gc)
3226 }
3227
3228 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3230 let window = self.owner_window();
3231 HTMLCollection::by_class_name(&window, self.upcast(), classes, can_gc)
3232 }
3233
3234 fn GetClientRects(&self, can_gc: CanGc) -> DomRoot<DOMRectList> {
3236 let win = self.owner_window();
3237 let raw_rects = self.upcast::<Node>().border_boxes();
3238 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3239 .map(|rect| {
3240 DOMRect::new(
3241 win.upcast(),
3242 rect.origin.x.to_f64_px(),
3243 rect.origin.y.to_f64_px(),
3244 rect.size.width.to_f64_px(),
3245 rect.size.height.to_f64_px(),
3246 can_gc,
3247 )
3248 })
3249 .collect();
3250 DOMRectList::new(&win, rects, can_gc)
3251 }
3252
3253 fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot<DOMRect> {
3255 let win = self.owner_window();
3256 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3257 DOMRect::new(
3258 win.upcast(),
3259 rect.origin.x.to_f64_px(),
3260 rect.origin.y.to_f64_px(),
3261 rect.size.width.to_f64_px(),
3262 rect.size.height.to_f64_px(),
3263 can_gc,
3264 )
3265 }
3266
3267 fn Scroll(&self, options: &ScrollToOptions) {
3269 let left = options.left.unwrap_or(self.ScrollLeft());
3271 let top = options.top.unwrap_or(self.ScrollTop());
3272 self.scroll(left, top, options.parent.behavior);
3273 }
3274
3275 fn Scroll_(&self, x: f64, y: f64) {
3277 self.scroll(x, y, ScrollBehavior::Auto);
3278 }
3279
3280 fn ScrollTo(&self, options: &ScrollToOptions) {
3282 self.Scroll(options);
3283 }
3284
3285 fn ScrollTo_(&self, x: f64, y: f64) {
3287 self.Scroll_(x, y);
3288 }
3289
3290 fn ScrollBy(&self, options: &ScrollToOptions) {
3292 let delta_left = options.left.unwrap_or(0.0f64);
3294 let delta_top = options.top.unwrap_or(0.0f64);
3295 let left = self.ScrollLeft();
3296 let top = self.ScrollTop();
3297 self.scroll(left + delta_left, top + delta_top, options.parent.behavior);
3298 }
3299
3300 fn ScrollBy_(&self, x: f64, y: f64) {
3302 let left = self.ScrollLeft();
3303 let top = self.ScrollTop();
3304 self.scroll(left + x, top + y, ScrollBehavior::Auto);
3305 }
3306
3307 fn ScrollTop(&self) -> f64 {
3309 let node = self.upcast::<Node>();
3310
3311 let doc = node.owner_doc();
3313
3314 if !doc.is_fully_active() {
3316 return 0.0;
3317 }
3318
3319 let win = match doc.GetDefaultView() {
3321 None => return 0.0,
3322 Some(win) => win,
3323 };
3324
3325 if self.is_document_element() {
3327 if doc.quirks_mode() == QuirksMode::Quirks {
3328 return 0.0;
3329 }
3330
3331 return win.ScrollY() as f64;
3333 }
3334
3335 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3337 doc.quirks_mode() == QuirksMode::Quirks &&
3338 !self.is_potentially_scrollable_body()
3339 {
3340 return win.ScrollY() as f64;
3341 }
3342
3343 if !self.has_css_layout_box() {
3345 return 0.0;
3346 }
3347
3348 let point = win.scroll_offset_query(node);
3350 point.y.abs() as f64
3351 }
3352
3353 fn SetScrollTop(&self, y_: f64) {
3356 let behavior = ScrollBehavior::Auto;
3357
3358 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3360
3361 let node = self.upcast::<Node>();
3362
3363 let doc = node.owner_doc();
3365
3366 if !doc.is_fully_active() {
3368 return;
3369 }
3370
3371 let win = match doc.GetDefaultView() {
3373 None => return,
3374 Some(win) => win,
3375 };
3376
3377 if self.is_document_element() {
3379 if doc.quirks_mode() != QuirksMode::Quirks {
3380 win.scroll(win.ScrollX() as f32, y, behavior);
3381 }
3382
3383 return;
3384 }
3385
3386 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3388 doc.quirks_mode() == QuirksMode::Quirks &&
3389 !self.is_potentially_scrollable_body()
3390 {
3391 win.scroll(win.ScrollX() as f32, y, behavior);
3392 return;
3393 }
3394
3395 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3397 return;
3398 }
3399
3400 win.scroll_an_element(self, self.ScrollLeft() as f32, y, behavior);
3402 }
3403
3404 fn ScrollLeft(&self) -> f64 {
3406 let node = self.upcast::<Node>();
3407
3408 let doc = node.owner_doc();
3410
3411 if !doc.is_fully_active() {
3413 return 0.0;
3414 }
3415
3416 let win = match doc.GetDefaultView() {
3418 None => return 0.0,
3419 Some(win) => win,
3420 };
3421
3422 if self.is_document_element() {
3424 if doc.quirks_mode() != QuirksMode::Quirks {
3425 return win.ScrollX() as f64;
3427 }
3428
3429 return 0.0;
3430 }
3431
3432 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3434 doc.quirks_mode() == QuirksMode::Quirks &&
3435 !self.is_potentially_scrollable_body()
3436 {
3437 return win.ScrollX() as f64;
3438 }
3439
3440 if !self.has_css_layout_box() {
3442 return 0.0;
3443 }
3444
3445 let point = win.scroll_offset_query(node);
3447 point.x.abs() as f64
3448 }
3449
3450 fn SetScrollLeft(&self, x: f64) {
3452 let behavior = ScrollBehavior::Auto;
3453
3454 let x = if x.is_finite() { x } else { 0.0 } as f32;
3456
3457 let node = self.upcast::<Node>();
3458
3459 let doc = node.owner_doc();
3461
3462 if !doc.is_fully_active() {
3464 return;
3465 }
3466
3467 let win = match doc.GetDefaultView() {
3469 None => return,
3470 Some(win) => win,
3471 };
3472
3473 if self.is_document_element() {
3475 if doc.quirks_mode() == QuirksMode::Quirks {
3476 return;
3477 }
3478
3479 win.scroll(x, win.ScrollY() as f32, behavior);
3480 return;
3481 }
3482
3483 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3485 doc.quirks_mode() == QuirksMode::Quirks &&
3486 !self.is_potentially_scrollable_body()
3487 {
3488 win.scroll(x, win.ScrollY() as f32, behavior);
3489 return;
3490 }
3491
3492 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3494 return;
3495 }
3496
3497 win.scroll_an_element(self, x, self.ScrollTop() as f32, behavior);
3499 }
3500
3501 fn ScrollIntoView(&self, arg: BooleanOrScrollIntoViewOptions) {
3503 let (behavior, block, inline, container) = match arg {
3504 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3506 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3511 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3514 options.parent.behavior,
3515 options.block,
3516 options.inline,
3517 if options.container == ScrollIntoViewContainer::Nearest {
3520 Some(self)
3521 } else {
3522 None
3523 },
3524 ),
3525 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3527 ScrollBehavior::Auto,
3528 ScrollLogicalPosition::End,
3529 ScrollLogicalPosition::Nearest,
3530 None,
3531 ),
3532 };
3533
3534 if !self.has_css_layout_box() {
3537 return;
3538 }
3539
3540 self.scroll_into_view_with_options(
3542 behavior,
3543 ScrollAxisState::new_always_scroll_position(block),
3544 ScrollAxisState::new_always_scroll_position(inline),
3545 container,
3546 None,
3547 );
3548
3549 }
3552
3553 fn ScrollWidth(&self) -> i32 {
3555 self.upcast::<Node>().scroll_area().size.width
3556 }
3557
3558 fn ScrollHeight(&self) -> i32 {
3560 self.upcast::<Node>().scroll_area().size.height
3561 }
3562
3563 fn ClientTop(&self) -> i32 {
3565 self.client_rect().origin.y
3566 }
3567
3568 fn ClientLeft(&self) -> i32 {
3570 self.client_rect().origin.x
3571 }
3572
3573 fn ClientWidth(&self) -> i32 {
3575 self.client_rect().size.width
3576 }
3577
3578 fn ClientHeight(&self) -> i32 {
3580 self.client_rect().size.height
3581 }
3582
3583 fn CurrentCSSZoom(&self) -> Finite<f64> {
3585 let window = self.owner_window();
3586 Finite::wrap(window.current_css_zoom_query(self.upcast::<Node>()) as f64)
3587 }
3588
3589 fn SetHTMLUnsafe(&self, html: TrustedHTMLOrString, can_gc: CanGc) -> ErrorResult {
3591 let html = TrustedHTML::get_trusted_script_compliant_string(
3595 &self.owner_global(),
3596 html,
3597 "Element setHTMLUnsafe",
3598 can_gc,
3599 )?;
3600 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3602 DomRoot::upcast(template.Content(can_gc))
3603 } else {
3604 DomRoot::from_ref(self.upcast())
3605 };
3606
3607 Node::unsafely_set_html(&target, self, html, can_gc);
3609 Ok(())
3610 }
3611
3612 fn GetHTML(&self, options: &GetHTMLOptions, can_gc: CanGc) -> DOMString {
3614 self.upcast::<Node>().html_serialize(
3617 TraversalScope::ChildrenOnly(None),
3618 options.serializableShadowRoots,
3619 options.shadowRoots.clone(),
3620 can_gc,
3621 )
3622 }
3623
3624 fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3626 let qname = QualName::new(
3627 self.prefix().clone(),
3628 self.namespace().clone(),
3629 self.local_name().clone(),
3630 );
3631
3632 let result = if self.owner_document().is_html_document() {
3635 self.upcast::<Node>()
3636 .html_serialize(ChildrenOnly(Some(qname)), false, vec![], can_gc)
3637 } else {
3638 self.upcast::<Node>()
3639 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3640 };
3641
3642 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3643 }
3644
3645 fn SetInnerHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3647 let value = TrustedHTML::get_trusted_script_compliant_string(
3651 &self.owner_global(),
3652 value.convert(),
3653 "Element innerHTML",
3654 can_gc,
3655 )?;
3656 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3658 DomRoot::upcast(template.Content(can_gc))
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, Some(value), can_gc);
3676 }
3677
3678 let frag = self.parse_fragment(value, can_gc)?;
3681
3682 Node::replace_all(Some(frag.upcast()), &target, can_gc);
3684 Ok(())
3685 }
3686
3687 fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3689 let result = if self.owner_document().is_html_document() {
3692 self.upcast::<Node>()
3693 .html_serialize(IncludeNode, false, vec![], can_gc)
3694 } else {
3695 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3696 };
3697
3698 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3699 }
3700
3701 fn SetOuterHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3703 let value = TrustedHTML::get_trusted_script_compliant_string(
3707 &self.owner_global(),
3708 value.convert(),
3709 "Element outerHTML",
3710 can_gc,
3711 )?;
3712 let context_document = self.owner_document();
3713 let context_node = self.upcast::<Node>();
3714 let context_parent = match context_node.GetParentNode() {
3716 None => {
3717 return Ok(());
3720 },
3721 Some(parent) => parent,
3722 };
3723
3724 let parent = match context_parent.type_id() {
3725 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed(None)),
3727
3728 NodeTypeId::DocumentFragment(_) => {
3731 let body_elem = Element::create(
3732 QualName::new(None, ns!(html), local_name!("body")),
3733 None,
3734 &context_document,
3735 ElementCreator::ScriptCreated,
3736 CustomElementCreationMode::Synchronous,
3737 None,
3738 can_gc,
3739 );
3740 DomRoot::upcast(body_elem)
3741 },
3742 _ => context_node.GetParentElement().unwrap(),
3743 };
3744
3745 let frag = parent.parse_fragment(value, can_gc)?;
3748 context_parent.ReplaceChild(frag.upcast(), context_node, can_gc)?;
3750 Ok(())
3751 }
3752
3753 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3755 self.upcast::<Node>()
3756 .preceding_siblings()
3757 .find_map(DomRoot::downcast)
3758 }
3759
3760 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3762 self.upcast::<Node>()
3763 .following_siblings()
3764 .find_map(DomRoot::downcast)
3765 }
3766
3767 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3769 let window = self.owner_window();
3770 HTMLCollection::children(&window, self.upcast(), can_gc)
3771 }
3772
3773 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3775 self.upcast::<Node>().child_elements().next()
3776 }
3777
3778 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3780 self.upcast::<Node>()
3781 .rev_children()
3782 .find_map(DomRoot::downcast::<Element>)
3783 }
3784
3785 fn ChildElementCount(&self) -> u32 {
3787 self.upcast::<Node>().child_elements().count() as u32
3788 }
3789
3790 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3792 self.upcast::<Node>().prepend(nodes, can_gc)
3793 }
3794
3795 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3797 self.upcast::<Node>().append(nodes, can_gc)
3798 }
3799
3800 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3802 self.upcast::<Node>().replace_children(nodes, can_gc)
3803 }
3804
3805 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3807 let root = self.upcast::<Node>();
3808 root.query_selector(selectors)
3809 }
3810
3811 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
3813 let root = self.upcast::<Node>();
3814 root.query_selector_all(selectors)
3815 }
3816
3817 fn Before(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3819 self.upcast::<Node>().before(nodes, can_gc)
3820 }
3821
3822 fn After(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3824 self.upcast::<Node>().after(nodes, can_gc)
3825 }
3826
3827 fn ReplaceWith(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3829 self.upcast::<Node>().replace_with(nodes, can_gc)
3830 }
3831
3832 fn Remove(&self, can_gc: CanGc) {
3834 self.upcast::<Node>().remove_self(can_gc);
3835 }
3836
3837 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3839 let doc = self.owner_document();
3840 let url = doc.url();
3841 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3842 &selectors.str(),
3843 &UrlExtraData(url.get_arc()),
3844 ) {
3845 Err(_) => return Err(Error::Syntax(None)),
3846 Ok(selectors) => selectors,
3847 };
3848
3849 let quirks_mode = doc.quirks_mode();
3850 let element = DomRoot::from_ref(self);
3851
3852 Ok(dom_apis::element_matches(
3853 &SelectorWrapper::Borrowed(&element),
3854 &selectors,
3855 quirks_mode,
3856 ))
3857 }
3858
3859 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3861 self.Matches(selectors)
3862 }
3863
3864 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3866 let doc = self.owner_document();
3867 let url = doc.url();
3868 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3869 &selectors.str(),
3870 &UrlExtraData(url.get_arc()),
3871 ) {
3872 Err(_) => return Err(Error::Syntax(None)),
3873 Ok(selectors) => selectors,
3874 };
3875
3876 let quirks_mode = doc.quirks_mode();
3877 Ok(dom_apis::element_closest(
3878 SelectorWrapper::Owned(DomRoot::from_ref(self)),
3879 &selectors,
3880 quirks_mode,
3881 )
3882 .map(SelectorWrapper::into_owned))
3883 }
3884
3885 fn InsertAdjacentElement(
3887 &self,
3888 where_: DOMString,
3889 element: &Element,
3890 can_gc: CanGc,
3891 ) -> Fallible<Option<DomRoot<Element>>> {
3892 let where_ = where_.parse::<AdjacentPosition>()?;
3893 let inserted_node = self.insert_adjacent(where_, element.upcast(), can_gc)?;
3894 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3895 }
3896
3897 fn InsertAdjacentText(&self, where_: DOMString, data: DOMString, can_gc: CanGc) -> ErrorResult {
3899 let text = Text::new(data, &self.owner_document(), can_gc);
3901
3902 let where_ = where_.parse::<AdjacentPosition>()?;
3904 self.insert_adjacent(where_, text.upcast(), can_gc)
3905 .map(|_| ())
3906 }
3907
3908 fn InsertAdjacentHTML(
3910 &self,
3911 position: DOMString,
3912 text: TrustedHTMLOrString,
3913 can_gc: CanGc,
3914 ) -> ErrorResult {
3915 let text = TrustedHTML::get_trusted_script_compliant_string(
3919 &self.owner_global(),
3920 text,
3921 "Element insertAdjacentHTML",
3922 can_gc,
3923 )?;
3924 let position = position.parse::<AdjacentPosition>()?;
3925
3926 let context = match position {
3929 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
3932 match self.upcast::<Node>().GetParentNode() {
3933 Some(ref node) if node.is::<Document>() => {
3935 return Err(Error::NoModificationAllowed(None));
3936 },
3937 None => return Err(Error::NoModificationAllowed(None)),
3938 Some(node) => node,
3940 }
3941 },
3942 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
3945 DomRoot::from_ref(self.upcast::<Node>())
3947 },
3948 };
3949
3950 let context = Element::fragment_parsing_context(
3952 &context.owner_doc(),
3953 context.downcast::<Element>(),
3954 can_gc,
3955 );
3956
3957 let fragment = context.parse_fragment(text, can_gc)?;
3960
3961 self.insert_adjacent(position, fragment.upcast(), can_gc)
3963 .map(|_| ())
3964 }
3965
3966 fn EnterFormalActivationState(&self) -> ErrorResult {
3968 match self.as_maybe_activatable() {
3969 Some(a) => {
3970 a.enter_formal_activation_state();
3971 Ok(())
3972 },
3973 None => Err(Error::NotSupported(None)),
3974 }
3975 }
3976
3977 fn ExitFormalActivationState(&self) -> ErrorResult {
3978 match self.as_maybe_activatable() {
3979 Some(a) => {
3980 a.exit_formal_activation_state();
3981 Ok(())
3982 },
3983 None => Err(Error::NotSupported(None)),
3984 }
3985 }
3986
3987 fn RequestFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
3989 let doc = self.owner_document();
3990 doc.enter_fullscreen(self, can_gc)
3991 }
3992
3993 fn AttachShadow(&self, init: &ShadowRootInit, can_gc: CanGc) -> Fallible<DomRoot<ShadowRoot>> {
3995 let shadow_root = self.attach_shadow(
3998 IsUserAgentWidget::No,
3999 init.mode,
4000 init.clonable,
4001 init.serializable,
4002 init.delegatesFocus,
4003 init.slotAssignment,
4004 can_gc,
4005 )?;
4006
4007 Ok(shadow_root)
4009 }
4010
4011 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
4013 let shadow_or_none = self.shadow_root();
4015
4016 let shadow = shadow_or_none?;
4018 if shadow.Mode() == ShadowRootMode::Closed {
4019 return None;
4020 }
4021
4022 Some(shadow)
4024 }
4025
4026 fn GetCustomElementRegistry(&self) -> Option<DomRoot<CustomElementRegistry>> {
4028 self.custom_element_registry()
4030 }
4031
4032 fn GetRole(&self) -> Option<DOMString> {
4033 self.get_nullable_string_attribute(&local_name!("role"))
4034 }
4035
4036 fn SetRole(&self, value: Option<DOMString>, can_gc: CanGc) {
4037 self.set_nullable_string_attribute(&local_name!("role"), value, can_gc);
4038 }
4039
4040 fn GetAriaAtomic(&self) -> Option<DOMString> {
4041 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
4042 }
4043
4044 fn SetAriaAtomic(&self, value: Option<DOMString>, can_gc: CanGc) {
4045 self.set_nullable_string_attribute(&local_name!("aria-atomic"), value, can_gc);
4046 }
4047
4048 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
4049 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
4050 }
4051
4052 fn SetAriaAutoComplete(&self, value: Option<DOMString>, can_gc: CanGc) {
4053 self.set_nullable_string_attribute(&local_name!("aria-autocomplete"), value, can_gc);
4054 }
4055
4056 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
4057 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
4058 }
4059
4060 fn SetAriaBrailleLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
4061 self.set_nullable_string_attribute(&local_name!("aria-braillelabel"), value, can_gc);
4062 }
4063
4064 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
4065 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
4066 }
4067
4068 fn SetAriaBrailleRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4069 self.set_nullable_string_attribute(
4070 &local_name!("aria-brailleroledescription"),
4071 value,
4072 can_gc,
4073 );
4074 }
4075
4076 fn GetAriaBusy(&self) -> Option<DOMString> {
4077 self.get_nullable_string_attribute(&local_name!("aria-busy"))
4078 }
4079
4080 fn SetAriaBusy(&self, value: Option<DOMString>, can_gc: CanGc) {
4081 self.set_nullable_string_attribute(&local_name!("aria-busy"), value, can_gc);
4082 }
4083
4084 fn GetAriaChecked(&self) -> Option<DOMString> {
4085 self.get_nullable_string_attribute(&local_name!("aria-checked"))
4086 }
4087
4088 fn SetAriaChecked(&self, value: Option<DOMString>, can_gc: CanGc) {
4089 self.set_nullable_string_attribute(&local_name!("aria-checked"), value, can_gc);
4090 }
4091
4092 fn GetAriaColCount(&self) -> Option<DOMString> {
4093 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
4094 }
4095
4096 fn SetAriaColCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4097 self.set_nullable_string_attribute(&local_name!("aria-colcount"), value, can_gc);
4098 }
4099
4100 fn GetAriaColIndex(&self) -> Option<DOMString> {
4101 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4102 }
4103
4104 fn SetAriaColIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4105 self.set_nullable_string_attribute(&local_name!("aria-colindex"), value, can_gc);
4106 }
4107
4108 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4109 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4110 }
4111
4112 fn SetAriaColIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4113 self.set_nullable_string_attribute(&local_name!("aria-colindextext"), value, can_gc);
4114 }
4115
4116 fn GetAriaColSpan(&self) -> Option<DOMString> {
4117 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4118 }
4119
4120 fn SetAriaColSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4121 self.set_nullable_string_attribute(&local_name!("aria-colspan"), value, can_gc);
4122 }
4123
4124 fn GetAriaCurrent(&self) -> Option<DOMString> {
4125 self.get_nullable_string_attribute(&local_name!("aria-current"))
4126 }
4127
4128 fn SetAriaCurrent(&self, value: Option<DOMString>, can_gc: CanGc) {
4129 self.set_nullable_string_attribute(&local_name!("aria-current"), value, can_gc);
4130 }
4131
4132 fn GetAriaDescription(&self) -> Option<DOMString> {
4133 self.get_nullable_string_attribute(&local_name!("aria-description"))
4134 }
4135
4136 fn SetAriaDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4137 self.set_nullable_string_attribute(&local_name!("aria-description"), value, can_gc);
4138 }
4139
4140 fn GetAriaDisabled(&self) -> Option<DOMString> {
4141 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4142 }
4143
4144 fn SetAriaDisabled(&self, value: Option<DOMString>, can_gc: CanGc) {
4145 self.set_nullable_string_attribute(&local_name!("aria-disabled"), value, can_gc);
4146 }
4147
4148 fn GetAriaExpanded(&self) -> Option<DOMString> {
4149 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4150 }
4151
4152 fn SetAriaExpanded(&self, value: Option<DOMString>, can_gc: CanGc) {
4153 self.set_nullable_string_attribute(&local_name!("aria-expanded"), value, can_gc);
4154 }
4155
4156 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4157 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4158 }
4159
4160 fn SetAriaHasPopup(&self, value: Option<DOMString>, can_gc: CanGc) {
4161 self.set_nullable_string_attribute(&local_name!("aria-haspopup"), value, can_gc);
4162 }
4163
4164 fn GetAriaHidden(&self) -> Option<DOMString> {
4165 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4166 }
4167
4168 fn SetAriaHidden(&self, value: Option<DOMString>, can_gc: CanGc) {
4169 self.set_nullable_string_attribute(&local_name!("aria-hidden"), value, can_gc);
4170 }
4171
4172 fn GetAriaInvalid(&self) -> Option<DOMString> {
4173 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4174 }
4175
4176 fn SetAriaInvalid(&self, value: Option<DOMString>, can_gc: CanGc) {
4177 self.set_nullable_string_attribute(&local_name!("aria-invalid"), value, can_gc);
4178 }
4179
4180 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4181 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4182 }
4183
4184 fn SetAriaKeyShortcuts(&self, value: Option<DOMString>, can_gc: CanGc) {
4185 self.set_nullable_string_attribute(&local_name!("aria-keyshortcuts"), value, can_gc);
4186 }
4187
4188 fn GetAriaLabel(&self) -> Option<DOMString> {
4189 self.get_nullable_string_attribute(&local_name!("aria-label"))
4190 }
4191
4192 fn SetAriaLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
4193 self.set_nullable_string_attribute(&local_name!("aria-label"), value, can_gc);
4194 }
4195
4196 fn GetAriaLevel(&self) -> Option<DOMString> {
4197 self.get_nullable_string_attribute(&local_name!("aria-level"))
4198 }
4199
4200 fn SetAriaLevel(&self, value: Option<DOMString>, can_gc: CanGc) {
4201 self.set_nullable_string_attribute(&local_name!("aria-level"), value, can_gc);
4202 }
4203
4204 fn GetAriaLive(&self) -> Option<DOMString> {
4205 self.get_nullable_string_attribute(&local_name!("aria-live"))
4206 }
4207
4208 fn SetAriaLive(&self, value: Option<DOMString>, can_gc: CanGc) {
4209 self.set_nullable_string_attribute(&local_name!("aria-live"), value, can_gc);
4210 }
4211
4212 fn GetAriaModal(&self) -> Option<DOMString> {
4213 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4214 }
4215
4216 fn SetAriaModal(&self, value: Option<DOMString>, can_gc: CanGc) {
4217 self.set_nullable_string_attribute(&local_name!("aria-modal"), value, can_gc);
4218 }
4219
4220 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4221 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4222 }
4223
4224 fn SetAriaMultiLine(&self, value: Option<DOMString>, can_gc: CanGc) {
4225 self.set_nullable_string_attribute(&local_name!("aria-multiline"), value, can_gc);
4226 }
4227
4228 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4229 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4230 }
4231
4232 fn SetAriaMultiSelectable(&self, value: Option<DOMString>, can_gc: CanGc) {
4233 self.set_nullable_string_attribute(&local_name!("aria-multiselectable"), value, can_gc);
4234 }
4235
4236 fn GetAriaOrientation(&self) -> Option<DOMString> {
4237 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4238 }
4239
4240 fn SetAriaOrientation(&self, value: Option<DOMString>, can_gc: CanGc) {
4241 self.set_nullable_string_attribute(&local_name!("aria-orientation"), value, can_gc);
4242 }
4243
4244 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4245 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4246 }
4247
4248 fn SetAriaPlaceholder(&self, value: Option<DOMString>, can_gc: CanGc) {
4249 self.set_nullable_string_attribute(&local_name!("aria-placeholder"), value, can_gc);
4250 }
4251
4252 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4253 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4254 }
4255
4256 fn SetAriaPosInSet(&self, value: Option<DOMString>, can_gc: CanGc) {
4257 self.set_nullable_string_attribute(&local_name!("aria-posinset"), value, can_gc);
4258 }
4259
4260 fn GetAriaPressed(&self) -> Option<DOMString> {
4261 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4262 }
4263
4264 fn SetAriaPressed(&self, value: Option<DOMString>, can_gc: CanGc) {
4265 self.set_nullable_string_attribute(&local_name!("aria-pressed"), value, can_gc);
4266 }
4267
4268 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4269 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4270 }
4271
4272 fn SetAriaReadOnly(&self, value: Option<DOMString>, can_gc: CanGc) {
4273 self.set_nullable_string_attribute(&local_name!("aria-readonly"), value, can_gc);
4274 }
4275
4276 fn GetAriaRelevant(&self) -> Option<DOMString> {
4277 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4278 }
4279
4280 fn SetAriaRelevant(&self, value: Option<DOMString>, can_gc: CanGc) {
4281 self.set_nullable_string_attribute(&local_name!("aria-relevant"), value, can_gc);
4282 }
4283
4284 fn GetAriaRequired(&self) -> Option<DOMString> {
4285 self.get_nullable_string_attribute(&local_name!("aria-required"))
4286 }
4287
4288 fn SetAriaRequired(&self, value: Option<DOMString>, can_gc: CanGc) {
4289 self.set_nullable_string_attribute(&local_name!("aria-required"), value, can_gc);
4290 }
4291
4292 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4293 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4294 }
4295
4296 fn SetAriaRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4297 self.set_nullable_string_attribute(&local_name!("aria-roledescription"), value, can_gc);
4298 }
4299
4300 fn GetAriaRowCount(&self) -> Option<DOMString> {
4301 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4302 }
4303
4304 fn SetAriaRowCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4305 self.set_nullable_string_attribute(&local_name!("aria-rowcount"), value, can_gc);
4306 }
4307
4308 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4309 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4310 }
4311
4312 fn SetAriaRowIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4313 self.set_nullable_string_attribute(&local_name!("aria-rowindex"), value, can_gc);
4314 }
4315
4316 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4317 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4318 }
4319
4320 fn SetAriaRowIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4321 self.set_nullable_string_attribute(&local_name!("aria-rowindextext"), value, can_gc);
4322 }
4323
4324 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4325 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4326 }
4327
4328 fn SetAriaRowSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4329 self.set_nullable_string_attribute(&local_name!("aria-rowspan"), value, can_gc);
4330 }
4331
4332 fn GetAriaSelected(&self) -> Option<DOMString> {
4333 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4334 }
4335
4336 fn SetAriaSelected(&self, value: Option<DOMString>, can_gc: CanGc) {
4337 self.set_nullable_string_attribute(&local_name!("aria-selected"), value, can_gc);
4338 }
4339
4340 fn GetAriaSetSize(&self) -> Option<DOMString> {
4341 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4342 }
4343
4344 fn SetAriaSetSize(&self, value: Option<DOMString>, can_gc: CanGc) {
4345 self.set_nullable_string_attribute(&local_name!("aria-setsize"), value, can_gc);
4346 }
4347
4348 fn GetAriaSort(&self) -> Option<DOMString> {
4349 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4350 }
4351
4352 fn SetAriaSort(&self, value: Option<DOMString>, can_gc: CanGc) {
4353 self.set_nullable_string_attribute(&local_name!("aria-sort"), value, can_gc);
4354 }
4355
4356 fn GetAriaValueMax(&self) -> Option<DOMString> {
4357 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4358 }
4359
4360 fn SetAriaValueMax(&self, value: Option<DOMString>, can_gc: CanGc) {
4361 self.set_nullable_string_attribute(&local_name!("aria-valuemax"), value, can_gc);
4362 }
4363
4364 fn GetAriaValueMin(&self) -> Option<DOMString> {
4365 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4366 }
4367
4368 fn SetAriaValueMin(&self, value: Option<DOMString>, can_gc: CanGc) {
4369 self.set_nullable_string_attribute(&local_name!("aria-valuemin"), value, can_gc);
4370 }
4371
4372 fn GetAriaValueNow(&self) -> Option<DOMString> {
4373 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4374 }
4375
4376 fn SetAriaValueNow(&self, value: Option<DOMString>, can_gc: CanGc) {
4377 self.set_nullable_string_attribute(&local_name!("aria-valuenow"), value, can_gc);
4378 }
4379
4380 fn GetAriaValueText(&self) -> Option<DOMString> {
4381 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4382 }
4383
4384 fn SetAriaValueText(&self, value: Option<DOMString>, can_gc: CanGc) {
4385 self.set_nullable_string_attribute(&local_name!("aria-valuetext"), value, can_gc);
4386 }
4387
4388 fn GetAssignedSlot(&self) -> Option<DomRoot<HTMLSlotElement>> {
4390 let cx = GlobalScope::get_cx();
4391
4392 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4395 slottable.find_a_slot(true)
4396 }
4397
4398 fn Part(&self) -> DomRoot<DOMTokenList> {
4400 self.ensure_rare_data()
4401 .part
4402 .or_init(|| DOMTokenList::new(self, &local_name!("part"), None, CanGc::note()))
4403 }
4404}
4405
4406impl VirtualMethods for Element {
4407 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4408 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4409 }
4410
4411 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
4412 if attr.local_name() == &local_name!("lang") {
4414 return true;
4415 }
4416
4417 self.super_type()
4418 .unwrap()
4419 .attribute_affects_presentational_hints(attr)
4420 }
4421
4422 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
4423 self.super_type()
4424 .unwrap()
4425 .attribute_mutated(attr, mutation, can_gc);
4426 let node = self.upcast::<Node>();
4427 let doc = node.owner_doc();
4428 match attr.local_name() {
4429 &local_name!("tabindex") | &local_name!("draggable") | &local_name!("hidden") => {
4430 self.update_sequentially_focusable_status(can_gc)
4431 },
4432 &local_name!("style") => self.update_style_attribute(attr, mutation),
4433 &local_name!("id") => {
4434 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4436 let value = value.as_atom();
4437 if value != &atom!("") {
4438 Some(value.clone())
4440 } else {
4441 None
4443 }
4444 });
4445
4446 let containing_shadow_root = self.containing_shadow_root();
4447 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4448 let value = attr.value().as_atom().clone();
4449 match mutation {
4450 AttributeMutation::Set(old_value, _) => {
4451 if let Some(old_value) = old_value {
4452 let old_value = old_value.as_atom().clone();
4453 if let Some(ref shadow_root) = containing_shadow_root {
4454 shadow_root.unregister_element_id(self, old_value, can_gc);
4455 } else {
4456 doc.unregister_element_id(self, old_value, can_gc);
4457 }
4458 }
4459 if value != atom!("") {
4460 if let Some(ref shadow_root) = containing_shadow_root {
4461 shadow_root.register_element_id(self, value, can_gc);
4462 } else {
4463 doc.register_element_id(self, value, can_gc);
4464 }
4465 }
4466 },
4467 AttributeMutation::Removed => {
4468 if value != atom!("") {
4469 if let Some(ref shadow_root) = containing_shadow_root {
4470 shadow_root.unregister_element_id(self, value, can_gc);
4471 } else {
4472 doc.unregister_element_id(self, value, can_gc);
4473 }
4474 }
4475 },
4476 }
4477 }
4478 },
4479 &local_name!("name") => {
4480 self.ensure_rare_data().name_attribute =
4482 mutation.new_value(attr).and_then(|value| {
4483 let value = value.as_atom();
4484 if value != &atom!("") {
4485 Some(value.clone())
4486 } else {
4487 None
4488 }
4489 });
4490 if node.is_connected() && node.containing_shadow_root().is_none() {
4493 let value = attr.value().as_atom().clone();
4494 match mutation {
4495 AttributeMutation::Set(old_value, _) => {
4496 if let Some(old_value) = old_value {
4497 let old_value = old_value.as_atom().clone();
4498 doc.unregister_element_name(self, old_value);
4499 }
4500 if value != atom!("") {
4501 doc.register_element_name(self, value);
4502 }
4503 },
4504 AttributeMutation::Removed => {
4505 if value != atom!("") {
4506 doc.unregister_element_name(self, value);
4507 }
4508 },
4509 }
4510 }
4511 },
4512 &local_name!("slot") => {
4513 let cx = GlobalScope::get_cx();
4515
4516 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4517
4518 if let Some(assigned_slot) = slottable.assigned_slot() {
4520 assigned_slot.assign_slottables();
4521 }
4522 slottable.assign_a_slot();
4523 },
4524 _ => {
4525 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4528 node.dirty(NodeDamage::Other);
4529 }
4530 },
4531 };
4532
4533 if self
4536 .upcast::<Node>()
4537 .get_flag(NodeFlags::USES_ATTR_IN_CONTENT_ATTRIBUTE)
4538 {
4539 node.dirty(NodeDamage::ContentOrHeritage);
4540 }
4541
4542 node.rev_version();
4546
4547 let global = self.owner_global();
4549 if global.live_devtools_updates() {
4550 if let Some(sender) = global.devtools_chan() {
4551 let pipeline_id = global.pipeline_id();
4552 let devtools_message = ScriptToDevtoolsControlMsg::DomMutation(
4553 pipeline_id,
4554 DomMutation::AttributeModified {
4555 node: self.upcast::<Node>().unique_id(pipeline_id),
4556 attribute_name: attr.local_name().to_string(),
4557 new_value: mutation.new_value(attr).map(|value| value.to_string()),
4558 },
4559 );
4560 sender.send(devtools_message).unwrap();
4561 }
4562 }
4563 }
4564
4565 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4566 match *name {
4567 local_name!("id") => AttrValue::Atom(value.into()),
4568 local_name!("name") => AttrValue::Atom(value.into()),
4569 local_name!("class") | local_name!("part") => {
4570 AttrValue::from_serialized_tokenlist(value.into())
4571 },
4572 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4573 _ => self
4574 .super_type()
4575 .unwrap()
4576 .parse_plain_attribute(name, value),
4577 }
4578 }
4579
4580 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
4581 if let Some(s) = self.super_type() {
4582 s.bind_to_tree(context, can_gc);
4583 }
4584
4585 if let Some(f) = self.as_maybe_form_control() {
4586 f.bind_form_control_to_tree(can_gc);
4587 }
4588
4589 let doc = self.owner_document();
4590
4591 if let Some(ref shadow_root) = self.shadow_root() {
4592 shadow_root.bind_to_tree(context, can_gc);
4593 }
4594
4595 if !context.is_in_tree() {
4596 return;
4597 }
4598
4599 self.update_sequentially_focusable_status(can_gc);
4600
4601 if let Some(ref id) = *self.id_attribute.borrow() {
4602 if let Some(shadow_root) = self.containing_shadow_root() {
4603 shadow_root.register_element_id(self, id.clone(), can_gc);
4604 } else {
4605 doc.register_element_id(self, id.clone(), can_gc);
4606 }
4607 }
4608 if let Some(ref name) = self.name_attribute() {
4609 if self.containing_shadow_root().is_none() {
4610 doc.register_element_name(self, name.clone());
4611 }
4612 }
4613
4614 doc.increment_dom_count();
4616 }
4617
4618 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
4619 self.super_type().unwrap().unbind_from_tree(context, can_gc);
4620
4621 if let Some(f) = self.as_maybe_form_control() {
4622 f.unbind_form_control_from_tree(can_gc);
4626 }
4627
4628 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4629 return;
4630 }
4631
4632 self.update_sequentially_focusable_status(can_gc);
4633
4634 let doc = self.owner_document();
4635
4636 let fullscreen = doc.fullscreen_element();
4637 if fullscreen.as_deref() == Some(self) {
4638 doc.exit_fullscreen(can_gc);
4639 }
4640 if let Some(ref value) = *self.id_attribute.borrow() {
4641 if let Some(ref shadow_root) = self.containing_shadow_root() {
4642 if !self.upcast::<Node>().is_in_a_shadow_tree() {
4645 shadow_root.unregister_element_id(self, value.clone(), can_gc);
4646 }
4647 } else {
4648 doc.unregister_element_id(self, value.clone(), can_gc);
4649 }
4650 }
4651 if let Some(ref value) = self.name_attribute() {
4652 if self.containing_shadow_root().is_none() {
4653 doc.unregister_element_name(self, value.clone());
4654 }
4655 }
4656 doc.decrement_dom_count();
4658 }
4659
4660 fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
4661 if let Some(s) = self.super_type() {
4662 s.children_changed(mutation, can_gc);
4663 }
4664
4665 let flags = self.selector_flags.get();
4666 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4667 self.upcast::<Node>().dirty(NodeDamage::Other);
4669 } else {
4670 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
4671 if let Some(next_child) = mutation.next_child() {
4672 for child in next_child.inclusively_following_siblings() {
4673 if child.is::<Element>() {
4674 child.dirty(NodeDamage::Other);
4675 }
4676 }
4677 }
4678 }
4679 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
4680 if let Some(child) = mutation.modified_edge_element() {
4681 child.dirty(NodeDamage::Other);
4682 }
4683 }
4684 }
4685 }
4686
4687 fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
4688 self.super_type().unwrap().adopting_steps(old_doc, can_gc);
4689
4690 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4691 self.tag_name.clear();
4692 }
4693 }
4694
4695 fn post_connection_steps(&self, cx: &mut js::context::JSContext) {
4696 if let Some(s) = self.super_type() {
4697 s.post_connection_steps(cx);
4698 }
4699
4700 self.update_nonce_post_connection();
4701 }
4702
4703 fn cloning_steps(
4705 &self,
4706 copy: &Node,
4707 maybe_doc: Option<&Document>,
4708 clone_children: CloneChildrenFlag,
4709 can_gc: CanGc,
4710 ) {
4711 if let Some(s) = self.super_type() {
4712 s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
4713 }
4714 let elem = copy.downcast::<Element>().unwrap();
4715 if let Some(rare_data) = self.rare_data().as_ref() {
4716 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone());
4717 }
4718 }
4719}
4720
4721#[derive(Clone, PartialEq)]
4722pub enum SelectorWrapper<'a> {
4727 Borrowed(&'a DomRoot<Element>),
4728 Owned(DomRoot<Element>),
4729}
4730
4731impl fmt::Debug for SelectorWrapper<'_> {
4732 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4733 self.deref().fmt(f)
4734 }
4735}
4736
4737impl Deref for SelectorWrapper<'_> {
4738 type Target = DomRoot<Element>;
4739
4740 fn deref(&self) -> &Self::Target {
4741 match self {
4742 SelectorWrapper::Owned(r) => r,
4743 SelectorWrapper::Borrowed(r) => r,
4744 }
4745 }
4746}
4747
4748impl SelectorWrapper<'_> {
4749 fn into_owned(self) -> DomRoot<Element> {
4750 match self {
4751 SelectorWrapper::Owned(r) => r,
4752 SelectorWrapper::Borrowed(r) => r.clone(),
4753 }
4754 }
4755}
4756
4757impl SelectorsElement for SelectorWrapper<'_> {
4758 type Impl = SelectorImpl;
4759
4760 #[expect(unsafe_code)]
4761 fn opaque(&self) -> ::selectors::OpaqueElement {
4762 ::selectors::OpaqueElement::new(unsafe { &*self.reflector().get_jsobject().get() })
4763 }
4764
4765 fn parent_element(&self) -> Option<Self> {
4766 self.upcast::<Node>()
4767 .GetParentElement()
4768 .map(SelectorWrapper::Owned)
4769 }
4770
4771 fn parent_node_is_shadow_root(&self) -> bool {
4772 match self.upcast::<Node>().GetParentNode() {
4773 None => false,
4774 Some(node) => node.is::<ShadowRoot>(),
4775 }
4776 }
4777
4778 fn containing_shadow_host(&self) -> Option<Self> {
4779 self.containing_shadow_root()
4780 .map(|shadow_root| shadow_root.Host())
4781 .map(SelectorWrapper::Owned)
4782 }
4783
4784 fn is_pseudo_element(&self) -> bool {
4785 false
4786 }
4787
4788 fn match_pseudo_element(
4789 &self,
4790 _pseudo: &PseudoElement,
4791 _context: &mut MatchingContext<Self::Impl>,
4792 ) -> bool {
4793 false
4794 }
4795
4796 fn prev_sibling_element(&self) -> Option<Self> {
4797 self.node
4798 .preceding_siblings()
4799 .find_map(DomRoot::downcast)
4800 .map(SelectorWrapper::Owned)
4801 }
4802
4803 fn next_sibling_element(&self) -> Option<Self> {
4804 self.node
4805 .following_siblings()
4806 .find_map(DomRoot::downcast)
4807 .map(SelectorWrapper::Owned)
4808 }
4809
4810 fn first_element_child(&self) -> Option<Self> {
4811 self.GetFirstElementChild().map(SelectorWrapper::Owned)
4812 }
4813
4814 fn attr_matches(
4815 &self,
4816 ns: &NamespaceConstraint<&style::Namespace>,
4817 local_name: &style::LocalName,
4818 operation: &AttrSelectorOperation<&AtomString>,
4819 ) -> bool {
4820 match *ns {
4821 NamespaceConstraint::Specific(ns) => self
4822 .get_attribute(ns, local_name)
4823 .is_some_and(|attr| attr.value().eval_selector(operation)),
4824 NamespaceConstraint::Any => self.attrs.borrow().iter().any(|attr| {
4825 *attr.local_name() == **local_name && attr.value().eval_selector(operation)
4826 }),
4827 }
4828 }
4829
4830 fn is_root(&self) -> bool {
4831 Element::is_root(self)
4832 }
4833
4834 fn is_empty(&self) -> bool {
4835 self.node.children().all(|node| {
4836 !node.is::<Element>() &&
4837 match node.downcast::<Text>() {
4838 None => true,
4839 Some(text) => text.upcast::<CharacterData>().data().is_empty(),
4840 }
4841 })
4842 }
4843
4844 fn has_local_name(&self, local_name: &LocalName) -> bool {
4845 Element::local_name(self) == local_name
4846 }
4847
4848 fn has_namespace(&self, ns: &Namespace) -> bool {
4849 Element::namespace(self) == ns
4850 }
4851
4852 fn is_same_type(&self, other: &Self) -> bool {
4853 Element::local_name(self) == Element::local_name(other) &&
4854 Element::namespace(self) == Element::namespace(other)
4855 }
4856
4857 fn match_non_ts_pseudo_class(
4858 &self,
4859 pseudo_class: &NonTSPseudoClass,
4860 _: &mut MatchingContext<Self::Impl>,
4861 ) -> bool {
4862 match *pseudo_class {
4863 NonTSPseudoClass::Link | NonTSPseudoClass::AnyLink => self.is_link(),
4865 NonTSPseudoClass::Visited => false,
4866
4867 NonTSPseudoClass::ServoNonZeroBorder => match self.downcast::<HTMLTableElement>() {
4868 None => false,
4869 Some(this) => match this.get_border() {
4870 None | Some(0) => false,
4871 Some(_) => true,
4872 },
4873 },
4874
4875 NonTSPseudoClass::CustomState(ref state) => self.has_custom_state(&state.0),
4876
4877 NonTSPseudoClass::Lang(ref lang) => {
4882 extended_filtering(&self.upcast::<Node>().get_lang().unwrap_or_default(), lang)
4883 },
4884
4885 NonTSPseudoClass::ReadOnly => {
4886 !Element::state(self).contains(NonTSPseudoClass::ReadWrite.state_flag())
4887 },
4888
4889 NonTSPseudoClass::Active |
4890 NonTSPseudoClass::Autofill |
4891 NonTSPseudoClass::Checked |
4892 NonTSPseudoClass::Default |
4893 NonTSPseudoClass::Defined |
4894 NonTSPseudoClass::Disabled |
4895 NonTSPseudoClass::Enabled |
4896 NonTSPseudoClass::Focus |
4897 NonTSPseudoClass::FocusVisible |
4898 NonTSPseudoClass::FocusWithin |
4899 NonTSPseudoClass::Fullscreen |
4900 NonTSPseudoClass::Hover |
4901 NonTSPseudoClass::InRange |
4902 NonTSPseudoClass::Indeterminate |
4903 NonTSPseudoClass::Invalid |
4904 NonTSPseudoClass::Modal |
4905 NonTSPseudoClass::MozMeterOptimum |
4906 NonTSPseudoClass::MozMeterSubOptimum |
4907 NonTSPseudoClass::MozMeterSubSubOptimum |
4908 NonTSPseudoClass::Open |
4909 NonTSPseudoClass::Optional |
4910 NonTSPseudoClass::OutOfRange |
4911 NonTSPseudoClass::PlaceholderShown |
4912 NonTSPseudoClass::PopoverOpen |
4913 NonTSPseudoClass::ReadWrite |
4914 NonTSPseudoClass::Required |
4915 NonTSPseudoClass::Target |
4916 NonTSPseudoClass::UserInvalid |
4917 NonTSPseudoClass::UserValid |
4918 NonTSPseudoClass::Valid => Element::state(self).contains(pseudo_class.state_flag()),
4919 }
4920 }
4921
4922 fn is_link(&self) -> bool {
4923 let node = self.upcast::<Node>();
4925 match node.type_id() {
4926 NodeTypeId::Element(ElementTypeId::HTMLElement(
4928 HTMLElementTypeId::HTMLAnchorElement,
4929 )) |
4930 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) |
4931 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
4932 self.has_attribute(&local_name!("href"))
4933 },
4934 _ => false,
4935 }
4936 }
4937
4938 fn has_id(&self, id: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4939 self.id_attribute
4940 .borrow()
4941 .as_ref()
4942 .is_some_and(|atom| case_sensitivity.eq_atom(id, atom))
4943 }
4944
4945 fn is_part(&self, name: &AtomIdent) -> bool {
4946 Element::is_part(self, name, CaseSensitivity::CaseSensitive)
4947 }
4948
4949 fn imported_part(&self, _: &AtomIdent) -> Option<AtomIdent> {
4950 None
4951 }
4952
4953 fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4954 Element::has_class(self, name, case_sensitivity)
4955 }
4956
4957 fn is_html_element_in_html_document(&self) -> bool {
4958 self.html_element_in_html_document()
4959 }
4960
4961 fn is_html_slot_element(&self) -> bool {
4962 self.is_html_element() && self.local_name() == &local_name!("slot")
4963 }
4964
4965 fn apply_selector_flags(&self, flags: ElementSelectorFlags) {
4966 let self_flags = flags.for_self();
4968 if !self_flags.is_empty() {
4969 #[expect(unsafe_code)]
4970 unsafe {
4971 Dom::from_ref(&***self)
4972 .to_layout()
4973 .insert_selector_flags(self_flags);
4974 }
4975 }
4976
4977 let parent_flags = flags.for_parent();
4979 if !parent_flags.is_empty() {
4980 if let Some(p) = self.parent_element() {
4981 #[expect(unsafe_code)]
4982 unsafe {
4983 Dom::from_ref(&**p)
4984 .to_layout()
4985 .insert_selector_flags(parent_flags);
4986 }
4987 }
4988 }
4989 }
4990
4991 fn add_element_unique_hashes(&self, filter: &mut BloomFilter) -> bool {
4992 let mut f = |hash| filter.insert_hash(hash & BLOOM_HASH_MASK);
4993
4994 f(Element::local_name(self).get_hash());
4997 f(Element::namespace(self).get_hash());
4998
4999 if let Some(ref id) = *self.id_attribute.borrow() {
5000 f(id.get_hash());
5001 }
5002
5003 if let Some(attr) = self.get_attribute(&ns!(), &local_name!("class")) {
5004 for class in attr.value().as_tokens() {
5005 f(AtomIdent::cast(class).get_hash());
5006 }
5007 }
5008
5009 for attr in self.attrs.borrow().iter() {
5010 let name = style::values::GenericAtomIdent::cast(attr.local_name());
5011 if !style::bloom::is_attr_name_excluded_from_filter(name) {
5012 f(name.get_hash());
5013 }
5014 }
5015
5016 true
5017 }
5018
5019 fn has_custom_state(&self, name: &AtomIdent) -> bool {
5020 let mut has_state = false;
5021 self.each_custom_state(|state| has_state |= state == name);
5022
5023 has_state
5024 }
5025}
5026
5027impl Element {
5028 fn each_custom_state<F>(&self, callback: F)
5029 where
5030 F: FnMut(&AtomIdent),
5031 {
5032 self.get_element_internals()
5033 .and_then(|internals| internals.custom_states())
5034 .inspect(|states| states.for_each_state(callback));
5035 }
5036
5037 pub(crate) fn client_rect(&self) -> Rect<i32, CSSPixel> {
5038 let doc = self.node.owner_doc();
5039
5040 if let Some(rect) = self
5041 .rare_data()
5042 .as_ref()
5043 .and_then(|data| data.client_rect.as_ref())
5044 .and_then(|rect| rect.get().ok())
5045 {
5046 if doc.restyle_reason().is_empty() {
5047 return rect;
5048 }
5049 }
5050
5051 let mut rect = self.upcast::<Node>().client_rect();
5052 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
5053
5054 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
5055 (!in_quirks_mode && self.is_document_element())
5056 {
5057 rect.size = doc.window().viewport_details().size.round().to_i32();
5058 }
5059
5060 self.ensure_rare_data().client_rect = Some(self.owner_window().cache_layout_value(rect));
5061 rect
5062 }
5063
5064 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
5065 let element = match self.upcast::<Node>().type_id() {
5066 NodeTypeId::Element(ElementTypeId::HTMLElement(
5067 HTMLElementTypeId::HTMLInputElement,
5068 )) => {
5069 let element = self.downcast::<HTMLInputElement>().unwrap();
5070 Some(element as &dyn Activatable)
5071 },
5072 NodeTypeId::Element(ElementTypeId::HTMLElement(
5073 HTMLElementTypeId::HTMLButtonElement,
5074 )) => {
5075 let element = self.downcast::<HTMLButtonElement>().unwrap();
5076 Some(element as &dyn Activatable)
5077 },
5078 NodeTypeId::Element(ElementTypeId::HTMLElement(
5079 HTMLElementTypeId::HTMLAnchorElement,
5080 )) => {
5081 let element = self.downcast::<HTMLAnchorElement>().unwrap();
5082 Some(element as &dyn Activatable)
5083 },
5084 NodeTypeId::Element(ElementTypeId::HTMLElement(
5085 HTMLElementTypeId::HTMLLabelElement,
5086 )) => {
5087 let element = self.downcast::<HTMLLabelElement>().unwrap();
5088 Some(element as &dyn Activatable)
5089 },
5090 NodeTypeId::Element(ElementTypeId::HTMLElement(
5091 HTMLElementTypeId::HTMLSelectElement,
5092 )) => {
5093 let element = self.downcast::<HTMLSelectElement>().unwrap();
5094 Some(element as &dyn Activatable)
5095 },
5096 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
5097 let element = self.downcast::<HTMLElement>().unwrap();
5098 Some(element as &dyn Activatable)
5099 },
5100 _ => None,
5101 };
5102 element.and_then(|elem| {
5103 if elem.is_instance_activatable() {
5104 Some(elem)
5105 } else {
5106 None
5107 }
5108 })
5109 }
5110
5111 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
5112 if let Some(s) = self.downcast::<HTMLStyleElement>() {
5113 return Some(s as &dyn StylesheetOwner);
5114 }
5115
5116 if let Some(l) = self.downcast::<HTMLLinkElement>() {
5117 return Some(l as &dyn StylesheetOwner);
5118 }
5119
5120 None
5121 }
5122
5123 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
5125 match self.upcast::<Node>().type_id() {
5126 NodeTypeId::Element(ElementTypeId::HTMLElement(
5127 HTMLElementTypeId::HTMLInputElement,
5128 )) => {
5129 let element = self.downcast::<HTMLInputElement>().unwrap();
5130 Some(element as &dyn Validatable)
5131 },
5132 NodeTypeId::Element(ElementTypeId::HTMLElement(
5133 HTMLElementTypeId::HTMLButtonElement,
5134 )) => {
5135 let element = self.downcast::<HTMLButtonElement>().unwrap();
5136 Some(element as &dyn Validatable)
5137 },
5138 NodeTypeId::Element(ElementTypeId::HTMLElement(
5139 HTMLElementTypeId::HTMLObjectElement,
5140 )) => {
5141 let element = self.downcast::<HTMLObjectElement>().unwrap();
5142 Some(element as &dyn Validatable)
5143 },
5144 NodeTypeId::Element(ElementTypeId::HTMLElement(
5145 HTMLElementTypeId::HTMLSelectElement,
5146 )) => {
5147 let element = self.downcast::<HTMLSelectElement>().unwrap();
5148 Some(element as &dyn Validatable)
5149 },
5150 NodeTypeId::Element(ElementTypeId::HTMLElement(
5151 HTMLElementTypeId::HTMLTextAreaElement,
5152 )) => {
5153 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
5154 Some(element as &dyn Validatable)
5155 },
5156 NodeTypeId::Element(ElementTypeId::HTMLElement(
5157 HTMLElementTypeId::HTMLFieldSetElement,
5158 )) => {
5159 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
5160 Some(element as &dyn Validatable)
5161 },
5162 NodeTypeId::Element(ElementTypeId::HTMLElement(
5163 HTMLElementTypeId::HTMLOutputElement,
5164 )) => {
5165 let element = self.downcast::<HTMLOutputElement>().unwrap();
5166 Some(element as &dyn Validatable)
5167 },
5168 _ => None,
5169 }
5170 }
5171
5172 pub(crate) fn is_invalid(&self, needs_update: bool, can_gc: CanGc) -> bool {
5173 if let Some(validatable) = self.as_maybe_validatable() {
5174 if needs_update {
5175 validatable
5176 .validity_state(can_gc)
5177 .perform_validation_and_update(ValidationFlags::all(), can_gc);
5178 }
5179 return validatable.is_instance_validatable() &&
5180 !validatable.satisfies_constraints(can_gc);
5181 }
5182
5183 if let Some(internals) = self.get_element_internals() {
5184 return internals.is_invalid(can_gc);
5185 }
5186 false
5187 }
5188
5189 pub(crate) fn is_instance_validatable(&self) -> bool {
5190 if let Some(validatable) = self.as_maybe_validatable() {
5191 return validatable.is_instance_validatable();
5192 }
5193 if let Some(internals) = self.get_element_internals() {
5194 return internals.is_instance_validatable();
5195 }
5196 false
5197 }
5198
5199 pub(crate) fn init_state_for_internals(&self) {
5200 self.set_enabled_state(true);
5201 self.set_state(ElementState::VALID, true);
5202 self.set_state(ElementState::INVALID, false);
5203 }
5204
5205 pub(crate) fn click_in_progress(&self) -> bool {
5206 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5207 }
5208
5209 pub(crate) fn set_click_in_progress(&self, click: bool) {
5210 self.upcast::<Node>()
5211 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5212 }
5213
5214 pub(crate) fn nearest_activable_element(&self) -> Option<DomRoot<Element>> {
5216 match self.as_maybe_activatable() {
5217 Some(el) => Some(DomRoot::from_ref(el.as_element())),
5218 None => {
5219 let node = self.upcast::<Node>();
5220 for node in node.ancestors() {
5221 if let Some(node) = node.downcast::<Element>() {
5222 if node.as_maybe_activatable().is_some() {
5223 return Some(DomRoot::from_ref(node));
5224 }
5225 }
5226 }
5227 None
5228 },
5229 }
5230 }
5231
5232 pub fn state(&self) -> ElementState {
5233 self.state.get()
5234 }
5235
5236 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5237 let mut state = self.state.get();
5238 let previous_state = state;
5239 if value {
5240 state.insert(which);
5241 } else {
5242 state.remove(which);
5243 }
5244
5245 if previous_state == state {
5246 return;
5248 }
5249
5250 {
5253 let document = self.owner_document();
5254 let mut entry = document.ensure_pending_restyle(self);
5255 if entry.snapshot.is_none() {
5256 entry.snapshot = Some(Snapshot::new());
5257 }
5258 let snapshot = entry.snapshot.as_mut().unwrap();
5259 if snapshot.state.is_none() {
5260 snapshot.state = Some(self.state());
5261 }
5262 }
5263
5264 self.state.set(state);
5265 }
5266
5267 pub(crate) fn set_active_state(&self, value: bool) {
5269 self.set_state(ElementState::ACTIVE, value);
5270
5271 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5272 parent.set_active_state(value);
5273 }
5274 }
5275
5276 pub(crate) fn focus_state(&self) -> bool {
5277 self.state.get().contains(ElementState::FOCUS)
5278 }
5279
5280 pub(crate) fn set_focus_state(&self, value: bool) {
5281 self.set_state(ElementState::FOCUS, value);
5282 }
5283
5284 pub(crate) fn hover_state(&self) -> bool {
5285 self.state.get().contains(ElementState::HOVER)
5286 }
5287
5288 pub(crate) fn set_hover_state(&self, value: bool) {
5289 self.set_state(ElementState::HOVER, value);
5290 }
5291
5292 pub(crate) fn enabled_state(&self) -> bool {
5293 self.state.get().contains(ElementState::ENABLED)
5294 }
5295
5296 pub(crate) fn set_enabled_state(&self, value: bool) {
5297 self.set_state(ElementState::ENABLED, value)
5298 }
5299
5300 pub(crate) fn disabled_state(&self) -> bool {
5301 self.state.get().contains(ElementState::DISABLED)
5302 }
5303
5304 pub(crate) fn set_disabled_state(&self, value: bool) {
5305 self.set_state(ElementState::DISABLED, value)
5306 }
5307
5308 pub(crate) fn read_write_state(&self) -> bool {
5309 self.state.get().contains(ElementState::READWRITE)
5310 }
5311
5312 pub(crate) fn set_read_write_state(&self, value: bool) {
5313 self.set_state(ElementState::READWRITE, value)
5314 }
5315
5316 pub(crate) fn open_state(&self) -> bool {
5317 self.state.get().contains(ElementState::OPEN)
5318 }
5319
5320 pub(crate) fn set_open_state(&self, value: bool) {
5321 self.set_state(ElementState::OPEN, value);
5322 }
5323
5324 pub(crate) fn placeholder_shown_state(&self) -> bool {
5325 self.state.get().contains(ElementState::PLACEHOLDER_SHOWN)
5326 }
5327
5328 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5329 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5330 }
5331
5332 pub(crate) fn set_modal_state(&self, value: bool) {
5333 self.set_state(ElementState::MODAL, value);
5334 }
5335
5336 pub(crate) fn set_target_state(&self, value: bool) {
5337 self.set_state(ElementState::URLTARGET, value)
5338 }
5339
5340 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5341 self.set_state(ElementState::FULLSCREEN, value)
5342 }
5343
5344 pub(crate) fn is_connected(&self) -> bool {
5346 self.upcast::<Node>().is_connected()
5347 }
5348
5349 pub(crate) fn cannot_navigate(&self) -> bool {
5351 let document = self.owner_document();
5352
5353 !document.is_fully_active() ||
5355 (
5356 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5358 )
5359 }
5360}
5361
5362impl Element {
5363 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5364 let node = self.upcast::<Node>();
5365 if self.disabled_state() {
5366 return;
5367 }
5368 for ancestor in node.ancestors() {
5369 if !ancestor.is::<HTMLFieldSetElement>() {
5370 continue;
5371 }
5372 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5373 continue;
5374 }
5375 if ancestor.is_parent_of(node) {
5376 self.set_disabled_state(true);
5377 self.set_enabled_state(false);
5378 return;
5379 }
5380 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5381 if node.ancestors().any(|ancestor| ancestor == *legend) {
5383 continue;
5384 }
5385 }
5386 self.set_disabled_state(true);
5387 self.set_enabled_state(false);
5388 return;
5389 }
5390 }
5391
5392 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5393 if self.disabled_state() {
5394 return;
5395 }
5396 let node = self.upcast::<Node>();
5397 if let Some(ref parent) = node.GetParentNode() {
5398 if parent.is::<HTMLOptGroupElement>() &&
5399 parent.downcast::<Element>().unwrap().disabled_state()
5400 {
5401 self.set_disabled_state(true);
5402 self.set_enabled_state(false);
5403 }
5404 }
5405 }
5406
5407 pub(crate) fn check_disabled_attribute(&self) {
5408 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5409 self.set_disabled_state(has_disabled_attrib);
5410 self.set_enabled_state(!has_disabled_attrib);
5411 }
5412
5413 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5414 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5415 self.set_read_write_state(has_readonly_attribute);
5416 }
5417}
5418
5419#[derive(Clone, Copy, PartialEq)]
5420pub(crate) enum AttributeMutationReason {
5421 ByCloning,
5422 ByParser,
5423 Directly,
5424}
5425
5426#[derive(Clone, Copy)]
5427pub(crate) enum AttributeMutation<'a> {
5428 Set(Option<&'a AttrValue>, AttributeMutationReason),
5431
5432 Removed,
5435}
5436
5437impl AttributeMutation<'_> {
5438 pub(crate) fn is_removal(&self) -> bool {
5439 match *self {
5440 AttributeMutation::Removed => true,
5441 AttributeMutation::Set(..) => false,
5442 }
5443 }
5444
5445 pub(crate) fn new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>> {
5446 match *self {
5447 AttributeMutation::Set(..) => Some(attr.value()),
5448 AttributeMutation::Removed => None,
5449 }
5450 }
5451}
5452
5453#[derive(JSTraceable, MallocSizeOf)]
5457struct TagName {
5458 #[no_trace]
5459 ptr: DomRefCell<Option<LocalName>>,
5460}
5461
5462impl TagName {
5463 fn new() -> TagName {
5464 TagName {
5465 ptr: DomRefCell::new(None),
5466 }
5467 }
5468
5469 fn or_init<F>(&self, cb: F) -> LocalName
5472 where
5473 F: FnOnce() -> LocalName,
5474 {
5475 match &mut *self.ptr.borrow_mut() {
5476 &mut Some(ref name) => name.clone(),
5477 ptr => {
5478 let name = cb();
5479 *ptr = Some(name.clone());
5480 name
5481 },
5482 }
5483 }
5484
5485 fn clear(&self) {
5488 *self.ptr.borrow_mut() = None;
5489 }
5490}
5491
5492pub(crate) struct ElementPerformFullscreenEnter {
5493 element: Trusted<Element>,
5494 document: Trusted<Document>,
5495 promise: TrustedPromise,
5496 error: bool,
5497}
5498
5499impl ElementPerformFullscreenEnter {
5500 pub(crate) fn new(
5501 element: Trusted<Element>,
5502 document: Trusted<Document>,
5503 promise: TrustedPromise,
5504 error: bool,
5505 ) -> Box<ElementPerformFullscreenEnter> {
5506 Box::new(ElementPerformFullscreenEnter {
5507 element,
5508 document,
5509 promise,
5510 error,
5511 })
5512 }
5513}
5514
5515impl TaskOnce for ElementPerformFullscreenEnter {
5516 fn run_once(self, cx: &mut js::context::JSContext) {
5518 let element = self.element.root();
5519 let promise = self.promise.root();
5520 let document = element.owner_document();
5521
5522 if self.document.root() != document ||
5531 !element.fullscreen_element_ready_check() ||
5532 self.error
5533 {
5534 document
5536 .upcast::<EventTarget>()
5537 .fire_event(atom!("fullscreenerror"), CanGc::from_cx(cx));
5538 promise.reject_error(
5539 Error::Type(c"fullscreen is not connected".to_owned()),
5540 CanGc::from_cx(cx),
5541 );
5542 return;
5543 }
5544
5545 element.set_fullscreen_state(true);
5548 document.set_fullscreen_element(Some(&element));
5549 document.upcast::<EventTarget>().fire_event_with_params(
5550 atom!("fullscreenchange"),
5551 EventBubbles::Bubbles,
5552 EventCancelable::NotCancelable,
5553 EventComposed::Composed,
5554 CanGc::from_cx(cx),
5555 );
5556
5557 promise.resolve_native(&(), CanGc::from_cx(cx));
5560 }
5561}
5562
5563pub(crate) struct ElementPerformFullscreenExit {
5564 element: Trusted<Element>,
5565 promise: TrustedPromise,
5566}
5567
5568impl ElementPerformFullscreenExit {
5569 pub(crate) fn new(
5570 element: Trusted<Element>,
5571 promise: TrustedPromise,
5572 ) -> Box<ElementPerformFullscreenExit> {
5573 Box::new(ElementPerformFullscreenExit { element, promise })
5574 }
5575}
5576
5577impl TaskOnce for ElementPerformFullscreenExit {
5578 fn run_once(self, cx: &mut js::context::JSContext) {
5580 let element = self.element.root();
5581 let document = element.owner_document();
5582 element.set_fullscreen_state(false);
5589 document.set_fullscreen_element(None);
5590 document.upcast::<EventTarget>().fire_event_with_params(
5591 atom!("fullscreenchange"),
5592 EventBubbles::Bubbles,
5593 EventCancelable::NotCancelable,
5594 EventComposed::Composed,
5595 CanGc::from_cx(cx),
5596 );
5597
5598 self.promise.root().resolve_native(&(), CanGc::from_cx(cx));
5601 }
5602}
5603
5604pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5606 element
5607 .get_attribute(&ns!(), &local_name!("crossorigin"))
5608 .map(|attribute| {
5609 let value = attribute.value().to_ascii_lowercase();
5610 if value == "anonymous" || value == "use-credentials" {
5611 DOMString::from(value)
5612 } else {
5613 DOMString::from("anonymous")
5614 }
5615 })
5616}
5617
5618pub(crate) fn set_cross_origin_attribute(
5619 element: &Element,
5620 value: Option<DOMString>,
5621 can_gc: CanGc,
5622) {
5623 match value {
5624 Some(val) => element.set_string_attribute(&local_name!("crossorigin"), val, can_gc),
5625 None => {
5626 element.remove_attribute(&ns!(), &local_name!("crossorigin"), can_gc);
5627 },
5628 }
5629}
5630
5631pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5633 element
5634 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5635 .map(|attribute| {
5636 let value = attribute.value().to_ascii_lowercase();
5637 if value == "no-referrer" ||
5638 value == "no-referrer-when-downgrade" ||
5639 value == "same-origin" ||
5640 value == "origin" ||
5641 value == "strict-origin" ||
5642 value == "origin-when-cross-origin" ||
5643 value == "strict-origin-when-cross-origin" ||
5644 value == "unsafe-url"
5645 {
5646 DOMString::from(value)
5647 } else {
5648 DOMString::new()
5649 }
5650 })
5651 .unwrap_or_default()
5652}
5653
5654pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5655 element
5656 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5657 .map(|attribute| ReferrerPolicy::from(&**attribute.value()))
5658 .unwrap_or(element.owner_document().get_referrer_policy())
5659}
5660
5661pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5662 element
5663 .get_attribute(&ns!(), &local_name!("crossorigin"))
5664 .map(|attribute| CorsSettings::from_enumerated_attribute(&attribute.value()))
5665}
5666
5667pub(crate) fn is_element_affected_by_legacy_background_presentational_hint(
5668 namespace: &Namespace,
5669 local_name: &LocalName,
5670) -> bool {
5671 *namespace == ns!(html) &&
5672 matches!(
5673 *local_name,
5674 local_name!("body") |
5675 local_name!("table") |
5676 local_name!("thead") |
5677 local_name!("tbody") |
5678 local_name!("tfoot") |
5679 local_name!("tr") |
5680 local_name!("td") |
5681 local_name!("th")
5682 )
5683}