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