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 embedder_traits::InputMethodType;
20use euclid::default::{Rect, Size2D};
21use html5ever::serialize::TraversalScope;
22use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
23use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
24use js::jsapi::{Heap, JSAutoRealm};
25use js::jsval::JSVal;
26use js::rust::HandleObject;
27use layout_api::{LayoutDamage, ScrollContainerQueryFlags};
28use net_traits::ReferrerPolicy;
29use net_traits::request::CorsSettings;
30use selectors::Element as SelectorsElement;
31use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
32use selectors::bloom::{BLOOM_HASH_MASK, BloomFilter};
33use selectors::matching::{ElementSelectorFlags, MatchingContext};
34use selectors::sink::Push;
35use servo_arc::Arc;
36use style::applicable_declarations::ApplicableDeclarationBlock;
37use style::attr::{AttrValue, LengthOrPercentageOrAuto};
38use style::context::QuirksMode;
39use style::invalidation::element::restyle_hints::RestyleHint;
40use style::properties::longhands::{
41 self, background_image, border_spacing, font_family, font_size,
42};
43use style::properties::{
44 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
45 parse_style_attribute,
46};
47use style::rule_tree::CascadeLevel;
48use style::selector_parser::{
49 NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser, Snapshot,
50 extended_filtering,
51};
52use style::shared_lock::Locked;
53use style::stylesheets::layer_rule::LayerOrder;
54use style::stylesheets::{CssRuleType, UrlExtraData};
55use style::values::computed::Overflow;
56use style::values::generics::NonNegative;
57use style::values::generics::position::PreferredRatio;
58use style::values::generics::ratio::Ratio;
59use style::values::{AtomIdent, AtomString, CSSFloat, computed, specified};
60use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
61use stylo_atoms::Atom;
62use stylo_dom::ElementState;
63use xml5ever::serialize::TraversalScope::{
64 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
65};
66
67use crate::conversions::Convert;
68use crate::dom::activation::Activatable;
69use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute};
70use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
71use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
72use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
73use crate::dom::bindings::codegen::Bindings::ElementBinding::{
74 ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
75};
76use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
77use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
78use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
79use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
80 ShadowRootMethods, ShadowRootMode, SlotAssignmentMode,
81};
82use crate::dom::bindings::codegen::Bindings::WindowBinding::{
83 ScrollBehavior, ScrollToOptions, WindowMethods,
84};
85use crate::dom::bindings::codegen::UnionTypes::{
86 BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
87 TrustedHTMLOrString,
88 TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString,
89 TrustedScriptURLOrUSVString,
90};
91use crate::dom::bindings::conversions::DerivedFrom;
92use crate::dom::bindings::domname::{
93 self, is_valid_attribute_local_name, namespace_from_domstring,
94};
95use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
96use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
97use crate::dom::bindings::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, LayoutNodeHelpers, Node, NodeDamage,
162 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::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);
610 }
611
612 if !is_valid_shadow_host_name(self.local_name()) {
615 if is_ua_widget != IsUserAgentWidget::Yes {
617 return Err(Error::NotSupported);
618 }
619 }
620
621 if is_valid_custom_element_name(self.local_name()) || self.get_is().is_some() {
624 let definition = self.get_custom_element_definition();
628 if definition.is_some_and(|definition| definition.disable_shadow) {
631 return Err(Error::NotSupported);
632 }
633 }
634
635 if let Some(current_shadow_root) = self.shadow_root() {
638 if !current_shadow_root.is_declarative() ||
642 current_shadow_root.shadow_root_mode() != mode
643 {
644 return Err(Error::NotSupported);
645 }
646
647 for child in current_shadow_root.upcast::<Node>().children() {
649 child.remove_self(can_gc);
650 }
651
652 current_shadow_root.set_declarative(false);
654
655 return Ok(current_shadow_root);
657 }
658
659 let shadow_root = ShadowRoot::new(
666 self,
667 &self.node.owner_doc(),
668 mode,
669 slot_assignment_mode,
670 clonable,
671 is_ua_widget,
672 can_gc,
673 );
674
675 shadow_root.set_delegates_focus(delegates_focus);
677
678 if matches!(
681 self.get_custom_element_state(),
682 CustomElementState::Precustomized | CustomElementState::Custom
683 ) {
684 shadow_root.set_available_to_element_internals(true);
685 }
686
687 shadow_root.set_declarative(false);
689
690 shadow_root.set_serializable(serializable);
692
693 self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root));
695 shadow_root
696 .upcast::<Node>()
697 .set_containing_shadow_root(Some(&shadow_root));
698
699 let bind_context = BindContext::new(&self.node);
700 shadow_root.bind_to_tree(&bind_context, can_gc);
701
702 let node = self.upcast::<Node>();
703 node.dirty(NodeDamage::Other);
704
705 Ok(shadow_root)
706 }
707
708 pub(crate) fn attach_ua_shadow_root(
724 &self,
725 use_ua_widget_styling: bool,
726 can_gc: CanGc,
727 ) -> DomRoot<ShadowRoot> {
728 let root = self
729 .attach_shadow(
730 IsUserAgentWidget::Yes,
731 ShadowRootMode::Closed,
732 false,
733 false,
734 false,
735 SlotAssignmentMode::Manual,
736 can_gc,
737 )
738 .expect("Attaching UA shadow root failed");
739
740 root.upcast::<Node>()
741 .set_in_ua_widget(use_ua_widget_styling);
742 root
743 }
744
745 pub(crate) fn is_translate_enabled(&self) -> bool {
747 let name = &local_name!("translate");
748 if self.has_attribute(name) {
749 let attribute = self.get_string_attribute(name);
750 match_ignore_ascii_case! { &*attribute.str(),
751 "yes" | "" => return true,
752 "no" => return false,
753 _ => {},
754 }
755 }
756 if let Some(parent) = self.upcast::<Node>().GetParentNode() {
757 if let Some(elem) = parent.downcast::<Element>() {
758 return elem.is_translate_enabled();
759 }
760 }
761 true
762 }
763
764 pub(crate) fn directionality(&self) -> String {
766 self.downcast::<HTMLElement>()
767 .and_then(|html_element| html_element.directionality())
768 .unwrap_or_else(|| {
769 let node = self.upcast::<Node>();
770 node.parent_directionality()
771 })
772 }
773
774 pub(crate) fn is_root(&self) -> bool {
775 match self.node.GetParentNode() {
776 None => false,
777 Some(node) => node.is::<Document>(),
778 }
779 }
780
781 pub(crate) fn registered_intersection_observers_mut(
784 &self,
785 ) -> RefMut<'_, Vec<IntersectionObserverRegistration>> {
786 RefMut::map(self.ensure_rare_data(), |rare_data| {
787 &mut rare_data.registered_intersection_observers
788 })
789 }
790
791 pub(crate) fn registered_intersection_observers(
792 &self,
793 ) -> Option<Ref<'_, Vec<IntersectionObserverRegistration>>> {
794 let rare_data: Ref<'_, _> = self.rare_data.borrow();
795
796 if rare_data.is_none() {
797 return None;
798 }
799 Some(Ref::map(rare_data, |rare_data| {
800 &rare_data
801 .as_ref()
802 .unwrap()
803 .registered_intersection_observers
804 }))
805 }
806
807 pub(crate) fn get_intersection_observer_registration(
808 &self,
809 observer: &IntersectionObserver,
810 ) -> Option<Ref<'_, IntersectionObserverRegistration>> {
811 if let Some(registrations) = self.registered_intersection_observers() {
812 registrations
813 .iter()
814 .position(|reg_obs| reg_obs.observer == observer)
815 .map(|index| Ref::map(registrations, |registrations| ®istrations[index]))
816 } else {
817 None
818 }
819 }
820
821 pub(crate) fn add_initial_intersection_observer_registration(
823 &self,
824 observer: &IntersectionObserver,
825 ) {
826 self.ensure_rare_data()
827 .registered_intersection_observers
828 .push(IntersectionObserverRegistration::new_initial(observer));
829 }
830
831 pub(crate) fn remove_intersection_observer(&self, observer: &IntersectionObserver) {
833 self.ensure_rare_data()
834 .registered_intersection_observers
835 .retain(|reg_obs| *reg_obs.observer != *observer)
836 }
837
838 pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
841 self.owner_window()
842 .scrolling_box_query(Some(self.upcast()), flags)
843 }
844
845 fn scroll_into_view_with_options(
847 &self,
848 behavior: ScrollBehavior,
849 block: ScrollLogicalPosition,
850 inline: ScrollLogicalPosition,
851 container: Option<&Element>,
852 inner_target_rect: Option<Rect<Au>>,
853 ) {
854 let get_target_rect = || match inner_target_rect {
855 None => self.upcast::<Node>().border_box().unwrap_or_default(),
856 Some(inner_target_rect) => inner_target_rect.translate(
857 self.upcast::<Node>()
858 .content_box()
859 .unwrap_or_default()
860 .origin
861 .to_vector(),
862 ),
863 };
864
865 let mut parent_scrolling_box = self.scrolling_box(ScrollContainerQueryFlags::empty());
868 while let Some(scrolling_box) = parent_scrolling_box {
869 parent_scrolling_box = scrolling_box.parent();
870
871 let position =
882 scrolling_box.determine_scroll_into_view_position(block, inline, get_target_rect());
883
884 if position != scrolling_box.scroll_position() {
889 scrolling_box.scroll_to(position, behavior);
900 }
901
902 if container.is_some_and(|container| {
906 let container_node = container.upcast::<Node>();
907 scrolling_box
908 .node()
909 .is_shadow_including_inclusive_ancestor_of(container_node)
910 }) {
911 return;
912 }
913 }
914
915 let window_proxy = self.owner_window().window_proxy();
916 let Some(frame_element) = window_proxy.frame_element() else {
917 return;
918 };
919
920 let inner_target_rect = Some(get_target_rect());
921 let parent_window = frame_element.owner_window();
922 let cx = GlobalScope::get_cx();
923 let _ac = JSAutoRealm::new(*cx, *parent_window.reflector().get_jsobject());
924 frame_element.scroll_into_view_with_options(
925 behavior,
926 block,
927 inline,
928 None,
929 inner_target_rect,
930 )
931 }
932}
933
934#[inline]
936pub(crate) fn is_valid_shadow_host_name(name: &LocalName) -> bool {
937 if is_valid_custom_element_name(name) {
940 return true;
941 }
942
943 matches!(
946 name,
947 &local_name!("article") |
948 &local_name!("aside") |
949 &local_name!("blockquote") |
950 &local_name!("body") |
951 &local_name!("div") |
952 &local_name!("footer") |
953 &local_name!("h1") |
954 &local_name!("h2") |
955 &local_name!("h3") |
956 &local_name!("h4") |
957 &local_name!("h5") |
958 &local_name!("h6") |
959 &local_name!("header") |
960 &local_name!("main") |
961 &local_name!("nav") |
962 &local_name!("p") |
963 &local_name!("section") |
964 &local_name!("span")
965 )
966}
967
968#[inline]
969pub(crate) fn get_attr_for_layout<'dom>(
970 elem: LayoutDom<'dom, Element>,
971 namespace: &Namespace,
972 name: &LocalName,
973) -> Option<LayoutDom<'dom, Attr>> {
974 elem.attrs()
975 .iter()
976 .find(|attr| name == attr.local_name() && namespace == attr.namespace())
977 .cloned()
978}
979
980pub(crate) trait LayoutElementHelpers<'dom> {
981 fn attrs(self) -> &'dom [LayoutDom<'dom, Attr>];
982 fn has_class_or_part_for_layout(
983 self,
984 name: &AtomIdent,
985 attr_name: &LocalName,
986 case_sensitivity: CaseSensitivity,
987 ) -> bool;
988 fn get_classes_for_layout(self) -> Option<&'dom [Atom]>;
989 fn get_parts_for_layout(self) -> Option<&'dom [Atom]>;
990
991 fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
992 where
993 V: Push<ApplicableDeclarationBlock>;
994 fn get_span(self) -> Option<u32>;
995 fn get_colspan(self) -> Option<u32>;
996 fn get_rowspan(self) -> Option<u32>;
997 fn is_html_element(&self) -> bool;
998 fn id_attribute(self) -> *const Option<Atom>;
999 fn style_attribute(self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
1000 fn local_name(self) -> &'dom LocalName;
1001 fn namespace(self) -> &'dom Namespace;
1002 fn get_lang_attr_val_for_layout(self) -> Option<&'dom str>;
1003 fn get_lang_for_layout(self) -> String;
1004 fn get_state_for_layout(self) -> ElementState;
1005 fn insert_selector_flags(self, flags: ElementSelectorFlags);
1006 fn get_selector_flags(self) -> ElementSelectorFlags;
1007 fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>>;
1009 fn get_attr_for_layout(
1010 self,
1011 namespace: &Namespace,
1012 name: &LocalName,
1013 ) -> Option<&'dom AttrValue>;
1014 fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str>;
1015 fn get_attr_vals_for_layout(self, name: &LocalName) -> Vec<&'dom AttrValue>;
1016 fn each_custom_state<F>(self, callback: F)
1017 where
1018 F: FnMut(&AtomIdent);
1019}
1020
1021impl LayoutDom<'_, Element> {
1022 pub(super) fn focus_state(self) -> bool {
1023 self.unsafe_get().state.get().contains(ElementState::FOCUS)
1024 }
1025}
1026
1027impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
1028 #[allow(unsafe_code)]
1029 #[inline]
1030 fn attrs(self) -> &'dom [LayoutDom<'dom, Attr>] {
1031 unsafe { LayoutDom::to_layout_slice(self.unsafe_get().attrs.borrow_for_layout()) }
1032 }
1033
1034 #[inline]
1035 fn has_class_or_part_for_layout(
1036 self,
1037 name: &AtomIdent,
1038 attr_name: &LocalName,
1039 case_sensitivity: CaseSensitivity,
1040 ) -> bool {
1041 get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
1042 attr.to_tokens()
1043 .unwrap()
1044 .iter()
1045 .any(|atom| case_sensitivity.eq_atom(atom, name))
1046 })
1047 }
1048
1049 #[inline]
1050 fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
1051 get_attr_for_layout(self, &ns!(), &local_name!("class"))
1052 .map(|attr| attr.to_tokens().unwrap())
1053 }
1054
1055 fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
1056 get_attr_for_layout(self, &ns!(), &local_name!("part"))
1057 .map(|attr| attr.to_tokens().unwrap())
1058 }
1059
1060 fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1061 where
1062 V: Push<ApplicableDeclarationBlock>,
1063 {
1064 let mut property_declaration_block = None;
1065 let mut push = |declaration| {
1066 property_declaration_block
1067 .get_or_insert_with(PropertyDeclarationBlock::default)
1068 .push(declaration, Importance::Normal);
1069 };
1070
1071 if let Some(lang) = self.get_lang_attr_val_for_layout() {
1074 push(PropertyDeclaration::XLang(specified::XLang(Atom::from(
1075 lang.to_owned(),
1076 ))));
1077 }
1078
1079 let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
1080 this.get_background_color()
1081 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1082 this.get_background_color()
1083 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1084 this.get_background_color()
1085 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1086 this.get_background_color()
1087 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1088 this.get_background_color()
1089 } else {
1090 None
1091 };
1092
1093 if let Some(color) = bgcolor {
1094 push(PropertyDeclaration::BackgroundColor(
1095 specified::Color::from_absolute_color(color),
1096 ));
1097 }
1098
1099 let background = self
1100 .downcast::<HTMLBodyElement>()
1101 .and_then(HTMLBodyElementLayoutHelpers::get_background);
1102 if let Some(url) = background {
1103 push(PropertyDeclaration::BackgroundImage(
1104 background_image::SpecifiedValue(
1105 vec![specified::Image::for_cascade(url.get_arc())].into(),
1106 ),
1107 ));
1108 }
1109
1110 let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
1111 this.get_color()
1112 } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
1113 this.get_color()
1115 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1116 this.get_color()
1118 } else {
1119 None
1120 };
1121
1122 if let Some(color) = color {
1123 push(PropertyDeclaration::Color(
1124 longhands::color::SpecifiedValue(specified::Color::from_absolute_color(color)),
1125 ));
1126 }
1127
1128 let font_face = self
1129 .downcast::<HTMLFontElement>()
1130 .and_then(HTMLFontElementLayoutHelpers::get_face);
1131 if let Some(font_face) = font_face {
1132 push(PropertyDeclaration::FontFamily(
1133 font_family::SpecifiedValue::Values(computed::font::FontFamilyList {
1134 list: ArcSlice::from_iter(
1135 HTMLFontElement::parse_face_attribute(font_face).into_iter(),
1136 ),
1137 }),
1138 ));
1139 }
1140
1141 let font_size = self
1142 .downcast::<HTMLFontElement>()
1143 .and_then(HTMLFontElementLayoutHelpers::get_size);
1144 if let Some(font_size) = font_size {
1145 push(PropertyDeclaration::FontSize(
1146 font_size::SpecifiedValue::from_html_size(font_size as u8),
1147 ));
1148 }
1149
1150 let cellspacing = self
1151 .downcast::<HTMLTableElement>()
1152 .and_then(HTMLTableElementLayoutHelpers::get_cellspacing);
1153 if let Some(cellspacing) = cellspacing {
1154 let width_value = specified::Length::from_px(cellspacing as f32);
1155 push(PropertyDeclaration::BorderSpacing(Box::new(
1156 border_spacing::SpecifiedValue::new(width_value.clone().into(), width_value.into()),
1157 )));
1158 }
1159
1160 let size = self
1166 .downcast::<HTMLInputElement>()
1167 .and_then(|input_element| {
1168 match self.get_attr_val_for_layout(&ns!(), &local_name!("type")) {
1170 Some("hidden") | Some("range") | Some("color") | Some("checkbox") |
1171 Some("radio") | Some("file") | Some("submit") | Some("image") |
1172 Some("reset") | Some("button") => None,
1173 _ => match input_element.size_for_layout() {
1175 0 => None,
1176 s => Some(s as i32),
1177 },
1178 }
1179 });
1180
1181 if let Some(size) = size {
1182 let value =
1183 specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size));
1184 push(PropertyDeclaration::Width(
1185 specified::Size::LengthPercentage(NonNegative(
1186 specified::LengthPercentage::Length(value),
1187 )),
1188 ));
1189 }
1190
1191 let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1192 this.get_width()
1193 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1194 this.get_width()
1195 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1196 this.get_width()
1197 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1198 this.get_width()
1199 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1200 this.get_width()
1201 } else if let Some(this) = self.downcast::<HTMLTableColElement>() {
1202 this.get_width()
1203 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1204 this.get_width()
1206 } else {
1207 LengthOrPercentageOrAuto::Auto
1208 };
1209
1210 match width {
1212 LengthOrPercentageOrAuto::Auto => {},
1213 LengthOrPercentageOrAuto::Percentage(percentage) => {
1214 let width_value = specified::Size::LengthPercentage(NonNegative(
1215 specified::LengthPercentage::Percentage(computed::Percentage(percentage)),
1216 ));
1217 push(PropertyDeclaration::Width(width_value));
1218 },
1219 LengthOrPercentageOrAuto::Length(length) => {
1220 let width_value = specified::Size::LengthPercentage(NonNegative(
1221 specified::LengthPercentage::Length(specified::NoCalcLength::Absolute(
1222 specified::AbsoluteLength::Px(length.to_f32_px()),
1223 )),
1224 ));
1225 push(PropertyDeclaration::Width(width_value));
1226 },
1227 }
1228
1229 let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1230 this.get_height()
1231 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1232 this.get_height()
1233 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1234 this.get_height()
1235 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1236 this.get_height()
1237 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1238 this.get_height()
1239 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1240 this.get_height()
1241 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1242 this.get_height()
1243 } else {
1244 LengthOrPercentageOrAuto::Auto
1245 };
1246
1247 match height {
1248 LengthOrPercentageOrAuto::Auto => {},
1249 LengthOrPercentageOrAuto::Percentage(percentage) => {
1250 let height_value = specified::Size::LengthPercentage(NonNegative(
1251 specified::LengthPercentage::Percentage(computed::Percentage(percentage)),
1252 ));
1253 push(PropertyDeclaration::Height(height_value));
1254 },
1255 LengthOrPercentageOrAuto::Length(length) => {
1256 let height_value = specified::Size::LengthPercentage(NonNegative(
1257 specified::LengthPercentage::Length(specified::NoCalcLength::Absolute(
1258 specified::AbsoluteLength::Px(length.to_f32_px()),
1259 )),
1260 ));
1261 push(PropertyDeclaration::Height(height_value));
1262 },
1263 }
1264
1265 if self.downcast::<HTMLImageElement>().is_some() ||
1268 self.downcast::<HTMLVideoElement>().is_some()
1269 {
1270 if let LengthOrPercentageOrAuto::Length(width) = width {
1271 if let LengthOrPercentageOrAuto::Length(height) = height {
1272 let width_value = NonNegative(specified::Number::new(width.to_f32_px()));
1273 let height_value = NonNegative(specified::Number::new(height.to_f32_px()));
1274 let aspect_ratio = specified::position::AspectRatio {
1275 auto: true,
1276 ratio: PreferredRatio::Ratio(Ratio(width_value, height_value)),
1277 };
1278 push(PropertyDeclaration::AspectRatio(aspect_ratio));
1279 }
1280 }
1281 }
1282
1283 let cols = self
1284 .downcast::<HTMLTextAreaElement>()
1285 .map(LayoutHTMLTextAreaElementHelpers::get_cols);
1286 if let Some(cols) = cols {
1287 let cols = cols as i32;
1288 if cols > 0 {
1289 let value =
1295 specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols));
1296 push(PropertyDeclaration::Width(
1297 specified::Size::LengthPercentage(NonNegative(
1298 specified::LengthPercentage::Length(value),
1299 )),
1300 ));
1301 }
1302 }
1303
1304 let rows = self
1305 .downcast::<HTMLTextAreaElement>()
1306 .map(LayoutHTMLTextAreaElementHelpers::get_rows);
1307 if let Some(rows) = rows {
1308 let rows = rows as i32;
1309 if rows > 0 {
1310 let value = specified::NoCalcLength::FontRelative(
1314 specified::FontRelativeLength::Em(rows as CSSFloat),
1315 );
1316 push(PropertyDeclaration::Height(
1317 specified::Size::LengthPercentage(NonNegative(
1318 specified::LengthPercentage::Length(value),
1319 )),
1320 ));
1321 }
1322 }
1323
1324 let border = self
1325 .downcast::<HTMLTableElement>()
1326 .and_then(|table| table.get_border());
1327 if let Some(border) = border {
1328 let width_value = specified::BorderSideWidth::from_px(border as f32);
1329 push(PropertyDeclaration::BorderTopWidth(width_value.clone()));
1330 push(PropertyDeclaration::BorderLeftWidth(width_value.clone()));
1331 push(PropertyDeclaration::BorderBottomWidth(width_value.clone()));
1332 push(PropertyDeclaration::BorderRightWidth(width_value));
1333 }
1334
1335 if let Some(cellpadding) = self
1336 .downcast::<HTMLTableCellElement>()
1337 .and_then(|this| this.get_table())
1338 .and_then(|table| table.get_cellpadding())
1339 {
1340 let cellpadding = NonNegative(specified::LengthPercentage::Length(
1341 specified::NoCalcLength::from_px(cellpadding as f32),
1342 ));
1343 push(PropertyDeclaration::PaddingTop(cellpadding.clone()));
1344 push(PropertyDeclaration::PaddingLeft(cellpadding.clone()));
1345 push(PropertyDeclaration::PaddingBottom(cellpadding.clone()));
1346 push(PropertyDeclaration::PaddingRight(cellpadding));
1347 }
1348
1349 if let Some(size_info) = self
1351 .downcast::<HTMLHRElement>()
1352 .and_then(|hr_element| hr_element.get_size_info())
1353 {
1354 match size_info {
1355 SizePresentationalHint::SetHeightTo(height) => {
1356 push(PropertyDeclaration::Height(height));
1357 },
1358 SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
1359 push(PropertyDeclaration::BorderLeftWidth(border_width.clone()));
1360 push(PropertyDeclaration::BorderRightWidth(border_width.clone()));
1361 push(PropertyDeclaration::BorderTopWidth(border_width.clone()));
1362 push(PropertyDeclaration::BorderBottomWidth(border_width));
1363 },
1364 SizePresentationalHint::SetBottomBorderWidthToZero => {
1365 push(PropertyDeclaration::BorderBottomWidth(
1366 specified::border::BorderSideWidth::from_px(0.),
1367 ));
1368 },
1369 }
1370 }
1371
1372 let Some(property_declaration_block) = property_declaration_block else {
1373 return;
1374 };
1375
1376 let document = self.upcast::<Node>().owner_doc_for_layout();
1377 let shared_lock = document.style_shared_lock();
1378 hints.push(ApplicableDeclarationBlock::from_declarations(
1379 Arc::new(shared_lock.wrap(property_declaration_block)),
1380 CascadeLevel::PresHints,
1381 LayerOrder::root(),
1382 ));
1383 }
1384
1385 fn get_span(self) -> Option<u32> {
1386 self.downcast::<HTMLTableColElement>()
1388 .and_then(|element| element.get_span())
1389 }
1390
1391 fn get_colspan(self) -> Option<u32> {
1392 self.downcast::<HTMLTableCellElement>()
1394 .and_then(|element| element.get_colspan())
1395 }
1396
1397 fn get_rowspan(self) -> Option<u32> {
1398 self.downcast::<HTMLTableCellElement>()
1400 .and_then(|element| element.get_rowspan())
1401 }
1402
1403 #[inline]
1404 fn is_html_element(&self) -> bool {
1405 *self.namespace() == ns!(html)
1406 }
1407
1408 #[allow(unsafe_code)]
1409 fn id_attribute(self) -> *const Option<Atom> {
1410 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1411 }
1412
1413 #[allow(unsafe_code)]
1414 fn style_attribute(self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
1415 unsafe { (self.unsafe_get()).style_attribute.borrow_for_layout() }
1416 }
1417
1418 #[allow(unsafe_code)]
1419 fn local_name(self) -> &'dom LocalName {
1420 &(self.unsafe_get()).local_name
1421 }
1422
1423 fn namespace(self) -> &'dom Namespace {
1424 &(self.unsafe_get()).namespace
1425 }
1426
1427 fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1428 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1429 return Some(attr);
1430 }
1431 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1432 return Some(attr);
1433 }
1434 None
1435 }
1436
1437 fn get_lang_for_layout(self) -> String {
1438 let mut current_node = Some(self.upcast::<Node>());
1439 while let Some(node) = current_node {
1440 current_node = node.composed_parent_node_ref();
1441 match node.downcast::<Element>() {
1442 Some(elem) => {
1443 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1444 return attr.to_owned();
1445 }
1446 },
1447 None => continue,
1448 }
1449 }
1450 String::new()
1453 }
1454
1455 #[inline]
1456 fn get_state_for_layout(self) -> ElementState {
1457 (self.unsafe_get()).state.get()
1458 }
1459
1460 #[inline]
1461 fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1462 debug_assert!(thread_state::get().is_layout());
1463 let f = &(self.unsafe_get()).selector_flags;
1464 f.set(f.get() | flags);
1465 }
1466
1467 #[inline]
1468 fn get_selector_flags(self) -> ElementSelectorFlags {
1469 self.unsafe_get().selector_flags.get()
1470 }
1471
1472 #[inline]
1473 #[allow(unsafe_code)]
1474 fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1475 unsafe {
1476 self.unsafe_get()
1477 .rare_data
1478 .borrow_for_layout()
1479 .as_ref()?
1480 .shadow_root
1481 .as_ref()
1482 .map(|sr| sr.to_layout())
1483 }
1484 }
1485
1486 #[inline]
1487 fn get_attr_for_layout(
1488 self,
1489 namespace: &Namespace,
1490 name: &LocalName,
1491 ) -> Option<&'dom AttrValue> {
1492 get_attr_for_layout(self, namespace, name).map(|attr| attr.value())
1493 }
1494
1495 #[inline]
1496 fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str> {
1497 get_attr_for_layout(self, namespace, name).map(|attr| attr.as_str())
1498 }
1499
1500 #[inline]
1501 fn get_attr_vals_for_layout(self, name: &LocalName) -> Vec<&'dom AttrValue> {
1502 self.attrs()
1503 .iter()
1504 .filter_map(|attr| {
1505 if name == attr.local_name() {
1506 Some(attr.value())
1507 } else {
1508 None
1509 }
1510 })
1511 .collect()
1512 }
1513
1514 fn each_custom_state<F>(self, callback: F)
1515 where
1516 F: FnMut(&AtomIdent),
1517 {
1518 self.unsafe_get().each_custom_state(callback)
1519 }
1520}
1521
1522impl Element {
1523 pub(crate) fn is_html_element(&self) -> bool {
1524 self.namespace == ns!(html)
1525 }
1526
1527 pub(crate) fn html_element_in_html_document(&self) -> bool {
1528 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1529 }
1530
1531 pub(crate) fn local_name(&self) -> &LocalName {
1532 &self.local_name
1533 }
1534
1535 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1536 if self.html_element_in_html_document() {
1537 name.make_ascii_lowercase();
1538 }
1539 LocalName::from(name)
1540 }
1541
1542 pub(crate) fn namespace(&self) -> &Namespace {
1543 &self.namespace
1544 }
1545
1546 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1547 self.prefix.borrow()
1548 }
1549
1550 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1551 *self.prefix.borrow_mut() = prefix;
1552 }
1553
1554 pub(crate) fn attrs(&self) -> Ref<'_, [Dom<Attr>]> {
1555 Ref::map(self.attrs.borrow(), |attrs| &**attrs)
1556 }
1557
1558 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1560 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1561
1562 if namespace_prefix == Some(namespace_prefix!("xml")) {
1564 return ns!(xml);
1565 }
1566
1567 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1569 return ns!(xmlns);
1570 }
1571
1572 let prefix = prefix.map(LocalName::from);
1573
1574 let inclusive_ancestor_elements = self
1575 .upcast::<Node>()
1576 .inclusive_ancestors(ShadowIncluding::No)
1577 .filter_map(DomRoot::downcast::<Self>);
1578
1579 for element in inclusive_ancestor_elements {
1582 if element.namespace() != &ns!() &&
1584 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1585 {
1586 return element.namespace().clone();
1587 }
1588
1589 let attr = Ref::filter_map(self.attrs(), |attrs| {
1594 attrs.iter().find(|attr| {
1595 if attr.namespace() != &ns!(xmlns) {
1596 return false;
1597 }
1598 match (attr.prefix(), prefix.as_ref()) {
1599 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1600 attr.local_name() == prefix
1601 },
1602 (None, None) => attr.local_name() == &local_name!("xmlns"),
1603 _ => false,
1604 }
1605 })
1606 })
1607 .ok();
1608
1609 if let Some(attr) = attr {
1610 return (**attr.value()).into();
1611 }
1612 }
1613
1614 ns!()
1615 }
1616
1617 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1618 self.rare_data().as_ref()?.name_attribute.clone()
1619 }
1620
1621 pub(crate) fn style_attribute(
1622 &self,
1623 ) -> &DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
1624 &self.style_attribute
1625 }
1626
1627 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1628 self.attrs
1629 .borrow()
1630 .iter()
1631 .map(|attr| attr.summarize())
1632 .collect()
1633 }
1634
1635 pub(crate) fn is_void(&self) -> bool {
1636 if self.namespace != ns!(html) {
1637 return false;
1638 }
1639 match self.local_name {
1640 local_name!("area") |
1643 local_name!("base") |
1644 local_name!("basefont") |
1645 local_name!("bgsound") |
1646 local_name!("br") |
1647 local_name!("col") |
1648 local_name!("embed") |
1649 local_name!("frame") |
1650 local_name!("hr") |
1651 local_name!("img") |
1652 local_name!("input") |
1653 local_name!("keygen") |
1654 local_name!("link") |
1655 local_name!("meta") |
1656 local_name!("param") |
1657 local_name!("source") |
1658 local_name!("track") |
1659 local_name!("wbr") => true,
1660 _ => false,
1661 }
1662 }
1663
1664 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1665 if self.node.is_in_a_document_tree() {
1666 self.upcast::<Node>()
1667 .owner_doc()
1668 .GetDocumentElement()
1669 .unwrap()
1670 } else {
1671 self.upcast::<Node>()
1672 .inclusive_ancestors(ShadowIncluding::No)
1673 .filter_map(DomRoot::downcast)
1674 .last()
1675 .expect("We know inclusive_ancestors will return `self` which is an element")
1676 }
1677 }
1678
1679 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1681 for node in self
1682 .upcast::<Node>()
1683 .inclusive_ancestors(ShadowIncluding::No)
1684 {
1685 let element = node.downcast::<Element>()?;
1686 if *element.namespace() == namespace {
1688 if let Some(prefix) = element.GetPrefix() {
1689 return Some(prefix);
1690 }
1691 }
1692
1693 for attr in element.attrs.borrow().iter() {
1695 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1696 **attr.value() == *namespace
1697 {
1698 return Some(attr.LocalName());
1699 }
1700 }
1701 }
1702 None
1703 }
1704
1705 pub(crate) fn input_method_type(&self) -> Option<InputMethodType> {
1707 if !self.is_focusable_area() {
1708 return None;
1709 }
1710
1711 if let Some(input) = self.downcast::<HTMLInputElement>() {
1712 input.input_type().as_ime_type()
1713 } else if self.is::<HTMLTextAreaElement>() {
1714 Some(InputMethodType::Text)
1715 } else {
1716 None
1718 }
1719 }
1720
1721 pub(crate) fn is_document_element(&self) -> bool {
1723 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1724 *document_element == *self
1725 } else {
1726 false
1727 }
1728 }
1729
1730 pub(crate) fn is_active_element(&self) -> bool {
1732 if let Some(active_element) = self.owner_document().GetActiveElement() {
1733 *active_element == *self
1734 } else {
1735 false
1736 }
1737 }
1738
1739 pub(crate) fn is_focusable_area(&self) -> bool {
1740 if self.is_actually_disabled() {
1741 return false;
1742 }
1743 let node = self.upcast::<Node>();
1744 if node.get_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE) {
1745 return true;
1746 }
1747
1748 matches!(
1750 node.type_id(),
1751 NodeTypeId::Element(ElementTypeId::HTMLElement(
1752 HTMLElementTypeId::HTMLAnchorElement,
1753 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1754 HTMLElementTypeId::HTMLInputElement,
1755 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1756 HTMLElementTypeId::HTMLSelectElement,
1757 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1758 HTMLElementTypeId::HTMLTextAreaElement,
1759 ))
1760 )
1761 }
1762
1763 pub(crate) fn find_focusable_shadow_host_if_necessary(&self) -> Option<DomRoot<Element>> {
1768 if self.is_focusable_area() {
1769 Some(DomRoot::from_ref(self))
1770 } else if self.upcast::<Node>().implemented_pseudo_element() ==
1771 Some(PseudoElement::ServoTextControlInnerEditor)
1772 {
1773 let containing_shadow_host = self.containing_shadow_root().map(|root| root.Host());
1774 debug_assert!(
1775 containing_shadow_host
1776 .as_ref()
1777 .is_some_and(|e| e.is_focusable_area()),
1778 "Containing shadow host is not focusable"
1779 );
1780 containing_shadow_host
1781 } else {
1782 None
1783 }
1784 }
1785
1786 pub(crate) fn is_actually_disabled(&self) -> bool {
1787 let node = self.upcast::<Node>();
1788 match node.type_id() {
1789 NodeTypeId::Element(ElementTypeId::HTMLElement(
1790 HTMLElementTypeId::HTMLButtonElement,
1791 )) |
1792 NodeTypeId::Element(ElementTypeId::HTMLElement(
1793 HTMLElementTypeId::HTMLInputElement,
1794 )) |
1795 NodeTypeId::Element(ElementTypeId::HTMLElement(
1796 HTMLElementTypeId::HTMLSelectElement,
1797 )) |
1798 NodeTypeId::Element(ElementTypeId::HTMLElement(
1799 HTMLElementTypeId::HTMLTextAreaElement,
1800 )) |
1801 NodeTypeId::Element(ElementTypeId::HTMLElement(
1802 HTMLElementTypeId::HTMLOptionElement,
1803 )) => self.disabled_state(),
1804 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1805 self.downcast::<HTMLElement>()
1806 .unwrap()
1807 .is_form_associated_custom_element() &&
1808 self.disabled_state()
1809 },
1810 _ => false,
1815 }
1816 }
1817
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 can_gc: CanGc,
1826 ) {
1827 let attr = Attr::new(
1828 &self.node.owner_doc(),
1829 local_name,
1830 value,
1831 name,
1832 namespace,
1833 prefix,
1834 Some(self),
1835 can_gc,
1836 );
1837 self.push_attribute(&attr, can_gc);
1838 }
1839
1840 fn handle_attribute_changes(
1842 &self,
1843 attr: &Attr,
1844 old_value: Option<&AttrValue>,
1845 new_value: Option<DOMString>,
1846 can_gc: CanGc,
1847 ) {
1848 let old_value_string = old_value.map(|old_value| DOMString::from(&**old_value));
1849 let name = attr.local_name().clone();
1852 let namespace = attr.namespace().clone();
1853 let mutation = LazyCell::new(|| Mutation::Attribute {
1854 name: name.clone(),
1855 namespace: namespace.clone(),
1856 old_value: old_value_string.clone(),
1857 });
1858 MutationObserver::queue_a_mutation_record(&self.node, mutation);
1859
1860 let has_new_value = new_value.is_none();
1862
1863 if self.is_custom() {
1866 let reaction = CallbackReaction::AttributeChanged(
1867 attr.local_name().clone(),
1868 old_value_string,
1869 new_value,
1870 attr.namespace().clone(),
1871 );
1872 ScriptThread::enqueue_callback_reaction(self, reaction, None);
1873 }
1874
1875 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
1877 let attribute_mutation = if has_new_value {
1878 AttributeMutation::Removed
1879 } else {
1880 AttributeMutation::Set(old_value)
1881 };
1882 vtable_for(self.upcast()).attribute_mutated(attr, attribute_mutation, can_gc);
1883 }
1884 }
1885
1886 pub(crate) fn change_attribute(&self, attr: &Attr, mut value: AttrValue, can_gc: CanGc) {
1888 let old_value = &attr.value().clone();
1892 self.will_mutate_attr(attr);
1894 attr.swap_value(&mut value);
1895 let new_value = DOMString::from(&**attr.value());
1899 self.handle_attribute_changes(attr, Some(old_value), Some(new_value), can_gc);
1900 }
1901
1902 pub(crate) fn push_attribute(&self, attr: &Attr, can_gc: CanGc) {
1904 assert!(attr.GetOwnerElement().as_deref() == Some(self));
1908 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
1912 self.will_mutate_attr(attr);
1914 self.attrs.borrow_mut().push(Dom::from_ref(attr));
1915 let new_value = DOMString::from(&**attr.value());
1919 self.handle_attribute_changes(attr, None, Some(new_value), can_gc);
1920 }
1921
1922 pub(crate) fn get_attribute(
1923 &self,
1924 namespace: &Namespace,
1925 local_name: &LocalName,
1926 ) -> Option<DomRoot<Attr>> {
1927 self.attrs
1928 .borrow()
1929 .iter()
1930 .find(|attr| attr.local_name() == local_name && attr.namespace() == namespace)
1931 .map(|js| DomRoot::from_ref(&**js))
1932 }
1933
1934 pub(crate) fn get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>> {
1936 let name = &self.parsed_name(name);
1937 let maybe_attribute = self
1938 .attrs
1939 .borrow()
1940 .iter()
1941 .find(|a| a.name() == name)
1942 .map(|js| DomRoot::from_ref(&**js));
1943 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
1944 if *name == local_name!("id") || *name == local_name!("name") {
1945 match maybe_attr {
1946 None => true,
1947 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
1948 }
1949 } else {
1950 true
1951 }
1952 }
1953 debug_assert!(id_and_name_must_be_atoms(name, &maybe_attribute));
1954 maybe_attribute
1955 }
1956
1957 pub(crate) fn set_attribute_from_parser(
1958 &self,
1959 qname: QualName,
1960 value: DOMString,
1961 prefix: Option<Prefix>,
1962 can_gc: CanGc,
1963 ) {
1964 if self
1966 .attrs
1967 .borrow()
1968 .iter()
1969 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
1970 {
1971 return;
1972 }
1973
1974 let name = match prefix {
1975 None => qname.local.clone(),
1976 Some(ref prefix) => {
1977 let name = format!("{}:{}", &**prefix, &*qname.local);
1978 LocalName::from(name)
1979 },
1980 };
1981 let value = self.parse_attribute(&qname.ns, &qname.local, value);
1982 self.push_new_attribute(qname.local, value, name, qname.ns, prefix, can_gc);
1983 }
1984
1985 pub(crate) fn set_attribute(&self, name: &LocalName, value: AttrValue, can_gc: CanGc) {
1986 assert!(name == &name.to_ascii_lowercase());
1987 assert!(!name.contains(':'));
1988
1989 self.set_first_matching_attribute(
1990 name.clone(),
1991 value,
1992 name.clone(),
1993 ns!(),
1994 None,
1995 |attr| attr.local_name() == name,
1996 can_gc,
1997 );
1998 }
1999
2000 pub(crate) fn set_custom_attribute(
2002 &self,
2003 name: DOMString,
2004 value: DOMString,
2005 can_gc: CanGc,
2006 ) -> ErrorResult {
2007 if !matches_name_production(&name.str()) {
2009 return Err(Error::InvalidCharacter);
2010 }
2011
2012 let name = LocalName::from(name);
2014 let value = self.parse_attribute(&ns!(), &name, value);
2015 self.set_first_matching_attribute(
2016 name.clone(),
2017 value,
2018 name.clone(),
2019 ns!(),
2020 None,
2021 |attr| *attr.name() == name && *attr.namespace() == ns!(),
2022 can_gc,
2023 );
2024 Ok(())
2025 }
2026
2027 #[allow(clippy::too_many_arguments)]
2029 fn set_first_matching_attribute<F>(
2030 &self,
2031 local_name: LocalName,
2032 value: AttrValue,
2033 name: LocalName,
2034 namespace: Namespace,
2035 prefix: Option<Prefix>,
2036 find: F,
2037 can_gc: CanGc,
2038 ) where
2039 F: Fn(&Attr) -> bool,
2040 {
2041 let attr = self
2043 .attrs
2044 .borrow()
2045 .iter()
2046 .find(|attr| find(attr))
2047 .map(|js| DomRoot::from_ref(&**js));
2048 if let Some(attr) = attr {
2049 self.will_mutate_attr(&attr);
2051 self.change_attribute(&attr, value, can_gc);
2052 } else {
2053 self.push_new_attribute(local_name, value, name, namespace, prefix, can_gc);
2058 };
2059 }
2060
2061 pub(crate) fn parse_attribute(
2062 &self,
2063 namespace: &Namespace,
2064 local_name: &LocalName,
2065 value: DOMString,
2066 ) -> AttrValue {
2067 if is_relevant_attribute(namespace, local_name) {
2068 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2069 } else {
2070 AttrValue::String(value.into())
2071 }
2072 }
2073
2074 pub(crate) fn remove_attribute(
2075 &self,
2076 namespace: &Namespace,
2077 local_name: &LocalName,
2078 can_gc: CanGc,
2079 ) -> Option<DomRoot<Attr>> {
2080 self.remove_first_matching_attribute(
2081 |attr| attr.namespace() == namespace && attr.local_name() == local_name,
2082 can_gc,
2083 )
2084 }
2085
2086 pub(crate) fn remove_attribute_by_name(
2087 &self,
2088 name: &LocalName,
2089 can_gc: CanGc,
2090 ) -> Option<DomRoot<Attr>> {
2091 self.remove_first_matching_attribute(|attr| attr.name() == name, can_gc)
2092 }
2093
2094 fn remove_first_matching_attribute<F>(&self, find: F, can_gc: CanGc) -> Option<DomRoot<Attr>>
2096 where
2097 F: Fn(&Attr) -> bool,
2098 {
2099 let idx = self.attrs.borrow().iter().position(|attr| find(attr));
2100 idx.map(|idx| {
2101 let attr = DomRoot::from_ref(&*(*self.attrs.borrow())[idx]);
2102
2103 self.will_mutate_attr(&attr);
2105 self.attrs.borrow_mut().remove(idx);
2106 attr.set_owner(None);
2108 self.handle_attribute_changes(&attr, Some(&attr.value()), None, can_gc);
2110
2111 attr
2112 })
2113 }
2114
2115 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2116 self.get_attribute(&ns!(), &local_name!("class"))
2117 .is_some_and(|attr| {
2118 attr.value()
2119 .as_tokens()
2120 .iter()
2121 .any(|atom| case_sensitivity.eq_atom(name, atom))
2122 })
2123 }
2124
2125 pub(crate) fn is_part(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2126 self.get_attribute(&ns!(), &LocalName::from("part"))
2127 .is_some_and(|attr| {
2128 attr.value()
2129 .as_tokens()
2130 .iter()
2131 .any(|atom| case_sensitivity.eq_atom(name, atom))
2132 })
2133 }
2134
2135 pub(crate) fn set_atomic_attribute(
2136 &self,
2137 local_name: &LocalName,
2138 value: DOMString,
2139 can_gc: CanGc,
2140 ) {
2141 assert!(*local_name == local_name.to_ascii_lowercase());
2142 let value = AttrValue::from_atomic(value.into());
2143 self.set_attribute(local_name, value, can_gc);
2144 }
2145
2146 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2147 assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b));
2148 self.attrs
2149 .borrow()
2150 .iter()
2151 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2152 }
2153
2154 pub(crate) fn set_bool_attribute(&self, local_name: &LocalName, value: bool, can_gc: CanGc) {
2155 if self.has_attribute(local_name) == value {
2156 return;
2157 }
2158 if value {
2159 self.set_string_attribute(local_name, DOMString::new(), can_gc);
2160 } else {
2161 self.remove_attribute(&ns!(), local_name, can_gc);
2162 }
2163 }
2164
2165 pub(crate) fn get_url_attribute(&self, local_name: &LocalName) -> USVString {
2166 assert!(*local_name == local_name.to_ascii_lowercase());
2167 let attr = match self.get_attribute(&ns!(), local_name) {
2168 Some(attr) => attr,
2169 None => return USVString::default(),
2170 };
2171 let value = &**attr.value();
2172 self.owner_document()
2174 .base_url()
2175 .join(value)
2176 .map(|parsed| USVString(parsed.into_string()))
2177 .unwrap_or_else(|_| USVString(value.to_owned()))
2178 }
2179
2180 pub(crate) fn set_url_attribute(
2181 &self,
2182 local_name: &LocalName,
2183 value: USVString,
2184 can_gc: CanGc,
2185 ) {
2186 assert!(*local_name == local_name.to_ascii_lowercase());
2187 self.set_attribute(local_name, AttrValue::String(value.to_string()), can_gc);
2188 }
2189
2190 pub(crate) fn get_trusted_type_url_attribute(
2191 &self,
2192 local_name: &LocalName,
2193 ) -> TrustedScriptURLOrUSVString {
2194 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2195 let attr = match self.get_attribute(&ns!(), local_name) {
2196 Some(attr) => attr,
2197 None => return TrustedScriptURLOrUSVString::USVString(USVString::default()),
2198 };
2199 let value = &**attr.value();
2200 self.owner_document()
2202 .base_url()
2203 .join(value)
2204 .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
2205 .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
2206 }
2207
2208 pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
2209 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2210 let value = match self.get_attribute(&ns!(), local_name) {
2211 Some(attr) => (&**attr.value()).into(),
2212 None => "".into(),
2213 };
2214 TrustedHTMLOrString::String(value)
2215 }
2216
2217 pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
2218 match self.get_attribute(&ns!(), local_name) {
2219 Some(x) => x.Value(),
2220 None => DOMString::new(),
2221 }
2222 }
2223
2224 pub(crate) fn set_string_attribute(
2225 &self,
2226 local_name: &LocalName,
2227 value: DOMString,
2228 can_gc: CanGc,
2229 ) {
2230 assert!(*local_name == local_name.to_ascii_lowercase());
2231 self.set_attribute(local_name, AttrValue::String(value.into()), can_gc);
2232 }
2233
2234 fn get_nullable_string_attribute(&self, local_name: &LocalName) -> Option<DOMString> {
2237 if self.has_attribute(local_name) {
2238 Some(self.get_string_attribute(local_name))
2239 } else {
2240 None
2241 }
2242 }
2243
2244 fn set_nullable_string_attribute(
2247 &self,
2248 local_name: &LocalName,
2249 value: Option<DOMString>,
2250 can_gc: CanGc,
2251 ) {
2252 match value {
2253 Some(val) => {
2254 self.set_string_attribute(local_name, val, can_gc);
2255 },
2256 None => {
2257 self.remove_attribute(&ns!(), local_name, can_gc);
2258 },
2259 }
2260 }
2261
2262 pub(crate) fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
2263 self.get_attribute(&ns!(), local_name)
2264 .map(|attr| attr.value().as_tokens().to_vec())
2265 .unwrap_or_default()
2266 }
2267
2268 pub(crate) fn set_tokenlist_attribute(
2269 &self,
2270 local_name: &LocalName,
2271 value: DOMString,
2272 can_gc: CanGc,
2273 ) {
2274 assert!(*local_name == local_name.to_ascii_lowercase());
2275 self.set_attribute(
2276 local_name,
2277 AttrValue::from_serialized_tokenlist(value.into()),
2278 can_gc,
2279 );
2280 }
2281
2282 pub(crate) fn set_atomic_tokenlist_attribute(
2283 &self,
2284 local_name: &LocalName,
2285 tokens: Vec<Atom>,
2286 can_gc: CanGc,
2287 ) {
2288 assert!(*local_name == local_name.to_ascii_lowercase());
2289 self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens), can_gc);
2290 }
2291
2292 pub(crate) fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
2293 assert!(
2295 local_name
2296 .chars()
2297 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2298 );
2299 let attribute = self.get_attribute(&ns!(), local_name);
2300
2301 match attribute {
2302 Some(ref attribute) => match *attribute.value() {
2303 AttrValue::Int(_, value) => value,
2304 _ => panic!(
2305 "Expected an AttrValue::Int: \
2306 implement parse_plain_attribute"
2307 ),
2308 },
2309 None => default,
2310 }
2311 }
2312
2313 pub(crate) fn set_int_attribute(&self, local_name: &LocalName, value: i32, can_gc: CanGc) {
2314 assert!(*local_name == local_name.to_ascii_lowercase());
2315 self.set_attribute(local_name, AttrValue::Int(value.to_string(), value), can_gc);
2316 }
2317
2318 pub(crate) fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
2319 assert!(
2320 local_name
2321 .chars()
2322 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2323 );
2324 let attribute = self.get_attribute(&ns!(), local_name);
2325 match attribute {
2326 Some(ref attribute) => match *attribute.value() {
2327 AttrValue::UInt(_, value) => value,
2328 _ => panic!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
2329 },
2330 None => default,
2331 }
2332 }
2333 pub(crate) fn set_uint_attribute(&self, local_name: &LocalName, value: u32, can_gc: CanGc) {
2334 assert!(*local_name == local_name.to_ascii_lowercase());
2335 self.set_attribute(
2336 local_name,
2337 AttrValue::UInt(value.to_string(), value),
2338 can_gc,
2339 );
2340 }
2341
2342 pub(crate) fn will_mutate_attr(&self, attr: &Attr) {
2343 let node = self.upcast::<Node>();
2344 node.owner_doc().element_attr_will_change(self, attr);
2345 }
2346
2347 fn update_style_attribute(&self, attr: &Attr, mutation: AttributeMutation) {
2349 let doc = self.upcast::<Node>().owner_doc();
2350 *self.style_attribute.borrow_mut() = match mutation {
2352 AttributeMutation::Set(..) => {
2353 let is_declaration = matches!(*attr.value(), AttrValue::Declaration(..));
2359
2360 let block = if is_declaration {
2361 let mut value = AttrValue::String(String::new());
2362 attr.swap_value(&mut value);
2363 let (serialization, block) = match value {
2364 AttrValue::Declaration(s, b) => (s, b),
2365 _ => unreachable!(),
2366 };
2367 let mut value = AttrValue::String(serialization);
2368 attr.swap_value(&mut value);
2369 block
2370 } else {
2371 let win = self.owner_window();
2372 let source = &**attr.value();
2373 let global = &self.owner_global();
2374 if global
2379 .get_csp_list()
2380 .should_elements_inline_type_behavior_be_blocked(
2381 global,
2382 self,
2383 InlineCheckType::StyleAttribute,
2384 source,
2385 )
2386 {
2387 return;
2388 }
2389 Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
2390 source,
2391 &UrlExtraData(doc.base_url().get_arc()),
2392 win.css_error_reporter(),
2393 doc.quirks_mode(),
2394 CssRuleType::Style,
2395 )))
2396 };
2397
2398 Some(block)
2399 },
2400 AttributeMutation::Removed => None,
2401 };
2402 }
2403
2404 fn set_attribute_node(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
2408 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2412 self.namespace(),
2413 self.local_name(),
2414 attr.local_name(),
2415 Some(attr.namespace()),
2416 TrustedTypeOrString::String(attr.Value()),
2417 &self.owner_global(),
2418 can_gc,
2419 )?;
2420
2421 if let Some(owner) = attr.GetOwnerElement() {
2424 if &*owner != self {
2425 return Err(Error::InUseAttribute);
2426 }
2427 }
2428
2429 let vtable = vtable_for(self.upcast());
2430
2431 attr.swap_value(
2437 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2438 );
2439
2440 let position = self.attrs.borrow().iter().position(|old_attr| {
2442 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2443 });
2444
2445 let old_attr = if let Some(position) = position {
2446 let old_attr = DomRoot::from_ref(&*self.attrs.borrow()[position]);
2447
2448 if &*old_attr == attr {
2450 return Ok(Some(DomRoot::from_ref(attr)));
2451 }
2452
2453 self.will_mutate_attr(attr);
2463 self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
2464 attr.set_owner(Some(self));
2466 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2468 old_attr.set_owner(None);
2470 self.handle_attribute_changes(
2472 attr,
2473 Some(&old_attr.value()),
2474 Some(verified_value),
2475 can_gc,
2476 );
2477
2478 Some(old_attr)
2479 } else {
2480 attr.set_owner(Some(self));
2482 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2483 self.push_attribute(attr, can_gc);
2484
2485 None
2486 };
2487
2488 Ok(old_attr)
2490 }
2491
2492 pub(crate) fn update_nonce_internal_slot(&self, nonce: String) {
2494 self.ensure_rare_data().cryptographic_nonce = nonce;
2495 }
2496
2497 pub(crate) fn nonce_value(&self) -> String {
2499 match self.rare_data().as_ref() {
2500 None => String::new(),
2501 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2502 }
2503 }
2504
2505 pub(crate) fn update_nonce_post_connection(&self) {
2507 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2510 return;
2511 }
2512 let global = self.owner_global();
2513 let csp_list = match global.get_csp_list() {
2515 None => return,
2516 Some(csp_list) => csp_list,
2517 };
2518 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2521 self.get_string_attribute(&local_name!("nonce")).is_empty()
2522 {
2523 return;
2524 }
2525 let nonce = self.nonce_value();
2527 self.set_string_attribute(&local_name!("nonce"), "".into(), CanGc::note());
2529 self.update_nonce_internal_slot(nonce);
2531 }
2532
2533 pub(crate) fn nonce_value_if_nonceable(&self) -> Option<String> {
2535 if !self.has_attribute(&local_name!("nonce")) {
2537 return None;
2538 }
2539 if self.downcast::<HTMLScriptElement>().is_some() {
2541 for attr in self.attrs().iter() {
2542 let attr_name = attr.name().to_ascii_lowercase();
2545 if attr_name.contains("<script") || attr_name.contains("<style") {
2546 return None;
2547 }
2548 let attr_value = attr.value().to_ascii_lowercase();
2551 if attr_value.contains("<script") || attr_value.contains("<style") {
2552 return None;
2553 }
2554 }
2555 }
2556 Some(self.nonce_value().trim().to_owned())
2561 }
2562
2563 pub(crate) fn insert_adjacent(
2565 &self,
2566 where_: AdjacentPosition,
2567 node: &Node,
2568 can_gc: CanGc,
2569 ) -> Fallible<Option<DomRoot<Node>>> {
2570 let self_node = self.upcast::<Node>();
2571 match where_ {
2572 AdjacentPosition::BeforeBegin => {
2573 if let Some(parent) = self_node.GetParentNode() {
2574 Node::pre_insert(node, &parent, Some(self_node), can_gc).map(Some)
2575 } else {
2576 Ok(None)
2577 }
2578 },
2579 AdjacentPosition::AfterBegin => Node::pre_insert(
2580 node,
2581 self_node,
2582 self_node.GetFirstChild().as_deref(),
2583 can_gc,
2584 )
2585 .map(Some),
2586 AdjacentPosition::BeforeEnd => {
2587 Node::pre_insert(node, self_node, None, can_gc).map(Some)
2588 },
2589 AdjacentPosition::AfterEnd => {
2590 if let Some(parent) = self_node.GetParentNode() {
2591 Node::pre_insert(node, &parent, self_node.GetNextSibling().as_deref(), can_gc)
2592 .map(Some)
2593 } else {
2594 Ok(None)
2595 }
2596 },
2597 }
2598 }
2599
2600 pub(crate) fn scroll(&self, x: f64, y: f64, behavior: ScrollBehavior) {
2605 let x = if x.is_finite() { x } else { 0.0 } as f32;
2607 let y = if y.is_finite() { y } else { 0.0 } as f32;
2608
2609 let node = self.upcast::<Node>();
2610
2611 let doc = node.owner_doc();
2613
2614 if !doc.is_fully_active() {
2616 return;
2617 }
2618
2619 let win = match doc.GetDefaultView() {
2621 None => return,
2622 Some(win) => win,
2623 };
2624
2625 if *self.root_element() == *self {
2627 if doc.quirks_mode() != QuirksMode::Quirks {
2628 win.scroll(x, y, behavior);
2629 }
2630
2631 return;
2632 }
2633
2634 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2636 doc.quirks_mode() == QuirksMode::Quirks &&
2637 !self.is_potentially_scrollable_body()
2638 {
2639 win.scroll(x, y, behavior);
2640 return;
2641 }
2642
2643 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
2645 return;
2646 }
2647
2648 win.scroll_an_element(self, x, y, behavior);
2650 }
2651
2652 pub(crate) fn parse_fragment(
2654 &self,
2655 markup: DOMString,
2656 can_gc: CanGc,
2657 ) -> Fallible<DomRoot<DocumentFragment>> {
2658 let new_children = ServoParser::parse_html_fragment(self, markup, false, can_gc);
2661 let context_document = {
2664 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2665 template.Content(can_gc).upcast::<Node>().owner_doc()
2666 } else {
2667 self.owner_document()
2668 }
2669 };
2670 let fragment = DocumentFragment::new(&context_document, can_gc);
2671 for child in new_children {
2673 fragment
2674 .upcast::<Node>()
2675 .AppendChild(&child, can_gc)
2676 .unwrap();
2677 }
2678 Ok(fragment)
2680 }
2681
2682 pub(crate) fn fragment_parsing_context(
2685 owner_doc: &Document,
2686 element: Option<&Self>,
2687 can_gc: CanGc,
2688 ) -> DomRoot<Self> {
2689 match element {
2691 Some(elem)
2692 if elem.local_name() != &local_name!("html") ||
2696 !elem.html_element_in_html_document() =>
2697 {
2698 DomRoot::from_ref(elem)
2699 },
2700 _ => Element::create(
2703 QualName::new(None, ns!(html), local_name!("body")),
2704 None,
2705 owner_doc,
2706 ElementCreator::ScriptCreated,
2707 CustomElementCreationMode::Asynchronous,
2708 None,
2709 can_gc,
2710 ),
2711 }
2712 }
2713
2714 pub(crate) fn fullscreen_element_ready_check(&self) -> bool {
2716 if !self.is_connected() {
2717 return false;
2718 }
2719 self.owner_document().get_allow_fullscreen()
2720 }
2721
2722 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2724 where
2725 T: DerivedFrom<Element> + DomObject,
2726 {
2727 let other = other.upcast::<Element>();
2728 self.root_element() == other.root_element()
2729 }
2730
2731 pub(crate) fn get_id(&self) -> Option<Atom> {
2732 self.id_attribute.borrow().clone()
2733 }
2734
2735 pub(crate) fn get_name(&self) -> Option<Atom> {
2736 self.rare_data().as_ref()?.name_attribute.clone()
2737 }
2738
2739 fn is_sequentially_focusable(&self) -> bool {
2740 let element = self.upcast::<Element>();
2741 let node = self.upcast::<Node>();
2742 if !node.is_connected() {
2743 return false;
2744 }
2745
2746 if element.has_attribute(&local_name!("hidden")) {
2747 return false;
2748 }
2749
2750 if self.disabled_state() {
2751 return false;
2752 }
2753
2754 if element.has_attribute(&local_name!("tabindex")) {
2755 return true;
2756 }
2757
2758 match node.type_id() {
2759 NodeTypeId::Element(ElementTypeId::HTMLElement(
2761 HTMLElementTypeId::HTMLButtonElement,
2762 )) |
2763 NodeTypeId::Element(ElementTypeId::HTMLElement(
2764 HTMLElementTypeId::HTMLSelectElement,
2765 )) |
2766 NodeTypeId::Element(ElementTypeId::HTMLElement(
2767 HTMLElementTypeId::HTMLIFrameElement,
2768 )) |
2769 NodeTypeId::Element(ElementTypeId::HTMLElement(
2770 HTMLElementTypeId::HTMLTextAreaElement,
2771 )) => true,
2772
2773 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) |
2775 NodeTypeId::Element(ElementTypeId::HTMLElement(
2776 HTMLElementTypeId::HTMLAnchorElement,
2777 )) => element.has_attribute(&local_name!("href")),
2778
2779 _ => {
2782 element.get_string_attribute(&local_name!("draggable")) == "true"
2784 },
2785 }
2786 }
2787
2788 pub(crate) fn update_sequentially_focusable_status(&self, can_gc: CanGc) {
2789 let node = self.upcast::<Node>();
2790 let is_sequentially_focusable = self.is_sequentially_focusable();
2791 node.set_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE, is_sequentially_focusable);
2792
2793 if !is_sequentially_focusable {
2795 self.owner_document().perform_focus_fixup_rule(self, can_gc);
2796 }
2797 }
2798
2799 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2800 self.rare_data()
2801 .as_ref()?
2802 .element_internals
2803 .as_ref()
2804 .map(|sr| DomRoot::from_ref(&**sr))
2805 }
2806
2807 pub(crate) fn ensure_element_internals(&self, can_gc: CanGc) -> DomRoot<ElementInternals> {
2808 let mut rare_data = self.ensure_rare_data();
2809 DomRoot::from_ref(rare_data.element_internals.get_or_insert_with(|| {
2810 let elem = self
2811 .downcast::<HTMLElement>()
2812 .expect("ensure_element_internals should only be called for an HTMLElement");
2813 Dom::from_ref(&*ElementInternals::new(elem, can_gc))
2814 }))
2815 }
2816
2817 pub(crate) fn outer_html(&self, can_gc: CanGc) -> Fallible<DOMString> {
2818 match self.GetOuterHTML(can_gc)? {
2819 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2820 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2821 }
2822 }
2823
2824 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2825 SourcePosition {
2826 source_file: self.owner_global().get_url().to_string(),
2827 line_number: line_number + 2,
2828 column_number: 0,
2829 }
2830 }
2831}
2832
2833#[allow(non_snake_case)]
2834impl ElementMethods<crate::DomTypeHolder> for Element {
2835 fn GetNamespaceURI(&self) -> Option<DOMString> {
2837 Node::namespace_to_string(self.namespace.clone())
2838 }
2839
2840 fn LocalName(&self) -> DOMString {
2842 DOMString::from(&*self.local_name)
2844 }
2845
2846 fn GetPrefix(&self) -> Option<DOMString> {
2848 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2849 }
2850
2851 fn TagName(&self) -> DOMString {
2853 let name = self.tag_name.or_init(|| {
2854 let qualified_name = match *self.prefix.borrow() {
2855 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2856 None => Cow::Borrowed(&*self.local_name),
2857 };
2858 if self.html_element_in_html_document() {
2859 LocalName::from(qualified_name.to_ascii_uppercase())
2860 } else {
2861 LocalName::from(qualified_name)
2862 }
2863 });
2864 DOMString::from(&*name)
2865 }
2866
2867 fn Id(&self) -> DOMString {
2871 self.get_string_attribute(&local_name!("id"))
2872 }
2873
2874 fn SetId(&self, id: DOMString, can_gc: CanGc) {
2876 self.set_atomic_attribute(&local_name!("id"), id, can_gc);
2877 }
2878
2879 fn ClassName(&self) -> DOMString {
2881 self.get_string_attribute(&local_name!("class"))
2882 }
2883
2884 fn SetClassName(&self, class: DOMString, can_gc: CanGc) {
2886 self.set_tokenlist_attribute(&local_name!("class"), class, can_gc);
2887 }
2888
2889 fn ClassList(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
2891 self.class_list
2892 .or_init(|| DOMTokenList::new(self, &local_name!("class"), None, can_gc))
2893 }
2894
2895 make_getter!(Slot, "slot");
2897
2898 make_setter!(SetSlot, "slot");
2900
2901 fn Attributes(&self, can_gc: CanGc) -> DomRoot<NamedNodeMap> {
2903 self.attr_list
2904 .or_init(|| NamedNodeMap::new(&self.owner_window(), self, can_gc))
2905 }
2906
2907 fn HasAttributes(&self) -> bool {
2909 !self.attrs.borrow().is_empty()
2910 }
2911
2912 fn GetAttributeNames(&self) -> Vec<DOMString> {
2914 self.attrs.borrow().iter().map(|attr| attr.Name()).collect()
2915 }
2916
2917 fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
2919 self.GetAttributeNode(name).map(|s| s.Value())
2920 }
2921
2922 fn GetAttributeNS(
2924 &self,
2925 namespace: Option<DOMString>,
2926 local_name: DOMString,
2927 ) -> Option<DOMString> {
2928 self.GetAttributeNodeNS(namespace, local_name)
2929 .map(|attr| attr.Value())
2930 }
2931
2932 fn GetAttributeNode(&self, name: DOMString) -> Option<DomRoot<Attr>> {
2934 self.get_attribute_by_name(name)
2935 }
2936
2937 fn GetAttributeNodeNS(
2939 &self,
2940 namespace: Option<DOMString>,
2941 local_name: DOMString,
2942 ) -> Option<DomRoot<Attr>> {
2943 let namespace = &namespace_from_domstring(namespace);
2944 self.get_attribute(namespace, &LocalName::from(local_name))
2945 }
2946
2947 fn ToggleAttribute(
2949 &self,
2950 name: DOMString,
2951 force: Option<bool>,
2952 can_gc: CanGc,
2953 ) -> Fallible<bool> {
2954 if !is_valid_attribute_local_name(&name.str()) {
2957 return Err(Error::InvalidCharacter);
2958 }
2959
2960 let attribute = self.GetAttribute(name.clone());
2962
2963 let name = self.parsed_name(name);
2965 match attribute {
2966 None => match force {
2968 None | Some(true) => {
2970 self.set_first_matching_attribute(
2971 name.clone(),
2972 AttrValue::String(String::new()),
2973 name.clone(),
2974 ns!(),
2975 None,
2976 |attr| *attr.name() == name,
2977 can_gc,
2978 );
2979 Ok(true)
2980 },
2981 Some(false) => Ok(false),
2983 },
2984 Some(_index) => match force {
2985 None | Some(false) => {
2987 self.remove_attribute_by_name(&name, can_gc);
2988 Ok(false)
2989 },
2990 Some(true) => Ok(true),
2992 },
2993 }
2994 }
2995
2996 fn SetAttribute(
2998 &self,
2999 name: DOMString,
3000 value: TrustedTypeOrString,
3001 can_gc: CanGc,
3002 ) -> ErrorResult {
3003 if !is_valid_attribute_local_name(&name.str()) {
3006 return Err(Error::InvalidCharacter);
3007 }
3008
3009 let name = self.parsed_name(name);
3012
3013 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3017 self.namespace(),
3018 self.local_name(),
3019 &name,
3020 None,
3021 value,
3022 &self.owner_global(),
3023 can_gc,
3024 )?;
3025
3026 let value = self.parse_attribute(&ns!(), &name, value);
3031 self.set_first_matching_attribute(
3032 name.clone(),
3033 value,
3034 name.clone(),
3035 ns!(),
3036 None,
3037 |attr| *attr.name() == name,
3038 can_gc,
3039 );
3040 Ok(())
3041 }
3042
3043 fn SetAttributeNS(
3045 &self,
3046 namespace: Option<DOMString>,
3047 qualified_name: DOMString,
3048 value: TrustedTypeOrString,
3049 can_gc: CanGc,
3050 ) -> ErrorResult {
3051 let (namespace, prefix, local_name) =
3053 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3054 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3057 self.namespace(),
3058 self.local_name(),
3059 &local_name,
3060 Some(&namespace),
3061 value,
3062 &self.owner_global(),
3063 can_gc,
3064 )?;
3065 let value = self.parse_attribute(&namespace, &local_name, value);
3067 self.set_first_matching_attribute(
3068 local_name.clone(),
3069 value,
3070 LocalName::from(qualified_name),
3071 namespace.clone(),
3072 prefix,
3073 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
3074 can_gc,
3075 );
3076 Ok(())
3077 }
3078
3079 fn SetAttributeNode(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
3081 self.set_attribute_node(attr, can_gc)
3082 }
3083
3084 fn SetAttributeNodeNS(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
3086 self.set_attribute_node(attr, can_gc)
3087 }
3088
3089 fn RemoveAttribute(&self, name: DOMString, can_gc: CanGc) {
3091 let name = self.parsed_name(name);
3092 self.remove_attribute_by_name(&name, can_gc);
3093 }
3094
3095 fn RemoveAttributeNS(
3097 &self,
3098 namespace: Option<DOMString>,
3099 local_name: DOMString,
3100 can_gc: CanGc,
3101 ) {
3102 let namespace = namespace_from_domstring(namespace);
3103 let local_name = LocalName::from(local_name);
3104 self.remove_attribute(&namespace, &local_name, can_gc);
3105 }
3106
3107 fn RemoveAttributeNode(&self, attr: &Attr, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
3109 self.remove_first_matching_attribute(|a| a == attr, can_gc)
3110 .ok_or(Error::NotFound(None))
3111 }
3112
3113 fn HasAttribute(&self, name: DOMString) -> bool {
3115 self.GetAttribute(name).is_some()
3116 }
3117
3118 fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
3120 self.GetAttributeNS(namespace, local_name).is_some()
3121 }
3122
3123 fn GetElementsByTagName(&self, localname: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3125 let window = self.owner_window();
3126 HTMLCollection::by_qualified_name(
3127 &window,
3128 self.upcast(),
3129 LocalName::from(localname),
3130 can_gc,
3131 )
3132 }
3133
3134 fn GetElementsByTagNameNS(
3136 &self,
3137 maybe_ns: Option<DOMString>,
3138 localname: DOMString,
3139 can_gc: CanGc,
3140 ) -> DomRoot<HTMLCollection> {
3141 let window = self.owner_window();
3142 HTMLCollection::by_tag_name_ns(&window, self.upcast(), localname, maybe_ns, can_gc)
3143 }
3144
3145 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3147 let window = self.owner_window();
3148 HTMLCollection::by_class_name(&window, self.upcast(), classes, can_gc)
3149 }
3150
3151 fn GetClientRects(&self, can_gc: CanGc) -> DomRoot<DOMRectList> {
3153 let win = self.owner_window();
3154 let raw_rects = self.upcast::<Node>().border_boxes();
3155 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3156 .iter()
3157 .map(|rect| {
3158 DOMRect::new(
3159 win.upcast(),
3160 rect.origin.x.to_f64_px(),
3161 rect.origin.y.to_f64_px(),
3162 rect.size.width.to_f64_px(),
3163 rect.size.height.to_f64_px(),
3164 can_gc,
3165 )
3166 })
3167 .collect();
3168 DOMRectList::new(&win, rects, can_gc)
3169 }
3170
3171 fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot<DOMRect> {
3173 let win = self.owner_window();
3174 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3175 DOMRect::new(
3176 win.upcast(),
3177 rect.origin.x.to_f64_px(),
3178 rect.origin.y.to_f64_px(),
3179 rect.size.width.to_f64_px(),
3180 rect.size.height.to_f64_px(),
3181 can_gc,
3182 )
3183 }
3184
3185 fn Scroll(&self, options: &ScrollToOptions) {
3187 let left = options.left.unwrap_or(self.ScrollLeft());
3189 let top = options.top.unwrap_or(self.ScrollTop());
3190 self.scroll(left, top, options.parent.behavior);
3191 }
3192
3193 fn Scroll_(&self, x: f64, y: f64) {
3195 self.scroll(x, y, ScrollBehavior::Auto);
3196 }
3197
3198 fn ScrollTo(&self, options: &ScrollToOptions) {
3200 self.Scroll(options);
3201 }
3202
3203 fn ScrollTo_(&self, x: f64, y: f64) {
3205 self.Scroll_(x, y);
3206 }
3207
3208 fn ScrollBy(&self, options: &ScrollToOptions) {
3210 let delta_left = options.left.unwrap_or(0.0f64);
3212 let delta_top = options.top.unwrap_or(0.0f64);
3213 let left = self.ScrollLeft();
3214 let top = self.ScrollTop();
3215 self.scroll(left + delta_left, top + delta_top, options.parent.behavior);
3216 }
3217
3218 fn ScrollBy_(&self, x: f64, y: f64) {
3220 let left = self.ScrollLeft();
3221 let top = self.ScrollTop();
3222 self.scroll(left + x, top + y, ScrollBehavior::Auto);
3223 }
3224
3225 fn ScrollTop(&self) -> f64 {
3227 let node = self.upcast::<Node>();
3228
3229 let doc = node.owner_doc();
3231
3232 if !doc.is_fully_active() {
3234 return 0.0;
3235 }
3236
3237 let win = match doc.GetDefaultView() {
3239 None => return 0.0,
3240 Some(win) => win,
3241 };
3242
3243 if *self.root_element() == *self {
3245 if doc.quirks_mode() == QuirksMode::Quirks {
3246 return 0.0;
3247 }
3248
3249 return win.ScrollY() as f64;
3251 }
3252
3253 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3255 doc.quirks_mode() == QuirksMode::Quirks &&
3256 !self.is_potentially_scrollable_body()
3257 {
3258 return win.ScrollY() as f64;
3259 }
3260
3261 if !self.has_css_layout_box() {
3263 return 0.0;
3264 }
3265
3266 let point = win.scroll_offset_query(node);
3268 point.y.abs() as f64
3269 }
3270
3271 fn SetScrollTop(&self, y_: f64) {
3274 let behavior = ScrollBehavior::Auto;
3275
3276 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3278
3279 let node = self.upcast::<Node>();
3280
3281 let doc = node.owner_doc();
3283
3284 if !doc.is_fully_active() {
3286 return;
3287 }
3288
3289 let win = match doc.GetDefaultView() {
3291 None => return,
3292 Some(win) => win,
3293 };
3294
3295 if *self.root_element() == *self {
3297 if doc.quirks_mode() != QuirksMode::Quirks {
3298 win.scroll(win.ScrollX() as f32, y, behavior);
3299 }
3300
3301 return;
3302 }
3303
3304 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3306 doc.quirks_mode() == QuirksMode::Quirks &&
3307 !self.is_potentially_scrollable_body()
3308 {
3309 win.scroll(win.ScrollX() as f32, y, behavior);
3310 return;
3311 }
3312
3313 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3315 return;
3316 }
3317
3318 win.scroll_an_element(self, self.ScrollLeft() as f32, y, behavior);
3320 }
3321
3322 fn ScrollLeft(&self) -> f64 {
3324 let node = self.upcast::<Node>();
3325
3326 let doc = node.owner_doc();
3328
3329 if !doc.is_fully_active() {
3331 return 0.0;
3332 }
3333
3334 let win = match doc.GetDefaultView() {
3336 None => return 0.0,
3337 Some(win) => win,
3338 };
3339
3340 if *self.root_element() == *self {
3342 if doc.quirks_mode() != QuirksMode::Quirks {
3343 return win.ScrollX() as f64;
3345 }
3346
3347 return 0.0;
3348 }
3349
3350 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3352 doc.quirks_mode() == QuirksMode::Quirks &&
3353 !self.is_potentially_scrollable_body()
3354 {
3355 return win.ScrollX() as f64;
3356 }
3357
3358 if !self.has_css_layout_box() {
3360 return 0.0;
3361 }
3362
3363 let point = win.scroll_offset_query(node);
3365 point.x.abs() as f64
3366 }
3367
3368 fn SetScrollLeft(&self, x: f64) {
3370 let behavior = ScrollBehavior::Auto;
3371
3372 let x = if x.is_finite() { x } else { 0.0 } as f32;
3374
3375 let node = self.upcast::<Node>();
3376
3377 let doc = node.owner_doc();
3379
3380 if !doc.is_fully_active() {
3382 return;
3383 }
3384
3385 let win = match doc.GetDefaultView() {
3387 None => return,
3388 Some(win) => win,
3389 };
3390
3391 if *self.root_element() == *self {
3393 if doc.quirks_mode() == QuirksMode::Quirks {
3394 return;
3395 }
3396
3397 win.scroll(x, win.ScrollY() as f32, behavior);
3398 return;
3399 }
3400
3401 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3403 doc.quirks_mode() == QuirksMode::Quirks &&
3404 !self.is_potentially_scrollable_body()
3405 {
3406 win.scroll(x, win.ScrollY() as f32, behavior);
3407 return;
3408 }
3409
3410 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3412 return;
3413 }
3414
3415 win.scroll_an_element(self, x, self.ScrollTop() as f32, behavior);
3417 }
3418
3419 fn ScrollIntoView(&self, arg: BooleanOrScrollIntoViewOptions) {
3421 let (behavior, block, inline, container) = match arg {
3422 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3424 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3429 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3432 options.parent.behavior,
3433 options.block,
3434 options.inline,
3435 if options.container == ScrollIntoViewContainer::Nearest {
3438 Some(self)
3439 } else {
3440 None
3441 },
3442 ),
3443 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3445 ScrollBehavior::Auto,
3446 ScrollLogicalPosition::End,
3447 ScrollLogicalPosition::Nearest,
3448 None,
3449 ),
3450 };
3451
3452 if !self.has_css_layout_box() {
3455 return;
3456 }
3457
3458 self.scroll_into_view_with_options(behavior, block, inline, container, None);
3460
3461 }
3464
3465 fn ScrollWidth(&self) -> i32 {
3467 self.upcast::<Node>().scroll_area().size.width
3468 }
3469
3470 fn ScrollHeight(&self) -> i32 {
3472 self.upcast::<Node>().scroll_area().size.height
3473 }
3474
3475 fn ClientTop(&self) -> i32 {
3477 self.client_rect().origin.y
3478 }
3479
3480 fn ClientLeft(&self) -> i32 {
3482 self.client_rect().origin.x
3483 }
3484
3485 fn ClientWidth(&self) -> i32 {
3487 self.client_rect().size.width
3488 }
3489
3490 fn ClientHeight(&self) -> i32 {
3492 self.client_rect().size.height
3493 }
3494
3495 fn SetHTMLUnsafe(&self, html: TrustedHTMLOrString, can_gc: CanGc) -> ErrorResult {
3497 let html = TrustedHTML::get_trusted_script_compliant_string(
3501 &self.owner_global(),
3502 html,
3503 "Element setHTMLUnsafe",
3504 can_gc,
3505 )?;
3506 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3508 DomRoot::upcast(template.Content(can_gc))
3509 } else {
3510 DomRoot::from_ref(self.upcast())
3511 };
3512
3513 Node::unsafely_set_html(&target, self, html, can_gc);
3515 Ok(())
3516 }
3517
3518 fn GetHTML(&self, options: &GetHTMLOptions, can_gc: CanGc) -> DOMString {
3520 self.upcast::<Node>().html_serialize(
3523 TraversalScope::ChildrenOnly(None),
3524 options.serializableShadowRoots,
3525 options.shadowRoots.clone(),
3526 can_gc,
3527 )
3528 }
3529
3530 fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3532 let qname = QualName::new(
3533 self.prefix().clone(),
3534 self.namespace().clone(),
3535 self.local_name().clone(),
3536 );
3537
3538 let result = if self.owner_document().is_html_document() {
3541 self.upcast::<Node>()
3542 .html_serialize(ChildrenOnly(Some(qname)), false, vec![], can_gc)
3543 } else {
3544 self.upcast::<Node>()
3545 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3546 };
3547
3548 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3549 }
3550
3551 fn SetInnerHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3553 let value = TrustedHTML::get_trusted_script_compliant_string(
3557 &self.owner_global(),
3558 value.convert(),
3559 "Element innerHTML",
3560 can_gc,
3561 )?;
3562 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3564 DomRoot::upcast(template.Content(can_gc))
3567 } else {
3568 DomRoot::from_ref(self.upcast())
3570 };
3571
3572 if !self.node.has_weird_parser_insertion_mode() &&
3575 value.len() < 100 &&
3576 !value
3577 .as_bytes()
3578 .iter()
3579 .any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
3580 {
3581 return Node::SetTextContent(&target, Some(value), can_gc);
3582 }
3583
3584 let frag = self.parse_fragment(value, can_gc)?;
3587
3588 Node::replace_all(Some(frag.upcast()), &target, can_gc);
3590 Ok(())
3591 }
3592
3593 fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3595 let result = if self.owner_document().is_html_document() {
3598 self.upcast::<Node>()
3599 .html_serialize(IncludeNode, false, vec![], can_gc)
3600 } else {
3601 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3602 };
3603
3604 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3605 }
3606
3607 fn SetOuterHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3609 let value = TrustedHTML::get_trusted_script_compliant_string(
3613 &self.owner_global(),
3614 value.convert(),
3615 "Element outerHTML",
3616 can_gc,
3617 )?;
3618 let context_document = self.owner_document();
3619 let context_node = self.upcast::<Node>();
3620 let context_parent = match context_node.GetParentNode() {
3622 None => {
3623 return Ok(());
3626 },
3627 Some(parent) => parent,
3628 };
3629
3630 let parent = match context_parent.type_id() {
3631 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed),
3633
3634 NodeTypeId::DocumentFragment(_) => {
3637 let body_elem = Element::create(
3638 QualName::new(None, ns!(html), local_name!("body")),
3639 None,
3640 &context_document,
3641 ElementCreator::ScriptCreated,
3642 CustomElementCreationMode::Synchronous,
3643 None,
3644 can_gc,
3645 );
3646 DomRoot::upcast(body_elem)
3647 },
3648 _ => context_node.GetParentElement().unwrap(),
3649 };
3650
3651 let frag = parent.parse_fragment(value, can_gc)?;
3654 context_parent.ReplaceChild(frag.upcast(), context_node, can_gc)?;
3656 Ok(())
3657 }
3658
3659 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3661 self.upcast::<Node>()
3662 .preceding_siblings()
3663 .filter_map(DomRoot::downcast)
3664 .next()
3665 }
3666
3667 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3669 self.upcast::<Node>()
3670 .following_siblings()
3671 .filter_map(DomRoot::downcast)
3672 .next()
3673 }
3674
3675 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3677 let window = self.owner_window();
3678 HTMLCollection::children(&window, self.upcast(), can_gc)
3679 }
3680
3681 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3683 self.upcast::<Node>().child_elements().next()
3684 }
3685
3686 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3688 self.upcast::<Node>()
3689 .rev_children()
3690 .filter_map(DomRoot::downcast::<Element>)
3691 .next()
3692 }
3693
3694 fn ChildElementCount(&self) -> u32 {
3696 self.upcast::<Node>().child_elements().count() as u32
3697 }
3698
3699 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3701 self.upcast::<Node>().prepend(nodes, can_gc)
3702 }
3703
3704 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3706 self.upcast::<Node>().append(nodes, can_gc)
3707 }
3708
3709 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3711 self.upcast::<Node>().replace_children(nodes, can_gc)
3712 }
3713
3714 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3716 let root = self.upcast::<Node>();
3717 root.query_selector(selectors)
3718 }
3719
3720 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
3722 let root = self.upcast::<Node>();
3723 root.query_selector_all(selectors)
3724 }
3725
3726 fn Before(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3728 self.upcast::<Node>().before(nodes, can_gc)
3729 }
3730
3731 fn After(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3733 self.upcast::<Node>().after(nodes, can_gc)
3734 }
3735
3736 fn ReplaceWith(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3738 self.upcast::<Node>().replace_with(nodes, can_gc)
3739 }
3740
3741 fn Remove(&self, can_gc: CanGc) {
3743 self.upcast::<Node>().remove_self(can_gc);
3744 }
3745
3746 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3748 let doc = self.owner_document();
3749 let url = doc.url();
3750 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3751 &selectors.str(),
3752 &UrlExtraData(url.get_arc()),
3753 ) {
3754 Err(_) => return Err(Error::Syntax(None)),
3755 Ok(selectors) => selectors,
3756 };
3757
3758 let quirks_mode = doc.quirks_mode();
3759 let element = DomRoot::from_ref(self);
3760
3761 Ok(dom_apis::element_matches(
3762 &SelectorWrapper::Borrowed(&element),
3763 &selectors,
3764 quirks_mode,
3765 ))
3766 }
3767
3768 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3770 self.Matches(selectors)
3771 }
3772
3773 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3775 let doc = self.owner_document();
3776 let url = doc.url();
3777 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3778 &selectors.str(),
3779 &UrlExtraData(url.get_arc()),
3780 ) {
3781 Err(_) => return Err(Error::Syntax(None)),
3782 Ok(selectors) => selectors,
3783 };
3784
3785 let quirks_mode = doc.quirks_mode();
3786 Ok(dom_apis::element_closest(
3787 SelectorWrapper::Owned(DomRoot::from_ref(self)),
3788 &selectors,
3789 quirks_mode,
3790 )
3791 .map(SelectorWrapper::into_owned))
3792 }
3793
3794 fn InsertAdjacentElement(
3796 &self,
3797 where_: DOMString,
3798 element: &Element,
3799 can_gc: CanGc,
3800 ) -> Fallible<Option<DomRoot<Element>>> {
3801 let where_ = where_.parse::<AdjacentPosition>()?;
3802 let inserted_node = self.insert_adjacent(where_, element.upcast(), can_gc)?;
3803 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3804 }
3805
3806 fn InsertAdjacentText(&self, where_: DOMString, data: DOMString, can_gc: CanGc) -> ErrorResult {
3808 let text = Text::new(data, &self.owner_document(), can_gc);
3810
3811 let where_ = where_.parse::<AdjacentPosition>()?;
3813 self.insert_adjacent(where_, text.upcast(), can_gc)
3814 .map(|_| ())
3815 }
3816
3817 fn InsertAdjacentHTML(
3819 &self,
3820 position: DOMString,
3821 text: TrustedHTMLOrString,
3822 can_gc: CanGc,
3823 ) -> ErrorResult {
3824 let text = TrustedHTML::get_trusted_script_compliant_string(
3828 &self.owner_global(),
3829 text,
3830 "Element insertAdjacentHTML",
3831 can_gc,
3832 )?;
3833 let position = position.parse::<AdjacentPosition>()?;
3834
3835 let context = match position {
3838 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
3841 match self.upcast::<Node>().GetParentNode() {
3842 Some(ref node) if node.is::<Document>() => {
3844 return Err(Error::NoModificationAllowed);
3845 },
3846 None => return Err(Error::NoModificationAllowed),
3847 Some(node) => node,
3849 }
3850 },
3851 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
3854 DomRoot::from_ref(self.upcast::<Node>())
3856 },
3857 };
3858
3859 let context = Element::fragment_parsing_context(
3861 &context.owner_doc(),
3862 context.downcast::<Element>(),
3863 can_gc,
3864 );
3865
3866 let fragment = context.parse_fragment(text, can_gc)?;
3869
3870 self.insert_adjacent(position, fragment.upcast(), can_gc)
3872 .map(|_| ())
3873 }
3874
3875 fn EnterFormalActivationState(&self) -> ErrorResult {
3877 match self.as_maybe_activatable() {
3878 Some(a) => {
3879 a.enter_formal_activation_state();
3880 Ok(())
3881 },
3882 None => Err(Error::NotSupported),
3883 }
3884 }
3885
3886 fn ExitFormalActivationState(&self) -> ErrorResult {
3887 match self.as_maybe_activatable() {
3888 Some(a) => {
3889 a.exit_formal_activation_state();
3890 Ok(())
3891 },
3892 None => Err(Error::NotSupported),
3893 }
3894 }
3895
3896 fn RequestFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
3898 let doc = self.owner_document();
3899 doc.enter_fullscreen(self, can_gc)
3900 }
3901
3902 fn AttachShadow(&self, init: &ShadowRootInit, can_gc: CanGc) -> Fallible<DomRoot<ShadowRoot>> {
3904 let shadow_root = self.attach_shadow(
3907 IsUserAgentWidget::No,
3908 init.mode,
3909 init.clonable,
3910 init.serializable,
3911 init.delegatesFocus,
3912 init.slotAssignment,
3913 can_gc,
3914 )?;
3915
3916 Ok(shadow_root)
3918 }
3919
3920 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
3922 let shadow_or_none = self.shadow_root();
3924
3925 let shadow = shadow_or_none?;
3927 if shadow.Mode() == ShadowRootMode::Closed {
3928 return None;
3929 }
3930
3931 Some(shadow)
3933 }
3934
3935 fn GetRole(&self) -> Option<DOMString> {
3936 self.get_nullable_string_attribute(&local_name!("role"))
3937 }
3938
3939 fn SetRole(&self, value: Option<DOMString>, can_gc: CanGc) {
3940 self.set_nullable_string_attribute(&local_name!("role"), value, can_gc);
3941 }
3942
3943 fn GetAriaAtomic(&self) -> Option<DOMString> {
3944 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
3945 }
3946
3947 fn SetAriaAtomic(&self, value: Option<DOMString>, can_gc: CanGc) {
3948 self.set_nullable_string_attribute(&local_name!("aria-atomic"), value, can_gc);
3949 }
3950
3951 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
3952 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
3953 }
3954
3955 fn SetAriaAutoComplete(&self, value: Option<DOMString>, can_gc: CanGc) {
3956 self.set_nullable_string_attribute(&local_name!("aria-autocomplete"), value, can_gc);
3957 }
3958
3959 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
3960 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
3961 }
3962
3963 fn SetAriaBrailleLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
3964 self.set_nullable_string_attribute(&local_name!("aria-braillelabel"), value, can_gc);
3965 }
3966
3967 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
3968 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
3969 }
3970
3971 fn SetAriaBrailleRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
3972 self.set_nullable_string_attribute(
3973 &local_name!("aria-brailleroledescription"),
3974 value,
3975 can_gc,
3976 );
3977 }
3978
3979 fn GetAriaBusy(&self) -> Option<DOMString> {
3980 self.get_nullable_string_attribute(&local_name!("aria-busy"))
3981 }
3982
3983 fn SetAriaBusy(&self, value: Option<DOMString>, can_gc: CanGc) {
3984 self.set_nullable_string_attribute(&local_name!("aria-busy"), value, can_gc);
3985 }
3986
3987 fn GetAriaChecked(&self) -> Option<DOMString> {
3988 self.get_nullable_string_attribute(&local_name!("aria-checked"))
3989 }
3990
3991 fn SetAriaChecked(&self, value: Option<DOMString>, can_gc: CanGc) {
3992 self.set_nullable_string_attribute(&local_name!("aria-checked"), value, can_gc);
3993 }
3994
3995 fn GetAriaColCount(&self) -> Option<DOMString> {
3996 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
3997 }
3998
3999 fn SetAriaColCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4000 self.set_nullable_string_attribute(&local_name!("aria-colcount"), value, can_gc);
4001 }
4002
4003 fn GetAriaColIndex(&self) -> Option<DOMString> {
4004 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4005 }
4006
4007 fn SetAriaColIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4008 self.set_nullable_string_attribute(&local_name!("aria-colindex"), value, can_gc);
4009 }
4010
4011 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4012 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4013 }
4014
4015 fn SetAriaColIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4016 self.set_nullable_string_attribute(&local_name!("aria-colindextext"), value, can_gc);
4017 }
4018
4019 fn GetAriaColSpan(&self) -> Option<DOMString> {
4020 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4021 }
4022
4023 fn SetAriaColSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4024 self.set_nullable_string_attribute(&local_name!("aria-colspan"), value, can_gc);
4025 }
4026
4027 fn GetAriaCurrent(&self) -> Option<DOMString> {
4028 self.get_nullable_string_attribute(&local_name!("aria-current"))
4029 }
4030
4031 fn SetAriaCurrent(&self, value: Option<DOMString>, can_gc: CanGc) {
4032 self.set_nullable_string_attribute(&local_name!("aria-current"), value, can_gc);
4033 }
4034
4035 fn GetAriaDescription(&self) -> Option<DOMString> {
4036 self.get_nullable_string_attribute(&local_name!("aria-description"))
4037 }
4038
4039 fn SetAriaDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4040 self.set_nullable_string_attribute(&local_name!("aria-description"), value, can_gc);
4041 }
4042
4043 fn GetAriaDisabled(&self) -> Option<DOMString> {
4044 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4045 }
4046
4047 fn SetAriaDisabled(&self, value: Option<DOMString>, can_gc: CanGc) {
4048 self.set_nullable_string_attribute(&local_name!("aria-disabled"), value, can_gc);
4049 }
4050
4051 fn GetAriaExpanded(&self) -> Option<DOMString> {
4052 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4053 }
4054
4055 fn SetAriaExpanded(&self, value: Option<DOMString>, can_gc: CanGc) {
4056 self.set_nullable_string_attribute(&local_name!("aria-expanded"), value, can_gc);
4057 }
4058
4059 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4060 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4061 }
4062
4063 fn SetAriaHasPopup(&self, value: Option<DOMString>, can_gc: CanGc) {
4064 self.set_nullable_string_attribute(&local_name!("aria-haspopup"), value, can_gc);
4065 }
4066
4067 fn GetAriaHidden(&self) -> Option<DOMString> {
4068 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4069 }
4070
4071 fn SetAriaHidden(&self, value: Option<DOMString>, can_gc: CanGc) {
4072 self.set_nullable_string_attribute(&local_name!("aria-hidden"), value, can_gc);
4073 }
4074
4075 fn GetAriaInvalid(&self) -> Option<DOMString> {
4076 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4077 }
4078
4079 fn SetAriaInvalid(&self, value: Option<DOMString>, can_gc: CanGc) {
4080 self.set_nullable_string_attribute(&local_name!("aria-invalid"), value, can_gc);
4081 }
4082
4083 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4084 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4085 }
4086
4087 fn SetAriaKeyShortcuts(&self, value: Option<DOMString>, can_gc: CanGc) {
4088 self.set_nullable_string_attribute(&local_name!("aria-keyshortcuts"), value, can_gc);
4089 }
4090
4091 fn GetAriaLabel(&self) -> Option<DOMString> {
4092 self.get_nullable_string_attribute(&local_name!("aria-label"))
4093 }
4094
4095 fn SetAriaLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
4096 self.set_nullable_string_attribute(&local_name!("aria-label"), value, can_gc);
4097 }
4098
4099 fn GetAriaLevel(&self) -> Option<DOMString> {
4100 self.get_nullable_string_attribute(&local_name!("aria-level"))
4101 }
4102
4103 fn SetAriaLevel(&self, value: Option<DOMString>, can_gc: CanGc) {
4104 self.set_nullable_string_attribute(&local_name!("aria-level"), value, can_gc);
4105 }
4106
4107 fn GetAriaLive(&self) -> Option<DOMString> {
4108 self.get_nullable_string_attribute(&local_name!("aria-live"))
4109 }
4110
4111 fn SetAriaLive(&self, value: Option<DOMString>, can_gc: CanGc) {
4112 self.set_nullable_string_attribute(&local_name!("aria-live"), value, can_gc);
4113 }
4114
4115 fn GetAriaModal(&self) -> Option<DOMString> {
4116 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4117 }
4118
4119 fn SetAriaModal(&self, value: Option<DOMString>, can_gc: CanGc) {
4120 self.set_nullable_string_attribute(&local_name!("aria-modal"), value, can_gc);
4121 }
4122
4123 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4124 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4125 }
4126
4127 fn SetAriaMultiLine(&self, value: Option<DOMString>, can_gc: CanGc) {
4128 self.set_nullable_string_attribute(&local_name!("aria-multiline"), value, can_gc);
4129 }
4130
4131 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4132 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4133 }
4134
4135 fn SetAriaMultiSelectable(&self, value: Option<DOMString>, can_gc: CanGc) {
4136 self.set_nullable_string_attribute(&local_name!("aria-multiselectable"), value, can_gc);
4137 }
4138
4139 fn GetAriaOrientation(&self) -> Option<DOMString> {
4140 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4141 }
4142
4143 fn SetAriaOrientation(&self, value: Option<DOMString>, can_gc: CanGc) {
4144 self.set_nullable_string_attribute(&local_name!("aria-orientation"), value, can_gc);
4145 }
4146
4147 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4148 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4149 }
4150
4151 fn SetAriaPlaceholder(&self, value: Option<DOMString>, can_gc: CanGc) {
4152 self.set_nullable_string_attribute(&local_name!("aria-placeholder"), value, can_gc);
4153 }
4154
4155 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4156 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4157 }
4158
4159 fn SetAriaPosInSet(&self, value: Option<DOMString>, can_gc: CanGc) {
4160 self.set_nullable_string_attribute(&local_name!("aria-posinset"), value, can_gc);
4161 }
4162
4163 fn GetAriaPressed(&self) -> Option<DOMString> {
4164 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4165 }
4166
4167 fn SetAriaPressed(&self, value: Option<DOMString>, can_gc: CanGc) {
4168 self.set_nullable_string_attribute(&local_name!("aria-pressed"), value, can_gc);
4169 }
4170
4171 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4172 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4173 }
4174
4175 fn SetAriaReadOnly(&self, value: Option<DOMString>, can_gc: CanGc) {
4176 self.set_nullable_string_attribute(&local_name!("aria-readonly"), value, can_gc);
4177 }
4178
4179 fn GetAriaRelevant(&self) -> Option<DOMString> {
4180 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4181 }
4182
4183 fn SetAriaRelevant(&self, value: Option<DOMString>, can_gc: CanGc) {
4184 self.set_nullable_string_attribute(&local_name!("aria-relevant"), value, can_gc);
4185 }
4186
4187 fn GetAriaRequired(&self) -> Option<DOMString> {
4188 self.get_nullable_string_attribute(&local_name!("aria-required"))
4189 }
4190
4191 fn SetAriaRequired(&self, value: Option<DOMString>, can_gc: CanGc) {
4192 self.set_nullable_string_attribute(&local_name!("aria-required"), value, can_gc);
4193 }
4194
4195 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4196 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4197 }
4198
4199 fn SetAriaRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4200 self.set_nullable_string_attribute(&local_name!("aria-roledescription"), value, can_gc);
4201 }
4202
4203 fn GetAriaRowCount(&self) -> Option<DOMString> {
4204 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4205 }
4206
4207 fn SetAriaRowCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4208 self.set_nullable_string_attribute(&local_name!("aria-rowcount"), value, can_gc);
4209 }
4210
4211 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4212 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4213 }
4214
4215 fn SetAriaRowIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4216 self.set_nullable_string_attribute(&local_name!("aria-rowindex"), value, can_gc);
4217 }
4218
4219 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4220 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4221 }
4222
4223 fn SetAriaRowIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4224 self.set_nullable_string_attribute(&local_name!("aria-rowindextext"), value, can_gc);
4225 }
4226
4227 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4228 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4229 }
4230
4231 fn SetAriaRowSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4232 self.set_nullable_string_attribute(&local_name!("aria-rowspan"), value, can_gc);
4233 }
4234
4235 fn GetAriaSelected(&self) -> Option<DOMString> {
4236 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4237 }
4238
4239 fn SetAriaSelected(&self, value: Option<DOMString>, can_gc: CanGc) {
4240 self.set_nullable_string_attribute(&local_name!("aria-selected"), value, can_gc);
4241 }
4242
4243 fn GetAriaSetSize(&self) -> Option<DOMString> {
4244 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4245 }
4246
4247 fn SetAriaSetSize(&self, value: Option<DOMString>, can_gc: CanGc) {
4248 self.set_nullable_string_attribute(&local_name!("aria-setsize"), value, can_gc);
4249 }
4250
4251 fn GetAriaSort(&self) -> Option<DOMString> {
4252 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4253 }
4254
4255 fn SetAriaSort(&self, value: Option<DOMString>, can_gc: CanGc) {
4256 self.set_nullable_string_attribute(&local_name!("aria-sort"), value, can_gc);
4257 }
4258
4259 fn GetAriaValueMax(&self) -> Option<DOMString> {
4260 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4261 }
4262
4263 fn SetAriaValueMax(&self, value: Option<DOMString>, can_gc: CanGc) {
4264 self.set_nullable_string_attribute(&local_name!("aria-valuemax"), value, can_gc);
4265 }
4266
4267 fn GetAriaValueMin(&self) -> Option<DOMString> {
4268 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4269 }
4270
4271 fn SetAriaValueMin(&self, value: Option<DOMString>, can_gc: CanGc) {
4272 self.set_nullable_string_attribute(&local_name!("aria-valuemin"), value, can_gc);
4273 }
4274
4275 fn GetAriaValueNow(&self) -> Option<DOMString> {
4276 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4277 }
4278
4279 fn SetAriaValueNow(&self, value: Option<DOMString>, can_gc: CanGc) {
4280 self.set_nullable_string_attribute(&local_name!("aria-valuenow"), value, can_gc);
4281 }
4282
4283 fn GetAriaValueText(&self) -> Option<DOMString> {
4284 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4285 }
4286
4287 fn SetAriaValueText(&self, value: Option<DOMString>, can_gc: CanGc) {
4288 self.set_nullable_string_attribute(&local_name!("aria-valuetext"), value, can_gc);
4289 }
4290
4291 fn GetAssignedSlot(&self) -> Option<DomRoot<HTMLSlotElement>> {
4293 let cx = GlobalScope::get_cx();
4294
4295 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4298 slottable.find_a_slot(true)
4299 }
4300
4301 fn Part(&self) -> DomRoot<DOMTokenList> {
4303 self.ensure_rare_data()
4304 .part
4305 .or_init(|| DOMTokenList::new(self, &local_name!("part"), None, CanGc::note()))
4306 }
4307}
4308
4309impl VirtualMethods for Element {
4310 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4311 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4312 }
4313
4314 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
4315 if attr.local_name() == &local_name!("lang") {
4317 return true;
4318 }
4319
4320 self.super_type()
4321 .unwrap()
4322 .attribute_affects_presentational_hints(attr)
4323 }
4324
4325 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
4326 self.super_type()
4327 .unwrap()
4328 .attribute_mutated(attr, mutation, can_gc);
4329 let node = self.upcast::<Node>();
4330 let doc = node.owner_doc();
4331 match attr.local_name() {
4332 &local_name!("tabindex") | &local_name!("draggable") | &local_name!("hidden") => {
4333 self.update_sequentially_focusable_status(can_gc)
4334 },
4335 &local_name!("style") => self.update_style_attribute(attr, mutation),
4336 &local_name!("id") => {
4337 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4339 let value = value.as_atom();
4340 if value != &atom!("") {
4341 Some(value.clone())
4343 } else {
4344 None
4346 }
4347 });
4348
4349 let containing_shadow_root = self.containing_shadow_root();
4350 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4351 let value = attr.value().as_atom().clone();
4352 match mutation {
4353 AttributeMutation::Set(old_value) => {
4354 if let Some(old_value) = old_value {
4355 let old_value = old_value.as_atom().clone();
4356 if let Some(ref shadow_root) = containing_shadow_root {
4357 shadow_root.unregister_element_id(self, old_value, can_gc);
4358 } else {
4359 doc.unregister_element_id(self, old_value, can_gc);
4360 }
4361 }
4362 if value != atom!("") {
4363 if let Some(ref shadow_root) = containing_shadow_root {
4364 shadow_root.register_element_id(self, value, can_gc);
4365 } else {
4366 doc.register_element_id(self, value, can_gc);
4367 }
4368 }
4369 },
4370 AttributeMutation::Removed => {
4371 if value != atom!("") {
4372 if let Some(ref shadow_root) = containing_shadow_root {
4373 shadow_root.unregister_element_id(self, value, can_gc);
4374 } else {
4375 doc.unregister_element_id(self, value, can_gc);
4376 }
4377 }
4378 },
4379 }
4380 }
4381 },
4382 &local_name!("name") => {
4383 self.ensure_rare_data().name_attribute =
4385 mutation.new_value(attr).and_then(|value| {
4386 let value = value.as_atom();
4387 if value != &atom!("") {
4388 Some(value.clone())
4389 } else {
4390 None
4391 }
4392 });
4393 if node.is_connected() && node.containing_shadow_root().is_none() {
4396 let value = attr.value().as_atom().clone();
4397 match mutation {
4398 AttributeMutation::Set(old_value) => {
4399 if let Some(old_value) = old_value {
4400 let old_value = old_value.as_atom().clone();
4401 doc.unregister_element_name(self, old_value);
4402 }
4403 if value != atom!("") {
4404 doc.register_element_name(self, value);
4405 }
4406 },
4407 AttributeMutation::Removed => {
4408 if value != atom!("") {
4409 doc.unregister_element_name(self, value);
4410 }
4411 },
4412 }
4413 }
4414 },
4415 &local_name!("slot") => {
4416 let cx = GlobalScope::get_cx();
4418
4419 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4420
4421 if let Some(assigned_slot) = slottable.assigned_slot() {
4423 assigned_slot.assign_slottables();
4424 }
4425 slottable.assign_a_slot();
4426 },
4427 _ => {
4428 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4431 node.dirty(NodeDamage::Other);
4432 }
4433 },
4434 };
4435
4436 node.rev_version();
4440 }
4441
4442 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4443 match *name {
4444 local_name!("id") => AttrValue::from_atomic(value.into()),
4445 local_name!("name") => AttrValue::from_atomic(value.into()),
4446 local_name!("class") | local_name!("part") => {
4447 AttrValue::from_serialized_tokenlist(value.into())
4448 },
4449 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4450 _ => self
4451 .super_type()
4452 .unwrap()
4453 .parse_plain_attribute(name, value),
4454 }
4455 }
4456
4457 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
4458 if let Some(s) = self.super_type() {
4459 s.bind_to_tree(context, can_gc);
4460 }
4461
4462 if let Some(f) = self.as_maybe_form_control() {
4463 f.bind_form_control_to_tree(can_gc);
4464 }
4465
4466 let doc = self.owner_document();
4467
4468 if let Some(ref shadow_root) = self.shadow_root() {
4469 shadow_root.bind_to_tree(context, can_gc);
4470 }
4471
4472 if !context.is_in_tree() {
4473 return;
4474 }
4475
4476 self.update_sequentially_focusable_status(can_gc);
4477
4478 if let Some(ref id) = *self.id_attribute.borrow() {
4479 if let Some(shadow_root) = self.containing_shadow_root() {
4480 shadow_root.register_element_id(self, id.clone(), can_gc);
4481 } else {
4482 doc.register_element_id(self, id.clone(), can_gc);
4483 }
4484 }
4485 if let Some(ref name) = self.name_attribute() {
4486 if self.containing_shadow_root().is_none() {
4487 doc.register_element_name(self, name.clone());
4488 }
4489 }
4490
4491 doc.increment_dom_count();
4493 }
4494
4495 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
4496 self.super_type().unwrap().unbind_from_tree(context, can_gc);
4497
4498 if let Some(f) = self.as_maybe_form_control() {
4499 f.unbind_form_control_from_tree(can_gc);
4503 }
4504
4505 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4506 return;
4507 }
4508
4509 self.update_sequentially_focusable_status(can_gc);
4510
4511 let doc = self.owner_document();
4512
4513 let fullscreen = doc.GetFullscreenElement();
4514 if fullscreen.as_deref() == Some(self) {
4515 doc.exit_fullscreen(can_gc);
4516 }
4517 if let Some(ref value) = *self.id_attribute.borrow() {
4518 if let Some(ref shadow_root) = self.containing_shadow_root() {
4519 if !self.upcast::<Node>().is_in_a_shadow_tree() {
4522 shadow_root.unregister_element_id(self, value.clone(), can_gc);
4523 }
4524 } else {
4525 doc.unregister_element_id(self, value.clone(), can_gc);
4526 }
4527 }
4528 if let Some(ref value) = self.name_attribute() {
4529 if self.containing_shadow_root().is_none() {
4530 doc.unregister_element_name(self, value.clone());
4531 }
4532 }
4533 doc.decrement_dom_count();
4535 }
4536
4537 fn children_changed(&self, mutation: &ChildrenMutation) {
4538 if let Some(s) = self.super_type() {
4539 s.children_changed(mutation);
4540 }
4541
4542 let flags = self.selector_flags.get();
4543 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4544 self.upcast::<Node>().dirty(NodeDamage::Other);
4546 } else {
4547 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
4548 if let Some(next_child) = mutation.next_child() {
4549 for child in next_child.inclusively_following_siblings() {
4550 if child.is::<Element>() {
4551 child.dirty(NodeDamage::Other);
4552 }
4553 }
4554 }
4555 }
4556 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
4557 if let Some(child) = mutation.modified_edge_element() {
4558 child.dirty(NodeDamage::Other);
4559 }
4560 }
4561 }
4562 }
4563
4564 fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
4565 self.super_type().unwrap().adopting_steps(old_doc, can_gc);
4566
4567 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4568 self.tag_name.clear();
4569 }
4570 }
4571
4572 fn post_connection_steps(&self) {
4573 if let Some(s) = self.super_type() {
4574 s.post_connection_steps();
4575 }
4576
4577 self.update_nonce_post_connection();
4578 }
4579
4580 fn cloning_steps(
4582 &self,
4583 copy: &Node,
4584 maybe_doc: Option<&Document>,
4585 clone_children: CloneChildrenFlag,
4586 can_gc: CanGc,
4587 ) {
4588 if let Some(s) = self.super_type() {
4589 s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
4590 }
4591 let elem = copy.downcast::<Element>().unwrap();
4592 if let Some(rare_data) = self.rare_data().as_ref() {
4593 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone());
4594 }
4595 }
4596}
4597
4598#[derive(Clone, PartialEq)]
4599pub enum SelectorWrapper<'a> {
4604 Borrowed(&'a DomRoot<Element>),
4605 Owned(DomRoot<Element>),
4606}
4607
4608impl fmt::Debug for SelectorWrapper<'_> {
4609 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4610 self.deref().fmt(f)
4611 }
4612}
4613
4614impl Deref for SelectorWrapper<'_> {
4615 type Target = DomRoot<Element>;
4616
4617 fn deref(&self) -> &Self::Target {
4618 match self {
4619 SelectorWrapper::Owned(r) => r,
4620 SelectorWrapper::Borrowed(r) => r,
4621 }
4622 }
4623}
4624
4625impl SelectorWrapper<'_> {
4626 fn into_owned(self) -> DomRoot<Element> {
4627 match self {
4628 SelectorWrapper::Owned(r) => r,
4629 SelectorWrapper::Borrowed(r) => r.clone(),
4630 }
4631 }
4632}
4633
4634impl SelectorsElement for SelectorWrapper<'_> {
4635 type Impl = SelectorImpl;
4636
4637 #[allow(unsafe_code)]
4638 fn opaque(&self) -> ::selectors::OpaqueElement {
4639 ::selectors::OpaqueElement::new(unsafe { &*self.reflector().get_jsobject().get() })
4640 }
4641
4642 fn parent_element(&self) -> Option<Self> {
4643 self.upcast::<Node>()
4644 .GetParentElement()
4645 .map(SelectorWrapper::Owned)
4646 }
4647
4648 fn parent_node_is_shadow_root(&self) -> bool {
4649 match self.upcast::<Node>().GetParentNode() {
4650 None => false,
4651 Some(node) => node.is::<ShadowRoot>(),
4652 }
4653 }
4654
4655 fn containing_shadow_host(&self) -> Option<Self> {
4656 self.containing_shadow_root()
4657 .map(|shadow_root| shadow_root.Host())
4658 .map(SelectorWrapper::Owned)
4659 }
4660
4661 fn is_pseudo_element(&self) -> bool {
4662 false
4663 }
4664
4665 fn match_pseudo_element(
4666 &self,
4667 _pseudo: &PseudoElement,
4668 _context: &mut MatchingContext<Self::Impl>,
4669 ) -> bool {
4670 false
4671 }
4672
4673 fn prev_sibling_element(&self) -> Option<Self> {
4674 self.node
4675 .preceding_siblings()
4676 .filter_map(DomRoot::downcast)
4677 .next()
4678 .map(SelectorWrapper::Owned)
4679 }
4680
4681 fn next_sibling_element(&self) -> Option<Self> {
4682 self.node
4683 .following_siblings()
4684 .filter_map(DomRoot::downcast)
4685 .next()
4686 .map(SelectorWrapper::Owned)
4687 }
4688
4689 fn first_element_child(&self) -> Option<Self> {
4690 self.GetFirstElementChild().map(SelectorWrapper::Owned)
4691 }
4692
4693 fn attr_matches(
4694 &self,
4695 ns: &NamespaceConstraint<&style::Namespace>,
4696 local_name: &style::LocalName,
4697 operation: &AttrSelectorOperation<&AtomString>,
4698 ) -> bool {
4699 match *ns {
4700 NamespaceConstraint::Specific(ns) => self
4701 .get_attribute(ns, local_name)
4702 .is_some_and(|attr| attr.value().eval_selector(operation)),
4703 NamespaceConstraint::Any => self.attrs.borrow().iter().any(|attr| {
4704 *attr.local_name() == **local_name && attr.value().eval_selector(operation)
4705 }),
4706 }
4707 }
4708
4709 fn is_root(&self) -> bool {
4710 Element::is_root(self)
4711 }
4712
4713 fn is_empty(&self) -> bool {
4714 self.node.children().all(|node| {
4715 !node.is::<Element>() &&
4716 match node.downcast::<Text>() {
4717 None => true,
4718 Some(text) => text.upcast::<CharacterData>().data().is_empty(),
4719 }
4720 })
4721 }
4722
4723 fn has_local_name(&self, local_name: &LocalName) -> bool {
4724 Element::local_name(self) == local_name
4725 }
4726
4727 fn has_namespace(&self, ns: &Namespace) -> bool {
4728 Element::namespace(self) == ns
4729 }
4730
4731 fn is_same_type(&self, other: &Self) -> bool {
4732 Element::local_name(self) == Element::local_name(other) &&
4733 Element::namespace(self) == Element::namespace(other)
4734 }
4735
4736 fn match_non_ts_pseudo_class(
4737 &self,
4738 pseudo_class: &NonTSPseudoClass,
4739 _: &mut MatchingContext<Self::Impl>,
4740 ) -> bool {
4741 match *pseudo_class {
4742 NonTSPseudoClass::Link | NonTSPseudoClass::AnyLink => self.is_link(),
4744 NonTSPseudoClass::Visited => false,
4745
4746 NonTSPseudoClass::ServoNonZeroBorder => match self.downcast::<HTMLTableElement>() {
4747 None => false,
4748 Some(this) => match this.get_border() {
4749 None | Some(0) => false,
4750 Some(_) => true,
4751 },
4752 },
4753
4754 NonTSPseudoClass::CustomState(ref state) => self.has_custom_state(&state.0),
4755
4756 NonTSPseudoClass::Lang(ref lang) => {
4761 extended_filtering(&self.upcast::<Node>().get_lang().unwrap_or_default(), lang)
4762 },
4763
4764 NonTSPseudoClass::ReadOnly => {
4765 !Element::state(self).contains(NonTSPseudoClass::ReadWrite.state_flag())
4766 },
4767
4768 NonTSPseudoClass::Active |
4769 NonTSPseudoClass::Autofill |
4770 NonTSPseudoClass::Checked |
4771 NonTSPseudoClass::Default |
4772 NonTSPseudoClass::Defined |
4773 NonTSPseudoClass::Disabled |
4774 NonTSPseudoClass::Enabled |
4775 NonTSPseudoClass::Focus |
4776 NonTSPseudoClass::FocusVisible |
4777 NonTSPseudoClass::FocusWithin |
4778 NonTSPseudoClass::Fullscreen |
4779 NonTSPseudoClass::Hover |
4780 NonTSPseudoClass::InRange |
4781 NonTSPseudoClass::Indeterminate |
4782 NonTSPseudoClass::Invalid |
4783 NonTSPseudoClass::Modal |
4784 NonTSPseudoClass::MozMeterOptimum |
4785 NonTSPseudoClass::MozMeterSubOptimum |
4786 NonTSPseudoClass::MozMeterSubSubOptimum |
4787 NonTSPseudoClass::Optional |
4788 NonTSPseudoClass::OutOfRange |
4789 NonTSPseudoClass::PlaceholderShown |
4790 NonTSPseudoClass::PopoverOpen |
4791 NonTSPseudoClass::ReadWrite |
4792 NonTSPseudoClass::Required |
4793 NonTSPseudoClass::Target |
4794 NonTSPseudoClass::UserInvalid |
4795 NonTSPseudoClass::UserValid |
4796 NonTSPseudoClass::Valid => Element::state(self).contains(pseudo_class.state_flag()),
4797 }
4798 }
4799
4800 fn is_link(&self) -> bool {
4801 let node = self.upcast::<Node>();
4803 match node.type_id() {
4804 NodeTypeId::Element(ElementTypeId::HTMLElement(
4806 HTMLElementTypeId::HTMLAnchorElement,
4807 )) |
4808 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) |
4809 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
4810 self.has_attribute(&local_name!("href"))
4811 },
4812 _ => false,
4813 }
4814 }
4815
4816 fn has_id(&self, id: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4817 self.id_attribute
4818 .borrow()
4819 .as_ref()
4820 .is_some_and(|atom| case_sensitivity.eq_atom(id, atom))
4821 }
4822
4823 fn is_part(&self, name: &AtomIdent) -> bool {
4824 Element::is_part(self, name, CaseSensitivity::CaseSensitive)
4825 }
4826
4827 fn imported_part(&self, _: &AtomIdent) -> Option<AtomIdent> {
4828 None
4829 }
4830
4831 fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4832 Element::has_class(self, name, case_sensitivity)
4833 }
4834
4835 fn is_html_element_in_html_document(&self) -> bool {
4836 self.html_element_in_html_document()
4837 }
4838
4839 fn is_html_slot_element(&self) -> bool {
4840 self.is_html_element() && self.local_name() == &local_name!("slot")
4841 }
4842
4843 fn apply_selector_flags(&self, flags: ElementSelectorFlags) {
4844 let self_flags = flags.for_self();
4846 if !self_flags.is_empty() {
4847 #[allow(unsafe_code)]
4848 unsafe {
4849 Dom::from_ref(&***self)
4850 .to_layout()
4851 .insert_selector_flags(self_flags);
4852 }
4853 }
4854
4855 let parent_flags = flags.for_parent();
4857 if !parent_flags.is_empty() {
4858 if let Some(p) = self.parent_element() {
4859 #[allow(unsafe_code)]
4860 unsafe {
4861 Dom::from_ref(&**p)
4862 .to_layout()
4863 .insert_selector_flags(parent_flags);
4864 }
4865 }
4866 }
4867 }
4868
4869 fn add_element_unique_hashes(&self, filter: &mut BloomFilter) -> bool {
4870 let mut f = |hash| filter.insert_hash(hash & BLOOM_HASH_MASK);
4871
4872 f(Element::local_name(self).get_hash());
4875 f(Element::namespace(self).get_hash());
4876
4877 if let Some(ref id) = *self.id_attribute.borrow() {
4878 f(id.get_hash());
4879 }
4880
4881 if let Some(attr) = self.get_attribute(&ns!(), &local_name!("class")) {
4882 for class in attr.value().as_tokens() {
4883 f(AtomIdent::cast(class).get_hash());
4884 }
4885 }
4886
4887 for attr in self.attrs.borrow().iter() {
4888 let name = style::values::GenericAtomIdent::cast(attr.local_name());
4889 if !style::bloom::is_attr_name_excluded_from_filter(name) {
4890 f(name.get_hash());
4891 }
4892 }
4893
4894 true
4895 }
4896
4897 fn has_custom_state(&self, name: &AtomIdent) -> bool {
4898 let mut has_state = false;
4899 self.each_custom_state(|state| has_state |= state == name);
4900
4901 has_state
4902 }
4903}
4904
4905impl Element {
4906 fn each_custom_state<F>(&self, callback: F)
4907 where
4908 F: FnMut(&AtomIdent),
4909 {
4910 self.get_element_internals()
4911 .and_then(|internals| internals.custom_states())
4912 .inspect(|states| states.for_each_state(callback));
4913 }
4914
4915 pub(crate) fn client_rect(&self) -> Rect<i32> {
4916 let doc = self.node.owner_doc();
4917
4918 if let Some(rect) = self
4919 .rare_data()
4920 .as_ref()
4921 .and_then(|data| data.client_rect.as_ref())
4922 .and_then(|rect| rect.get().ok())
4923 {
4924 if doc.restyle_reason().is_empty() {
4925 return rect;
4926 }
4927 }
4928
4929 let mut rect = self.upcast::<Node>().client_rect();
4930 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
4931
4932 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
4933 (!in_quirks_mode && *self.root_element() == *self)
4934 {
4935 let viewport_dimensions = doc.window().viewport_details().size.round().to_i32();
4936 rect.size = Size2D::<i32>::new(viewport_dimensions.width, viewport_dimensions.height);
4937 }
4938
4939 self.ensure_rare_data().client_rect = Some(self.owner_window().cache_layout_value(rect));
4940 rect
4941 }
4942
4943 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
4944 let element = match self.upcast::<Node>().type_id() {
4945 NodeTypeId::Element(ElementTypeId::HTMLElement(
4946 HTMLElementTypeId::HTMLInputElement,
4947 )) => {
4948 let element = self.downcast::<HTMLInputElement>().unwrap();
4949 Some(element as &dyn Activatable)
4950 },
4951 NodeTypeId::Element(ElementTypeId::HTMLElement(
4952 HTMLElementTypeId::HTMLButtonElement,
4953 )) => {
4954 let element = self.downcast::<HTMLButtonElement>().unwrap();
4955 Some(element as &dyn Activatable)
4956 },
4957 NodeTypeId::Element(ElementTypeId::HTMLElement(
4958 HTMLElementTypeId::HTMLAnchorElement,
4959 )) => {
4960 let element = self.downcast::<HTMLAnchorElement>().unwrap();
4961 Some(element as &dyn Activatable)
4962 },
4963 NodeTypeId::Element(ElementTypeId::HTMLElement(
4964 HTMLElementTypeId::HTMLLabelElement,
4965 )) => {
4966 let element = self.downcast::<HTMLLabelElement>().unwrap();
4967 Some(element as &dyn Activatable)
4968 },
4969 NodeTypeId::Element(ElementTypeId::HTMLElement(
4970 HTMLElementTypeId::HTMLSelectElement,
4971 )) => {
4972 let element = self.downcast::<HTMLSelectElement>().unwrap();
4973 Some(element as &dyn Activatable)
4974 },
4975 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
4976 let element = self.downcast::<HTMLElement>().unwrap();
4977 Some(element as &dyn Activatable)
4978 },
4979 _ => None,
4980 };
4981 element.and_then(|elem| {
4982 if elem.is_instance_activatable() {
4983 Some(elem)
4984 } else {
4985 None
4986 }
4987 })
4988 }
4989
4990 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
4991 if let Some(s) = self.downcast::<HTMLStyleElement>() {
4992 return Some(s as &dyn StylesheetOwner);
4993 }
4994
4995 if let Some(l) = self.downcast::<HTMLLinkElement>() {
4996 return Some(l as &dyn StylesheetOwner);
4997 }
4998
4999 None
5000 }
5001
5002 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
5004 match self.upcast::<Node>().type_id() {
5005 NodeTypeId::Element(ElementTypeId::HTMLElement(
5006 HTMLElementTypeId::HTMLInputElement,
5007 )) => {
5008 let element = self.downcast::<HTMLInputElement>().unwrap();
5009 Some(element as &dyn Validatable)
5010 },
5011 NodeTypeId::Element(ElementTypeId::HTMLElement(
5012 HTMLElementTypeId::HTMLButtonElement,
5013 )) => {
5014 let element = self.downcast::<HTMLButtonElement>().unwrap();
5015 Some(element as &dyn Validatable)
5016 },
5017 NodeTypeId::Element(ElementTypeId::HTMLElement(
5018 HTMLElementTypeId::HTMLObjectElement,
5019 )) => {
5020 let element = self.downcast::<HTMLObjectElement>().unwrap();
5021 Some(element as &dyn Validatable)
5022 },
5023 NodeTypeId::Element(ElementTypeId::HTMLElement(
5024 HTMLElementTypeId::HTMLSelectElement,
5025 )) => {
5026 let element = self.downcast::<HTMLSelectElement>().unwrap();
5027 Some(element as &dyn Validatable)
5028 },
5029 NodeTypeId::Element(ElementTypeId::HTMLElement(
5030 HTMLElementTypeId::HTMLTextAreaElement,
5031 )) => {
5032 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
5033 Some(element as &dyn Validatable)
5034 },
5035 NodeTypeId::Element(ElementTypeId::HTMLElement(
5036 HTMLElementTypeId::HTMLFieldSetElement,
5037 )) => {
5038 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
5039 Some(element as &dyn Validatable)
5040 },
5041 NodeTypeId::Element(ElementTypeId::HTMLElement(
5042 HTMLElementTypeId::HTMLOutputElement,
5043 )) => {
5044 let element = self.downcast::<HTMLOutputElement>().unwrap();
5045 Some(element as &dyn Validatable)
5046 },
5047 _ => None,
5048 }
5049 }
5050
5051 pub(crate) fn is_invalid(&self, needs_update: bool, can_gc: CanGc) -> bool {
5052 if let Some(validatable) = self.as_maybe_validatable() {
5053 if needs_update {
5054 validatable
5055 .validity_state()
5056 .perform_validation_and_update(ValidationFlags::all(), can_gc);
5057 }
5058 return validatable.is_instance_validatable() && !validatable.satisfies_constraints();
5059 }
5060
5061 if let Some(internals) = self.get_element_internals() {
5062 return internals.is_invalid();
5063 }
5064 false
5065 }
5066
5067 pub(crate) fn is_instance_validatable(&self) -> bool {
5068 if let Some(validatable) = self.as_maybe_validatable() {
5069 return validatable.is_instance_validatable();
5070 }
5071 if let Some(internals) = self.get_element_internals() {
5072 return internals.is_instance_validatable();
5073 }
5074 false
5075 }
5076
5077 pub(crate) fn init_state_for_internals(&self) {
5078 self.set_enabled_state(true);
5079 self.set_state(ElementState::VALID, true);
5080 self.set_state(ElementState::INVALID, false);
5081 }
5082
5083 pub(crate) fn click_in_progress(&self) -> bool {
5084 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5085 }
5086
5087 pub(crate) fn set_click_in_progress(&self, click: bool) {
5088 self.upcast::<Node>()
5089 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5090 }
5091
5092 pub(crate) fn nearest_activable_element(&self) -> Option<DomRoot<Element>> {
5094 match self.as_maybe_activatable() {
5095 Some(el) => Some(DomRoot::from_ref(el.as_element())),
5096 None => {
5097 let node = self.upcast::<Node>();
5098 for node in node.ancestors() {
5099 if let Some(node) = node.downcast::<Element>() {
5100 if node.as_maybe_activatable().is_some() {
5101 return Some(DomRoot::from_ref(node));
5102 }
5103 }
5104 }
5105 None
5106 },
5107 }
5108 }
5109
5110 pub fn state(&self) -> ElementState {
5111 self.state.get()
5112 }
5113
5114 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5115 let mut state = self.state.get();
5116 let previous_state = state;
5117 if value {
5118 state.insert(which);
5119 } else {
5120 state.remove(which);
5121 }
5122
5123 if previous_state == state {
5124 return;
5126 }
5127
5128 {
5131 let document = self.owner_document();
5132 let mut entry = document.ensure_pending_restyle(self);
5133 if entry.snapshot.is_none() {
5134 entry.snapshot = Some(Snapshot::new());
5135 }
5136 let snapshot = entry.snapshot.as_mut().unwrap();
5137 if snapshot.state.is_none() {
5138 snapshot.state = Some(self.state());
5139 }
5140 }
5141
5142 self.upcast::<Node>().dirty(NodeDamage::ContentOrHeritage);
5144
5145 self.state.set(state);
5146 }
5147
5148 pub(crate) fn set_active_state(&self, value: bool) {
5150 self.set_state(ElementState::ACTIVE, value);
5151
5152 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5153 parent.set_active_state(value);
5154 }
5155 }
5156
5157 pub(crate) fn focus_state(&self) -> bool {
5158 self.state.get().contains(ElementState::FOCUS)
5159 }
5160
5161 pub(crate) fn set_focus_state(&self, value: bool) {
5162 self.set_state(ElementState::FOCUS, value);
5163 }
5164
5165 pub(crate) fn hover_state(&self) -> bool {
5166 self.state.get().contains(ElementState::HOVER)
5167 }
5168
5169 pub(crate) fn set_hover_state(&self, value: bool) {
5170 self.set_state(ElementState::HOVER, value);
5171 }
5172
5173 pub(crate) fn enabled_state(&self) -> bool {
5174 self.state.get().contains(ElementState::ENABLED)
5175 }
5176
5177 pub(crate) fn set_enabled_state(&self, value: bool) {
5178 self.set_state(ElementState::ENABLED, value)
5179 }
5180
5181 pub(crate) fn disabled_state(&self) -> bool {
5182 self.state.get().contains(ElementState::DISABLED)
5183 }
5184
5185 pub(crate) fn set_disabled_state(&self, value: bool) {
5186 self.set_state(ElementState::DISABLED, value)
5187 }
5188
5189 pub(crate) fn read_write_state(&self) -> bool {
5190 self.state.get().contains(ElementState::READWRITE)
5191 }
5192
5193 pub(crate) fn set_read_write_state(&self, value: bool) {
5194 self.set_state(ElementState::READWRITE, value)
5195 }
5196
5197 pub(crate) fn placeholder_shown_state(&self) -> bool {
5198 self.state.get().contains(ElementState::PLACEHOLDER_SHOWN)
5199 }
5200
5201 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5202 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5203 }
5204
5205 pub(crate) fn set_target_state(&self, value: bool) {
5206 self.set_state(ElementState::URLTARGET, value)
5207 }
5208
5209 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5210 self.set_state(ElementState::FULLSCREEN, value)
5211 }
5212
5213 pub(crate) fn is_connected(&self) -> bool {
5215 self.upcast::<Node>().is_connected()
5216 }
5217
5218 pub(crate) fn cannot_navigate(&self) -> bool {
5220 let document = self.owner_document();
5221
5222 !document.is_fully_active() ||
5224 (
5225 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5227 )
5228 }
5229}
5230
5231impl Element {
5232 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5233 let node = self.upcast::<Node>();
5234 if self.disabled_state() {
5235 return;
5236 }
5237 for ancestor in node.ancestors() {
5238 if !ancestor.is::<HTMLFieldSetElement>() {
5239 continue;
5240 }
5241 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5242 continue;
5243 }
5244 if ancestor.is_parent_of(node) {
5245 self.set_disabled_state(true);
5246 self.set_enabled_state(false);
5247 return;
5248 }
5249 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5250 if node.ancestors().any(|ancestor| ancestor == *legend) {
5252 continue;
5253 }
5254 }
5255 self.set_disabled_state(true);
5256 self.set_enabled_state(false);
5257 return;
5258 }
5259 }
5260
5261 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5262 if self.disabled_state() {
5263 return;
5264 }
5265 let node = self.upcast::<Node>();
5266 if let Some(ref parent) = node.GetParentNode() {
5267 if parent.is::<HTMLOptGroupElement>() &&
5268 parent.downcast::<Element>().unwrap().disabled_state()
5269 {
5270 self.set_disabled_state(true);
5271 self.set_enabled_state(false);
5272 }
5273 }
5274 }
5275
5276 pub(crate) fn check_disabled_attribute(&self) {
5277 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5278 self.set_disabled_state(has_disabled_attrib);
5279 self.set_enabled_state(!has_disabled_attrib);
5280 }
5281
5282 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5283 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5284 self.set_read_write_state(has_readonly_attribute);
5285 }
5286}
5287
5288#[derive(Clone, Copy)]
5289pub(crate) enum AttributeMutation<'a> {
5290 Set(Option<&'a AttrValue>),
5293
5294 Removed,
5297}
5298
5299impl AttributeMutation<'_> {
5300 pub(crate) fn is_removal(&self) -> bool {
5301 match *self {
5302 AttributeMutation::Removed => true,
5303 AttributeMutation::Set(..) => false,
5304 }
5305 }
5306
5307 pub(crate) fn new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>> {
5308 match *self {
5309 AttributeMutation::Set(_) => Some(attr.value()),
5310 AttributeMutation::Removed => None,
5311 }
5312 }
5313}
5314
5315#[derive(JSTraceable, MallocSizeOf)]
5319struct TagName {
5320 #[no_trace]
5321 ptr: DomRefCell<Option<LocalName>>,
5322}
5323
5324impl TagName {
5325 fn new() -> TagName {
5326 TagName {
5327 ptr: DomRefCell::new(None),
5328 }
5329 }
5330
5331 fn or_init<F>(&self, cb: F) -> LocalName
5334 where
5335 F: FnOnce() -> LocalName,
5336 {
5337 match &mut *self.ptr.borrow_mut() {
5338 &mut Some(ref name) => name.clone(),
5339 ptr => {
5340 let name = cb();
5341 *ptr = Some(name.clone());
5342 name
5343 },
5344 }
5345 }
5346
5347 fn clear(&self) {
5350 *self.ptr.borrow_mut() = None;
5351 }
5352}
5353
5354pub(crate) struct ElementPerformFullscreenEnter {
5355 element: Trusted<Element>,
5356 promise: TrustedPromise,
5357 error: bool,
5358}
5359
5360impl ElementPerformFullscreenEnter {
5361 pub(crate) fn new(
5362 element: Trusted<Element>,
5363 promise: TrustedPromise,
5364 error: bool,
5365 ) -> Box<ElementPerformFullscreenEnter> {
5366 Box::new(ElementPerformFullscreenEnter {
5367 element,
5368 promise,
5369 error,
5370 })
5371 }
5372}
5373
5374impl TaskOnce for ElementPerformFullscreenEnter {
5375 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
5376 fn run_once(self) {
5377 let element = self.element.root();
5378 let promise = self.promise.root();
5379 let document = element.owner_document();
5380
5381 if self.error || !element.fullscreen_element_ready_check() {
5383 document
5384 .upcast::<EventTarget>()
5385 .fire_event(atom!("fullscreenerror"), CanGc::note());
5386 promise.reject_error(
5387 Error::Type(String::from("fullscreen is not connected")),
5388 CanGc::note(),
5389 );
5390 return;
5391 }
5392
5393 element.set_fullscreen_state(true);
5396 document.set_fullscreen_element(Some(&element));
5397
5398 document
5400 .upcast::<EventTarget>()
5401 .fire_event(atom!("fullscreenchange"), CanGc::note());
5402
5403 promise.resolve_native(&(), CanGc::note());
5405 }
5406}
5407
5408pub(crate) struct ElementPerformFullscreenExit {
5409 element: Trusted<Element>,
5410 promise: TrustedPromise,
5411}
5412
5413impl ElementPerformFullscreenExit {
5414 pub(crate) fn new(
5415 element: Trusted<Element>,
5416 promise: TrustedPromise,
5417 ) -> Box<ElementPerformFullscreenExit> {
5418 Box::new(ElementPerformFullscreenExit { element, promise })
5419 }
5420}
5421
5422impl TaskOnce for ElementPerformFullscreenExit {
5423 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
5424 fn run_once(self) {
5425 let element = self.element.root();
5426 let document = element.owner_document();
5427 element.set_fullscreen_state(false);
5430 document.set_fullscreen_element(None);
5431
5432 document
5434 .upcast::<EventTarget>()
5435 .fire_event(atom!("fullscreenchange"), CanGc::note());
5436
5437 self.promise.root().resolve_native(&(), CanGc::note());
5439 }
5440}
5441
5442pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5444 element
5445 .get_attribute(&ns!(), &local_name!("crossorigin"))
5446 .map(|attribute| {
5447 let value = attribute.value().to_ascii_lowercase();
5448 if value == "anonymous" || value == "use-credentials" {
5449 DOMString::from(value)
5450 } else {
5451 DOMString::from("anonymous")
5452 }
5453 })
5454}
5455
5456pub(crate) fn set_cross_origin_attribute(
5457 element: &Element,
5458 value: Option<DOMString>,
5459 can_gc: CanGc,
5460) {
5461 match value {
5462 Some(val) => element.set_string_attribute(&local_name!("crossorigin"), val, can_gc),
5463 None => {
5464 element.remove_attribute(&ns!(), &local_name!("crossorigin"), can_gc);
5465 },
5466 }
5467}
5468
5469pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5471 element
5472 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5473 .map(|attribute| {
5474 let value = attribute.value().to_ascii_lowercase();
5475 if value == "no-referrer" ||
5476 value == "no-referrer-when-downgrade" ||
5477 value == "same-origin" ||
5478 value == "origin" ||
5479 value == "strict-origin" ||
5480 value == "origin-when-cross-origin" ||
5481 value == "strict-origin-when-cross-origin" ||
5482 value == "unsafe-url"
5483 {
5484 DOMString::from(value)
5485 } else {
5486 DOMString::new()
5487 }
5488 })
5489 .unwrap_or_default()
5490}
5491
5492pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5493 element
5494 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5495 .map(|attribute| ReferrerPolicy::from(&**attribute.value()))
5496 .unwrap_or(element.owner_document().get_referrer_policy())
5497}
5498
5499pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5500 element
5501 .get_attribute(&ns!(), &local_name!("crossorigin"))
5502 .map(|attribute| CorsSettings::from_enumerated_attribute(&attribute.value()))
5503}