1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell};
9use std::default::Default;
10use std::ops::Deref;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::{fmt, mem};
14
15use app_units::Au;
16use cssparser::match_ignore_ascii_case;
17use devtools_traits::AttrInfo;
18use dom_struct::dom_struct;
19use euclid::default::{Rect, Size2D};
20use html5ever::serialize::TraversalScope;
21use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
22use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
23use js::jsapi::{Heap, JSAutoRealm};
24use js::jsval::JSVal;
25use js::rust::HandleObject;
26use layout_api::{LayoutDamage, ScrollContainerQueryFlags};
27use net_traits::ReferrerPolicy;
28use net_traits::request::CorsSettings;
29use selectors::Element as SelectorsElement;
30use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
31use selectors::bloom::{BLOOM_HASH_MASK, BloomFilter};
32use selectors::matching::{ElementSelectorFlags, MatchingContext};
33use selectors::sink::Push;
34use servo_arc::Arc;
35use style::applicable_declarations::ApplicableDeclarationBlock;
36use style::attr::{AttrValue, LengthOrPercentageOrAuto};
37use style::context::QuirksMode;
38use style::invalidation::element::restyle_hints::RestyleHint;
39use style::properties::longhands::{
40 self, background_image, border_spacing, font_family, font_size,
41};
42use style::properties::{
43 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
44 parse_style_attribute,
45};
46use style::rule_tree::CascadeLevel;
47use style::selector_parser::{
48 NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser, Snapshot,
49 extended_filtering,
50};
51use style::shared_lock::Locked;
52use style::stylesheets::layer_rule::LayerOrder;
53use style::stylesheets::{CssRuleType, UrlExtraData};
54use style::values::computed::Overflow;
55use style::values::generics::NonNegative;
56use style::values::generics::position::PreferredRatio;
57use style::values::generics::ratio::Ratio;
58use style::values::{AtomIdent, AtomString, CSSFloat, computed, specified};
59use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
60use stylo_atoms::Atom;
61use stylo_dom::ElementState;
62use xml5ever::serialize::TraversalScope::{
63 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
64};
65
66use crate::conversions::Convert;
67use crate::dom::activation::Activatable;
68use crate::dom::attr::{Attr, AttrHelpersForLayout, is_relevant_attribute};
69use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
70use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
71use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
72use crate::dom::bindings::codegen::Bindings::ElementBinding::{
73 ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
74};
75use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
76use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
77use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
78use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
79 ShadowRootMethods, ShadowRootMode, SlotAssignmentMode,
80};
81use crate::dom::bindings::codegen::Bindings::WindowBinding::{
82 ScrollBehavior, ScrollToOptions, WindowMethods,
83};
84use crate::dom::bindings::codegen::UnionTypes::{
85 BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
86 TrustedHTMLOrString,
87 TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString,
88 TrustedScriptURLOrUSVString,
89};
90use crate::dom::bindings::conversions::DerivedFrom;
91use crate::dom::bindings::domname::{
92 self, is_valid_attribute_local_name, namespace_from_domstring,
93};
94use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
95use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
96use crate::dom::bindings::num::Finite;
97use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
98use crate::dom::bindings::reflector::DomObject;
99use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
100use crate::dom::bindings::str::{DOMString, USVString};
101use crate::dom::bindings::xmlname::matches_name_production;
102use crate::dom::characterdata::CharacterData;
103use crate::dom::create::create_element;
104use crate::dom::csp::{CspReporting, InlineCheckType, SourcePosition};
105use crate::dom::customelementregistry::{
106 CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementState,
107 is_valid_custom_element_name,
108};
109use crate::dom::document::{Document, LayoutDocumentHelpers};
110use crate::dom::documentfragment::DocumentFragment;
111use crate::dom::domrect::DOMRect;
112use crate::dom::domrectlist::DOMRectList;
113use crate::dom::domtokenlist::DOMTokenList;
114use crate::dom::elementinternals::ElementInternals;
115use crate::dom::eventtarget::EventTarget;
116use crate::dom::globalscope::GlobalScope;
117use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
118use crate::dom::html::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers};
119use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
120use crate::dom::html::htmlcollection::HTMLCollection;
121use crate::dom::html::htmlelement::HTMLElement;
122use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
123use crate::dom::html::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers};
124use crate::dom::html::htmlformelement::FormControlElementHelpers;
125use crate::dom::html::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers, SizePresentationalHint};
126use crate::dom::html::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
127use crate::dom::html::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
128use crate::dom::html::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
129use crate::dom::html::htmllabelelement::HTMLLabelElement;
130use crate::dom::html::htmllegendelement::HTMLLegendElement;
131use crate::dom::html::htmllinkelement::HTMLLinkElement;
132use crate::dom::html::htmlobjectelement::HTMLObjectElement;
133use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
134use crate::dom::html::htmloutputelement::HTMLOutputElement;
135use crate::dom::html::htmlscriptelement::HTMLScriptElement;
136use crate::dom::html::htmlselectelement::HTMLSelectElement;
137use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
138use crate::dom::html::htmlstyleelement::HTMLStyleElement;
139use crate::dom::html::htmltablecellelement::{
140 HTMLTableCellElement, HTMLTableCellElementLayoutHelpers,
141};
142use crate::dom::html::htmltablecolelement::{
143 HTMLTableColElement, HTMLTableColElementLayoutHelpers,
144};
145use crate::dom::html::htmltableelement::{HTMLTableElement, HTMLTableElementLayoutHelpers};
146use crate::dom::html::htmltablerowelement::{
147 HTMLTableRowElement, HTMLTableRowElementLayoutHelpers,
148};
149use crate::dom::html::htmltablesectionelement::{
150 HTMLTableSectionElement, HTMLTableSectionElementLayoutHelpers,
151};
152use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
153use crate::dom::html::htmltextareaelement::{
154 HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers,
155};
156use crate::dom::html::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers};
157use crate::dom::intersectionobserver::{IntersectionObserver, IntersectionObserverRegistration};
158use crate::dom::mutationobserver::{Mutation, MutationObserver};
159use crate::dom::namednodemap::NamedNodeMap;
160use crate::dom::node::{
161 BindContext, ChildrenMutation, CloneChildrenFlag, IsShadowTree, LayoutNodeHelpers, Node,
162 NodeDamage, NodeFlags, NodeTraits, ShadowIncluding, UnbindContext,
163};
164use crate::dom::nodelist::NodeList;
165use crate::dom::promise::Promise;
166use crate::dom::raredata::ElementRareData;
167use crate::dom::scrolling_box::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.upcast(), IsShadowTree::Yes);
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 #[expect(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 #[expect(unsafe_code)]
1409 fn id_attribute(self) -> *const Option<Atom> {
1410 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1411 }
1412
1413 #[expect(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 fn local_name(self) -> &'dom LocalName {
1419 &(self.unsafe_get()).local_name
1420 }
1421
1422 fn namespace(self) -> &'dom Namespace {
1423 &(self.unsafe_get()).namespace
1424 }
1425
1426 fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1427 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1428 return Some(attr);
1429 }
1430 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1431 return Some(attr);
1432 }
1433 None
1434 }
1435
1436 fn get_lang_for_layout(self) -> String {
1437 let mut current_node = Some(self.upcast::<Node>());
1438 while let Some(node) = current_node {
1439 current_node = node.composed_parent_node_ref();
1440 match node.downcast::<Element>() {
1441 Some(elem) => {
1442 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1443 return attr.to_owned();
1444 }
1445 },
1446 None => continue,
1447 }
1448 }
1449 String::new()
1452 }
1453
1454 #[inline]
1455 fn get_state_for_layout(self) -> ElementState {
1456 (self.unsafe_get()).state.get()
1457 }
1458
1459 #[inline]
1460 fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1461 debug_assert!(thread_state::get().is_layout());
1462 let f = &(self.unsafe_get()).selector_flags;
1463 f.set(f.get() | flags);
1464 }
1465
1466 #[inline]
1467 fn get_selector_flags(self) -> ElementSelectorFlags {
1468 self.unsafe_get().selector_flags.get()
1469 }
1470
1471 #[inline]
1472 #[expect(unsafe_code)]
1473 fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1474 unsafe {
1475 self.unsafe_get()
1476 .rare_data
1477 .borrow_for_layout()
1478 .as_ref()?
1479 .shadow_root
1480 .as_ref()
1481 .map(|sr| sr.to_layout())
1482 }
1483 }
1484
1485 #[inline]
1486 fn get_attr_for_layout(
1487 self,
1488 namespace: &Namespace,
1489 name: &LocalName,
1490 ) -> Option<&'dom AttrValue> {
1491 get_attr_for_layout(self, namespace, name).map(|attr| attr.value())
1492 }
1493
1494 #[inline]
1495 fn get_attr_val_for_layout(self, namespace: &Namespace, name: &LocalName) -> Option<&'dom str> {
1496 get_attr_for_layout(self, namespace, name).map(|attr| attr.as_str())
1497 }
1498
1499 #[inline]
1500 fn get_attr_vals_for_layout(self, name: &LocalName) -> Vec<&'dom AttrValue> {
1501 self.attrs()
1502 .iter()
1503 .filter_map(|attr| {
1504 if name == attr.local_name() {
1505 Some(attr.value())
1506 } else {
1507 None
1508 }
1509 })
1510 .collect()
1511 }
1512
1513 fn each_custom_state<F>(self, callback: F)
1514 where
1515 F: FnMut(&AtomIdent),
1516 {
1517 self.unsafe_get().each_custom_state(callback)
1518 }
1519}
1520
1521impl Element {
1522 pub(crate) fn is_html_element(&self) -> bool {
1523 self.namespace == ns!(html)
1524 }
1525
1526 pub(crate) fn html_element_in_html_document(&self) -> bool {
1527 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1528 }
1529
1530 pub(crate) fn local_name(&self) -> &LocalName {
1531 &self.local_name
1532 }
1533
1534 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1535 if self.html_element_in_html_document() {
1536 name.make_ascii_lowercase();
1537 }
1538 LocalName::from(name)
1539 }
1540
1541 pub(crate) fn namespace(&self) -> &Namespace {
1542 &self.namespace
1543 }
1544
1545 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1546 self.prefix.borrow()
1547 }
1548
1549 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1550 *self.prefix.borrow_mut() = prefix;
1551 }
1552
1553 pub(crate) fn attrs(&self) -> Ref<'_, [Dom<Attr>]> {
1554 Ref::map(self.attrs.borrow(), |attrs| &**attrs)
1555 }
1556
1557 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1559 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1560
1561 if namespace_prefix == Some(namespace_prefix!("xml")) {
1563 return ns!(xml);
1564 }
1565
1566 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1568 return ns!(xmlns);
1569 }
1570
1571 let prefix = prefix.map(LocalName::from);
1572
1573 let inclusive_ancestor_elements = self
1574 .upcast::<Node>()
1575 .inclusive_ancestors(ShadowIncluding::No)
1576 .filter_map(DomRoot::downcast::<Self>);
1577
1578 for element in inclusive_ancestor_elements {
1581 if element.namespace() != &ns!() &&
1583 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1584 {
1585 return element.namespace().clone();
1586 }
1587
1588 let attr = Ref::filter_map(self.attrs(), |attrs| {
1593 attrs.iter().find(|attr| {
1594 if attr.namespace() != &ns!(xmlns) {
1595 return false;
1596 }
1597 match (attr.prefix(), prefix.as_ref()) {
1598 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1599 attr.local_name() == prefix
1600 },
1601 (None, None) => attr.local_name() == &local_name!("xmlns"),
1602 _ => false,
1603 }
1604 })
1605 })
1606 .ok();
1607
1608 if let Some(attr) = attr {
1609 return (**attr.value()).into();
1610 }
1611 }
1612
1613 ns!()
1614 }
1615
1616 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1617 self.rare_data().as_ref()?.name_attribute.clone()
1618 }
1619
1620 pub(crate) fn style_attribute(
1621 &self,
1622 ) -> &DomRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
1623 &self.style_attribute
1624 }
1625
1626 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1627 self.attrs
1628 .borrow()
1629 .iter()
1630 .map(|attr| attr.summarize())
1631 .collect()
1632 }
1633
1634 pub(crate) fn is_void(&self) -> bool {
1635 if self.namespace != ns!(html) {
1636 return false;
1637 }
1638 match self.local_name {
1639 local_name!("area") |
1642 local_name!("base") |
1643 local_name!("basefont") |
1644 local_name!("bgsound") |
1645 local_name!("br") |
1646 local_name!("col") |
1647 local_name!("embed") |
1648 local_name!("frame") |
1649 local_name!("hr") |
1650 local_name!("img") |
1651 local_name!("input") |
1652 local_name!("keygen") |
1653 local_name!("link") |
1654 local_name!("meta") |
1655 local_name!("param") |
1656 local_name!("source") |
1657 local_name!("track") |
1658 local_name!("wbr") => true,
1659 _ => false,
1660 }
1661 }
1662
1663 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1664 if self.node.is_in_a_document_tree() {
1665 self.upcast::<Node>()
1666 .owner_doc()
1667 .GetDocumentElement()
1668 .unwrap()
1669 } else {
1670 self.upcast::<Node>()
1671 .inclusive_ancestors(ShadowIncluding::No)
1672 .filter_map(DomRoot::downcast)
1673 .last()
1674 .expect("We know inclusive_ancestors will return `self` which is an element")
1675 }
1676 }
1677
1678 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1680 for node in self
1681 .upcast::<Node>()
1682 .inclusive_ancestors(ShadowIncluding::No)
1683 {
1684 let element = node.downcast::<Element>()?;
1685 if *element.namespace() == namespace {
1687 if let Some(prefix) = element.GetPrefix() {
1688 return Some(prefix);
1689 }
1690 }
1691
1692 for attr in element.attrs.borrow().iter() {
1694 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1695 **attr.value() == *namespace
1696 {
1697 return Some(attr.LocalName());
1698 }
1699 }
1700 }
1701 None
1702 }
1703
1704 pub(crate) fn is_document_element(&self) -> bool {
1706 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1707 *document_element == *self
1708 } else {
1709 false
1710 }
1711 }
1712
1713 pub(crate) fn is_active_element(&self) -> bool {
1715 if let Some(active_element) = self.owner_document().GetActiveElement() {
1716 *active_element == *self
1717 } else {
1718 false
1719 }
1720 }
1721
1722 pub(crate) fn is_focusable_area(&self) -> bool {
1723 if self.is_actually_disabled() {
1724 return false;
1725 }
1726 let node = self.upcast::<Node>();
1727 if node.get_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE) {
1728 return true;
1729 }
1730
1731 matches!(
1733 node.type_id(),
1734 NodeTypeId::Element(ElementTypeId::HTMLElement(
1735 HTMLElementTypeId::HTMLAnchorElement,
1736 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1737 HTMLElementTypeId::HTMLInputElement,
1738 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1739 HTMLElementTypeId::HTMLSelectElement,
1740 )) | NodeTypeId::Element(ElementTypeId::HTMLElement(
1741 HTMLElementTypeId::HTMLTextAreaElement,
1742 ))
1743 )
1744 }
1745
1746 pub(crate) fn find_focusable_shadow_host_if_necessary(&self) -> Option<DomRoot<Element>> {
1751 if self.is_focusable_area() {
1752 Some(DomRoot::from_ref(self))
1753 } else if self.upcast::<Node>().implemented_pseudo_element() ==
1754 Some(PseudoElement::ServoTextControlInnerEditor)
1755 {
1756 let containing_shadow_host = self.containing_shadow_root().map(|root| root.Host());
1757 debug_assert!(
1758 containing_shadow_host
1759 .as_ref()
1760 .is_some_and(|e| e.is_focusable_area()),
1761 "Containing shadow host is not focusable"
1762 );
1763 containing_shadow_host
1764 } else {
1765 None
1766 }
1767 }
1768
1769 pub(crate) fn is_actually_disabled(&self) -> bool {
1770 let node = self.upcast::<Node>();
1771 match node.type_id() {
1772 NodeTypeId::Element(ElementTypeId::HTMLElement(
1773 HTMLElementTypeId::HTMLButtonElement,
1774 )) |
1775 NodeTypeId::Element(ElementTypeId::HTMLElement(
1776 HTMLElementTypeId::HTMLInputElement,
1777 )) |
1778 NodeTypeId::Element(ElementTypeId::HTMLElement(
1779 HTMLElementTypeId::HTMLSelectElement,
1780 )) |
1781 NodeTypeId::Element(ElementTypeId::HTMLElement(
1782 HTMLElementTypeId::HTMLTextAreaElement,
1783 )) |
1784 NodeTypeId::Element(ElementTypeId::HTMLElement(
1785 HTMLElementTypeId::HTMLOptionElement,
1786 )) => self.disabled_state(),
1787 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1788 self.downcast::<HTMLElement>()
1789 .unwrap()
1790 .is_form_associated_custom_element() &&
1791 self.disabled_state()
1792 },
1793 _ => false,
1798 }
1799 }
1800
1801 #[allow(clippy::too_many_arguments)]
1802 pub(crate) fn push_new_attribute(
1803 &self,
1804 local_name: LocalName,
1805 value: AttrValue,
1806 name: LocalName,
1807 namespace: Namespace,
1808 prefix: Option<Prefix>,
1809 reason: AttributeMutationReason,
1810 can_gc: CanGc,
1811 ) {
1812 let attr = Attr::new(
1813 &self.node.owner_doc(),
1814 local_name,
1815 value,
1816 name,
1817 namespace,
1818 prefix,
1819 Some(self),
1820 can_gc,
1821 );
1822 self.push_attribute(&attr, reason, can_gc);
1823 }
1824
1825 fn handle_attribute_changes(
1827 &self,
1828 attr: &Attr,
1829 old_value: Option<&AttrValue>,
1830 new_value: Option<DOMString>,
1831 reason: AttributeMutationReason,
1832 can_gc: CanGc,
1833 ) {
1834 let old_value_string = old_value.map(|old_value| DOMString::from(&**old_value));
1835 let name = attr.local_name().clone();
1838 let namespace = attr.namespace().clone();
1839 let mutation = LazyCell::new(|| Mutation::Attribute {
1840 name: name.clone(),
1841 namespace: namespace.clone(),
1842 old_value: old_value_string.clone(),
1843 });
1844 MutationObserver::queue_a_mutation_record(&self.node, mutation);
1845
1846 let has_new_value = new_value.is_some();
1848
1849 if self.is_custom() {
1852 let reaction = CallbackReaction::AttributeChanged(
1853 attr.local_name().clone(),
1854 old_value_string,
1855 new_value,
1856 attr.namespace().clone(),
1857 );
1858 ScriptThread::enqueue_callback_reaction(self, reaction, None);
1859 }
1860
1861 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
1863 let attribute_mutation = if has_new_value {
1864 AttributeMutation::Set(old_value, reason)
1865 } else {
1866 AttributeMutation::Removed
1867 };
1868 vtable_for(self.upcast()).attribute_mutated(attr, attribute_mutation, can_gc);
1869 }
1870 }
1871
1872 pub(crate) fn change_attribute(&self, attr: &Attr, mut value: AttrValue, can_gc: CanGc) {
1874 let old_value = &attr.value().clone();
1878 self.will_mutate_attr(attr);
1880 attr.swap_value(&mut value);
1881 let new_value = DOMString::from(&**attr.value());
1885 self.handle_attribute_changes(
1886 attr,
1887 Some(old_value),
1888 Some(new_value),
1889 AttributeMutationReason::Directly,
1890 can_gc,
1891 );
1892 }
1893
1894 pub(crate) fn push_attribute(
1896 &self,
1897 attr: &Attr,
1898 reason: AttributeMutationReason,
1899 can_gc: CanGc,
1900 ) {
1901 assert!(attr.GetOwnerElement().as_deref() == Some(self));
1905 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
1909 self.will_mutate_attr(attr);
1911 self.attrs.borrow_mut().push(Dom::from_ref(attr));
1912 let new_value = DOMString::from(&**attr.value());
1916 self.handle_attribute_changes(attr, None, Some(new_value), reason, can_gc);
1917 }
1918
1919 pub(crate) fn get_attribute(
1920 &self,
1921 namespace: &Namespace,
1922 local_name: &LocalName,
1923 ) -> Option<DomRoot<Attr>> {
1924 self.attrs
1925 .borrow()
1926 .iter()
1927 .find(|attr| attr.local_name() == local_name && attr.namespace() == namespace)
1928 .map(|js| DomRoot::from_ref(&**js))
1929 }
1930
1931 pub(crate) fn get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>> {
1933 let name = &self.parsed_name(name);
1934 let maybe_attribute = self
1935 .attrs
1936 .borrow()
1937 .iter()
1938 .find(|a| a.name() == name)
1939 .map(|js| DomRoot::from_ref(&**js));
1940 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
1941 if *name == local_name!("id") || *name == local_name!("name") {
1942 match maybe_attr {
1943 None => true,
1944 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
1945 }
1946 } else {
1947 true
1948 }
1949 }
1950 debug_assert!(id_and_name_must_be_atoms(name, &maybe_attribute));
1951 maybe_attribute
1952 }
1953
1954 pub(crate) fn set_attribute_from_parser(
1955 &self,
1956 qname: QualName,
1957 value: DOMString,
1958 prefix: Option<Prefix>,
1959 can_gc: CanGc,
1960 ) {
1961 if self
1963 .attrs
1964 .borrow()
1965 .iter()
1966 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
1967 {
1968 return;
1969 }
1970
1971 let name = match prefix {
1972 None => qname.local.clone(),
1973 Some(ref prefix) => {
1974 let name = format!("{}:{}", &**prefix, &*qname.local);
1975 LocalName::from(name)
1976 },
1977 };
1978 let value = self.parse_attribute(&qname.ns, &qname.local, value);
1979 self.push_new_attribute(
1980 qname.local,
1981 value,
1982 name,
1983 qname.ns,
1984 prefix,
1985 AttributeMutationReason::ByParser,
1986 can_gc,
1987 );
1988 }
1989
1990 pub(crate) fn set_attribute(&self, name: &LocalName, value: AttrValue, can_gc: CanGc) {
1991 assert!(name == &name.to_ascii_lowercase());
1992 assert!(!name.contains(':'));
1993
1994 self.set_first_matching_attribute(
1995 name.clone(),
1996 value,
1997 name.clone(),
1998 ns!(),
1999 None,
2000 |attr| attr.local_name() == name,
2001 can_gc,
2002 );
2003 }
2004
2005 pub(crate) fn set_custom_attribute(
2007 &self,
2008 name: DOMString,
2009 value: DOMString,
2010 can_gc: CanGc,
2011 ) -> ErrorResult {
2012 if !matches_name_production(&name.str()) {
2014 return Err(Error::InvalidCharacter(None));
2015 }
2016
2017 let name = LocalName::from(name);
2019 let value = self.parse_attribute(&ns!(), &name, value);
2020 self.set_first_matching_attribute(
2021 name.clone(),
2022 value,
2023 name.clone(),
2024 ns!(),
2025 None,
2026 |attr| *attr.name() == name && *attr.namespace() == ns!(),
2027 can_gc,
2028 );
2029 Ok(())
2030 }
2031
2032 #[allow(clippy::too_many_arguments)]
2034 fn set_first_matching_attribute<F>(
2035 &self,
2036 local_name: LocalName,
2037 value: AttrValue,
2038 name: LocalName,
2039 namespace: Namespace,
2040 prefix: Option<Prefix>,
2041 find: F,
2042 can_gc: CanGc,
2043 ) where
2044 F: Fn(&Attr) -> bool,
2045 {
2046 let attr = self
2048 .attrs
2049 .borrow()
2050 .iter()
2051 .find(|attr| find(attr))
2052 .map(|js| DomRoot::from_ref(&**js));
2053 if let Some(attr) = attr {
2054 self.will_mutate_attr(&attr);
2056 self.change_attribute(&attr, value, can_gc);
2057 } else {
2058 self.push_new_attribute(
2063 local_name,
2064 value,
2065 name,
2066 namespace,
2067 prefix,
2068 AttributeMutationReason::Directly,
2069 can_gc,
2070 );
2071 };
2072 }
2073
2074 pub(crate) fn parse_attribute(
2075 &self,
2076 namespace: &Namespace,
2077 local_name: &LocalName,
2078 value: DOMString,
2079 ) -> AttrValue {
2080 if is_relevant_attribute(namespace, local_name) {
2081 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2082 } else {
2083 AttrValue::String(value.into())
2084 }
2085 }
2086
2087 pub(crate) fn remove_attribute(
2088 &self,
2089 namespace: &Namespace,
2090 local_name: &LocalName,
2091 can_gc: CanGc,
2092 ) -> Option<DomRoot<Attr>> {
2093 self.remove_first_matching_attribute(
2094 |attr| attr.namespace() == namespace && attr.local_name() == local_name,
2095 can_gc,
2096 )
2097 }
2098
2099 pub(crate) fn remove_attribute_by_name(
2100 &self,
2101 name: &LocalName,
2102 can_gc: CanGc,
2103 ) -> Option<DomRoot<Attr>> {
2104 self.remove_first_matching_attribute(|attr| attr.name() == name, can_gc)
2105 }
2106
2107 fn remove_first_matching_attribute<F>(&self, find: F, can_gc: CanGc) -> Option<DomRoot<Attr>>
2109 where
2110 F: Fn(&Attr) -> bool,
2111 {
2112 let idx = self.attrs.borrow().iter().position(|attr| find(attr));
2113 idx.map(|idx| {
2114 let attr = DomRoot::from_ref(&*(*self.attrs.borrow())[idx]);
2115
2116 self.will_mutate_attr(&attr);
2118 self.attrs.borrow_mut().remove(idx);
2119 attr.set_owner(None);
2121 self.handle_attribute_changes(
2123 &attr,
2124 Some(&attr.value()),
2125 None,
2126 AttributeMutationReason::Directly,
2127 can_gc,
2128 );
2129
2130 attr
2131 })
2132 }
2133
2134 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2135 self.get_attribute(&ns!(), &local_name!("class"))
2136 .is_some_and(|attr| {
2137 attr.value()
2138 .as_tokens()
2139 .iter()
2140 .any(|atom| case_sensitivity.eq_atom(name, atom))
2141 })
2142 }
2143
2144 pub(crate) fn is_part(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2145 self.get_attribute(&ns!(), &LocalName::from("part"))
2146 .is_some_and(|attr| {
2147 attr.value()
2148 .as_tokens()
2149 .iter()
2150 .any(|atom| case_sensitivity.eq_atom(name, atom))
2151 })
2152 }
2153
2154 pub(crate) fn set_atomic_attribute(
2155 &self,
2156 local_name: &LocalName,
2157 value: DOMString,
2158 can_gc: CanGc,
2159 ) {
2160 assert!(*local_name == local_name.to_ascii_lowercase());
2161 let value = AttrValue::from_atomic(value.into());
2162 self.set_attribute(local_name, value, can_gc);
2163 }
2164
2165 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2166 assert!(local_name.bytes().all(|b| b.to_ascii_lowercase() == b));
2167 self.attrs
2168 .borrow()
2169 .iter()
2170 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2171 }
2172
2173 pub(crate) fn set_bool_attribute(&self, local_name: &LocalName, value: bool, can_gc: CanGc) {
2174 if self.has_attribute(local_name) == value {
2175 return;
2176 }
2177 if value {
2178 self.set_string_attribute(local_name, DOMString::new(), can_gc);
2179 } else {
2180 self.remove_attribute(&ns!(), local_name, can_gc);
2181 }
2182 }
2183
2184 pub(crate) fn get_url_attribute(&self, local_name: &LocalName) -> USVString {
2185 assert!(*local_name == local_name.to_ascii_lowercase());
2186 let attr = match self.get_attribute(&ns!(), local_name) {
2187 Some(attr) => attr,
2188 None => return USVString::default(),
2189 };
2190 let value = &**attr.value();
2191 self.owner_document()
2193 .base_url()
2194 .join(value)
2195 .map(|parsed| USVString(parsed.into_string()))
2196 .unwrap_or_else(|_| USVString(value.to_owned()))
2197 }
2198
2199 pub(crate) fn set_url_attribute(
2200 &self,
2201 local_name: &LocalName,
2202 value: USVString,
2203 can_gc: CanGc,
2204 ) {
2205 assert!(*local_name == local_name.to_ascii_lowercase());
2206 self.set_attribute(local_name, AttrValue::String(value.to_string()), can_gc);
2207 }
2208
2209 pub(crate) fn get_trusted_type_url_attribute(
2210 &self,
2211 local_name: &LocalName,
2212 ) -> TrustedScriptURLOrUSVString {
2213 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2214 let attr = match self.get_attribute(&ns!(), local_name) {
2215 Some(attr) => attr,
2216 None => return TrustedScriptURLOrUSVString::USVString(USVString::default()),
2217 };
2218 let value = &**attr.value();
2219 self.owner_document()
2221 .base_url()
2222 .join(value)
2223 .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
2224 .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
2225 }
2226
2227 pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
2228 assert_eq!(*local_name, local_name.to_ascii_lowercase());
2229 let value = match self.get_attribute(&ns!(), local_name) {
2230 Some(attr) => (&**attr.value()).into(),
2231 None => "".into(),
2232 };
2233 TrustedHTMLOrString::String(value)
2234 }
2235
2236 pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
2237 match self.get_attribute(&ns!(), local_name) {
2238 Some(x) => x.Value(),
2239 None => DOMString::new(),
2240 }
2241 }
2242
2243 pub(crate) fn set_string_attribute(
2244 &self,
2245 local_name: &LocalName,
2246 value: DOMString,
2247 can_gc: CanGc,
2248 ) {
2249 assert!(*local_name == local_name.to_ascii_lowercase());
2250 self.set_attribute(local_name, AttrValue::String(value.into()), can_gc);
2251 }
2252
2253 fn get_nullable_string_attribute(&self, local_name: &LocalName) -> Option<DOMString> {
2256 if self.has_attribute(local_name) {
2257 Some(self.get_string_attribute(local_name))
2258 } else {
2259 None
2260 }
2261 }
2262
2263 fn set_nullable_string_attribute(
2266 &self,
2267 local_name: &LocalName,
2268 value: Option<DOMString>,
2269 can_gc: CanGc,
2270 ) {
2271 match value {
2272 Some(val) => {
2273 self.set_string_attribute(local_name, val, can_gc);
2274 },
2275 None => {
2276 self.remove_attribute(&ns!(), local_name, can_gc);
2277 },
2278 }
2279 }
2280
2281 pub(crate) fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
2282 self.get_attribute(&ns!(), local_name)
2283 .map(|attr| attr.value().as_tokens().to_vec())
2284 .unwrap_or_default()
2285 }
2286
2287 pub(crate) fn set_tokenlist_attribute(
2288 &self,
2289 local_name: &LocalName,
2290 value: DOMString,
2291 can_gc: CanGc,
2292 ) {
2293 assert!(*local_name == local_name.to_ascii_lowercase());
2294 self.set_attribute(
2295 local_name,
2296 AttrValue::from_serialized_tokenlist(value.into()),
2297 can_gc,
2298 );
2299 }
2300
2301 pub(crate) fn set_atomic_tokenlist_attribute(
2302 &self,
2303 local_name: &LocalName,
2304 tokens: Vec<Atom>,
2305 can_gc: CanGc,
2306 ) {
2307 assert!(*local_name == local_name.to_ascii_lowercase());
2308 self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens), can_gc);
2309 }
2310
2311 pub(crate) fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
2312 assert!(
2314 local_name
2315 .chars()
2316 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2317 );
2318 let attribute = self.get_attribute(&ns!(), local_name);
2319
2320 match attribute {
2321 Some(ref attribute) => match *attribute.value() {
2322 AttrValue::Int(_, value) => value,
2323 _ => panic!(
2324 "Expected an AttrValue::Int: \
2325 implement parse_plain_attribute"
2326 ),
2327 },
2328 None => default,
2329 }
2330 }
2331
2332 pub(crate) fn set_int_attribute(&self, local_name: &LocalName, value: i32, can_gc: CanGc) {
2333 assert!(*local_name == local_name.to_ascii_lowercase());
2334 self.set_attribute(local_name, AttrValue::Int(value.to_string(), value), can_gc);
2335 }
2336
2337 pub(crate) fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
2338 assert!(
2339 local_name
2340 .chars()
2341 .all(|ch| !ch.is_ascii() || ch.to_ascii_lowercase() == ch)
2342 );
2343 let attribute = self.get_attribute(&ns!(), local_name);
2344 match attribute {
2345 Some(ref attribute) => match *attribute.value() {
2346 AttrValue::UInt(_, value) => value,
2347 _ => panic!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
2348 },
2349 None => default,
2350 }
2351 }
2352 pub(crate) fn set_uint_attribute(&self, local_name: &LocalName, value: u32, can_gc: CanGc) {
2353 assert!(*local_name == local_name.to_ascii_lowercase());
2354 self.set_attribute(
2355 local_name,
2356 AttrValue::UInt(value.to_string(), value),
2357 can_gc,
2358 );
2359 }
2360
2361 pub(crate) fn will_mutate_attr(&self, attr: &Attr) {
2362 let node = self.upcast::<Node>();
2363 node.owner_doc().element_attr_will_change(self, attr);
2364 }
2365
2366 fn update_style_attribute(&self, attr: &Attr, mutation: AttributeMutation) {
2368 let doc = self.upcast::<Node>().owner_doc();
2369 *self.style_attribute.borrow_mut() = match mutation {
2371 AttributeMutation::Set(..) => {
2372 let is_declaration = matches!(*attr.value(), AttrValue::Declaration(..));
2378
2379 let block = if is_declaration {
2380 let mut value = AttrValue::String(String::new());
2381 attr.swap_value(&mut value);
2382 let (serialization, block) = match value {
2383 AttrValue::Declaration(s, b) => (s, b),
2384 _ => unreachable!(),
2385 };
2386 let mut value = AttrValue::String(serialization);
2387 attr.swap_value(&mut value);
2388 block
2389 } else {
2390 let win = self.owner_window();
2391 let source = &**attr.value();
2392 let global = &self.owner_global();
2393 if global
2398 .get_csp_list()
2399 .should_elements_inline_type_behavior_be_blocked(
2400 global,
2401 self,
2402 InlineCheckType::StyleAttribute,
2403 source,
2404 doc.get_current_parser_line(),
2405 )
2406 {
2407 return;
2408 }
2409 Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
2410 source,
2411 &UrlExtraData(doc.base_url().get_arc()),
2412 win.css_error_reporter(),
2413 doc.quirks_mode(),
2414 CssRuleType::Style,
2415 )))
2416 };
2417
2418 Some(block)
2419 },
2420 AttributeMutation::Removed => None,
2421 };
2422 }
2423
2424 fn set_attribute_node(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
2428 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2432 self.namespace(),
2433 self.local_name(),
2434 attr.local_name(),
2435 Some(attr.namespace()),
2436 TrustedTypeOrString::String(attr.Value()),
2437 &self.owner_global(),
2438 can_gc,
2439 )?;
2440
2441 if let Some(owner) = attr.GetOwnerElement() {
2444 if &*owner != self {
2445 return Err(Error::InUseAttribute);
2446 }
2447 }
2448
2449 let vtable = vtable_for(self.upcast());
2450
2451 attr.swap_value(
2457 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2458 );
2459
2460 let position = self.attrs.borrow().iter().position(|old_attr| {
2462 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2463 });
2464
2465 let old_attr = if let Some(position) = position {
2466 let old_attr = DomRoot::from_ref(&*self.attrs.borrow()[position]);
2467
2468 if &*old_attr == attr {
2470 return Ok(Some(DomRoot::from_ref(attr)));
2471 }
2472
2473 self.will_mutate_attr(attr);
2483 self.attrs.borrow_mut()[position] = Dom::from_ref(attr);
2484 attr.set_owner(Some(self));
2486 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2488 old_attr.set_owner(None);
2490 self.handle_attribute_changes(
2492 attr,
2493 Some(&old_attr.value()),
2494 Some(verified_value),
2495 AttributeMutationReason::Directly,
2496 can_gc,
2497 );
2498
2499 Some(old_attr)
2500 } else {
2501 attr.set_owner(Some(self));
2503 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2504 self.push_attribute(attr, AttributeMutationReason::Directly, can_gc);
2505
2506 None
2507 };
2508
2509 Ok(old_attr)
2511 }
2512
2513 pub(crate) fn update_nonce_internal_slot(&self, nonce: String) {
2515 self.ensure_rare_data().cryptographic_nonce = nonce;
2516 }
2517
2518 pub(crate) fn nonce_value(&self) -> String {
2520 match self.rare_data().as_ref() {
2521 None => String::new(),
2522 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2523 }
2524 }
2525
2526 pub(crate) fn update_nonce_post_connection(&self) {
2528 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2531 return;
2532 }
2533 let global = self.owner_global();
2534 let csp_list = match global.get_csp_list() {
2536 None => return,
2537 Some(csp_list) => csp_list,
2538 };
2539 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2542 self.get_string_attribute(&local_name!("nonce")).is_empty()
2543 {
2544 return;
2545 }
2546 let nonce = self.nonce_value();
2548 self.set_string_attribute(&local_name!("nonce"), "".into(), CanGc::note());
2550 self.update_nonce_internal_slot(nonce);
2552 }
2553
2554 pub(crate) fn nonce_value_if_nonceable(&self) -> Option<String> {
2556 if !self.has_attribute(&local_name!("nonce")) {
2558 return None;
2559 }
2560 if self.downcast::<HTMLScriptElement>().is_some() {
2562 for attr in self.attrs().iter() {
2563 let attr_name = attr.name().to_ascii_lowercase();
2566 if attr_name.contains("<script") || attr_name.contains("<style") {
2567 return None;
2568 }
2569 let attr_value = attr.value().to_ascii_lowercase();
2572 if attr_value.contains("<script") || attr_value.contains("<style") {
2573 return None;
2574 }
2575 }
2576 }
2577 Some(self.nonce_value().trim().to_owned())
2582 }
2583
2584 pub(crate) fn insert_adjacent(
2586 &self,
2587 where_: AdjacentPosition,
2588 node: &Node,
2589 can_gc: CanGc,
2590 ) -> Fallible<Option<DomRoot<Node>>> {
2591 let self_node = self.upcast::<Node>();
2592 match where_ {
2593 AdjacentPosition::BeforeBegin => {
2594 if let Some(parent) = self_node.GetParentNode() {
2595 Node::pre_insert(node, &parent, Some(self_node), can_gc).map(Some)
2596 } else {
2597 Ok(None)
2598 }
2599 },
2600 AdjacentPosition::AfterBegin => Node::pre_insert(
2601 node,
2602 self_node,
2603 self_node.GetFirstChild().as_deref(),
2604 can_gc,
2605 )
2606 .map(Some),
2607 AdjacentPosition::BeforeEnd => {
2608 Node::pre_insert(node, self_node, None, can_gc).map(Some)
2609 },
2610 AdjacentPosition::AfterEnd => {
2611 if let Some(parent) = self_node.GetParentNode() {
2612 Node::pre_insert(node, &parent, self_node.GetNextSibling().as_deref(), can_gc)
2613 .map(Some)
2614 } else {
2615 Ok(None)
2616 }
2617 },
2618 }
2619 }
2620
2621 pub(crate) fn scroll(&self, x: f64, y: f64, behavior: ScrollBehavior) {
2626 let x = if x.is_finite() { x } else { 0.0 } as f32;
2628 let y = if y.is_finite() { y } else { 0.0 } as f32;
2629
2630 let node = self.upcast::<Node>();
2631
2632 let doc = node.owner_doc();
2634
2635 if !doc.is_fully_active() {
2637 return;
2638 }
2639
2640 let win = match doc.GetDefaultView() {
2642 None => return,
2643 Some(win) => win,
2644 };
2645
2646 if *self.root_element() == *self {
2648 if doc.quirks_mode() != QuirksMode::Quirks {
2649 win.scroll(x, y, behavior);
2650 }
2651
2652 return;
2653 }
2654
2655 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2657 doc.quirks_mode() == QuirksMode::Quirks &&
2658 !self.is_potentially_scrollable_body()
2659 {
2660 win.scroll(x, y, behavior);
2661 return;
2662 }
2663
2664 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
2666 return;
2667 }
2668
2669 win.scroll_an_element(self, x, y, behavior);
2671 }
2672
2673 pub(crate) fn parse_fragment(
2675 &self,
2676 markup: DOMString,
2677 can_gc: CanGc,
2678 ) -> Fallible<DomRoot<DocumentFragment>> {
2679 let new_children = ServoParser::parse_html_fragment(self, markup, false, can_gc);
2682 let context_document = {
2685 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2686 template.Content(can_gc).upcast::<Node>().owner_doc()
2687 } else {
2688 self.owner_document()
2689 }
2690 };
2691 let fragment = DocumentFragment::new(&context_document, can_gc);
2692 for child in new_children {
2694 fragment
2695 .upcast::<Node>()
2696 .AppendChild(&child, can_gc)
2697 .unwrap();
2698 }
2699 Ok(fragment)
2701 }
2702
2703 pub(crate) fn fragment_parsing_context(
2706 owner_doc: &Document,
2707 element: Option<&Self>,
2708 can_gc: CanGc,
2709 ) -> DomRoot<Self> {
2710 match element {
2712 Some(elem)
2713 if elem.local_name() != &local_name!("html") ||
2717 !elem.html_element_in_html_document() =>
2718 {
2719 DomRoot::from_ref(elem)
2720 },
2721 _ => Element::create(
2724 QualName::new(None, ns!(html), local_name!("body")),
2725 None,
2726 owner_doc,
2727 ElementCreator::ScriptCreated,
2728 CustomElementCreationMode::Asynchronous,
2729 None,
2730 can_gc,
2731 ),
2732 }
2733 }
2734
2735 pub(crate) fn fullscreen_element_ready_check(&self) -> bool {
2737 if !self.is_connected() {
2738 return false;
2739 }
2740 self.owner_document().get_allow_fullscreen()
2741 }
2742
2743 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2745 where
2746 T: DerivedFrom<Element> + DomObject,
2747 {
2748 let other = other.upcast::<Element>();
2749 self.root_element() == other.root_element()
2750 }
2751
2752 pub(crate) fn get_id(&self) -> Option<Atom> {
2753 self.id_attribute.borrow().clone()
2754 }
2755
2756 pub(crate) fn get_name(&self) -> Option<Atom> {
2757 self.rare_data().as_ref()?.name_attribute.clone()
2758 }
2759
2760 fn is_sequentially_focusable(&self) -> bool {
2761 let element = self.upcast::<Element>();
2762 let node = self.upcast::<Node>();
2763 if !node.is_connected() {
2764 return false;
2765 }
2766
2767 if element.has_attribute(&local_name!("hidden")) {
2768 return false;
2769 }
2770
2771 if self.disabled_state() {
2772 return false;
2773 }
2774
2775 if element.has_attribute(&local_name!("tabindex")) {
2776 return true;
2777 }
2778
2779 match node.type_id() {
2780 NodeTypeId::Element(ElementTypeId::HTMLElement(
2782 HTMLElementTypeId::HTMLButtonElement,
2783 )) |
2784 NodeTypeId::Element(ElementTypeId::HTMLElement(
2785 HTMLElementTypeId::HTMLSelectElement,
2786 )) |
2787 NodeTypeId::Element(ElementTypeId::HTMLElement(
2788 HTMLElementTypeId::HTMLIFrameElement,
2789 )) |
2790 NodeTypeId::Element(ElementTypeId::HTMLElement(
2791 HTMLElementTypeId::HTMLTextAreaElement,
2792 )) => true,
2793
2794 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) |
2796 NodeTypeId::Element(ElementTypeId::HTMLElement(
2797 HTMLElementTypeId::HTMLAnchorElement,
2798 )) => element.has_attribute(&local_name!("href")),
2799
2800 _ => {
2803 element.get_string_attribute(&local_name!("draggable")) == "true"
2805 },
2806 }
2807 }
2808
2809 pub(crate) fn update_sequentially_focusable_status(&self, can_gc: CanGc) {
2810 let node = self.upcast::<Node>();
2811 let is_sequentially_focusable = self.is_sequentially_focusable();
2812 node.set_flag(NodeFlags::SEQUENTIALLY_FOCUSABLE, is_sequentially_focusable);
2813
2814 if !is_sequentially_focusable {
2816 self.owner_document().perform_focus_fixup_rule(self, can_gc);
2817 }
2818 }
2819
2820 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2821 self.rare_data()
2822 .as_ref()?
2823 .element_internals
2824 .as_ref()
2825 .map(|sr| DomRoot::from_ref(&**sr))
2826 }
2827
2828 pub(crate) fn ensure_element_internals(&self, can_gc: CanGc) -> DomRoot<ElementInternals> {
2829 let mut rare_data = self.ensure_rare_data();
2830 DomRoot::from_ref(rare_data.element_internals.get_or_insert_with(|| {
2831 let elem = self
2832 .downcast::<HTMLElement>()
2833 .expect("ensure_element_internals should only be called for an HTMLElement");
2834 Dom::from_ref(&*ElementInternals::new(elem, can_gc))
2835 }))
2836 }
2837
2838 pub(crate) fn outer_html(&self, can_gc: CanGc) -> Fallible<DOMString> {
2839 match self.GetOuterHTML(can_gc)? {
2840 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2841 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2842 }
2843 }
2844
2845 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2846 SourcePosition {
2847 source_file: self.owner_global().get_url().to_string(),
2848 line_number: line_number + 2,
2849 column_number: 0,
2850 }
2851 }
2852}
2853
2854#[allow(non_snake_case)]
2855impl ElementMethods<crate::DomTypeHolder> for Element {
2856 fn GetNamespaceURI(&self) -> Option<DOMString> {
2858 Node::namespace_to_string(self.namespace.clone())
2859 }
2860
2861 fn LocalName(&self) -> DOMString {
2863 DOMString::from(&*self.local_name)
2865 }
2866
2867 fn GetPrefix(&self) -> Option<DOMString> {
2869 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2870 }
2871
2872 fn TagName(&self) -> DOMString {
2874 let name = self.tag_name.or_init(|| {
2875 let qualified_name = match *self.prefix.borrow() {
2876 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2877 None => Cow::Borrowed(&*self.local_name),
2878 };
2879 if self.html_element_in_html_document() {
2880 LocalName::from(qualified_name.to_ascii_uppercase())
2881 } else {
2882 LocalName::from(qualified_name)
2883 }
2884 });
2885 DOMString::from(&*name)
2886 }
2887
2888 fn Id(&self) -> DOMString {
2892 self.get_string_attribute(&local_name!("id"))
2893 }
2894
2895 fn SetId(&self, id: DOMString, can_gc: CanGc) {
2897 self.set_atomic_attribute(&local_name!("id"), id, can_gc);
2898 }
2899
2900 fn ClassName(&self) -> DOMString {
2902 self.get_string_attribute(&local_name!("class"))
2903 }
2904
2905 fn SetClassName(&self, class: DOMString, can_gc: CanGc) {
2907 self.set_tokenlist_attribute(&local_name!("class"), class, can_gc);
2908 }
2909
2910 fn ClassList(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
2912 self.class_list
2913 .or_init(|| DOMTokenList::new(self, &local_name!("class"), None, can_gc))
2914 }
2915
2916 make_getter!(Slot, "slot");
2918
2919 make_setter!(SetSlot, "slot");
2921
2922 fn Attributes(&self, can_gc: CanGc) -> DomRoot<NamedNodeMap> {
2924 self.attr_list
2925 .or_init(|| NamedNodeMap::new(&self.owner_window(), self, can_gc))
2926 }
2927
2928 fn HasAttributes(&self) -> bool {
2930 !self.attrs.borrow().is_empty()
2931 }
2932
2933 fn GetAttributeNames(&self) -> Vec<DOMString> {
2935 self.attrs.borrow().iter().map(|attr| attr.Name()).collect()
2936 }
2937
2938 fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
2940 self.GetAttributeNode(name).map(|s| s.Value())
2941 }
2942
2943 fn GetAttributeNS(
2945 &self,
2946 namespace: Option<DOMString>,
2947 local_name: DOMString,
2948 ) -> Option<DOMString> {
2949 self.GetAttributeNodeNS(namespace, local_name)
2950 .map(|attr| attr.Value())
2951 }
2952
2953 fn GetAttributeNode(&self, name: DOMString) -> Option<DomRoot<Attr>> {
2955 self.get_attribute_by_name(name)
2956 }
2957
2958 fn GetAttributeNodeNS(
2960 &self,
2961 namespace: Option<DOMString>,
2962 local_name: DOMString,
2963 ) -> Option<DomRoot<Attr>> {
2964 let namespace = &namespace_from_domstring(namespace);
2965 self.get_attribute(namespace, &LocalName::from(local_name))
2966 }
2967
2968 fn ToggleAttribute(
2970 &self,
2971 name: DOMString,
2972 force: Option<bool>,
2973 can_gc: CanGc,
2974 ) -> Fallible<bool> {
2975 if !is_valid_attribute_local_name(&name.str()) {
2978 return Err(Error::InvalidCharacter(None));
2979 }
2980
2981 let attribute = self.GetAttribute(name.clone());
2983
2984 let name = self.parsed_name(name);
2986 match attribute {
2987 None => match force {
2989 None | Some(true) => {
2991 self.set_first_matching_attribute(
2992 name.clone(),
2993 AttrValue::String(String::new()),
2994 name.clone(),
2995 ns!(),
2996 None,
2997 |attr| *attr.name() == name,
2998 can_gc,
2999 );
3000 Ok(true)
3001 },
3002 Some(false) => Ok(false),
3004 },
3005 Some(_index) => match force {
3006 None | Some(false) => {
3008 self.remove_attribute_by_name(&name, can_gc);
3009 Ok(false)
3010 },
3011 Some(true) => Ok(true),
3013 },
3014 }
3015 }
3016
3017 fn SetAttribute(
3019 &self,
3020 name: DOMString,
3021 value: TrustedTypeOrString,
3022 can_gc: CanGc,
3023 ) -> ErrorResult {
3024 if !is_valid_attribute_local_name(&name.str()) {
3027 return Err(Error::InvalidCharacter(None));
3028 }
3029
3030 let name = self.parsed_name(name);
3033
3034 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3038 self.namespace(),
3039 self.local_name(),
3040 &name,
3041 None,
3042 value,
3043 &self.owner_global(),
3044 can_gc,
3045 )?;
3046
3047 let value = self.parse_attribute(&ns!(), &name, value);
3052 self.set_first_matching_attribute(
3053 name.clone(),
3054 value,
3055 name.clone(),
3056 ns!(),
3057 None,
3058 |attr| *attr.name() == name,
3059 can_gc,
3060 );
3061 Ok(())
3062 }
3063
3064 fn SetAttributeNS(
3066 &self,
3067 namespace: Option<DOMString>,
3068 qualified_name: DOMString,
3069 value: TrustedTypeOrString,
3070 can_gc: CanGc,
3071 ) -> ErrorResult {
3072 let (namespace, prefix, local_name) =
3074 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3075 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3078 self.namespace(),
3079 self.local_name(),
3080 &local_name,
3081 Some(&namespace),
3082 value,
3083 &self.owner_global(),
3084 can_gc,
3085 )?;
3086 let value = self.parse_attribute(&namespace, &local_name, value);
3088 self.set_first_matching_attribute(
3089 local_name.clone(),
3090 value,
3091 LocalName::from(qualified_name),
3092 namespace.clone(),
3093 prefix,
3094 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
3095 can_gc,
3096 );
3097 Ok(())
3098 }
3099
3100 fn SetAttributeNode(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
3102 self.set_attribute_node(attr, can_gc)
3103 }
3104
3105 fn SetAttributeNodeNS(&self, attr: &Attr, can_gc: CanGc) -> Fallible<Option<DomRoot<Attr>>> {
3107 self.set_attribute_node(attr, can_gc)
3108 }
3109
3110 fn RemoveAttribute(&self, name: DOMString, can_gc: CanGc) {
3112 let name = self.parsed_name(name);
3113 self.remove_attribute_by_name(&name, can_gc);
3114 }
3115
3116 fn RemoveAttributeNS(
3118 &self,
3119 namespace: Option<DOMString>,
3120 local_name: DOMString,
3121 can_gc: CanGc,
3122 ) {
3123 let namespace = namespace_from_domstring(namespace);
3124 let local_name = LocalName::from(local_name);
3125 self.remove_attribute(&namespace, &local_name, can_gc);
3126 }
3127
3128 fn RemoveAttributeNode(&self, attr: &Attr, can_gc: CanGc) -> Fallible<DomRoot<Attr>> {
3130 self.remove_first_matching_attribute(|a| a == attr, can_gc)
3131 .ok_or(Error::NotFound(None))
3132 }
3133
3134 fn HasAttribute(&self, name: DOMString) -> bool {
3136 self.GetAttribute(name).is_some()
3137 }
3138
3139 fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
3141 self.GetAttributeNS(namespace, local_name).is_some()
3142 }
3143
3144 fn GetElementsByTagName(&self, localname: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3146 let window = self.owner_window();
3147 HTMLCollection::by_qualified_name(
3148 &window,
3149 self.upcast(),
3150 LocalName::from(localname),
3151 can_gc,
3152 )
3153 }
3154
3155 fn GetElementsByTagNameNS(
3157 &self,
3158 maybe_ns: Option<DOMString>,
3159 localname: DOMString,
3160 can_gc: CanGc,
3161 ) -> DomRoot<HTMLCollection> {
3162 let window = self.owner_window();
3163 HTMLCollection::by_tag_name_ns(&window, self.upcast(), localname, maybe_ns, can_gc)
3164 }
3165
3166 fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3168 let window = self.owner_window();
3169 HTMLCollection::by_class_name(&window, self.upcast(), classes, can_gc)
3170 }
3171
3172 fn GetClientRects(&self, can_gc: CanGc) -> DomRoot<DOMRectList> {
3174 let win = self.owner_window();
3175 let raw_rects = self.upcast::<Node>().border_boxes();
3176 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3177 .iter()
3178 .map(|rect| {
3179 DOMRect::new(
3180 win.upcast(),
3181 rect.origin.x.to_f64_px(),
3182 rect.origin.y.to_f64_px(),
3183 rect.size.width.to_f64_px(),
3184 rect.size.height.to_f64_px(),
3185 can_gc,
3186 )
3187 })
3188 .collect();
3189 DOMRectList::new(&win, rects, can_gc)
3190 }
3191
3192 fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot<DOMRect> {
3194 let win = self.owner_window();
3195 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3196 DOMRect::new(
3197 win.upcast(),
3198 rect.origin.x.to_f64_px(),
3199 rect.origin.y.to_f64_px(),
3200 rect.size.width.to_f64_px(),
3201 rect.size.height.to_f64_px(),
3202 can_gc,
3203 )
3204 }
3205
3206 fn Scroll(&self, options: &ScrollToOptions) {
3208 let left = options.left.unwrap_or(self.ScrollLeft());
3210 let top = options.top.unwrap_or(self.ScrollTop());
3211 self.scroll(left, top, options.parent.behavior);
3212 }
3213
3214 fn Scroll_(&self, x: f64, y: f64) {
3216 self.scroll(x, y, ScrollBehavior::Auto);
3217 }
3218
3219 fn ScrollTo(&self, options: &ScrollToOptions) {
3221 self.Scroll(options);
3222 }
3223
3224 fn ScrollTo_(&self, x: f64, y: f64) {
3226 self.Scroll_(x, y);
3227 }
3228
3229 fn ScrollBy(&self, options: &ScrollToOptions) {
3231 let delta_left = options.left.unwrap_or(0.0f64);
3233 let delta_top = options.top.unwrap_or(0.0f64);
3234 let left = self.ScrollLeft();
3235 let top = self.ScrollTop();
3236 self.scroll(left + delta_left, top + delta_top, options.parent.behavior);
3237 }
3238
3239 fn ScrollBy_(&self, x: f64, y: f64) {
3241 let left = self.ScrollLeft();
3242 let top = self.ScrollTop();
3243 self.scroll(left + x, top + y, ScrollBehavior::Auto);
3244 }
3245
3246 fn ScrollTop(&self) -> f64 {
3248 let node = self.upcast::<Node>();
3249
3250 let doc = node.owner_doc();
3252
3253 if !doc.is_fully_active() {
3255 return 0.0;
3256 }
3257
3258 let win = match doc.GetDefaultView() {
3260 None => return 0.0,
3261 Some(win) => win,
3262 };
3263
3264 if *self.root_element() == *self {
3266 if doc.quirks_mode() == QuirksMode::Quirks {
3267 return 0.0;
3268 }
3269
3270 return win.ScrollY() as f64;
3272 }
3273
3274 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3276 doc.quirks_mode() == QuirksMode::Quirks &&
3277 !self.is_potentially_scrollable_body()
3278 {
3279 return win.ScrollY() as f64;
3280 }
3281
3282 if !self.has_css_layout_box() {
3284 return 0.0;
3285 }
3286
3287 let point = win.scroll_offset_query(node);
3289 point.y.abs() as f64
3290 }
3291
3292 fn SetScrollTop(&self, y_: f64) {
3295 let behavior = ScrollBehavior::Auto;
3296
3297 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3299
3300 let node = self.upcast::<Node>();
3301
3302 let doc = node.owner_doc();
3304
3305 if !doc.is_fully_active() {
3307 return;
3308 }
3309
3310 let win = match doc.GetDefaultView() {
3312 None => return,
3313 Some(win) => win,
3314 };
3315
3316 if *self.root_element() == *self {
3318 if doc.quirks_mode() != QuirksMode::Quirks {
3319 win.scroll(win.ScrollX() as f32, y, behavior);
3320 }
3321
3322 return;
3323 }
3324
3325 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3327 doc.quirks_mode() == QuirksMode::Quirks &&
3328 !self.is_potentially_scrollable_body()
3329 {
3330 win.scroll(win.ScrollX() as f32, y, behavior);
3331 return;
3332 }
3333
3334 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3336 return;
3337 }
3338
3339 win.scroll_an_element(self, self.ScrollLeft() as f32, y, behavior);
3341 }
3342
3343 fn ScrollLeft(&self) -> f64 {
3345 let node = self.upcast::<Node>();
3346
3347 let doc = node.owner_doc();
3349
3350 if !doc.is_fully_active() {
3352 return 0.0;
3353 }
3354
3355 let win = match doc.GetDefaultView() {
3357 None => return 0.0,
3358 Some(win) => win,
3359 };
3360
3361 if *self.root_element() == *self {
3363 if doc.quirks_mode() != QuirksMode::Quirks {
3364 return win.ScrollX() as f64;
3366 }
3367
3368 return 0.0;
3369 }
3370
3371 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3373 doc.quirks_mode() == QuirksMode::Quirks &&
3374 !self.is_potentially_scrollable_body()
3375 {
3376 return win.ScrollX() as f64;
3377 }
3378
3379 if !self.has_css_layout_box() {
3381 return 0.0;
3382 }
3383
3384 let point = win.scroll_offset_query(node);
3386 point.x.abs() as f64
3387 }
3388
3389 fn SetScrollLeft(&self, x: f64) {
3391 let behavior = ScrollBehavior::Auto;
3392
3393 let x = if x.is_finite() { x } else { 0.0 } as f32;
3395
3396 let node = self.upcast::<Node>();
3397
3398 let doc = node.owner_doc();
3400
3401 if !doc.is_fully_active() {
3403 return;
3404 }
3405
3406 let win = match doc.GetDefaultView() {
3408 None => return,
3409 Some(win) => win,
3410 };
3411
3412 if *self.root_element() == *self {
3414 if doc.quirks_mode() == QuirksMode::Quirks {
3415 return;
3416 }
3417
3418 win.scroll(x, win.ScrollY() as f32, behavior);
3419 return;
3420 }
3421
3422 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3424 doc.quirks_mode() == QuirksMode::Quirks &&
3425 !self.is_potentially_scrollable_body()
3426 {
3427 win.scroll(x, win.ScrollY() as f32, behavior);
3428 return;
3429 }
3430
3431 if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() {
3433 return;
3434 }
3435
3436 win.scroll_an_element(self, x, self.ScrollTop() as f32, behavior);
3438 }
3439
3440 fn ScrollIntoView(&self, arg: BooleanOrScrollIntoViewOptions) {
3442 let (behavior, block, inline, container) = match arg {
3443 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3445 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3450 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3453 options.parent.behavior,
3454 options.block,
3455 options.inline,
3456 if options.container == ScrollIntoViewContainer::Nearest {
3459 Some(self)
3460 } else {
3461 None
3462 },
3463 ),
3464 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3466 ScrollBehavior::Auto,
3467 ScrollLogicalPosition::End,
3468 ScrollLogicalPosition::Nearest,
3469 None,
3470 ),
3471 };
3472
3473 if !self.has_css_layout_box() {
3476 return;
3477 }
3478
3479 self.scroll_into_view_with_options(behavior, block, inline, container, None);
3481
3482 }
3485
3486 fn ScrollWidth(&self) -> i32 {
3488 self.upcast::<Node>().scroll_area().size.width
3489 }
3490
3491 fn ScrollHeight(&self) -> i32 {
3493 self.upcast::<Node>().scroll_area().size.height
3494 }
3495
3496 fn ClientTop(&self) -> i32 {
3498 self.client_rect().origin.y
3499 }
3500
3501 fn ClientLeft(&self) -> i32 {
3503 self.client_rect().origin.x
3504 }
3505
3506 fn ClientWidth(&self) -> i32 {
3508 self.client_rect().size.width
3509 }
3510
3511 fn ClientHeight(&self) -> i32 {
3513 self.client_rect().size.height
3514 }
3515
3516 fn CurrentCSSZoom(&self) -> Finite<f64> {
3518 let window = self.owner_window();
3519 Finite::wrap(window.current_css_zoom_query(self.upcast::<Node>()) as f64)
3520 }
3521
3522 fn SetHTMLUnsafe(&self, html: TrustedHTMLOrString, can_gc: CanGc) -> ErrorResult {
3524 let html = TrustedHTML::get_trusted_script_compliant_string(
3528 &self.owner_global(),
3529 html,
3530 "Element setHTMLUnsafe",
3531 can_gc,
3532 )?;
3533 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3535 DomRoot::upcast(template.Content(can_gc))
3536 } else {
3537 DomRoot::from_ref(self.upcast())
3538 };
3539
3540 Node::unsafely_set_html(&target, self, html, can_gc);
3542 Ok(())
3543 }
3544
3545 fn GetHTML(&self, options: &GetHTMLOptions, can_gc: CanGc) -> DOMString {
3547 self.upcast::<Node>().html_serialize(
3550 TraversalScope::ChildrenOnly(None),
3551 options.serializableShadowRoots,
3552 options.shadowRoots.clone(),
3553 can_gc,
3554 )
3555 }
3556
3557 fn GetInnerHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3559 let qname = QualName::new(
3560 self.prefix().clone(),
3561 self.namespace().clone(),
3562 self.local_name().clone(),
3563 );
3564
3565 let result = if self.owner_document().is_html_document() {
3568 self.upcast::<Node>()
3569 .html_serialize(ChildrenOnly(Some(qname)), false, vec![], can_gc)
3570 } else {
3571 self.upcast::<Node>()
3572 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3573 };
3574
3575 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3576 }
3577
3578 fn SetInnerHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3580 let value = TrustedHTML::get_trusted_script_compliant_string(
3584 &self.owner_global(),
3585 value.convert(),
3586 "Element innerHTML",
3587 can_gc,
3588 )?;
3589 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3591 DomRoot::upcast(template.Content(can_gc))
3594 } else {
3595 DomRoot::from_ref(self.upcast())
3597 };
3598
3599 if !self.node.has_weird_parser_insertion_mode() &&
3602 value.len() < 100 &&
3603 !value
3604 .as_bytes()
3605 .iter()
3606 .any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
3607 {
3608 return Node::SetTextContent(&target, Some(value), can_gc);
3609 }
3610
3611 let frag = self.parse_fragment(value, can_gc)?;
3614
3615 Node::replace_all(Some(frag.upcast()), &target, can_gc);
3617 Ok(())
3618 }
3619
3620 fn GetOuterHTML(&self, can_gc: CanGc) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3622 let result = if self.owner_document().is_html_document() {
3625 self.upcast::<Node>()
3626 .html_serialize(IncludeNode, false, vec![], can_gc)
3627 } else {
3628 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3629 };
3630
3631 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3632 }
3633
3634 fn SetOuterHTML(&self, value: TrustedHTMLOrNullIsEmptyString, can_gc: CanGc) -> ErrorResult {
3636 let value = TrustedHTML::get_trusted_script_compliant_string(
3640 &self.owner_global(),
3641 value.convert(),
3642 "Element outerHTML",
3643 can_gc,
3644 )?;
3645 let context_document = self.owner_document();
3646 let context_node = self.upcast::<Node>();
3647 let context_parent = match context_node.GetParentNode() {
3649 None => {
3650 return Ok(());
3653 },
3654 Some(parent) => parent,
3655 };
3656
3657 let parent = match context_parent.type_id() {
3658 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed),
3660
3661 NodeTypeId::DocumentFragment(_) => {
3664 let body_elem = Element::create(
3665 QualName::new(None, ns!(html), local_name!("body")),
3666 None,
3667 &context_document,
3668 ElementCreator::ScriptCreated,
3669 CustomElementCreationMode::Synchronous,
3670 None,
3671 can_gc,
3672 );
3673 DomRoot::upcast(body_elem)
3674 },
3675 _ => context_node.GetParentElement().unwrap(),
3676 };
3677
3678 let frag = parent.parse_fragment(value, can_gc)?;
3681 context_parent.ReplaceChild(frag.upcast(), context_node, can_gc)?;
3683 Ok(())
3684 }
3685
3686 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3688 self.upcast::<Node>()
3689 .preceding_siblings()
3690 .find_map(DomRoot::downcast)
3691 }
3692
3693 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3695 self.upcast::<Node>()
3696 .following_siblings()
3697 .find_map(DomRoot::downcast)
3698 }
3699
3700 fn Children(&self, can_gc: CanGc) -> DomRoot<HTMLCollection> {
3702 let window = self.owner_window();
3703 HTMLCollection::children(&window, self.upcast(), can_gc)
3704 }
3705
3706 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3708 self.upcast::<Node>().child_elements().next()
3709 }
3710
3711 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3713 self.upcast::<Node>()
3714 .rev_children()
3715 .find_map(DomRoot::downcast::<Element>)
3716 }
3717
3718 fn ChildElementCount(&self) -> u32 {
3720 self.upcast::<Node>().child_elements().count() as u32
3721 }
3722
3723 fn Prepend(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3725 self.upcast::<Node>().prepend(nodes, can_gc)
3726 }
3727
3728 fn Append(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3730 self.upcast::<Node>().append(nodes, can_gc)
3731 }
3732
3733 fn ReplaceChildren(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3735 self.upcast::<Node>().replace_children(nodes, can_gc)
3736 }
3737
3738 fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3740 let root = self.upcast::<Node>();
3741 root.query_selector(selectors)
3742 }
3743
3744 fn QuerySelectorAll(&self, selectors: DOMString) -> Fallible<DomRoot<NodeList>> {
3746 let root = self.upcast::<Node>();
3747 root.query_selector_all(selectors)
3748 }
3749
3750 fn Before(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3752 self.upcast::<Node>().before(nodes, can_gc)
3753 }
3754
3755 fn After(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3757 self.upcast::<Node>().after(nodes, can_gc)
3758 }
3759
3760 fn ReplaceWith(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
3762 self.upcast::<Node>().replace_with(nodes, can_gc)
3763 }
3764
3765 fn Remove(&self, can_gc: CanGc) {
3767 self.upcast::<Node>().remove_self(can_gc);
3768 }
3769
3770 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3772 let doc = self.owner_document();
3773 let url = doc.url();
3774 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3775 &selectors.str(),
3776 &UrlExtraData(url.get_arc()),
3777 ) {
3778 Err(_) => return Err(Error::Syntax(None)),
3779 Ok(selectors) => selectors,
3780 };
3781
3782 let quirks_mode = doc.quirks_mode();
3783 let element = DomRoot::from_ref(self);
3784
3785 Ok(dom_apis::element_matches(
3786 &SelectorWrapper::Borrowed(&element),
3787 &selectors,
3788 quirks_mode,
3789 ))
3790 }
3791
3792 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3794 self.Matches(selectors)
3795 }
3796
3797 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3799 let doc = self.owner_document();
3800 let url = doc.url();
3801 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3802 &selectors.str(),
3803 &UrlExtraData(url.get_arc()),
3804 ) {
3805 Err(_) => return Err(Error::Syntax(None)),
3806 Ok(selectors) => selectors,
3807 };
3808
3809 let quirks_mode = doc.quirks_mode();
3810 Ok(dom_apis::element_closest(
3811 SelectorWrapper::Owned(DomRoot::from_ref(self)),
3812 &selectors,
3813 quirks_mode,
3814 )
3815 .map(SelectorWrapper::into_owned))
3816 }
3817
3818 fn InsertAdjacentElement(
3820 &self,
3821 where_: DOMString,
3822 element: &Element,
3823 can_gc: CanGc,
3824 ) -> Fallible<Option<DomRoot<Element>>> {
3825 let where_ = where_.parse::<AdjacentPosition>()?;
3826 let inserted_node = self.insert_adjacent(where_, element.upcast(), can_gc)?;
3827 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3828 }
3829
3830 fn InsertAdjacentText(&self, where_: DOMString, data: DOMString, can_gc: CanGc) -> ErrorResult {
3832 let text = Text::new(data, &self.owner_document(), can_gc);
3834
3835 let where_ = where_.parse::<AdjacentPosition>()?;
3837 self.insert_adjacent(where_, text.upcast(), can_gc)
3838 .map(|_| ())
3839 }
3840
3841 fn InsertAdjacentHTML(
3843 &self,
3844 position: DOMString,
3845 text: TrustedHTMLOrString,
3846 can_gc: CanGc,
3847 ) -> ErrorResult {
3848 let text = TrustedHTML::get_trusted_script_compliant_string(
3852 &self.owner_global(),
3853 text,
3854 "Element insertAdjacentHTML",
3855 can_gc,
3856 )?;
3857 let position = position.parse::<AdjacentPosition>()?;
3858
3859 let context = match position {
3862 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
3865 match self.upcast::<Node>().GetParentNode() {
3866 Some(ref node) if node.is::<Document>() => {
3868 return Err(Error::NoModificationAllowed);
3869 },
3870 None => return Err(Error::NoModificationAllowed),
3871 Some(node) => node,
3873 }
3874 },
3875 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
3878 DomRoot::from_ref(self.upcast::<Node>())
3880 },
3881 };
3882
3883 let context = Element::fragment_parsing_context(
3885 &context.owner_doc(),
3886 context.downcast::<Element>(),
3887 can_gc,
3888 );
3889
3890 let fragment = context.parse_fragment(text, can_gc)?;
3893
3894 self.insert_adjacent(position, fragment.upcast(), can_gc)
3896 .map(|_| ())
3897 }
3898
3899 fn EnterFormalActivationState(&self) -> ErrorResult {
3901 match self.as_maybe_activatable() {
3902 Some(a) => {
3903 a.enter_formal_activation_state();
3904 Ok(())
3905 },
3906 None => Err(Error::NotSupported),
3907 }
3908 }
3909
3910 fn ExitFormalActivationState(&self) -> ErrorResult {
3911 match self.as_maybe_activatable() {
3912 Some(a) => {
3913 a.exit_formal_activation_state();
3914 Ok(())
3915 },
3916 None => Err(Error::NotSupported),
3917 }
3918 }
3919
3920 fn RequestFullscreen(&self, can_gc: CanGc) -> Rc<Promise> {
3922 let doc = self.owner_document();
3923 doc.enter_fullscreen(self, can_gc)
3924 }
3925
3926 fn AttachShadow(&self, init: &ShadowRootInit, can_gc: CanGc) -> Fallible<DomRoot<ShadowRoot>> {
3928 let shadow_root = self.attach_shadow(
3931 IsUserAgentWidget::No,
3932 init.mode,
3933 init.clonable,
3934 init.serializable,
3935 init.delegatesFocus,
3936 init.slotAssignment,
3937 can_gc,
3938 )?;
3939
3940 Ok(shadow_root)
3942 }
3943
3944 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
3946 let shadow_or_none = self.shadow_root();
3948
3949 let shadow = shadow_or_none?;
3951 if shadow.Mode() == ShadowRootMode::Closed {
3952 return None;
3953 }
3954
3955 Some(shadow)
3957 }
3958
3959 fn GetRole(&self) -> Option<DOMString> {
3960 self.get_nullable_string_attribute(&local_name!("role"))
3961 }
3962
3963 fn SetRole(&self, value: Option<DOMString>, can_gc: CanGc) {
3964 self.set_nullable_string_attribute(&local_name!("role"), value, can_gc);
3965 }
3966
3967 fn GetAriaAtomic(&self) -> Option<DOMString> {
3968 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
3969 }
3970
3971 fn SetAriaAtomic(&self, value: Option<DOMString>, can_gc: CanGc) {
3972 self.set_nullable_string_attribute(&local_name!("aria-atomic"), value, can_gc);
3973 }
3974
3975 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
3976 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
3977 }
3978
3979 fn SetAriaAutoComplete(&self, value: Option<DOMString>, can_gc: CanGc) {
3980 self.set_nullable_string_attribute(&local_name!("aria-autocomplete"), value, can_gc);
3981 }
3982
3983 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
3984 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
3985 }
3986
3987 fn SetAriaBrailleLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
3988 self.set_nullable_string_attribute(&local_name!("aria-braillelabel"), value, can_gc);
3989 }
3990
3991 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
3992 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
3993 }
3994
3995 fn SetAriaBrailleRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
3996 self.set_nullable_string_attribute(
3997 &local_name!("aria-brailleroledescription"),
3998 value,
3999 can_gc,
4000 );
4001 }
4002
4003 fn GetAriaBusy(&self) -> Option<DOMString> {
4004 self.get_nullable_string_attribute(&local_name!("aria-busy"))
4005 }
4006
4007 fn SetAriaBusy(&self, value: Option<DOMString>, can_gc: CanGc) {
4008 self.set_nullable_string_attribute(&local_name!("aria-busy"), value, can_gc);
4009 }
4010
4011 fn GetAriaChecked(&self) -> Option<DOMString> {
4012 self.get_nullable_string_attribute(&local_name!("aria-checked"))
4013 }
4014
4015 fn SetAriaChecked(&self, value: Option<DOMString>, can_gc: CanGc) {
4016 self.set_nullable_string_attribute(&local_name!("aria-checked"), value, can_gc);
4017 }
4018
4019 fn GetAriaColCount(&self) -> Option<DOMString> {
4020 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
4021 }
4022
4023 fn SetAriaColCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4024 self.set_nullable_string_attribute(&local_name!("aria-colcount"), value, can_gc);
4025 }
4026
4027 fn GetAriaColIndex(&self) -> Option<DOMString> {
4028 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4029 }
4030
4031 fn SetAriaColIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4032 self.set_nullable_string_attribute(&local_name!("aria-colindex"), value, can_gc);
4033 }
4034
4035 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4036 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4037 }
4038
4039 fn SetAriaColIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4040 self.set_nullable_string_attribute(&local_name!("aria-colindextext"), value, can_gc);
4041 }
4042
4043 fn GetAriaColSpan(&self) -> Option<DOMString> {
4044 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4045 }
4046
4047 fn SetAriaColSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4048 self.set_nullable_string_attribute(&local_name!("aria-colspan"), value, can_gc);
4049 }
4050
4051 fn GetAriaCurrent(&self) -> Option<DOMString> {
4052 self.get_nullable_string_attribute(&local_name!("aria-current"))
4053 }
4054
4055 fn SetAriaCurrent(&self, value: Option<DOMString>, can_gc: CanGc) {
4056 self.set_nullable_string_attribute(&local_name!("aria-current"), value, can_gc);
4057 }
4058
4059 fn GetAriaDescription(&self) -> Option<DOMString> {
4060 self.get_nullable_string_attribute(&local_name!("aria-description"))
4061 }
4062
4063 fn SetAriaDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4064 self.set_nullable_string_attribute(&local_name!("aria-description"), value, can_gc);
4065 }
4066
4067 fn GetAriaDisabled(&self) -> Option<DOMString> {
4068 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4069 }
4070
4071 fn SetAriaDisabled(&self, value: Option<DOMString>, can_gc: CanGc) {
4072 self.set_nullable_string_attribute(&local_name!("aria-disabled"), value, can_gc);
4073 }
4074
4075 fn GetAriaExpanded(&self) -> Option<DOMString> {
4076 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4077 }
4078
4079 fn SetAriaExpanded(&self, value: Option<DOMString>, can_gc: CanGc) {
4080 self.set_nullable_string_attribute(&local_name!("aria-expanded"), value, can_gc);
4081 }
4082
4083 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4084 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4085 }
4086
4087 fn SetAriaHasPopup(&self, value: Option<DOMString>, can_gc: CanGc) {
4088 self.set_nullable_string_attribute(&local_name!("aria-haspopup"), value, can_gc);
4089 }
4090
4091 fn GetAriaHidden(&self) -> Option<DOMString> {
4092 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4093 }
4094
4095 fn SetAriaHidden(&self, value: Option<DOMString>, can_gc: CanGc) {
4096 self.set_nullable_string_attribute(&local_name!("aria-hidden"), value, can_gc);
4097 }
4098
4099 fn GetAriaInvalid(&self) -> Option<DOMString> {
4100 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4101 }
4102
4103 fn SetAriaInvalid(&self, value: Option<DOMString>, can_gc: CanGc) {
4104 self.set_nullable_string_attribute(&local_name!("aria-invalid"), value, can_gc);
4105 }
4106
4107 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4108 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4109 }
4110
4111 fn SetAriaKeyShortcuts(&self, value: Option<DOMString>, can_gc: CanGc) {
4112 self.set_nullable_string_attribute(&local_name!("aria-keyshortcuts"), value, can_gc);
4113 }
4114
4115 fn GetAriaLabel(&self) -> Option<DOMString> {
4116 self.get_nullable_string_attribute(&local_name!("aria-label"))
4117 }
4118
4119 fn SetAriaLabel(&self, value: Option<DOMString>, can_gc: CanGc) {
4120 self.set_nullable_string_attribute(&local_name!("aria-label"), value, can_gc);
4121 }
4122
4123 fn GetAriaLevel(&self) -> Option<DOMString> {
4124 self.get_nullable_string_attribute(&local_name!("aria-level"))
4125 }
4126
4127 fn SetAriaLevel(&self, value: Option<DOMString>, can_gc: CanGc) {
4128 self.set_nullable_string_attribute(&local_name!("aria-level"), value, can_gc);
4129 }
4130
4131 fn GetAriaLive(&self) -> Option<DOMString> {
4132 self.get_nullable_string_attribute(&local_name!("aria-live"))
4133 }
4134
4135 fn SetAriaLive(&self, value: Option<DOMString>, can_gc: CanGc) {
4136 self.set_nullable_string_attribute(&local_name!("aria-live"), value, can_gc);
4137 }
4138
4139 fn GetAriaModal(&self) -> Option<DOMString> {
4140 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4141 }
4142
4143 fn SetAriaModal(&self, value: Option<DOMString>, can_gc: CanGc) {
4144 self.set_nullable_string_attribute(&local_name!("aria-modal"), value, can_gc);
4145 }
4146
4147 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4148 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4149 }
4150
4151 fn SetAriaMultiLine(&self, value: Option<DOMString>, can_gc: CanGc) {
4152 self.set_nullable_string_attribute(&local_name!("aria-multiline"), value, can_gc);
4153 }
4154
4155 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4156 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4157 }
4158
4159 fn SetAriaMultiSelectable(&self, value: Option<DOMString>, can_gc: CanGc) {
4160 self.set_nullable_string_attribute(&local_name!("aria-multiselectable"), value, can_gc);
4161 }
4162
4163 fn GetAriaOrientation(&self) -> Option<DOMString> {
4164 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4165 }
4166
4167 fn SetAriaOrientation(&self, value: Option<DOMString>, can_gc: CanGc) {
4168 self.set_nullable_string_attribute(&local_name!("aria-orientation"), value, can_gc);
4169 }
4170
4171 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4172 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4173 }
4174
4175 fn SetAriaPlaceholder(&self, value: Option<DOMString>, can_gc: CanGc) {
4176 self.set_nullable_string_attribute(&local_name!("aria-placeholder"), value, can_gc);
4177 }
4178
4179 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4180 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4181 }
4182
4183 fn SetAriaPosInSet(&self, value: Option<DOMString>, can_gc: CanGc) {
4184 self.set_nullable_string_attribute(&local_name!("aria-posinset"), value, can_gc);
4185 }
4186
4187 fn GetAriaPressed(&self) -> Option<DOMString> {
4188 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4189 }
4190
4191 fn SetAriaPressed(&self, value: Option<DOMString>, can_gc: CanGc) {
4192 self.set_nullable_string_attribute(&local_name!("aria-pressed"), value, can_gc);
4193 }
4194
4195 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4196 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4197 }
4198
4199 fn SetAriaReadOnly(&self, value: Option<DOMString>, can_gc: CanGc) {
4200 self.set_nullable_string_attribute(&local_name!("aria-readonly"), value, can_gc);
4201 }
4202
4203 fn GetAriaRelevant(&self) -> Option<DOMString> {
4204 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4205 }
4206
4207 fn SetAriaRelevant(&self, value: Option<DOMString>, can_gc: CanGc) {
4208 self.set_nullable_string_attribute(&local_name!("aria-relevant"), value, can_gc);
4209 }
4210
4211 fn GetAriaRequired(&self) -> Option<DOMString> {
4212 self.get_nullable_string_attribute(&local_name!("aria-required"))
4213 }
4214
4215 fn SetAriaRequired(&self, value: Option<DOMString>, can_gc: CanGc) {
4216 self.set_nullable_string_attribute(&local_name!("aria-required"), value, can_gc);
4217 }
4218
4219 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4220 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4221 }
4222
4223 fn SetAriaRoleDescription(&self, value: Option<DOMString>, can_gc: CanGc) {
4224 self.set_nullable_string_attribute(&local_name!("aria-roledescription"), value, can_gc);
4225 }
4226
4227 fn GetAriaRowCount(&self) -> Option<DOMString> {
4228 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4229 }
4230
4231 fn SetAriaRowCount(&self, value: Option<DOMString>, can_gc: CanGc) {
4232 self.set_nullable_string_attribute(&local_name!("aria-rowcount"), value, can_gc);
4233 }
4234
4235 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4236 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4237 }
4238
4239 fn SetAriaRowIndex(&self, value: Option<DOMString>, can_gc: CanGc) {
4240 self.set_nullable_string_attribute(&local_name!("aria-rowindex"), value, can_gc);
4241 }
4242
4243 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4244 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4245 }
4246
4247 fn SetAriaRowIndexText(&self, value: Option<DOMString>, can_gc: CanGc) {
4248 self.set_nullable_string_attribute(&local_name!("aria-rowindextext"), value, can_gc);
4249 }
4250
4251 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4252 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4253 }
4254
4255 fn SetAriaRowSpan(&self, value: Option<DOMString>, can_gc: CanGc) {
4256 self.set_nullable_string_attribute(&local_name!("aria-rowspan"), value, can_gc);
4257 }
4258
4259 fn GetAriaSelected(&self) -> Option<DOMString> {
4260 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4261 }
4262
4263 fn SetAriaSelected(&self, value: Option<DOMString>, can_gc: CanGc) {
4264 self.set_nullable_string_attribute(&local_name!("aria-selected"), value, can_gc);
4265 }
4266
4267 fn GetAriaSetSize(&self) -> Option<DOMString> {
4268 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4269 }
4270
4271 fn SetAriaSetSize(&self, value: Option<DOMString>, can_gc: CanGc) {
4272 self.set_nullable_string_attribute(&local_name!("aria-setsize"), value, can_gc);
4273 }
4274
4275 fn GetAriaSort(&self) -> Option<DOMString> {
4276 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4277 }
4278
4279 fn SetAriaSort(&self, value: Option<DOMString>, can_gc: CanGc) {
4280 self.set_nullable_string_attribute(&local_name!("aria-sort"), value, can_gc);
4281 }
4282
4283 fn GetAriaValueMax(&self) -> Option<DOMString> {
4284 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4285 }
4286
4287 fn SetAriaValueMax(&self, value: Option<DOMString>, can_gc: CanGc) {
4288 self.set_nullable_string_attribute(&local_name!("aria-valuemax"), value, can_gc);
4289 }
4290
4291 fn GetAriaValueMin(&self) -> Option<DOMString> {
4292 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4293 }
4294
4295 fn SetAriaValueMin(&self, value: Option<DOMString>, can_gc: CanGc) {
4296 self.set_nullable_string_attribute(&local_name!("aria-valuemin"), value, can_gc);
4297 }
4298
4299 fn GetAriaValueNow(&self) -> Option<DOMString> {
4300 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4301 }
4302
4303 fn SetAriaValueNow(&self, value: Option<DOMString>, can_gc: CanGc) {
4304 self.set_nullable_string_attribute(&local_name!("aria-valuenow"), value, can_gc);
4305 }
4306
4307 fn GetAriaValueText(&self) -> Option<DOMString> {
4308 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4309 }
4310
4311 fn SetAriaValueText(&self, value: Option<DOMString>, can_gc: CanGc) {
4312 self.set_nullable_string_attribute(&local_name!("aria-valuetext"), value, can_gc);
4313 }
4314
4315 fn GetAssignedSlot(&self) -> Option<DomRoot<HTMLSlotElement>> {
4317 let cx = GlobalScope::get_cx();
4318
4319 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4322 slottable.find_a_slot(true)
4323 }
4324
4325 fn Part(&self) -> DomRoot<DOMTokenList> {
4327 self.ensure_rare_data()
4328 .part
4329 .or_init(|| DOMTokenList::new(self, &local_name!("part"), None, CanGc::note()))
4330 }
4331}
4332
4333impl VirtualMethods for Element {
4334 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4335 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4336 }
4337
4338 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
4339 if attr.local_name() == &local_name!("lang") {
4341 return true;
4342 }
4343
4344 self.super_type()
4345 .unwrap()
4346 .attribute_affects_presentational_hints(attr)
4347 }
4348
4349 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
4350 self.super_type()
4351 .unwrap()
4352 .attribute_mutated(attr, mutation, can_gc);
4353 let node = self.upcast::<Node>();
4354 let doc = node.owner_doc();
4355 match attr.local_name() {
4356 &local_name!("tabindex") | &local_name!("draggable") | &local_name!("hidden") => {
4357 self.update_sequentially_focusable_status(can_gc)
4358 },
4359 &local_name!("style") => self.update_style_attribute(attr, mutation),
4360 &local_name!("id") => {
4361 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4363 let value = value.as_atom();
4364 if value != &atom!("") {
4365 Some(value.clone())
4367 } else {
4368 None
4370 }
4371 });
4372
4373 let containing_shadow_root = self.containing_shadow_root();
4374 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4375 let value = attr.value().as_atom().clone();
4376 match mutation {
4377 AttributeMutation::Set(old_value, _) => {
4378 if let Some(old_value) = old_value {
4379 let old_value = old_value.as_atom().clone();
4380 if let Some(ref shadow_root) = containing_shadow_root {
4381 shadow_root.unregister_element_id(self, old_value, can_gc);
4382 } else {
4383 doc.unregister_element_id(self, old_value, can_gc);
4384 }
4385 }
4386 if value != atom!("") {
4387 if let Some(ref shadow_root) = containing_shadow_root {
4388 shadow_root.register_element_id(self, value, can_gc);
4389 } else {
4390 doc.register_element_id(self, value, can_gc);
4391 }
4392 }
4393 },
4394 AttributeMutation::Removed => {
4395 if value != atom!("") {
4396 if let Some(ref shadow_root) = containing_shadow_root {
4397 shadow_root.unregister_element_id(self, value, can_gc);
4398 } else {
4399 doc.unregister_element_id(self, value, can_gc);
4400 }
4401 }
4402 },
4403 }
4404 }
4405 },
4406 &local_name!("name") => {
4407 self.ensure_rare_data().name_attribute =
4409 mutation.new_value(attr).and_then(|value| {
4410 let value = value.as_atom();
4411 if value != &atom!("") {
4412 Some(value.clone())
4413 } else {
4414 None
4415 }
4416 });
4417 if node.is_connected() && node.containing_shadow_root().is_none() {
4420 let value = attr.value().as_atom().clone();
4421 match mutation {
4422 AttributeMutation::Set(old_value, _) => {
4423 if let Some(old_value) = old_value {
4424 let old_value = old_value.as_atom().clone();
4425 doc.unregister_element_name(self, old_value);
4426 }
4427 if value != atom!("") {
4428 doc.register_element_name(self, value);
4429 }
4430 },
4431 AttributeMutation::Removed => {
4432 if value != atom!("") {
4433 doc.unregister_element_name(self, value);
4434 }
4435 },
4436 }
4437 }
4438 },
4439 &local_name!("slot") => {
4440 let cx = GlobalScope::get_cx();
4442
4443 rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4444
4445 if let Some(assigned_slot) = slottable.assigned_slot() {
4447 assigned_slot.assign_slottables();
4448 }
4449 slottable.assign_a_slot();
4450 },
4451 _ => {
4452 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4455 node.dirty(NodeDamage::Other);
4456 }
4457 },
4458 };
4459
4460 node.rev_version();
4464 }
4465
4466 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4467 match *name {
4468 local_name!("id") => AttrValue::Atom(value.into()),
4469 local_name!("name") => AttrValue::Atom(value.into()),
4470 local_name!("class") | local_name!("part") => {
4471 AttrValue::from_serialized_tokenlist(value.into())
4472 },
4473 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4474 _ => self
4475 .super_type()
4476 .unwrap()
4477 .parse_plain_attribute(name, value),
4478 }
4479 }
4480
4481 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
4482 if let Some(s) = self.super_type() {
4483 s.bind_to_tree(context, can_gc);
4484 }
4485
4486 if let Some(f) = self.as_maybe_form_control() {
4487 f.bind_form_control_to_tree(can_gc);
4488 }
4489
4490 let doc = self.owner_document();
4491
4492 if let Some(ref shadow_root) = self.shadow_root() {
4493 shadow_root.bind_to_tree(context, can_gc);
4494 }
4495
4496 if !context.is_in_tree() {
4497 return;
4498 }
4499
4500 self.update_sequentially_focusable_status(can_gc);
4501
4502 if let Some(ref id) = *self.id_attribute.borrow() {
4503 if let Some(shadow_root) = self.containing_shadow_root() {
4504 shadow_root.register_element_id(self, id.clone(), can_gc);
4505 } else {
4506 doc.register_element_id(self, id.clone(), can_gc);
4507 }
4508 }
4509 if let Some(ref name) = self.name_attribute() {
4510 if self.containing_shadow_root().is_none() {
4511 doc.register_element_name(self, name.clone());
4512 }
4513 }
4514
4515 doc.increment_dom_count();
4517 }
4518
4519 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
4520 self.super_type().unwrap().unbind_from_tree(context, can_gc);
4521
4522 if let Some(f) = self.as_maybe_form_control() {
4523 f.unbind_form_control_from_tree(can_gc);
4527 }
4528
4529 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4530 return;
4531 }
4532
4533 self.update_sequentially_focusable_status(can_gc);
4534
4535 let doc = self.owner_document();
4536
4537 let fullscreen = doc.GetFullscreenElement();
4538 if fullscreen.as_deref() == Some(self) {
4539 doc.exit_fullscreen(can_gc);
4540 }
4541 if let Some(ref value) = *self.id_attribute.borrow() {
4542 if let Some(ref shadow_root) = self.containing_shadow_root() {
4543 if !self.upcast::<Node>().is_in_a_shadow_tree() {
4546 shadow_root.unregister_element_id(self, value.clone(), can_gc);
4547 }
4548 } else {
4549 doc.unregister_element_id(self, value.clone(), can_gc);
4550 }
4551 }
4552 if let Some(ref value) = self.name_attribute() {
4553 if self.containing_shadow_root().is_none() {
4554 doc.unregister_element_name(self, value.clone());
4555 }
4556 }
4557 doc.decrement_dom_count();
4559 }
4560
4561 fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
4562 if let Some(s) = self.super_type() {
4563 s.children_changed(mutation, can_gc);
4564 }
4565
4566 let flags = self.selector_flags.get();
4567 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4568 self.upcast::<Node>().dirty(NodeDamage::Other);
4570 } else {
4571 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
4572 if let Some(next_child) = mutation.next_child() {
4573 for child in next_child.inclusively_following_siblings() {
4574 if child.is::<Element>() {
4575 child.dirty(NodeDamage::Other);
4576 }
4577 }
4578 }
4579 }
4580 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
4581 if let Some(child) = mutation.modified_edge_element() {
4582 child.dirty(NodeDamage::Other);
4583 }
4584 }
4585 }
4586 }
4587
4588 fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
4589 self.super_type().unwrap().adopting_steps(old_doc, can_gc);
4590
4591 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4592 self.tag_name.clear();
4593 }
4594 }
4595
4596 fn post_connection_steps(&self, can_gc: CanGc) {
4597 if let Some(s) = self.super_type() {
4598 s.post_connection_steps(can_gc);
4599 }
4600
4601 self.update_nonce_post_connection();
4602 }
4603
4604 fn cloning_steps(
4606 &self,
4607 copy: &Node,
4608 maybe_doc: Option<&Document>,
4609 clone_children: CloneChildrenFlag,
4610 can_gc: CanGc,
4611 ) {
4612 if let Some(s) = self.super_type() {
4613 s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
4614 }
4615 let elem = copy.downcast::<Element>().unwrap();
4616 if let Some(rare_data) = self.rare_data().as_ref() {
4617 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone());
4618 }
4619 }
4620}
4621
4622#[derive(Clone, PartialEq)]
4623pub enum SelectorWrapper<'a> {
4628 Borrowed(&'a DomRoot<Element>),
4629 Owned(DomRoot<Element>),
4630}
4631
4632impl fmt::Debug for SelectorWrapper<'_> {
4633 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4634 self.deref().fmt(f)
4635 }
4636}
4637
4638impl Deref for SelectorWrapper<'_> {
4639 type Target = DomRoot<Element>;
4640
4641 fn deref(&self) -> &Self::Target {
4642 match self {
4643 SelectorWrapper::Owned(r) => r,
4644 SelectorWrapper::Borrowed(r) => r,
4645 }
4646 }
4647}
4648
4649impl SelectorWrapper<'_> {
4650 fn into_owned(self) -> DomRoot<Element> {
4651 match self {
4652 SelectorWrapper::Owned(r) => r,
4653 SelectorWrapper::Borrowed(r) => r.clone(),
4654 }
4655 }
4656}
4657
4658impl SelectorsElement for SelectorWrapper<'_> {
4659 type Impl = SelectorImpl;
4660
4661 #[expect(unsafe_code)]
4662 fn opaque(&self) -> ::selectors::OpaqueElement {
4663 ::selectors::OpaqueElement::new(unsafe { &*self.reflector().get_jsobject().get() })
4664 }
4665
4666 fn parent_element(&self) -> Option<Self> {
4667 self.upcast::<Node>()
4668 .GetParentElement()
4669 .map(SelectorWrapper::Owned)
4670 }
4671
4672 fn parent_node_is_shadow_root(&self) -> bool {
4673 match self.upcast::<Node>().GetParentNode() {
4674 None => false,
4675 Some(node) => node.is::<ShadowRoot>(),
4676 }
4677 }
4678
4679 fn containing_shadow_host(&self) -> Option<Self> {
4680 self.containing_shadow_root()
4681 .map(|shadow_root| shadow_root.Host())
4682 .map(SelectorWrapper::Owned)
4683 }
4684
4685 fn is_pseudo_element(&self) -> bool {
4686 false
4687 }
4688
4689 fn match_pseudo_element(
4690 &self,
4691 _pseudo: &PseudoElement,
4692 _context: &mut MatchingContext<Self::Impl>,
4693 ) -> bool {
4694 false
4695 }
4696
4697 fn prev_sibling_element(&self) -> Option<Self> {
4698 self.node
4699 .preceding_siblings()
4700 .find_map(DomRoot::downcast)
4701 .map(SelectorWrapper::Owned)
4702 }
4703
4704 fn next_sibling_element(&self) -> Option<Self> {
4705 self.node
4706 .following_siblings()
4707 .find_map(DomRoot::downcast)
4708 .map(SelectorWrapper::Owned)
4709 }
4710
4711 fn first_element_child(&self) -> Option<Self> {
4712 self.GetFirstElementChild().map(SelectorWrapper::Owned)
4713 }
4714
4715 fn attr_matches(
4716 &self,
4717 ns: &NamespaceConstraint<&style::Namespace>,
4718 local_name: &style::LocalName,
4719 operation: &AttrSelectorOperation<&AtomString>,
4720 ) -> bool {
4721 match *ns {
4722 NamespaceConstraint::Specific(ns) => self
4723 .get_attribute(ns, local_name)
4724 .is_some_and(|attr| attr.value().eval_selector(operation)),
4725 NamespaceConstraint::Any => self.attrs.borrow().iter().any(|attr| {
4726 *attr.local_name() == **local_name && attr.value().eval_selector(operation)
4727 }),
4728 }
4729 }
4730
4731 fn is_root(&self) -> bool {
4732 Element::is_root(self)
4733 }
4734
4735 fn is_empty(&self) -> bool {
4736 self.node.children().all(|node| {
4737 !node.is::<Element>() &&
4738 match node.downcast::<Text>() {
4739 None => true,
4740 Some(text) => text.upcast::<CharacterData>().data().is_empty(),
4741 }
4742 })
4743 }
4744
4745 fn has_local_name(&self, local_name: &LocalName) -> bool {
4746 Element::local_name(self) == local_name
4747 }
4748
4749 fn has_namespace(&self, ns: &Namespace) -> bool {
4750 Element::namespace(self) == ns
4751 }
4752
4753 fn is_same_type(&self, other: &Self) -> bool {
4754 Element::local_name(self) == Element::local_name(other) &&
4755 Element::namespace(self) == Element::namespace(other)
4756 }
4757
4758 fn match_non_ts_pseudo_class(
4759 &self,
4760 pseudo_class: &NonTSPseudoClass,
4761 _: &mut MatchingContext<Self::Impl>,
4762 ) -> bool {
4763 match *pseudo_class {
4764 NonTSPseudoClass::Link | NonTSPseudoClass::AnyLink => self.is_link(),
4766 NonTSPseudoClass::Visited => false,
4767
4768 NonTSPseudoClass::ServoNonZeroBorder => match self.downcast::<HTMLTableElement>() {
4769 None => false,
4770 Some(this) => match this.get_border() {
4771 None | Some(0) => false,
4772 Some(_) => true,
4773 },
4774 },
4775
4776 NonTSPseudoClass::CustomState(ref state) => self.has_custom_state(&state.0),
4777
4778 NonTSPseudoClass::Lang(ref lang) => {
4783 extended_filtering(&self.upcast::<Node>().get_lang().unwrap_or_default(), lang)
4784 },
4785
4786 NonTSPseudoClass::ReadOnly => {
4787 !Element::state(self).contains(NonTSPseudoClass::ReadWrite.state_flag())
4788 },
4789
4790 NonTSPseudoClass::Active |
4791 NonTSPseudoClass::Autofill |
4792 NonTSPseudoClass::Checked |
4793 NonTSPseudoClass::Default |
4794 NonTSPseudoClass::Defined |
4795 NonTSPseudoClass::Disabled |
4796 NonTSPseudoClass::Enabled |
4797 NonTSPseudoClass::Focus |
4798 NonTSPseudoClass::FocusVisible |
4799 NonTSPseudoClass::FocusWithin |
4800 NonTSPseudoClass::Fullscreen |
4801 NonTSPseudoClass::Hover |
4802 NonTSPseudoClass::InRange |
4803 NonTSPseudoClass::Indeterminate |
4804 NonTSPseudoClass::Invalid |
4805 NonTSPseudoClass::Modal |
4806 NonTSPseudoClass::MozMeterOptimum |
4807 NonTSPseudoClass::MozMeterSubOptimum |
4808 NonTSPseudoClass::MozMeterSubSubOptimum |
4809 NonTSPseudoClass::Optional |
4810 NonTSPseudoClass::OutOfRange |
4811 NonTSPseudoClass::PlaceholderShown |
4812 NonTSPseudoClass::PopoverOpen |
4813 NonTSPseudoClass::ReadWrite |
4814 NonTSPseudoClass::Required |
4815 NonTSPseudoClass::Target |
4816 NonTSPseudoClass::UserInvalid |
4817 NonTSPseudoClass::UserValid |
4818 NonTSPseudoClass::Valid => Element::state(self).contains(pseudo_class.state_flag()),
4819 }
4820 }
4821
4822 fn is_link(&self) -> bool {
4823 let node = self.upcast::<Node>();
4825 match node.type_id() {
4826 NodeTypeId::Element(ElementTypeId::HTMLElement(
4828 HTMLElementTypeId::HTMLAnchorElement,
4829 )) |
4830 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) |
4831 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
4832 self.has_attribute(&local_name!("href"))
4833 },
4834 _ => false,
4835 }
4836 }
4837
4838 fn has_id(&self, id: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4839 self.id_attribute
4840 .borrow()
4841 .as_ref()
4842 .is_some_and(|atom| case_sensitivity.eq_atom(id, atom))
4843 }
4844
4845 fn is_part(&self, name: &AtomIdent) -> bool {
4846 Element::is_part(self, name, CaseSensitivity::CaseSensitive)
4847 }
4848
4849 fn imported_part(&self, _: &AtomIdent) -> Option<AtomIdent> {
4850 None
4851 }
4852
4853 fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
4854 Element::has_class(self, name, case_sensitivity)
4855 }
4856
4857 fn is_html_element_in_html_document(&self) -> bool {
4858 self.html_element_in_html_document()
4859 }
4860
4861 fn is_html_slot_element(&self) -> bool {
4862 self.is_html_element() && self.local_name() == &local_name!("slot")
4863 }
4864
4865 fn apply_selector_flags(&self, flags: ElementSelectorFlags) {
4866 let self_flags = flags.for_self();
4868 if !self_flags.is_empty() {
4869 #[expect(unsafe_code)]
4870 unsafe {
4871 Dom::from_ref(&***self)
4872 .to_layout()
4873 .insert_selector_flags(self_flags);
4874 }
4875 }
4876
4877 let parent_flags = flags.for_parent();
4879 if !parent_flags.is_empty() {
4880 if let Some(p) = self.parent_element() {
4881 #[expect(unsafe_code)]
4882 unsafe {
4883 Dom::from_ref(&**p)
4884 .to_layout()
4885 .insert_selector_flags(parent_flags);
4886 }
4887 }
4888 }
4889 }
4890
4891 fn add_element_unique_hashes(&self, filter: &mut BloomFilter) -> bool {
4892 let mut f = |hash| filter.insert_hash(hash & BLOOM_HASH_MASK);
4893
4894 f(Element::local_name(self).get_hash());
4897 f(Element::namespace(self).get_hash());
4898
4899 if let Some(ref id) = *self.id_attribute.borrow() {
4900 f(id.get_hash());
4901 }
4902
4903 if let Some(attr) = self.get_attribute(&ns!(), &local_name!("class")) {
4904 for class in attr.value().as_tokens() {
4905 f(AtomIdent::cast(class).get_hash());
4906 }
4907 }
4908
4909 for attr in self.attrs.borrow().iter() {
4910 let name = style::values::GenericAtomIdent::cast(attr.local_name());
4911 if !style::bloom::is_attr_name_excluded_from_filter(name) {
4912 f(name.get_hash());
4913 }
4914 }
4915
4916 true
4917 }
4918
4919 fn has_custom_state(&self, name: &AtomIdent) -> bool {
4920 let mut has_state = false;
4921 self.each_custom_state(|state| has_state |= state == name);
4922
4923 has_state
4924 }
4925}
4926
4927impl Element {
4928 fn each_custom_state<F>(&self, callback: F)
4929 where
4930 F: FnMut(&AtomIdent),
4931 {
4932 self.get_element_internals()
4933 .and_then(|internals| internals.custom_states())
4934 .inspect(|states| states.for_each_state(callback));
4935 }
4936
4937 pub(crate) fn client_rect(&self) -> Rect<i32> {
4938 let doc = self.node.owner_doc();
4939
4940 if let Some(rect) = self
4941 .rare_data()
4942 .as_ref()
4943 .and_then(|data| data.client_rect.as_ref())
4944 .and_then(|rect| rect.get().ok())
4945 {
4946 if doc.restyle_reason().is_empty() {
4947 return rect;
4948 }
4949 }
4950
4951 let mut rect = self.upcast::<Node>().client_rect();
4952 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
4953
4954 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
4955 (!in_quirks_mode && *self.root_element() == *self)
4956 {
4957 let viewport_dimensions = doc.window().viewport_details().size.round().to_i32();
4958 rect.size = Size2D::<i32>::new(viewport_dimensions.width, viewport_dimensions.height);
4959 }
4960
4961 self.ensure_rare_data().client_rect = Some(self.owner_window().cache_layout_value(rect));
4962 rect
4963 }
4964
4965 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
4966 let element = match self.upcast::<Node>().type_id() {
4967 NodeTypeId::Element(ElementTypeId::HTMLElement(
4968 HTMLElementTypeId::HTMLInputElement,
4969 )) => {
4970 let element = self.downcast::<HTMLInputElement>().unwrap();
4971 Some(element as &dyn Activatable)
4972 },
4973 NodeTypeId::Element(ElementTypeId::HTMLElement(
4974 HTMLElementTypeId::HTMLButtonElement,
4975 )) => {
4976 let element = self.downcast::<HTMLButtonElement>().unwrap();
4977 Some(element as &dyn Activatable)
4978 },
4979 NodeTypeId::Element(ElementTypeId::HTMLElement(
4980 HTMLElementTypeId::HTMLAnchorElement,
4981 )) => {
4982 let element = self.downcast::<HTMLAnchorElement>().unwrap();
4983 Some(element as &dyn Activatable)
4984 },
4985 NodeTypeId::Element(ElementTypeId::HTMLElement(
4986 HTMLElementTypeId::HTMLLabelElement,
4987 )) => {
4988 let element = self.downcast::<HTMLLabelElement>().unwrap();
4989 Some(element as &dyn Activatable)
4990 },
4991 NodeTypeId::Element(ElementTypeId::HTMLElement(
4992 HTMLElementTypeId::HTMLSelectElement,
4993 )) => {
4994 let element = self.downcast::<HTMLSelectElement>().unwrap();
4995 Some(element as &dyn Activatable)
4996 },
4997 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
4998 let element = self.downcast::<HTMLElement>().unwrap();
4999 Some(element as &dyn Activatable)
5000 },
5001 _ => None,
5002 };
5003 element.and_then(|elem| {
5004 if elem.is_instance_activatable() {
5005 Some(elem)
5006 } else {
5007 None
5008 }
5009 })
5010 }
5011
5012 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
5013 if let Some(s) = self.downcast::<HTMLStyleElement>() {
5014 return Some(s as &dyn StylesheetOwner);
5015 }
5016
5017 if let Some(l) = self.downcast::<HTMLLinkElement>() {
5018 return Some(l as &dyn StylesheetOwner);
5019 }
5020
5021 None
5022 }
5023
5024 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
5026 match self.upcast::<Node>().type_id() {
5027 NodeTypeId::Element(ElementTypeId::HTMLElement(
5028 HTMLElementTypeId::HTMLInputElement,
5029 )) => {
5030 let element = self.downcast::<HTMLInputElement>().unwrap();
5031 Some(element as &dyn Validatable)
5032 },
5033 NodeTypeId::Element(ElementTypeId::HTMLElement(
5034 HTMLElementTypeId::HTMLButtonElement,
5035 )) => {
5036 let element = self.downcast::<HTMLButtonElement>().unwrap();
5037 Some(element as &dyn Validatable)
5038 },
5039 NodeTypeId::Element(ElementTypeId::HTMLElement(
5040 HTMLElementTypeId::HTMLObjectElement,
5041 )) => {
5042 let element = self.downcast::<HTMLObjectElement>().unwrap();
5043 Some(element as &dyn Validatable)
5044 },
5045 NodeTypeId::Element(ElementTypeId::HTMLElement(
5046 HTMLElementTypeId::HTMLSelectElement,
5047 )) => {
5048 let element = self.downcast::<HTMLSelectElement>().unwrap();
5049 Some(element as &dyn Validatable)
5050 },
5051 NodeTypeId::Element(ElementTypeId::HTMLElement(
5052 HTMLElementTypeId::HTMLTextAreaElement,
5053 )) => {
5054 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
5055 Some(element as &dyn Validatable)
5056 },
5057 NodeTypeId::Element(ElementTypeId::HTMLElement(
5058 HTMLElementTypeId::HTMLFieldSetElement,
5059 )) => {
5060 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
5061 Some(element as &dyn Validatable)
5062 },
5063 NodeTypeId::Element(ElementTypeId::HTMLElement(
5064 HTMLElementTypeId::HTMLOutputElement,
5065 )) => {
5066 let element = self.downcast::<HTMLOutputElement>().unwrap();
5067 Some(element as &dyn Validatable)
5068 },
5069 _ => None,
5070 }
5071 }
5072
5073 pub(crate) fn is_invalid(&self, needs_update: bool, can_gc: CanGc) -> bool {
5074 if let Some(validatable) = self.as_maybe_validatable() {
5075 if needs_update {
5076 validatable
5077 .validity_state(can_gc)
5078 .perform_validation_and_update(ValidationFlags::all(), can_gc);
5079 }
5080 return validatable.is_instance_validatable() &&
5081 !validatable.satisfies_constraints(can_gc);
5082 }
5083
5084 if let Some(internals) = self.get_element_internals() {
5085 return internals.is_invalid(can_gc);
5086 }
5087 false
5088 }
5089
5090 pub(crate) fn is_instance_validatable(&self) -> bool {
5091 if let Some(validatable) = self.as_maybe_validatable() {
5092 return validatable.is_instance_validatable();
5093 }
5094 if let Some(internals) = self.get_element_internals() {
5095 return internals.is_instance_validatable();
5096 }
5097 false
5098 }
5099
5100 pub(crate) fn init_state_for_internals(&self) {
5101 self.set_enabled_state(true);
5102 self.set_state(ElementState::VALID, true);
5103 self.set_state(ElementState::INVALID, false);
5104 }
5105
5106 pub(crate) fn click_in_progress(&self) -> bool {
5107 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5108 }
5109
5110 pub(crate) fn set_click_in_progress(&self, click: bool) {
5111 self.upcast::<Node>()
5112 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5113 }
5114
5115 pub(crate) fn nearest_activable_element(&self) -> Option<DomRoot<Element>> {
5117 match self.as_maybe_activatable() {
5118 Some(el) => Some(DomRoot::from_ref(el.as_element())),
5119 None => {
5120 let node = self.upcast::<Node>();
5121 for node in node.ancestors() {
5122 if let Some(node) = node.downcast::<Element>() {
5123 if node.as_maybe_activatable().is_some() {
5124 return Some(DomRoot::from_ref(node));
5125 }
5126 }
5127 }
5128 None
5129 },
5130 }
5131 }
5132
5133 pub fn state(&self) -> ElementState {
5134 self.state.get()
5135 }
5136
5137 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5138 let mut state = self.state.get();
5139 let previous_state = state;
5140 if value {
5141 state.insert(which);
5142 } else {
5143 state.remove(which);
5144 }
5145
5146 if previous_state == state {
5147 return;
5149 }
5150
5151 {
5154 let document = self.owner_document();
5155 let mut entry = document.ensure_pending_restyle(self);
5156 if entry.snapshot.is_none() {
5157 entry.snapshot = Some(Snapshot::new());
5158 }
5159 let snapshot = entry.snapshot.as_mut().unwrap();
5160 if snapshot.state.is_none() {
5161 snapshot.state = Some(self.state());
5162 }
5163 }
5164
5165 self.upcast::<Node>().dirty(NodeDamage::ContentOrHeritage);
5167
5168 self.state.set(state);
5169 }
5170
5171 pub(crate) fn set_active_state(&self, value: bool) {
5173 self.set_state(ElementState::ACTIVE, value);
5174
5175 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5176 parent.set_active_state(value);
5177 }
5178 }
5179
5180 pub(crate) fn focus_state(&self) -> bool {
5181 self.state.get().contains(ElementState::FOCUS)
5182 }
5183
5184 pub(crate) fn set_focus_state(&self, value: bool) {
5185 self.set_state(ElementState::FOCUS, value);
5186 }
5187
5188 pub(crate) fn hover_state(&self) -> bool {
5189 self.state.get().contains(ElementState::HOVER)
5190 }
5191
5192 pub(crate) fn set_hover_state(&self, value: bool) {
5193 self.set_state(ElementState::HOVER, value);
5194 }
5195
5196 pub(crate) fn enabled_state(&self) -> bool {
5197 self.state.get().contains(ElementState::ENABLED)
5198 }
5199
5200 pub(crate) fn set_enabled_state(&self, value: bool) {
5201 self.set_state(ElementState::ENABLED, value)
5202 }
5203
5204 pub(crate) fn disabled_state(&self) -> bool {
5205 self.state.get().contains(ElementState::DISABLED)
5206 }
5207
5208 pub(crate) fn set_disabled_state(&self, value: bool) {
5209 self.set_state(ElementState::DISABLED, value)
5210 }
5211
5212 pub(crate) fn read_write_state(&self) -> bool {
5213 self.state.get().contains(ElementState::READWRITE)
5214 }
5215
5216 pub(crate) fn set_read_write_state(&self, value: bool) {
5217 self.set_state(ElementState::READWRITE, value)
5218 }
5219
5220 pub(crate) fn placeholder_shown_state(&self) -> bool {
5221 self.state.get().contains(ElementState::PLACEHOLDER_SHOWN)
5222 }
5223
5224 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5225 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5226 }
5227
5228 pub(crate) fn set_target_state(&self, value: bool) {
5229 self.set_state(ElementState::URLTARGET, value)
5230 }
5231
5232 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5233 self.set_state(ElementState::FULLSCREEN, value)
5234 }
5235
5236 pub(crate) fn is_connected(&self) -> bool {
5238 self.upcast::<Node>().is_connected()
5239 }
5240
5241 pub(crate) fn cannot_navigate(&self) -> bool {
5243 let document = self.owner_document();
5244
5245 !document.is_fully_active() ||
5247 (
5248 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5250 )
5251 }
5252}
5253
5254impl Element {
5255 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5256 let node = self.upcast::<Node>();
5257 if self.disabled_state() {
5258 return;
5259 }
5260 for ancestor in node.ancestors() {
5261 if !ancestor.is::<HTMLFieldSetElement>() {
5262 continue;
5263 }
5264 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5265 continue;
5266 }
5267 if ancestor.is_parent_of(node) {
5268 self.set_disabled_state(true);
5269 self.set_enabled_state(false);
5270 return;
5271 }
5272 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5273 if node.ancestors().any(|ancestor| ancestor == *legend) {
5275 continue;
5276 }
5277 }
5278 self.set_disabled_state(true);
5279 self.set_enabled_state(false);
5280 return;
5281 }
5282 }
5283
5284 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5285 if self.disabled_state() {
5286 return;
5287 }
5288 let node = self.upcast::<Node>();
5289 if let Some(ref parent) = node.GetParentNode() {
5290 if parent.is::<HTMLOptGroupElement>() &&
5291 parent.downcast::<Element>().unwrap().disabled_state()
5292 {
5293 self.set_disabled_state(true);
5294 self.set_enabled_state(false);
5295 }
5296 }
5297 }
5298
5299 pub(crate) fn check_disabled_attribute(&self) {
5300 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5301 self.set_disabled_state(has_disabled_attrib);
5302 self.set_enabled_state(!has_disabled_attrib);
5303 }
5304
5305 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5306 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5307 self.set_read_write_state(has_readonly_attribute);
5308 }
5309}
5310
5311#[derive(Clone, Copy, PartialEq)]
5312pub(crate) enum AttributeMutationReason {
5313 ByCloning,
5314 ByParser,
5315 Directly,
5316}
5317
5318#[derive(Clone, Copy)]
5319pub(crate) enum AttributeMutation<'a> {
5320 Set(Option<&'a AttrValue>, AttributeMutationReason),
5323
5324 Removed,
5327}
5328
5329impl AttributeMutation<'_> {
5330 pub(crate) fn is_removal(&self) -> bool {
5331 match *self {
5332 AttributeMutation::Removed => true,
5333 AttributeMutation::Set(..) => false,
5334 }
5335 }
5336
5337 pub(crate) fn new_value<'b>(&self, attr: &'b Attr) -> Option<Ref<'b, AttrValue>> {
5338 match *self {
5339 AttributeMutation::Set(..) => Some(attr.value()),
5340 AttributeMutation::Removed => None,
5341 }
5342 }
5343}
5344
5345#[derive(JSTraceable, MallocSizeOf)]
5349struct TagName {
5350 #[no_trace]
5351 ptr: DomRefCell<Option<LocalName>>,
5352}
5353
5354impl TagName {
5355 fn new() -> TagName {
5356 TagName {
5357 ptr: DomRefCell::new(None),
5358 }
5359 }
5360
5361 fn or_init<F>(&self, cb: F) -> LocalName
5364 where
5365 F: FnOnce() -> LocalName,
5366 {
5367 match &mut *self.ptr.borrow_mut() {
5368 &mut Some(ref name) => name.clone(),
5369 ptr => {
5370 let name = cb();
5371 *ptr = Some(name.clone());
5372 name
5373 },
5374 }
5375 }
5376
5377 fn clear(&self) {
5380 *self.ptr.borrow_mut() = None;
5381 }
5382}
5383
5384pub(crate) struct ElementPerformFullscreenEnter {
5385 element: Trusted<Element>,
5386 promise: TrustedPromise,
5387 error: bool,
5388}
5389
5390impl ElementPerformFullscreenEnter {
5391 pub(crate) fn new(
5392 element: Trusted<Element>,
5393 promise: TrustedPromise,
5394 error: bool,
5395 ) -> Box<ElementPerformFullscreenEnter> {
5396 Box::new(ElementPerformFullscreenEnter {
5397 element,
5398 promise,
5399 error,
5400 })
5401 }
5402}
5403
5404impl TaskOnce for ElementPerformFullscreenEnter {
5405 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
5406 fn run_once(self) {
5407 let element = self.element.root();
5408 let promise = self.promise.root();
5409 let document = element.owner_document();
5410
5411 if self.error || !element.fullscreen_element_ready_check() {
5413 document
5414 .upcast::<EventTarget>()
5415 .fire_event(atom!("fullscreenerror"), CanGc::note());
5416 promise.reject_error(
5417 Error::Type(String::from("fullscreen is not connected")),
5418 CanGc::note(),
5419 );
5420 return;
5421 }
5422
5423 element.set_fullscreen_state(true);
5426 document.set_fullscreen_element(Some(&element));
5427
5428 document
5430 .upcast::<EventTarget>()
5431 .fire_event(atom!("fullscreenchange"), CanGc::note());
5432
5433 promise.resolve_native(&(), CanGc::note());
5435 }
5436}
5437
5438pub(crate) struct ElementPerformFullscreenExit {
5439 element: Trusted<Element>,
5440 promise: TrustedPromise,
5441}
5442
5443impl ElementPerformFullscreenExit {
5444 pub(crate) fn new(
5445 element: Trusted<Element>,
5446 promise: TrustedPromise,
5447 ) -> Box<ElementPerformFullscreenExit> {
5448 Box::new(ElementPerformFullscreenExit { element, promise })
5449 }
5450}
5451
5452impl TaskOnce for ElementPerformFullscreenExit {
5453 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
5454 fn run_once(self) {
5455 let element = self.element.root();
5456 let document = element.owner_document();
5457 element.set_fullscreen_state(false);
5460 document.set_fullscreen_element(None);
5461
5462 document
5464 .upcast::<EventTarget>()
5465 .fire_event(atom!("fullscreenchange"), CanGc::note());
5466
5467 self.promise.root().resolve_native(&(), CanGc::note());
5469 }
5470}
5471
5472pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5474 element
5475 .get_attribute(&ns!(), &local_name!("crossorigin"))
5476 .map(|attribute| {
5477 let value = attribute.value().to_ascii_lowercase();
5478 if value == "anonymous" || value == "use-credentials" {
5479 DOMString::from(value)
5480 } else {
5481 DOMString::from("anonymous")
5482 }
5483 })
5484}
5485
5486pub(crate) fn set_cross_origin_attribute(
5487 element: &Element,
5488 value: Option<DOMString>,
5489 can_gc: CanGc,
5490) {
5491 match value {
5492 Some(val) => element.set_string_attribute(&local_name!("crossorigin"), val, can_gc),
5493 None => {
5494 element.remove_attribute(&ns!(), &local_name!("crossorigin"), can_gc);
5495 },
5496 }
5497}
5498
5499pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5501 element
5502 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5503 .map(|attribute| {
5504 let value = attribute.value().to_ascii_lowercase();
5505 if value == "no-referrer" ||
5506 value == "no-referrer-when-downgrade" ||
5507 value == "same-origin" ||
5508 value == "origin" ||
5509 value == "strict-origin" ||
5510 value == "origin-when-cross-origin" ||
5511 value == "strict-origin-when-cross-origin" ||
5512 value == "unsafe-url"
5513 {
5514 DOMString::from(value)
5515 } else {
5516 DOMString::new()
5517 }
5518 })
5519 .unwrap_or_default()
5520}
5521
5522pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5523 element
5524 .get_attribute(&ns!(), &local_name!("referrerpolicy"))
5525 .map(|attribute| ReferrerPolicy::from(&**attribute.value()))
5526 .unwrap_or(element.owner_document().get_referrer_policy())
5527}
5528
5529pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5530 element
5531 .get_attribute(&ns!(), &local_name!("crossorigin"))
5532 .map(|attribute| CorsSettings::from_enumerated_attribute(&attribute.value()))
5533}