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