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