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