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