1use std::borrow::Cow;
8use std::cell::{Cell, LazyCell};
9use std::default::Default;
10use std::rc::Rc;
11use std::str::FromStr;
12use std::sync::atomic::{AtomicUsize, Ordering};
13use std::{fmt, mem};
14
15use app_units::Au;
16use cssparser::match_ignore_ascii_case;
17use devtools_traits::{AttrInfo, DomMutation, ScriptToDevtoolsControlMsg};
18use dom_struct::dom_struct;
19use euclid::Rect;
20use html5ever::serialize::TraversalScope;
21use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
22use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_prefix, ns};
23use js::context::{JSContext, NoGC};
24use js::jsapi::{Heap, JSObject};
25use js::jsval::JSVal;
26use js::realm::CurrentRealm;
27use js::rust::HandleObject;
28use layout_api::{LayoutDamage, QueryMsg, ScrollContainerQueryFlags, StyleData, with_layout_state};
29use net_traits::ReferrerPolicy;
30use net_traits::request::{CorsSettings, CredentialsMode};
31use script_bindings::cell::{DomRefCell, Ref, RefMut};
32use script_bindings::codegen::GenericBindings::AnimationBinding::AnimationMethods;
33use script_bindings::codegen::GenericBindings::KeyframeEffectBinding::KeyframeEffectMethods;
34use script_bindings::dom::UnrootedDom;
35use script_bindings::reflector::DomObject;
36use selectors::attr::CaseSensitivity;
37use selectors::matching::ElementSelectorFlags;
38use selectors::sink::Push;
39use servo_arc::Arc as ServoArc;
40use style::applicable_declarations::ApplicableDeclarationBlock;
41use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
42use style::context::QuirksMode;
43use style::invalidation::element::restyle_hints::RestyleHint;
44use style::properties::longhands::{
45 self, background_image, border_spacing, color, font_family, font_size,
46};
47use style::properties::{
48 ComputedValues, Importance, PropertyDeclaration, PropertyDeclarationBlock,
49 parse_style_attribute,
50};
51use style::rule_tree::{CascadeLevel, CascadeOrigin};
52use style::selector_parser::{RestyleDamage, SelectorParser, Snapshot};
53use style::shared_lock::Locked;
54use style::stylesheets::layer_rule::LayerOrder;
55use style::stylesheets::{CssRuleType, UrlExtraData};
56use style::values::computed::Overflow;
57use style::values::generics::NonNegative;
58use style::values::generics::position::PreferredRatio;
59use style::values::generics::ratio::Ratio;
60use style::values::{AtomIdent, AtomString, CSSFloat, GenericAtomIdent, computed, specified};
61use style::{ArcSlice, CaseSensitivityExt, dom_apis, thread_state};
62use style_traits::CSSPixel;
63use stylo_atoms::Atom;
64use stylo_dom::ElementState;
65use xml5ever::serialize::TraversalScope::{
66 ChildrenOnly as XmlChildrenOnly, IncludeNode as XmlIncludeNode,
67};
68
69use crate::conversions::Convert;
70use crate::dom::activation::Activatable;
71use crate::dom::animation::Animation;
72use crate::dom::animations::keyframeeffect::KeyframeEffect;
73use crate::dom::attr::{Attr, is_relevant_attribute};
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::EventHandlerBinding::EventHandlerNonNull;
80use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
81use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
82use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
83use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
84use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
85 SetHTMLOptions, SetHTMLUnsafeOptions,
86};
87use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
88 ShadowRootMethods, ShadowRootMode, SlotAssignmentMode,
89};
90use crate::dom::bindings::codegen::Bindings::WindowBinding::{
91 ScrollBehavior, ScrollToOptions, WindowMethods,
92};
93use crate::dom::bindings::codegen::UnionTypes::{
94 BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
95 TrustedHTMLOrString,
96 TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString,
97 UnrestrictedDoubleOrKeyframeAnimationOptions, UnrestrictedDoubleOrKeyframeEffectOptions,
98};
99use crate::dom::bindings::conversions::DerivedFrom;
100use crate::dom::bindings::domname::{
101 self, is_valid_attribute_local_name, namespace_from_domstring,
102};
103use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
104use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
105use crate::dom::bindings::num::Finite;
106use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom, ToLayout};
107use crate::dom::bindings::str::DOMString;
108use crate::dom::csp::{CspReporting, InlineCheckType, SourcePosition};
109use crate::dom::customelementregistry::{
110 CallbackReaction, CustomElementDefinition, CustomElementReaction, CustomElementRegistry,
111 CustomElementState, is_valid_custom_element_name,
112};
113use crate::dom::document::Document;
114use crate::dom::documentfragment::DocumentFragment;
115use crate::dom::domrect::DOMRect;
116use crate::dom::domrectlist::DOMRectList;
117use crate::dom::domtokenlist::DOMTokenList;
118use crate::dom::element::attributes::storage::{
119 AttrRef, AttrValueRef, AttributeEntry, AttributeStorage, ContentAttributeData,
120};
121use crate::dom::element::create::create_element;
122use crate::dom::elementinternals::ElementInternals;
123use crate::dom::eventtarget::EventTarget;
124use crate::dom::globalscope::GlobalScope;
125use crate::dom::html::form_controls::htmlinputelement::HTMLInputElement;
126use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
127use crate::dom::html::htmlareaelement::HTMLAreaElement;
128use crate::dom::html::htmlbodyelement::HTMLBodyElement;
129use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
130use crate::dom::html::htmlcollection::HTMLCollection;
131use crate::dom::html::htmlelement::HTMLElement;
132use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
133use crate::dom::html::htmlfontelement::HTMLFontElement;
134use crate::dom::html::htmlformelement::FormControlElementHelpers;
135use crate::dom::html::htmlhrelement::{HTMLHRElement, SizePresentationalHint};
136use crate::dom::html::htmliframeelement::HTMLIFrameElement;
137use crate::dom::html::htmlimageelement::HTMLImageElement;
138use crate::dom::html::htmllabelelement::HTMLLabelElement;
139use crate::dom::html::htmllegendelement::HTMLLegendElement;
140use crate::dom::html::htmllinkelement::HTMLLinkElement;
141use crate::dom::html::htmlobjectelement::HTMLObjectElement;
142use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
143use crate::dom::html::htmloutputelement::HTMLOutputElement;
144use crate::dom::html::htmlscriptelement::HTMLScriptElement;
145use crate::dom::html::htmlselectelement::HTMLSelectElement;
146use crate::dom::html::htmlslotelement::{HTMLSlotElement, Slottable};
147use crate::dom::html::htmlstyleelement::HTMLStyleElement;
148use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
149use crate::dom::html::htmltablecolelement::HTMLTableColElement;
150use crate::dom::html::htmltableelement::HTMLTableElement;
151use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
152use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
153use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
154use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
155use crate::dom::html::htmlvideoelement::HTMLVideoElement;
156use crate::dom::intersectionobserver::{IntersectionObserver, IntersectionObserverRegistration};
157use crate::dom::iterators::ShadowIncluding;
158use crate::dom::mutationobserver::{Mutation, MutationObserver};
159use crate::dom::namednodemap::NamedNodeMap;
160use crate::dom::node::virtualmethods::{VirtualMethods, vtable_for};
161use crate::dom::node::{
162 BindContext, ChildrenMutation, CloneChildrenFlag, IsShadowTree, Node, NodeDamage, NodeFlags,
163 NodeTraits, UnbindContext,
164};
165use crate::dom::nodelist::NodeList;
166use crate::dom::promise::Promise;
167use crate::dom::range::Range;
168use crate::dom::raredata::ElementRareData;
169use crate::dom::sanitizer::Sanitizer;
170use crate::dom::servoparser::ServoParser;
171use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
172use crate::dom::svg::svgelement::SVGElement;
173use crate::dom::text::Text;
174use crate::dom::trustedtypes::trustedhtml::TrustedHTML;
175use crate::dom::trustedtypes::trustedtypepolicyfactory::TrustedTypePolicyFactory;
176use crate::dom::validation::Validatable;
177use crate::dom::validitystate::ValidationFlags;
178use crate::dom::window::Window;
179use crate::dom::window::scrolling_box::{ScrollAxisState, ScrollingBox};
180use crate::event_loop::script_thread::ScriptThread;
181use crate::layout_dom::ServoDangerousStyleElement;
182use crate::realms::enter_auto_realm;
183use crate::stylesheet_loader::StylesheetOwner;
184
185#[dom_struct]
191pub struct Element {
192 node: Node,
193 #[no_trace]
194 local_name: LocalName,
195 tag_name: TagName,
196 #[no_trace]
197 namespace: Namespace,
198 #[no_trace]
199 prefix: DomRefCell<Option<Prefix>>,
200 attrs: AttributeStorage,
201 #[no_trace]
202 id_attribute: DomRefCell<Option<Atom>>,
203 #[no_trace]
205 is: DomRefCell<Option<LocalName>>,
206 #[conditional_malloc_size_of]
207 #[no_trace]
208 style_attribute: DomRefCell<Option<ServoArc<Locked<PropertyDeclarationBlock>>>>,
209 attr_list: MutNullableDom<NamedNodeMap>,
210 class_list: MutNullableDom<DOMTokenList>,
211 #[no_trace]
212 state: Cell<ElementState>,
213 selector_flags: AtomicUsize,
216 rare_data: DomRefCell<Option<Box<ElementRareData>>>,
217
218 #[no_trace]
221 style_data: DomRefCell<Option<Box<StyleData>>>,
222}
223
224impl fmt::Debug for Element {
225 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 write!(f, "<{}", self.local_name)?;
227 if let Some(ref id) = *self.id_attribute.borrow() {
228 write!(f, " id={}", id)?;
229 }
230 write!(f, ">")
231 }
232}
233
234#[derive(MallocSizeOf, PartialEq)]
235pub(crate) enum ElementCreator {
236 ParserCreated(u64),
237 ScriptCreated,
238}
239
240pub(crate) enum CustomElementCreationMode {
241 Synchronous,
242 Asynchronous,
243}
244
245impl ElementCreator {
246 pub(crate) fn is_parser_created(&self) -> bool {
247 match *self {
248 ElementCreator::ParserCreated(_) => true,
249 ElementCreator::ScriptCreated => false,
250 }
251 }
252 pub(crate) fn return_line_number(&self) -> u64 {
253 match *self {
254 ElementCreator::ParserCreated(l) => l,
255 ElementCreator::ScriptCreated => 1,
256 }
257 }
258}
259
260pub(crate) enum AdjacentPosition {
261 BeforeBegin,
262 AfterEnd,
263 AfterBegin,
264 BeforeEnd,
265}
266
267impl FromStr for AdjacentPosition {
268 type Err = Error;
269
270 fn from_str(position: &str) -> Result<Self, Self::Err> {
271 match_ignore_ascii_case! { position,
272 "beforebegin" => Ok(AdjacentPosition::BeforeBegin),
273 "afterbegin" => Ok(AdjacentPosition::AfterBegin),
274 "beforeend" => Ok(AdjacentPosition::BeforeEnd),
275 "afterend" => Ok(AdjacentPosition::AfterEnd),
276 _ => Err(Error::Syntax(None))
277 }
278 }
279}
280
281impl Element {
285 pub(crate) fn create(
286 cx: &mut JSContext,
287 name: QualName,
288 is: Option<LocalName>,
289 document: &Document,
290 creator: ElementCreator,
291 mode: CustomElementCreationMode,
292 proto: Option<HandleObject>,
293 ) -> DomRoot<Element> {
294 create_element(cx, name, is, document, creator, mode, proto)
295 }
296
297 pub(crate) fn new_inherited(
298 local_name: LocalName,
299 namespace: Namespace,
300 prefix: Option<Prefix>,
301 document: &Document,
302 ) -> Element {
303 Element::new_inherited_with_state(
304 ElementState::empty(),
305 local_name,
306 namespace,
307 prefix,
308 document,
309 )
310 }
311
312 pub(crate) fn new_inherited_with_state(
313 state: ElementState,
314 local_name: LocalName,
315 namespace: Namespace,
316 prefix: Option<Prefix>,
317 document: &Document,
318 ) -> Element {
319 Element {
320 node: Node::new_inherited(document),
321 local_name,
322 tag_name: TagName::new(),
323 namespace,
324 prefix: DomRefCell::new(prefix),
325 attrs: Default::default(),
326 id_attribute: DomRefCell::new(None),
327 is: DomRefCell::new(None),
328 style_attribute: DomRefCell::new(None),
329 attr_list: Default::default(),
330 class_list: Default::default(),
331 state: Cell::new(state),
332 selector_flags: Default::default(),
333 rare_data: Default::default(),
334 style_data: Default::default(),
335 }
336 }
337
338 pub(crate) fn set_had_duplicate_attributes(&self, no_gc: &NoGC) {
339 self.ensure_rare_data(no_gc).had_duplicate_attributes = true;
340 }
341
342 pub(crate) fn new(
343 cx: &mut JSContext,
344 local_name: LocalName,
345 namespace: Namespace,
346 prefix: Option<Prefix>,
347 document: &Document,
348 proto: Option<HandleObject>,
349 ) -> DomRoot<Element> {
350 Node::reflect_node_with_proto(
351 cx,
352 Box::new(Element::new_inherited(
353 local_name, namespace, prefix, document,
354 )),
355 document,
356 proto,
357 )
358 }
359
360 fn rare_data(&self) -> Ref<'_, Option<Box<ElementRareData>>> {
361 self.rare_data.borrow()
362 }
363
364 fn rare_data_mut(&self) -> RefMut<'_, Option<Box<ElementRareData>>> {
365 self.rare_data.borrow_mut()
366 }
367
368 pub(crate) fn ensure_rare_data<'a: 'b, 'b>(
369 &'a self,
370 no_gc: &'b NoGC,
371 ) -> RefMut<'b, Box<ElementRareData>> {
372 let mut rare_data = self.rare_data.safe_borrow_mut(no_gc);
373 if rare_data.is_none() {
374 *rare_data = Some(Default::default());
375 }
376 RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
377 }
378
379 pub(crate) fn clean_up_style_data(&self) {
380 self.style_data.borrow_mut().take();
381 }
382
383 pub(crate) fn restyle(&self, no_gc: &NoGC, damage: NodeDamage) {
384 let doc = self.node.owner_doc();
385 let mut restyle = doc.ensure_pending_restyle(self);
386
387 restyle.hint.insert(RestyleHint::RESTYLE_SELF);
390
391 match damage {
392 NodeDamage::Style => {},
393 NodeDamage::ContentOrHeritage => {
394 doc.note_dirty_element(no_gc, self);
395 restyle
396 .damage
397 .insert(RestyleDamage::from(LayoutDamage::DescendantHasBoxDamage));
398 },
399 NodeDamage::Other => {
400 doc.note_dirty_element(no_gc, self);
401 restyle.damage.insert(RestyleDamage::reconstruct());
402 },
403 }
404 }
405
406 pub(crate) fn has_dirty_descendants(&self) -> bool {
407 self.upcast::<Node>()
408 .get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS)
409 }
410
411 pub(crate) fn note_dirty_descendants(&self, no_gc: &NoGC) {
412 self.upcast::<Node>()
413 .owner_doc_unrooted(no_gc)
414 .note_dirty_element(no_gc, self);
415 }
416
417 pub(crate) fn set_is(&self, is: LocalName) {
418 *self.is.borrow_mut() = Some(is);
419 }
420
421 pub(crate) fn get_is(&self) -> Option<LocalName> {
423 self.is.borrow().clone()
424 }
425
426 pub(crate) fn set_initial_custom_element_state_to_uncustomized(&self) {
435 let mut state = self.state.get();
436 state.insert(ElementState::DEFINED);
437 self.state.set(state);
438 }
439
440 pub(crate) fn set_custom_element_state(&self, state: CustomElementState, no_gc: &NoGC) {
442 if state != CustomElementState::Uncustomized {
444 self.ensure_rare_data(no_gc).custom_element_state = state;
445 }
446
447 let in_defined_state = matches!(
448 state,
449 CustomElementState::Uncustomized | CustomElementState::Custom
450 );
451 self.set_state(ElementState::DEFINED, in_defined_state)
452 }
453
454 pub(crate) fn get_custom_element_state(&self) -> CustomElementState {
455 if let Some(rare_data) = self.rare_data().as_ref() {
456 return rare_data.custom_element_state;
457 }
458 CustomElementState::Uncustomized
459 }
460
461 pub(crate) fn is_custom(&self) -> bool {
463 self.get_custom_element_state() == CustomElementState::Custom
464 }
465
466 pub(crate) fn set_custom_element_definition(
467 &self,
468 definition: Rc<CustomElementDefinition>,
469 no_gc: &NoGC,
470 ) {
471 self.ensure_rare_data(no_gc).custom_element_definition = Some(definition);
472 }
473
474 pub(crate) fn get_custom_element_definition(&self) -> Option<Rc<CustomElementDefinition>> {
475 self.rare_data().as_ref()?.custom_element_definition.clone()
476 }
477
478 pub(crate) fn clear_custom_element_definition(&self, no_gc: &NoGC) {
479 self.ensure_rare_data(no_gc).custom_element_definition = None;
480 }
481
482 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
483 pub(crate) fn push_callback_reaction(
484 &self,
485 function: Rc<Function>,
486 args: Box<[Heap<JSVal>]>,
487 no_gc: &NoGC,
488 ) {
489 self.ensure_rare_data(no_gc)
490 .custom_element_reaction_queue
491 .push(CustomElementReaction::Callback(function, args));
492 }
493
494 pub(crate) fn push_upgrade_reaction(
495 &self,
496 definition: Rc<CustomElementDefinition>,
497 no_gc: &NoGC,
498 ) {
499 self.ensure_rare_data(no_gc)
500 .custom_element_reaction_queue
501 .push(CustomElementReaction::Upgrade(definition));
502 }
503
504 pub(crate) fn clear_reaction_queue(&self) {
505 if let Some(ref mut rare_data) = *self.rare_data_mut() {
506 rare_data.custom_element_reaction_queue.clear();
507 }
508 }
509
510 pub(crate) fn invoke_reactions(&self, cx: &mut JSContext) {
511 loop {
512 rooted_vec!(let mut reactions);
513 match *self.rare_data_mut() {
514 Some(ref mut data) => {
515 mem::swap(&mut *reactions, &mut data.custom_element_reaction_queue)
516 },
517 None => break,
518 };
519
520 if reactions.is_empty() {
521 break;
522 }
523
524 for reaction in reactions.iter() {
525 reaction.invoke(cx, self);
526 }
527
528 reactions.clear();
529 }
530 }
531
532 pub(crate) fn has_css_layout_box(&self) -> bool {
534 self.style()
535 .is_some_and(|s| !s.get_box().clone_display().is_none())
536 }
537
538 pub(crate) fn is_potentially_scrollable_body(&self) -> bool {
540 self.is_potentially_scrollable_body_shared_logic(false)
541 }
542
543 pub(crate) fn is_potentially_scrollable_body_for_scrolling_element(&self) -> bool {
545 self.is_potentially_scrollable_body_shared_logic(true)
546 }
547
548 fn is_potentially_scrollable_body_shared_logic(
550 &self,
551 treat_overflow_clip_on_parent_as_hidden: bool,
552 ) -> bool {
553 let node = self.upcast::<Node>();
554 debug_assert!(
555 node.owner_doc().GetBody().as_deref() == self.downcast::<HTMLElement>(),
556 "Called is_potentially_scrollable_body on element that is not the <body>"
557 );
558
559 if !self.has_css_layout_box() {
563 return false;
564 }
565
566 if let Some(parent) = node.GetParentElement() &&
569 let Some(style) = parent.style()
570 {
571 let mut overflow_x = style.get_box().clone_overflow_x();
572 let mut overflow_y = style.get_box().clone_overflow_y();
573
574 if treat_overflow_clip_on_parent_as_hidden {
577 if overflow_x == Overflow::Clip {
578 overflow_x = Overflow::Hidden;
579 }
580 if overflow_y == Overflow::Clip {
581 overflow_y = Overflow::Hidden;
582 }
583 }
584
585 if !overflow_x.is_scrollable() && !overflow_y.is_scrollable() {
586 return false;
587 }
588 };
589
590 if let Some(style) = self.style() &&
593 !style.get_box().clone_overflow_x().is_scrollable() &&
594 !style.get_box().clone_overflow_y().is_scrollable()
595 {
596 return false;
597 };
598
599 true
600 }
601
602 pub(crate) fn establishes_scroll_container(&self) -> bool {
605 self.upcast::<Node>()
607 .effective_overflow()
608 .is_some_and(|overflow| overflow.establishes_scroll_container())
609 }
610
611 pub(crate) fn establishes_scroll_container_without_reflow(&self) -> bool {
613 self.upcast::<Node>()
614 .effective_overflow_without_reflow()
615 .is_some_and(|overflow| overflow.establishes_scroll_container())
616 }
617
618 pub(crate) fn has_overflow(&self, no_gc: &NoGC) -> bool {
619 self.ScrollHeight() > self.ClientHeight(no_gc) ||
620 self.ScrollWidth() > self.ClientWidth(no_gc)
621 }
622
623 fn has_scrolling_box(&self, no_gc: &NoGC) -> bool {
631 self.has_css_layout_box() && self.establishes_scroll_container() && self.has_overflow(no_gc)
632 }
633
634 pub(crate) fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
635 self.rare_data()
636 .as_ref()?
637 .shadow_root
638 .as_ref()
639 .map(|sr| DomRoot::from_ref(&**sr))
640 }
641
642 pub(crate) fn shadow_root_unrooted<'a>(
643 &self,
644 no_gc: &'a NoGC,
645 ) -> Option<UnrootedDom<'a, ShadowRoot>> {
646 self.rare_data()
647 .as_ref()?
648 .shadow_root
649 .as_ref()
650 .map(|shadow_root| UnrootedDom::from_dom(shadow_root.clone(), no_gc))
651 }
652
653 pub(crate) fn is_shadow_host(&self) -> bool {
654 self.shadow_root().is_some()
655 }
656
657 #[allow(clippy::too_many_arguments)]
659 pub(crate) fn attach_shadow(
660 &self,
661 cx: &mut JSContext,
662 is_ua_widget: IsUserAgentWidget,
663 mode: ShadowRootMode,
664 clonable: bool,
665 serializable: bool,
666 delegates_focus: bool,
667 slot_assignment_mode: SlotAssignmentMode,
668 ) -> Fallible<DomRoot<ShadowRoot>> {
669 if self.namespace != ns!(html) {
672 return Err(Error::NotSupported(Some(
673 "Cannot attach shadow roots to elements with non-HTML namespaces".to_owned(),
674 )));
675 }
676
677 if !is_valid_shadow_host_name(self.local_name()) {
680 if is_ua_widget != IsUserAgentWidget::Yes {
682 let error_message = format!(
683 "Cannot attach shadow roots to <{}> elements",
684 *self.local_name()
685 );
686 return Err(Error::NotSupported(Some(error_message)));
687 }
688 }
689
690 if is_valid_custom_element_name(self.local_name()) || self.get_is().is_some() {
693 let definition = self.get_custom_element_definition();
697 if definition.is_some_and(|definition| definition.disable_shadow) {
700 let error_message = format!(
701 "The custom element constructor of <{}> disabled attachment of shadow roots",
702 self.local_name()
703 );
704 return Err(Error::NotSupported(Some(error_message)));
705 }
706 }
707
708 if let Some(current_shadow_root) = self.shadow_root() {
711 if !current_shadow_root.is_declarative() ||
715 current_shadow_root.shadow_root_mode() != mode
716 {
717 return Err(Error::NotSupported(Some(
718 "Cannot attach a second shadow root to the same element".into(),
719 )));
720 }
721
722 for child in current_shadow_root.upcast::<Node>().children() {
724 child.remove_self(cx);
725 }
726
727 current_shadow_root.set_declarative(false);
729
730 return Ok(current_shadow_root);
732 }
733
734 let document = self.node.owner_doc();
741 let shadow_root = ShadowRoot::new(
742 cx,
743 self,
744 &document,
745 mode,
746 slot_assignment_mode,
747 clonable,
748 is_ua_widget,
749 );
750
751 let node = self.upcast::<Node>();
755 if node.is_connected() {
756 document.remove_style_and_layout_data_from_subtree(cx.no_gc(), node);
757 }
758 if let Some(selection) = self.owner_document().selection() &&
759 node.get_flag(NodeFlags::OVERLAPS_DOCUMENT_SELECTION)
760 {
761 selection.set_visible_selection_dirty();
762 }
763
764 shadow_root.set_delegates_focus(delegates_focus);
766
767 if matches!(
770 self.get_custom_element_state(),
771 CustomElementState::Precustomized | CustomElementState::Custom
772 ) {
773 shadow_root.set_available_to_element_internals(true);
774 }
775
776 shadow_root.set_declarative(false);
778
779 shadow_root.set_serializable(serializable);
781
782 self.ensure_rare_data(cx.no_gc()).shadow_root = Some(Dom::from_ref(&*shadow_root));
784 shadow_root
785 .upcast::<Node>()
786 .set_containing_shadow_root(Some(&shadow_root));
787
788 let bind_context = BindContext::new(self.upcast(), IsShadowTree::Yes);
789 shadow_root.bind_to_tree(cx, &bind_context);
790
791 node.dirty(cx.no_gc(), NodeDamage::Other);
792
793 Ok(shadow_root)
794 }
795
796 pub(crate) fn attach_ua_shadow_root(
812 &self,
813 cx: &mut JSContext,
814 use_ua_widget_styling: bool,
815 ) -> DomRoot<ShadowRoot> {
816 let root = self
817 .attach_shadow(
818 cx,
819 IsUserAgentWidget::Yes,
820 ShadowRootMode::Closed,
821 false,
822 false,
823 false,
824 SlotAssignmentMode::Manual,
825 )
826 .expect("Attaching UA shadow root failed");
827
828 root.upcast::<Node>()
829 .set_in_ua_widget(use_ua_widget_styling);
830 root
831 }
832
833 pub(crate) fn is_translate_enabled(&self) -> bool {
835 let name = &local_name!("translate");
836 if self.has_attribute(name) {
837 let attribute = self.get_string_attribute(name);
838 match_ignore_ascii_case! { &*attribute.str(),
839 "yes" | "" => return true,
840 "no" => return false,
841 _ => {},
842 }
843 }
844 if let Some(parent) = self.upcast::<Node>().GetParentNode() &&
845 let Some(elem) = parent.downcast::<Element>()
846 {
847 return elem.is_translate_enabled();
848 }
849 true
850 }
851
852 pub(crate) fn directionality(&self) -> String {
854 self.downcast::<HTMLElement>()
855 .and_then(|html_element| html_element.directionality())
856 .unwrap_or_else(|| {
857 let node = self.upcast::<Node>();
858 node.parent_directionality()
859 })
860 }
861
862 pub(crate) fn is_root(&self) -> bool {
863 match self.node.GetParentNode() {
864 None => false,
865 Some(node) => node.is::<Document>(),
866 }
867 }
868
869 pub(crate) fn registered_intersection_observers_mut<'a: 'b, 'b>(
872 &'a self,
873 no_gc: &'b NoGC,
874 ) -> RefMut<'b, Vec<IntersectionObserverRegistration>> {
875 RefMut::map(self.ensure_rare_data(no_gc), |rare_data| {
876 &mut rare_data.registered_intersection_observers
877 })
878 }
879
880 pub(crate) fn registered_intersection_observers(
881 &self,
882 ) -> Option<Ref<'_, Vec<IntersectionObserverRegistration>>> {
883 let rare_data: Ref<'_, _> = self.rare_data.borrow();
884
885 if rare_data.is_none() {
886 return None;
887 }
888 Some(Ref::map(rare_data, |rare_data| {
889 &rare_data
890 .as_ref()
891 .unwrap()
892 .registered_intersection_observers
893 }))
894 }
895
896 pub(crate) fn get_intersection_observer_registration(
897 &self,
898 observer: &IntersectionObserver,
899 ) -> Option<Ref<'_, IntersectionObserverRegistration>> {
900 if let Some(registrations) = self.registered_intersection_observers() {
901 registrations
902 .iter()
903 .position(|reg_obs| reg_obs.observer == observer)
904 .map(|index| Ref::map(registrations, |registrations| ®istrations[index]))
905 } else {
906 None
907 }
908 }
909
910 pub(crate) fn add_initial_intersection_observer_registration(
912 &self,
913 observer: &IntersectionObserver,
914 no_gc: &NoGC,
915 ) {
916 self.ensure_rare_data(no_gc)
917 .registered_intersection_observers
918 .push(IntersectionObserverRegistration::new_initial(observer));
919 }
920
921 pub(crate) fn remove_intersection_observer(
923 &self,
924 observer: &IntersectionObserver,
925 no_gc: &NoGC,
926 ) {
927 self.ensure_rare_data(no_gc)
928 .registered_intersection_observers
929 .retain(|reg_obs| *reg_obs.observer != *observer)
930 }
931
932 pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
935 self.owner_window()
936 .scrolling_box_query(Some(self.upcast()), flags)
937 }
938
939 pub(crate) fn scroll_into_view_with_options(
941 &self,
942 cx: &mut JSContext,
943 behavior: ScrollBehavior,
944 block: ScrollAxisState,
945 inline: ScrollAxisState,
946 container: Option<&Element>,
947 inner_target_rect: Option<Rect<Au, CSSPixel>>,
948 ) {
949 let get_target_rect = || match inner_target_rect {
950 None => self.upcast::<Node>().border_box().unwrap_or_default(),
951 Some(inner_target_rect) => inner_target_rect.translate(
952 self.upcast::<Node>()
953 .content_box()
954 .unwrap_or_default()
955 .origin
956 .to_vector(),
957 ),
958 };
959
960 let mut parent_scrolling_box = self.scrolling_box(ScrollContainerQueryFlags::empty());
963 while let Some(scrolling_box) = parent_scrolling_box {
964 parent_scrolling_box = scrolling_box.parent();
965
966 let position = scrolling_box.determine_scroll_into_view_position(
977 cx.no_gc(),
978 block,
979 inline,
980 get_target_rect(),
981 );
982
983 if position != scrolling_box.scroll_position() {
988 scrolling_box.scroll_to(cx, position, behavior);
999 }
1000
1001 if container.is_some_and(|container| {
1005 let container_node = container.upcast::<Node>();
1006 scrolling_box
1007 .node()
1008 .is_shadow_including_inclusive_ancestor_of(container_node)
1009 }) {
1010 return;
1011 }
1012 }
1013
1014 let window_proxy = self.owner_window().window_proxy();
1015 let Some(frame_element) = window_proxy.frame_element() else {
1016 return;
1017 };
1018
1019 let inner_target_rect = Some(get_target_rect());
1020
1021 let mut realm = enter_auto_realm(cx, frame_element);
1022 let cx = &mut realm;
1023
1024 frame_element.scroll_into_view_with_options(
1025 cx,
1026 behavior,
1027 block,
1028 inline,
1029 None,
1030 inner_target_rect,
1031 )
1032 }
1033
1034 pub(crate) fn ensure_contenteditable_selection_range(
1035 &self,
1036 cx: &mut JSContext,
1037 document: &Document,
1038 ) -> DomRoot<Range> {
1039 let Some(selection_range) = self
1040 .rare_data()
1041 .as_ref()
1042 .and_then(|data| data.contenteditable_selection_range.get())
1043 else {
1044 let range = Range::new_with_doc(cx, document, None);
1045 self.ensure_rare_data(cx.no_gc())
1046 .contenteditable_selection_range
1047 .set(Some(&*range));
1048 return range;
1049 };
1050 selection_range
1051 }
1052
1053 pub(crate) fn handle_scroll_event(&self) {
1058 let document = self.owner_document();
1060
1061 document.finish_handle_scroll_event(self.upcast());
1070 }
1071
1072 pub(crate) fn style(&self) -> Option<ServoArc<ComputedValues>> {
1073 self.owner_window().layout_reflow(QueryMsg::StyleQuery);
1074 self.style_data
1075 .borrow()
1076 .as_ref()
1077 .map(|data| data.element_data.borrow().styles.primary().clone())
1078 }
1079
1080 pub(crate) fn is_styled(&self) -> bool {
1081 self.style_data.borrow().is_some()
1082 }
1083
1084 pub(crate) fn is_display_none(&self) -> bool {
1085 self.style_data.borrow().as_ref().is_none_or(|data| {
1086 data.element_data
1087 .borrow()
1088 .styles
1089 .primary()
1090 .get_box()
1091 .display
1092 .is_none()
1093 })
1094 }
1095
1096 pub(crate) fn check_style_on_self_or_eager_pseudos(
1097 &self,
1098 check_styles_fn: impl Fn(&ComputedValues) -> bool,
1099 ) -> bool {
1100 let style_data = self.style_data.borrow();
1101 let Some(data) = style_data.as_ref().map(|data| data.element_data.borrow()) else {
1102 return false;
1103 };
1104
1105 if check_styles_fn(data.styles.primary()) {
1106 return true;
1107 }
1108
1109 let mut pseudo_styles = data.styles.pseudos.as_array().iter();
1110 pseudo_styles.any(|style| style.as_deref().is_some_and(&check_styles_fn))
1111 }
1112}
1113
1114#[inline]
1116pub(crate) fn is_valid_shadow_host_name(name: &LocalName) -> bool {
1117 if is_valid_custom_element_name(name) {
1120 return true;
1121 }
1122
1123 matches!(
1126 name,
1127 &local_name!("article") |
1128 &local_name!("aside") |
1129 &local_name!("blockquote") |
1130 &local_name!("body") |
1131 &local_name!("div") |
1132 &local_name!("footer") |
1133 &local_name!("h1") |
1134 &local_name!("h2") |
1135 &local_name!("h3") |
1136 &local_name!("h4") |
1137 &local_name!("h5") |
1138 &local_name!("h6") |
1139 &local_name!("header") |
1140 &local_name!("main") |
1141 &local_name!("nav") |
1142 &local_name!("p") |
1143 &local_name!("section") |
1144 &local_name!("span")
1145 )
1146}
1147
1148#[inline]
1149#[expect(unsafe_code)]
1150pub(crate) fn get_attr_for_layout<'dom>(
1151 elem: LayoutDom<'dom, Element>,
1152 namespace: &Namespace,
1153 name: &LocalName,
1154) -> Option<&'dom AttrValue> {
1155 let storage = unsafe { elem.unsafe_get().attrs.borrow_for_layout() };
1156 storage
1157 .iter()
1158 .find(|e: &&AttributeEntry| {
1159 name == e.local_name_for_layout() && namespace == e.namespace_for_layout()
1160 })
1161 .map(|e: &AttributeEntry| e.value_for_layout())
1162}
1163
1164impl<'dom> LayoutDom<'dom, Element> {
1165 #[inline]
1166 pub(crate) fn is_root(&self) -> bool {
1167 self.upcast::<Node>()
1168 .parent_node_ref()
1169 .is_some_and(|parent| matches!(parent.type_id_for_layout(), NodeTypeId::Document(_)))
1170 }
1171
1172 pub(crate) fn is_body_element_of_html_element_root(&self) -> bool {
1174 if self.local_name() != &local_name!("body") {
1175 return false;
1176 }
1177 let Some(parent_node) = self.upcast::<Node>().parent_node_ref() else {
1178 return false;
1179 };
1180 let Some(parent_element) = parent_node.downcast::<Element>() else {
1181 return false;
1182 };
1183 parent_element.local_name() == &local_name!("html")
1184 }
1185
1186 #[expect(unsafe_code)]
1188 #[inline]
1189 pub(crate) fn each_attr_name_for_layout<F>(self, mut callback: F)
1190 where
1191 F: FnMut(&LocalName),
1192 {
1193 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1194 for entry in storage.iter() {
1195 callback(entry.local_name_for_layout());
1196 }
1197 }
1198
1199 #[inline]
1200 pub(crate) fn has_class_or_part_for_layout(
1201 self,
1202 name: &AtomIdent,
1203 attr_name: &LocalName,
1204 case_sensitivity: CaseSensitivity,
1205 ) -> bool {
1206 get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
1207 attr.as_tokens()
1208 .iter()
1209 .any(|atom| case_sensitivity.eq_atom(atom, name))
1210 })
1211 }
1212
1213 #[inline]
1214 pub(crate) fn get_classes_for_layout(self) -> Option<&'dom [Atom]> {
1215 get_attr_for_layout(self, &ns!(), &local_name!("class")).map(|attr| attr.as_tokens())
1216 }
1217
1218 pub(crate) fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
1219 get_attr_for_layout(self, &ns!(), &local_name!("part")).map(|attr| attr.as_tokens())
1220 }
1221
1222 #[inline]
1223 #[expect(unsafe_code)]
1224 pub(crate) fn style_data(self) -> Option<&'dom StyleData> {
1225 unsafe { self.unsafe_get().style_data.borrow_for_layout().as_deref() }
1226 }
1227
1228 #[inline]
1229 #[expect(unsafe_code)]
1230 pub(crate) unsafe fn initialize_style_data(self) {
1231 let data = unsafe { self.unsafe_get().style_data.borrow_mut_for_layout() };
1232 debug_assert!(data.is_none());
1233 *data = Some(Box::default());
1234 }
1235
1236 #[inline]
1237 #[expect(unsafe_code)]
1238 pub(crate) unsafe fn clear_style_data(self) {
1239 unsafe {
1240 self.unsafe_get().style_data.borrow_mut_for_layout().take();
1241 }
1242 }
1243
1244 pub(crate) fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
1245 where
1246 V: Push<ApplicableDeclarationBlock>,
1247 {
1248 let document = self.upcast::<Node>().owner_doc_for_layout();
1251 let mut property_declaration_block = None;
1252 let mut push = |declaration| {
1253 property_declaration_block
1254 .get_or_insert_with(PropertyDeclarationBlock::default)
1255 .push(declaration, Importance::Normal);
1256 };
1257
1258 if let Some(lang) = self.get_lang_attr_val_for_layout() {
1261 push(PropertyDeclaration::XLang(specified::XLang(Atom::from(
1262 lang.to_owned(),
1263 ))));
1264 }
1265
1266 let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
1267 this.get_background_color()
1268 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1269 this.get_background_color()
1270 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1271 this.get_background_color()
1272 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1273 this.get_background_color()
1274 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1275 this.get_background_color()
1276 } else {
1277 None
1278 };
1279
1280 if let Some(color) = bgcolor {
1281 push(PropertyDeclaration::BackgroundColor(
1282 specified::Color::from_absolute_color(color),
1283 ));
1284 }
1285
1286 if is_element_affected_by_legacy_background_presentational_hint(
1287 self.namespace(),
1288 self.local_name(),
1289 ) && let Some(url) = self
1290 .get_attr_for_layout(&ns!(), &local_name!("background"))
1291 .and_then(AttrValue::as_resolved_url)
1292 .cloned()
1293 {
1294 push(PropertyDeclaration::BackgroundImage(
1295 background_image::SpecifiedValue(vec![specified::Image::for_cascade(url)].into()),
1296 ));
1297 }
1298
1299 let color = if let Some(this) = self.downcast::<HTMLFontElement>() {
1300 this.get_color()
1301 } else if let Some(this) = self.downcast::<HTMLBodyElement>() {
1302 this.get_color()
1304 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1305 this.get_color()
1307 } else {
1308 None
1309 };
1310
1311 if let Some(color) = color {
1312 push(PropertyDeclaration::Color(
1313 longhands::color::SpecifiedValue(specified::Color::from_absolute_color(color)),
1314 ));
1315 }
1316
1317 let font_face = self
1318 .downcast::<HTMLFontElement>()
1319 .and_then(LayoutDom::get_face);
1320 if let Some(font_face) = font_face {
1321 push(PropertyDeclaration::FontFamily(
1322 font_family::SpecifiedValue::Values(computed::font::FontFamilyList {
1323 list: ArcSlice::from_iter(
1324 HTMLFontElement::parse_face_attribute(font_face).into_iter(),
1325 ),
1326 }),
1327 ));
1328 }
1329
1330 let font_size = self
1331 .downcast::<HTMLFontElement>()
1332 .and_then(LayoutDom::get_size);
1333 if let Some(font_size) = font_size {
1334 push(PropertyDeclaration::FontSize(
1335 font_size::SpecifiedValue::from_html_size(font_size as u8),
1336 ));
1337 }
1338
1339 let size = self
1345 .downcast::<HTMLInputElement>()
1346 .and_then(|input_element| {
1347 match self.get_attr_val_for_layout(&ns!(), &local_name!("type")) {
1349 Some("hidden") | Some("range") | Some("color") | Some("checkbox") |
1350 Some("radio") | Some("file") | Some("submit") | Some("image") |
1351 Some("reset") | Some("button") => None,
1352 _ => match input_element.size_for_layout() {
1354 0 => None,
1355 s => Some(s as i32),
1356 },
1357 }
1358 });
1359
1360 if let Some(size) = size {
1361 let value = specified::NoCalcLength::from_servo_character_width(size);
1362 push(PropertyDeclaration::Width(
1363 specified::Size::LengthPercentage(NonNegative(
1364 specified::LengthPercentage::Length(value),
1365 )),
1366 ));
1367 }
1368
1369 let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1370 this.get_width()
1371 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1372 this.get_width()
1373 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1374 this.get_width()
1375 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1376 this.get_width()
1377 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1378 this.get_width()
1379 } else if let Some(this) = self.downcast::<HTMLTableColElement>() {
1380 this.get_width()
1381 } else if let Some(this) = self.downcast::<HTMLHRElement>() {
1382 this.get_width()
1384 } else {
1385 LengthOrPercentageOrAuto::Auto
1386 };
1387
1388 match width {
1390 LengthOrPercentageOrAuto::Auto => {},
1391 LengthOrPercentageOrAuto::Percentage(percentage) => {
1392 let width_value = specified::Size::LengthPercentage(NonNegative(
1393 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1394 percentage,
1395 )),
1396 ));
1397 push(PropertyDeclaration::Width(width_value));
1398 },
1399 LengthOrPercentageOrAuto::Length(length) => {
1400 let width_value = specified::Size::LengthPercentage(NonNegative(
1401 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1402 length.to_f32_px(),
1403 )),
1404 ));
1405 push(PropertyDeclaration::Width(width_value));
1406 },
1407 }
1408
1409 let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
1410 this.get_height()
1411 } else if let Some(this) = self.downcast::<HTMLImageElement>() {
1412 this.get_height()
1413 } else if let Some(this) = self.downcast::<HTMLVideoElement>() {
1414 this.get_height()
1415 } else if let Some(this) = self.downcast::<HTMLTableElement>() {
1416 this.get_height()
1417 } else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
1418 this.get_height()
1419 } else if let Some(this) = self.downcast::<HTMLTableRowElement>() {
1420 this.get_height()
1421 } else if let Some(this) = self.downcast::<HTMLTableSectionElement>() {
1422 this.get_height()
1423 } else {
1424 LengthOrPercentageOrAuto::Auto
1425 };
1426
1427 match height {
1428 LengthOrPercentageOrAuto::Auto => {},
1429 LengthOrPercentageOrAuto::Percentage(percentage) => {
1430 let height_value = specified::Size::LengthPercentage(NonNegative(
1431 specified::LengthPercentage::Percentage(specified::NoCalcPercentage::new(
1432 percentage,
1433 )),
1434 ));
1435 push(PropertyDeclaration::Height(height_value));
1436 },
1437 LengthOrPercentageOrAuto::Length(length) => {
1438 let height_value = specified::Size::LengthPercentage(NonNegative(
1439 specified::LengthPercentage::Length(specified::NoCalcLength::from_px(
1440 length.to_f32_px(),
1441 )),
1442 ));
1443 push(PropertyDeclaration::Height(height_value));
1444 },
1445 }
1446
1447 if let Some(svg_element) = self.downcast::<SVGElement>() {
1448 svg_element.synthesize_presentational_hints(document, &mut push);
1449 }
1450
1451 if (self.is::<HTMLImageElement>() || self.is::<HTMLVideoElement>()) &&
1454 let LengthOrPercentageOrAuto::Length(width) = width &&
1455 let LengthOrPercentageOrAuto::Length(height) = height
1456 {
1457 let width_value = NonNegative(specified::Number::new(width.to_f32_px()));
1458 let height_value = NonNegative(specified::Number::new(height.to_f32_px()));
1459 let aspect_ratio = specified::position::AspectRatio {
1460 auto: true,
1461 ratio: PreferredRatio::Ratio(Ratio(width_value, height_value)),
1462 };
1463 push(PropertyDeclaration::AspectRatio(Box::new(aspect_ratio)));
1464 }
1465
1466 let cols = self
1467 .downcast::<HTMLTextAreaElement>()
1468 .map(LayoutDom::get_cols);
1469 if let Some(cols) = cols {
1470 let cols = cols as i32;
1471 if cols > 0 {
1472 let value = specified::NoCalcLength::from_servo_character_width(cols);
1478 push(PropertyDeclaration::Width(
1479 specified::Size::LengthPercentage(NonNegative(
1480 specified::LengthPercentage::Length(value),
1481 )),
1482 ));
1483 }
1484 }
1485
1486 let rows = self
1487 .downcast::<HTMLTextAreaElement>()
1488 .map(LayoutDom::get_rows);
1489 if let Some(rows) = rows {
1490 let rows = rows as i32;
1491 if rows > 0 {
1492 let value = specified::NoCalcLength::from_em(rows as CSSFloat);
1496 push(PropertyDeclaration::Height(
1497 specified::Size::LengthPercentage(NonNegative(
1498 specified::LengthPercentage::Length(value),
1499 )),
1500 ));
1501 }
1502 }
1503
1504 if let Some(table) = self.downcast::<HTMLTableElement>() {
1505 if let Some(cellspacing) = table.get_cellspacing() {
1506 let width_value = specified::Length::from_px(cellspacing as f32);
1507 push(PropertyDeclaration::BorderSpacing(
1508 border_spacing::SpecifiedValue::new(
1509 width_value.clone().into(),
1510 width_value.into(),
1511 ),
1512 ));
1513 }
1514 if let Some(border) = table.get_border() {
1515 let width_value = specified::BorderSideWidth::from_px(border as f32);
1516 push(PropertyDeclaration::BorderTopWidth(width_value.clone()));
1517 push(PropertyDeclaration::BorderLeftWidth(width_value.clone()));
1518 push(PropertyDeclaration::BorderBottomWidth(width_value.clone()));
1519 push(PropertyDeclaration::BorderRightWidth(width_value));
1520 }
1521 if document.quirks_mode() == QuirksMode::Quirks {
1522 push(PropertyDeclaration::Color(color::SpecifiedValue(
1524 specified::Color::InheritFromBodyQuirk,
1525 )));
1526 }
1527 }
1528
1529 if let Some(cellpadding) = self
1530 .downcast::<HTMLTableCellElement>()
1531 .and_then(|this| this.get_table())
1532 .and_then(|table| table.get_cellpadding())
1533 {
1534 let cellpadding = NonNegative(specified::LengthPercentage::Length(
1535 specified::NoCalcLength::from_px(cellpadding as f32),
1536 ));
1537 push(PropertyDeclaration::PaddingTop(cellpadding.clone()));
1538 push(PropertyDeclaration::PaddingLeft(cellpadding.clone()));
1539 push(PropertyDeclaration::PaddingBottom(cellpadding.clone()));
1540 push(PropertyDeclaration::PaddingRight(cellpadding));
1541 }
1542
1543 if let Some(size_info) = self
1545 .downcast::<HTMLHRElement>()
1546 .and_then(|hr_element| hr_element.get_size_info())
1547 {
1548 match size_info {
1549 SizePresentationalHint::SetHeightTo(height) => {
1550 push(PropertyDeclaration::Height(height));
1551 },
1552 SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
1553 push(PropertyDeclaration::BorderLeftWidth(border_width.clone()));
1554 push(PropertyDeclaration::BorderRightWidth(border_width.clone()));
1555 push(PropertyDeclaration::BorderTopWidth(border_width.clone()));
1556 push(PropertyDeclaration::BorderBottomWidth(border_width));
1557 },
1558 SizePresentationalHint::SetBottomBorderWidthToZero => {
1559 push(PropertyDeclaration::BorderBottomWidth(
1560 specified::border::BorderSideWidth::from_px(0.),
1561 ));
1562 },
1563 }
1564 }
1565
1566 let Some(property_declaration_block) = property_declaration_block else {
1567 return;
1568 };
1569
1570 let shared_lock = &document.shared_style_locks().author;
1571 hints.push(ApplicableDeclarationBlock::from_declarations(
1572 ServoArc::new(shared_lock.wrap(property_declaration_block)),
1573 CascadeLevel::new(CascadeOrigin::PresHints),
1574 LayerOrder::root(),
1575 ));
1576 }
1577
1578 pub(crate) fn get_span(self) -> Option<u32> {
1579 self.downcast::<HTMLTableColElement>()
1581 .and_then(|element| element.get_span())
1582 }
1583
1584 pub(crate) fn get_colspan(self) -> Option<u32> {
1585 self.downcast::<HTMLTableCellElement>()
1587 .and_then(|element| element.get_colspan())
1588 }
1589
1590 pub(crate) fn get_rowspan(self) -> Option<u32> {
1591 self.downcast::<HTMLTableCellElement>()
1593 .and_then(|element| element.get_rowspan())
1594 }
1595
1596 #[inline]
1597 pub(crate) fn is_html_element(&self) -> bool {
1598 *self.namespace() == ns!(html)
1599 }
1600
1601 #[expect(unsafe_code)]
1602 pub(crate) fn id_attribute(self) -> *const Option<Atom> {
1603 unsafe { (self.unsafe_get()).id_attribute.borrow_for_layout() }
1604 }
1605
1606 #[expect(unsafe_code)]
1607 pub(crate) fn style_attribute(
1608 self,
1609 ) -> *const Option<ServoArc<Locked<PropertyDeclarationBlock>>> {
1610 unsafe { (self.unsafe_get()).style_attribute.borrow_for_layout() }
1611 }
1612
1613 pub(crate) fn local_name(self) -> &'dom LocalName {
1614 &(self.unsafe_get()).local_name
1615 }
1616
1617 pub(crate) fn namespace(self) -> &'dom Namespace {
1618 &(self.unsafe_get()).namespace
1619 }
1620
1621 pub(crate) fn get_lang_attr_val_for_layout(self) -> Option<&'dom str> {
1622 if let Some(attr) = self.get_attr_val_for_layout(&ns!(xml), &local_name!("lang")) {
1623 return Some(attr);
1624 }
1625 if let Some(attr) = self.get_attr_val_for_layout(&ns!(), &local_name!("lang")) {
1626 return Some(attr);
1627 }
1628 None
1629 }
1630
1631 pub(crate) fn get_lang_for_layout(self) -> AtomString {
1632 let mut current_node = Some(self.upcast::<Node>());
1633 while let Some(node) = current_node {
1634 current_node = node.composed_parent_node_ref();
1635 match node.downcast::<Element>() {
1636 Some(elem) => {
1637 if let Some(attr) = elem.get_lang_attr_val_for_layout() {
1638 return AtomString::from(attr);
1639 }
1640 },
1641 None => continue,
1642 }
1643 }
1644 AtomString::default()
1647 }
1648
1649 #[inline]
1650 pub(crate) fn get_state_for_layout(self) -> ElementState {
1651 (self.unsafe_get()).state.get()
1652 }
1653
1654 #[inline]
1655 pub(crate) fn insert_selector_flags(self, flags: ElementSelectorFlags) {
1656 debug_assert!(thread_state::get().is_layout());
1657 self.unsafe_get().insert_selector_flags(flags);
1658 }
1659
1660 #[inline]
1661 pub(crate) fn get_selector_flags(self) -> ElementSelectorFlags {
1662 self.unsafe_get().get_selector_flags()
1663 }
1664
1665 #[inline]
1666 #[expect(unsafe_code)]
1667 pub(crate) fn get_shadow_root_for_layout(self) -> Option<LayoutDom<'dom, ShadowRoot>> {
1668 unsafe {
1669 self.unsafe_get()
1670 .rare_data
1671 .borrow_for_layout()
1672 .as_ref()?
1673 .shadow_root
1674 .as_ref()
1675 .map(|sr| sr.to_layout())
1676 }
1677 }
1678
1679 #[inline]
1680 pub(crate) fn get_attr_for_layout(
1681 self,
1682 namespace: &Namespace,
1683 name: &LocalName,
1684 ) -> Option<&'dom AttrValue> {
1685 get_attr_for_layout(self, namespace, name)
1686 }
1687
1688 #[inline]
1689 pub(crate) fn get_attr_val_for_layout(
1690 self,
1691 namespace: &Namespace,
1692 name: &LocalName,
1693 ) -> Option<&'dom str> {
1694 get_attr_for_layout(self, namespace, name).map(|attr| &**attr)
1695 }
1696
1697 #[inline]
1698 #[expect(unsafe_code)]
1699 pub(crate) fn get_attr_vals_for_layout(
1700 self,
1701 name: &LocalName,
1702 ) -> impl Iterator<Item = &'dom AttrValue> {
1703 let storage = unsafe { self.unsafe_get().attrs.borrow_for_layout() };
1704 storage
1705 .iter()
1706 .filter(move |e: &&AttributeEntry| name == e.local_name_for_layout())
1707 .map(|e: &AttributeEntry| e.value_for_layout())
1708 }
1709
1710 #[expect(unsafe_code)]
1711 pub(crate) fn each_custom_state_for_layout(self, mut callback: impl FnMut(&AtomIdent)) {
1712 let rare_data = unsafe { self.unsafe_get().rare_data.borrow_for_layout() };
1713 let Some(rare_data) = rare_data.as_ref() else {
1714 return;
1715 };
1716 let Some(element_internals) = rare_data.element_internals.as_ref() else {
1717 return;
1718 };
1719
1720 let element_internals: LayoutDom<'_, _> = unsafe { element_internals.to_layout() };
1721 if let Some(states) = element_internals.unsafe_get().custom_states_for_layout() {
1722 for state in states.unsafe_get().set_for_layout().iter() {
1723 callback(&AtomIdent::from(&*state.str()));
1725 }
1726 }
1727 }
1728}
1729
1730impl Element {
1731 pub(crate) fn is_html_element(&self) -> bool {
1732 self.namespace == ns!(html)
1733 }
1734
1735 pub(crate) fn is_svg_element(&self) -> bool {
1736 self.namespace == ns!(svg)
1737 }
1738
1739 pub(crate) fn html_element_in_html_document(&self) -> bool {
1740 self.is_html_element() && self.upcast::<Node>().is_in_html_doc()
1741 }
1742
1743 pub(crate) fn local_name(&self) -> &LocalName {
1744 &self.local_name
1745 }
1746
1747 pub(crate) fn parsed_name(&self, mut name: DOMString) -> LocalName {
1748 if self.html_element_in_html_document() {
1749 name.make_ascii_lowercase();
1750 }
1751 LocalName::from(name)
1752 }
1753
1754 pub(crate) fn namespace(&self) -> &Namespace {
1755 &self.namespace
1756 }
1757
1758 pub(crate) fn prefix(&self) -> Ref<'_, Option<Prefix>> {
1759 self.prefix.borrow()
1760 }
1761
1762 pub(crate) fn set_prefix(&self, prefix: Option<Prefix>) {
1763 *self.prefix.borrow_mut() = prefix;
1764 }
1765
1766 pub(crate) fn set_custom_element_registry(
1767 &self,
1768 registry: Option<&CustomElementRegistry>,
1769 no_gc: &NoGC,
1770 ) {
1771 self.ensure_rare_data(no_gc).custom_element_registry = registry.map(Dom::from_ref);
1772 }
1773
1774 pub(crate) fn custom_element_registry(&self) -> Option<DomRoot<CustomElementRegistry>> {
1775 self.rare_data()
1776 .as_ref()?
1777 .custom_element_registry
1778 .as_deref()
1779 .map(DomRoot::from_ref)
1780 }
1781
1782 pub(crate) fn attrs(&self) -> &AttributeStorage {
1783 &self.attrs
1784 }
1785
1786 pub(crate) fn dom_attrs(&self, cx: &mut JSContext) -> &AttributeStorage {
1787 let len = self.attrs.borrow().len();
1789 for i in 0..len {
1790 self.attrs.ensure_dom(cx, i, self);
1791 }
1792 &self.attrs
1793 }
1794
1795 pub(crate) fn locate_namespace(&self, prefix: Option<DOMString>) -> Namespace {
1797 let namespace_prefix = prefix.clone().map(|s| Prefix::from(&*s.str()));
1798
1799 if namespace_prefix == Some(namespace_prefix!("xml")) {
1801 return ns!(xml);
1802 }
1803
1804 if namespace_prefix == Some(namespace_prefix!("xmlns")) {
1806 return ns!(xmlns);
1807 }
1808
1809 let prefix = prefix.map(LocalName::from);
1810
1811 let inclusive_ancestor_elements = self
1812 .upcast::<Node>()
1813 .inclusive_ancestors(ShadowIncluding::No)
1814 .filter_map(DomRoot::downcast::<Self>);
1815
1816 for element in inclusive_ancestor_elements {
1819 if element.namespace() != &ns!() &&
1821 element.prefix().as_ref().map(|p| &**p) == prefix.as_deref()
1822 {
1823 return element.namespace().clone();
1824 }
1825
1826 let found_ns = element.attrs.borrow().iter().find_map(|attr| {
1831 if attr.namespace() != &ns!(xmlns) {
1832 return None;
1833 }
1834 match (attr.prefix(), prefix.as_ref()) {
1835 (Some(&namespace_prefix!("xmlns")), Some(prefix)) => {
1836 if attr.local_name() == prefix {
1837 Some(Namespace::from(&**attr.value()))
1838 } else {
1839 None
1840 }
1841 },
1842 (None, None) => {
1843 if attr.local_name() == &local_name!("xmlns") {
1844 Some(Namespace::from(&**attr.value()))
1845 } else {
1846 None
1847 }
1848 },
1849 _ => None,
1850 }
1851 });
1852
1853 if let Some(ns) = found_ns {
1854 return ns;
1855 }
1856 }
1857
1858 ns!()
1859 }
1860
1861 pub(crate) fn name_attribute(&self) -> Option<Atom> {
1862 self.rare_data().as_ref()?.name_attribute.clone()
1863 }
1864
1865 pub(crate) fn style_attribute(
1866 &self,
1867 ) -> &DomRefCell<Option<ServoArc<Locked<PropertyDeclarationBlock>>>> {
1868 &self.style_attribute
1869 }
1870
1871 pub(crate) fn summarize(&self) -> Vec<AttrInfo> {
1872 self.attrs
1873 .borrow()
1874 .iter()
1875 .map(|attr| attr.summarize())
1876 .collect()
1877 }
1878
1879 pub(crate) fn is_void(&self) -> bool {
1880 if self.namespace != ns!(html) {
1881 return false;
1882 }
1883 match self.local_name {
1884 local_name!("area") |
1887 local_name!("base") |
1888 local_name!("basefont") |
1889 local_name!("bgsound") |
1890 local_name!("br") |
1891 local_name!("col") |
1892 local_name!("embed") |
1893 local_name!("frame") |
1894 local_name!("hr") |
1895 local_name!("img") |
1896 local_name!("input") |
1897 local_name!("keygen") |
1898 local_name!("link") |
1899 local_name!("meta") |
1900 local_name!("param") |
1901 local_name!("source") |
1902 local_name!("track") |
1903 local_name!("wbr") => true,
1904 _ => false,
1905 }
1906 }
1907
1908 pub(crate) fn root_element(&self) -> DomRoot<Element> {
1909 if self.node.is_in_a_document_tree() {
1910 self.upcast::<Node>()
1911 .owner_doc()
1912 .GetDocumentElement()
1913 .unwrap()
1914 } else {
1915 self.upcast::<Node>()
1916 .inclusive_ancestors(ShadowIncluding::No)
1917 .filter_map(DomRoot::downcast)
1918 .last()
1919 .expect("We know inclusive_ancestors will return `self` which is an element")
1920 }
1921 }
1922
1923 pub(crate) fn lookup_prefix(&self, namespace: Namespace) -> Option<DOMString> {
1925 for node in self
1926 .upcast::<Node>()
1927 .inclusive_ancestors(ShadowIncluding::No)
1928 {
1929 let element = node.downcast::<Element>()?;
1930 if *element.namespace() == namespace &&
1932 let Some(prefix) = element.GetPrefix()
1933 {
1934 return Some(prefix);
1935 }
1936
1937 for attr in element.attrs.borrow().iter() {
1939 if attr.prefix() == Some(&namespace_prefix!("xmlns")) &&
1940 **attr.value() == *namespace
1941 {
1942 return Some(DOMString::from(&**attr.local_name()));
1943 }
1944 }
1945 }
1946 None
1947 }
1948
1949 pub(crate) fn is_document_element(&self) -> bool {
1951 if let Some(document_element) = self.owner_document().GetDocumentElement() {
1952 *document_element == *self
1953 } else {
1954 false
1955 }
1956 }
1957
1958 pub(crate) fn is_active_element(&self) -> bool {
1960 if let Some(active_element) = self.owner_document().GetActiveElement() {
1961 *active_element == *self
1962 } else {
1963 false
1964 }
1965 }
1966
1967 pub(crate) fn is_editing_host(&self) -> bool {
1968 self.downcast::<HTMLElement>()
1969 .is_some_and(|element| element.IsContentEditable())
1970 }
1971
1972 pub(crate) fn is_actually_disabled(&self) -> bool {
1973 let node = self.upcast::<Node>();
1974 match node.type_id() {
1975 NodeTypeId::Element(ElementTypeId::HTMLElement(
1976 HTMLElementTypeId::HTMLButtonElement,
1977 )) |
1978 NodeTypeId::Element(ElementTypeId::HTMLElement(
1979 HTMLElementTypeId::HTMLInputElement,
1980 )) |
1981 NodeTypeId::Element(ElementTypeId::HTMLElement(
1982 HTMLElementTypeId::HTMLSelectElement,
1983 )) |
1984 NodeTypeId::Element(ElementTypeId::HTMLElement(
1985 HTMLElementTypeId::HTMLTextAreaElement,
1986 )) |
1987 NodeTypeId::Element(ElementTypeId::HTMLElement(
1988 HTMLElementTypeId::HTMLOptionElement,
1989 )) => self.disabled_state(),
1990 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
1991 self.downcast::<HTMLElement>()
1992 .unwrap()
1993 .is_form_associated_custom_element() &&
1994 self.disabled_state()
1995 },
1996 _ => false,
2001 }
2002 }
2003
2004 #[allow(clippy::too_many_arguments)]
2005 pub(crate) fn push_new_attribute(
2006 &self,
2007 cx: &mut JSContext,
2008 local_name: LocalName,
2009 value: AttrValue,
2010 name: LocalName,
2011 namespace: Namespace,
2012 prefix: Option<Prefix>,
2013 reason: AttributeMutationReason,
2014 ) {
2015 let data = ContentAttributeData {
2020 identifier: AttrIdentifier {
2021 local_name: GenericAtomIdent(local_name),
2022 name: GenericAtomIdent(name),
2023 namespace: GenericAtomIdent(namespace),
2024 prefix: prefix.map(GenericAtomIdent),
2025 },
2026 value,
2027 };
2028 let attr_ref = AttrRef::Raw(&data);
2029 self.will_mutate_attr(attr_ref);
2030 self.attrs.push_raw(ContentAttributeData {
2032 identifier: data.identifier.clone(),
2033 value: data.value.clone(),
2034 });
2035 self.handle_attribute_changes(cx, attr_ref, None, Some(&*attr_ref.value()), reason);
2037 }
2038
2039 fn handle_attribute_changes(
2041 &self,
2042 cx: &mut JSContext,
2043 attr: AttrRef<'_>,
2044 old_value: Option<&AttrValue>,
2045 new_value: Option<&AttrValue>,
2046 reason: AttributeMutationReason,
2047 ) {
2048 let name = attr.local_name().clone();
2051 let namespace = attr.namespace().clone();
2052 let mutation = LazyCell::new(|| Mutation::Attribute {
2053 name: name.clone(),
2054 namespace: namespace.clone(),
2055 old_value: old_value.map(|old_value| DOMString::from(&**old_value)),
2056 });
2057 MutationObserver::queue_a_mutation_record(cx, &self.node, mutation);
2058
2059 let has_new_value = new_value.is_some();
2061
2062 if self.is_custom() {
2065 let reaction = CallbackReaction::AttributeChanged(
2066 attr.local_name().clone(),
2067 old_value,
2068 new_value,
2069 attr.namespace().clone(),
2070 );
2071 ScriptThread::enqueue_callback_reaction(cx, self, reaction, None);
2072 }
2073
2074 if is_relevant_attribute(attr.namespace(), attr.local_name()) {
2076 let attribute_mutation = if has_new_value {
2077 AttributeMutation::Set(old_value, reason)
2078 } else {
2079 AttributeMutation::Removed
2080 };
2081 vtable_for(self.upcast()).attribute_mutated(cx, attr, attribute_mutation);
2082 }
2083 }
2084
2085 pub(crate) fn change_attribute(&self, cx: &mut JSContext, attr: &Attr, mut value: AttrValue) {
2087 let old_value = &attr.value().clone();
2091 self.will_mutate_attr(AttrRef::Dom(attr));
2093 attr.swap_value(&mut value);
2094 self.handle_attribute_changes(
2098 cx,
2099 AttrRef::Dom(attr),
2100 Some(old_value),
2101 Some(&*attr.value()),
2102 AttributeMutationReason::Directly,
2103 );
2104 }
2105
2106 pub(crate) fn push_attribute(
2108 &self,
2109 cx: &mut JSContext,
2110 attr: &Attr,
2111 reason: AttributeMutationReason,
2112 ) {
2113 assert!(attr.GetOwnerElement().as_deref() == Some(self));
2117 assert!(attr.upcast::<Node>().owner_doc() == self.node.owner_doc());
2121 self.will_mutate_attr(AttrRef::Dom(attr));
2123 self.attrs.push_dom(attr);
2124 self.handle_attribute_changes(cx, AttrRef::Dom(attr), None, Some(&*attr.value()), reason);
2128 }
2129
2130 pub(crate) fn with_attribute<R, F>(
2131 &self,
2132 namespace: &Namespace,
2133 local_name: &LocalName,
2134 map_func: F,
2135 ) -> Option<R>
2136 where
2137 F: FnOnce(AttrRef<'_>) -> R,
2138 {
2139 self.attrs
2140 .borrow()
2141 .iter()
2142 .find(|attribute| {
2143 attribute.local_name() == local_name && attribute.namespace() == namespace
2144 })
2145 .map(map_func)
2146 }
2147
2148 pub(crate) fn get_attribute_with_namespace(
2154 &self,
2155 cx: &mut JSContext,
2156 namespace: &Namespace,
2157 local_name: &LocalName,
2158 ) -> Option<DomRoot<Attr>> {
2159 let idx = self
2160 .attrs
2161 .borrow()
2162 .iter()
2163 .position(|a| a.local_name() == local_name && a.namespace() == namespace)?;
2164 Some(self.attrs.ensure_dom(cx, idx, self))
2165 }
2166
2167 pub(crate) fn get_attribute_by_name(
2169 &self,
2170 cx: &mut JSContext,
2171 name: DOMString,
2172 ) -> Option<DomRoot<Attr>> {
2173 let name = &self.parsed_name(name);
2174 let idx = self.attrs.borrow().iter().position(|a| a.name() == name)?;
2175 let attr_dom = Some(self.attrs.ensure_dom(cx, idx, self));
2176 fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
2177 if *name == local_name!("id") || *name == local_name!("name") {
2178 match maybe_attr {
2179 None => true,
2180 Some(attr) => matches!(*attr.value(), AttrValue::Atom(_)),
2181 }
2182 } else {
2183 true
2184 }
2185 }
2186 debug_assert!(id_and_name_must_be_atoms(name, &attr_dom));
2187 attr_dom
2188 }
2189
2190 pub(crate) fn set_attribute_from_parser(
2191 &self,
2192 cx: &mut JSContext,
2193 qname: QualName,
2194 value: DOMString,
2195 ) {
2196 if self
2198 .attrs
2199 .borrow()
2200 .iter()
2201 .any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns)
2202 {
2203 return;
2204 }
2205
2206 let name = match qname.prefix {
2207 None => qname.local.clone(),
2208 Some(ref prefix) => {
2209 let name = format!("{}:{}", &**prefix, &*qname.local);
2210 LocalName::from(name)
2211 },
2212 };
2213 let value = self.parse_attribute(&qname.ns, &qname.local, value);
2214 self.push_new_attribute(
2215 cx,
2216 qname.local,
2217 value,
2218 name,
2219 qname.ns,
2220 qname.prefix,
2221 AttributeMutationReason::ByParser,
2222 );
2223 }
2224
2225 pub(crate) fn set_attribute(&self, cx: &mut JSContext, name: &LocalName, value: AttrValue) {
2226 debug_assert_eq!(
2227 *name,
2228 name.to_ascii_lowercase(),
2229 "All attribute accesses should use a lowercase ASCII name"
2230 );
2231 debug_assert!(!name.contains(':'));
2232
2233 self.set_first_matching_attribute(
2234 cx,
2235 name.clone(),
2236 value,
2237 name.clone(),
2238 ns!(),
2239 None,
2240 |attr| attr.local_name() == name,
2241 );
2242 }
2243
2244 pub(crate) fn set_attribute_with_namespace(
2245 &self,
2246 cx: &mut JSContext,
2247 local_name: LocalName,
2248 value: AttrValue,
2249 name: LocalName,
2250 namespace: Namespace,
2251 prefix: Option<Prefix>,
2252 ) {
2253 self.set_first_matching_attribute(
2254 cx,
2255 local_name.clone(),
2256 value,
2257 name,
2258 namespace.clone(),
2259 prefix,
2260 |attr| *attr.local_name() == local_name && *attr.namespace() == namespace,
2261 );
2262 }
2263
2264 #[allow(clippy::too_many_arguments)]
2266 fn set_first_matching_attribute<F>(
2267 &self,
2268 cx: &mut JSContext,
2269 local_name: LocalName,
2270 value: AttrValue,
2271 name: LocalName,
2272 namespace: Namespace,
2273 prefix: Option<Prefix>,
2274 find: F,
2275 ) where
2276 F: Fn(AttrRef<'_>) -> bool,
2277 {
2278 let found_idx = self.attrs.borrow().iter().position(find);
2281 if let Some(idx) = found_idx {
2282 let attr = self.attrs.ensure_dom(cx, idx, self);
2283 self.will_mutate_attr(AttrRef::Dom(&attr));
2285 self.change_attribute(cx, &attr, value);
2286 } else {
2287 self.push_new_attribute(
2292 cx,
2293 local_name,
2294 value,
2295 name,
2296 namespace,
2297 prefix,
2298 AttributeMutationReason::Directly,
2299 );
2300 };
2301 }
2302
2303 pub(crate) fn parse_attribute(
2304 &self,
2305 namespace: &Namespace,
2306 local_name: &LocalName,
2307 value: DOMString,
2308 ) -> AttrValue {
2309 if is_relevant_attribute(namespace, local_name) {
2310 vtable_for(self.upcast()).parse_plain_attribute(local_name, value)
2311 } else {
2312 AttrValue::String(value.into())
2313 }
2314 }
2315
2316 pub(crate) fn remove_attribute(
2317 &self,
2318 cx: &mut JSContext,
2319 namespace: &Namespace,
2320 local_name: &LocalName,
2321 ) -> Option<DomRoot<Attr>> {
2322 self.remove_first_matching_attribute(cx, |attr| {
2323 attr.namespace() == namespace && attr.local_name() == local_name
2324 })
2325 }
2326
2327 pub(crate) fn remove_attribute_by_name(
2328 &self,
2329 cx: &mut JSContext,
2330 name: &LocalName,
2331 ) -> Option<DomRoot<Attr>> {
2332 self.remove_first_matching_attribute(cx, |attr| attr.name() == name)
2333 }
2334
2335 fn remove_first_matching_attribute<F>(
2337 &self,
2338 cx: &mut JSContext,
2339 find: F,
2340 ) -> Option<DomRoot<Attr>>
2341 where
2342 F: Fn(AttrRef<'_>) -> bool,
2343 {
2344 let idx = self.attrs.borrow().iter().position(find);
2345 idx.map(|idx| {
2346 let attr = self.attrs.ensure_dom(cx, idx, self);
2347
2348 self.will_mutate_attr(AttrRef::Dom(&attr));
2350 self.attrs.remove(idx);
2351 attr.set_owner(cx, None);
2353 self.handle_attribute_changes(
2355 cx,
2356 AttrRef::Dom(&attr),
2357 Some(&attr.value()),
2358 None,
2359 AttributeMutationReason::Directly,
2360 );
2361
2362 attr
2363 })
2364 }
2365
2366 pub(crate) fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
2367 self.any_tokenlist_attribute(&local_name!("class"), |atom| {
2368 case_sensitivity.eq_atom(name, atom)
2369 })
2370 }
2371
2372 pub(crate) fn has_attribute(&self, local_name: &LocalName) -> bool {
2373 debug_assert_eq!(
2374 *local_name,
2375 local_name.to_ascii_lowercase(),
2376 "All attribute accesses should use a lowercase ASCII name"
2377 );
2378 debug_assert!(!local_name.contains(':'));
2379 self.attrs
2380 .borrow()
2381 .iter()
2382 .any(|attr| attr.local_name() == local_name && attr.namespace() == &ns!())
2383 }
2384
2385 pub(crate) fn will_mutate_attr(&self, attr: AttrRef<'_>) {
2386 let node = self.upcast::<Node>();
2387 node.owner_doc().element_attr_will_change(self, attr);
2388 }
2389
2390 fn update_style_attribute(
2392 &self,
2393 cx: &mut JSContext,
2394 attr: AttrRef<'_>,
2395 mutation: AttributeMutation,
2396 ) {
2397 let doc = self.upcast::<Node>().owner_doc();
2398 *self.style_attribute.borrow_mut() = match mutation {
2400 AttributeMutation::Set(..) => {
2401 let value = attr.as_attr().map_or_else(
2402 || attr.value(),
2403 |attribute| AttrValueRef::Borrowed(attribute.value()),
2404 );
2405
2406 Some(match &*value {
2407 AttrValue::Declaration { block, .. } => block.clone(),
2408 _ => {
2409 let win = self.owner_window();
2410 let source = &**attr.value();
2411 let global = &self.owner_global();
2412 if global
2417 .get_csp_list()
2418 .should_elements_inline_type_behavior_be_blocked(
2419 cx,
2420 global,
2421 self,
2422 InlineCheckType::StyleAttribute,
2423 source,
2424 doc.get_current_parser_line(),
2425 )
2426 {
2427 return;
2428 }
2429 ServoArc::new(doc.style_shared_author_lock().wrap(parse_style_attribute(
2430 source,
2431 &UrlExtraData(doc.base_url().get_arc()),
2432 Some(win.css_error_reporter()),
2433 doc.quirks_mode(),
2434 CssRuleType::Style,
2435 )))
2436 },
2437 })
2438 },
2439 AttributeMutation::Removed => None,
2440 };
2441 }
2442
2443 fn set_attribute_node(
2447 &self,
2448 cx: &mut JSContext,
2449 attr: &Attr,
2450 ) -> Fallible<Option<DomRoot<Attr>>> {
2451 let verified_value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
2455 cx,
2456 self.namespace(),
2457 self.local_name(),
2458 attr.local_name(),
2459 Some(attr.namespace()),
2460 TrustedTypeOrString::String(attr.Value()),
2461 &self.owner_global(),
2462 )?;
2463
2464 if let Some(owner) = attr.GetOwnerElement() &&
2467 &*owner != self
2468 {
2469 return Err(Error::InUseAttribute(None));
2470 }
2471
2472 let vtable = vtable_for(self.upcast());
2473
2474 attr.swap_value(
2480 &mut vtable.parse_plain_attribute(attr.local_name(), verified_value.clone()),
2481 );
2482
2483 let position = self.attrs.borrow().iter().position(|old_attr| {
2485 attr.namespace() == old_attr.namespace() && attr.local_name() == old_attr.local_name()
2486 });
2487
2488 let old_attr = if let Some(position) = position {
2489 let old_attr = self.attrs.ensure_dom(cx, position, self);
2490
2491 if &*old_attr == attr {
2493 return Ok(Some(DomRoot::from_ref(attr)));
2494 }
2495
2496 self.will_mutate_attr(AttrRef::Dom(attr));
2506 self.attrs
2507 .set(position, AttributeEntry::Dom(Dom::from_ref(attr)));
2508 attr.set_owner(cx, Some(self));
2510 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2512 old_attr.set_owner(cx, None);
2514 self.handle_attribute_changes(
2516 cx,
2517 AttrRef::Dom(attr),
2518 Some(&old_attr.value()),
2519 Some(&AttrValue::String(verified_value.into())),
2520 AttributeMutationReason::Directly,
2521 );
2522
2523 Some(old_attr)
2524 } else {
2525 attr.set_owner(cx, Some(self));
2527 attr.upcast::<Node>().set_owner_doc(&self.node.owner_doc());
2528 self.push_attribute(cx, attr, AttributeMutationReason::Directly);
2529
2530 None
2531 };
2532
2533 Ok(old_attr)
2535 }
2536
2537 pub(crate) fn update_nonce_internal_slot(&self, nonce: String, no_gc: &NoGC) {
2539 self.ensure_rare_data(no_gc).cryptographic_nonce = nonce;
2540 }
2541
2542 pub(crate) fn nonce_value(&self) -> String {
2544 match self.rare_data().as_ref() {
2545 None => String::new(),
2546 Some(rare_data) => rare_data.cryptographic_nonce.clone(),
2547 }
2548 }
2549
2550 pub(crate) fn update_nonce_post_connection(&self, cx: &mut JSContext) {
2552 if !self.upcast::<Node>().is_connected_with_browsing_context() {
2555 return;
2556 }
2557 let global = self.owner_global();
2558 let csp_list = match global.get_csp_list() {
2560 None => return,
2561 Some(csp_list) => csp_list,
2562 };
2563 if !csp_list.contains_a_header_delivered_content_security_policy() ||
2566 self.get_string_attribute(&local_name!("nonce")).is_empty()
2567 {
2568 return;
2569 }
2570 let nonce = self.nonce_value();
2572 self.set_string_attribute(cx, &local_name!("nonce"), "".into());
2574 self.update_nonce_internal_slot(nonce, cx.no_gc());
2576 }
2577
2578 pub(crate) fn is_nonceable(&self) -> bool {
2580 if !self.has_attribute(&local_name!("nonce")) {
2582 return false;
2583 }
2584 if self.is::<HTMLScriptElement>() {
2586 for attr in self.attrs().borrow().iter() {
2587 let attr_name = attr.name().to_ascii_lowercase();
2590 if attr_name.contains("<script") || attr_name.contains("<style") {
2591 return false;
2592 }
2593 let attr_value = attr.value().to_ascii_lowercase();
2596 if attr_value.contains("<script") || attr_value.contains("<style") {
2597 return false;
2598 }
2599 }
2600 }
2601 if self
2603 .rare_data()
2604 .as_ref()
2605 .is_some_and(|d| d.had_duplicate_attributes)
2606 {
2607 return false;
2608 }
2609 true
2611 }
2612
2613 pub(crate) fn insert_adjacent(
2615 &self,
2616 cx: &mut JSContext,
2617 where_: AdjacentPosition,
2618 node: &Node,
2619 ) -> Fallible<Option<DomRoot<Node>>> {
2620 let self_node = self.upcast::<Node>();
2621 match where_ {
2622 AdjacentPosition::BeforeBegin => {
2623 if let Some(parent) = self_node.GetParentNode() {
2624 Node::pre_insert(cx, node, &parent, Some(self_node)).map(Some)
2625 } else {
2626 Ok(None)
2627 }
2628 },
2629 AdjacentPosition::AfterBegin => {
2630 Node::pre_insert(cx, node, self_node, self_node.GetFirstChild().as_deref())
2631 .map(Some)
2632 },
2633 AdjacentPosition::BeforeEnd => Node::pre_insert(cx, node, self_node, None).map(Some),
2634 AdjacentPosition::AfterEnd => {
2635 if let Some(parent) = self_node.GetParentNode() {
2636 Node::pre_insert(cx, node, &parent, self_node.GetNextSibling().as_deref())
2637 .map(Some)
2638 } else {
2639 Ok(None)
2640 }
2641 },
2642 }
2643 }
2644
2645 pub(crate) fn scroll(&self, cx: &mut JSContext, x: f64, y: f64, behavior: ScrollBehavior) {
2650 let x = if x.is_finite() { x } else { 0.0 } as f32;
2652 let y = if y.is_finite() { y } else { 0.0 } as f32;
2653
2654 let node = self.upcast::<Node>();
2655
2656 let doc = node.owner_doc();
2658
2659 if !doc.is_fully_active() {
2661 return;
2662 }
2663
2664 let win = match doc.GetDefaultView() {
2666 None => return,
2667 Some(win) => win,
2668 };
2669
2670 if *self.root_element() == *self {
2672 if doc.quirks_mode() != QuirksMode::Quirks {
2673 win.scroll(cx, x, y, behavior);
2674 }
2675
2676 return;
2677 }
2678
2679 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
2681 doc.quirks_mode() == QuirksMode::Quirks &&
2682 !self.is_potentially_scrollable_body()
2683 {
2684 win.scroll(cx, x, y, behavior);
2685 return;
2686 }
2687
2688 if !self.has_scrolling_box(cx.no_gc()) {
2690 return;
2691 }
2692
2693 win.scroll_an_element(cx, self, x, y, behavior);
2695 }
2696
2697 pub(crate) fn parse_fragment(
2699 &self,
2700 markup: DOMString,
2701 cx: &mut JSContext,
2702 ) -> Fallible<DomRoot<DocumentFragment>> {
2703 let new_children = ServoParser::parse_html_fragment(cx, self, markup, false);
2706 let context_document = {
2709 if let Some(template) = self.downcast::<HTMLTemplateElement>() {
2710 template.Content(cx).upcast::<Node>().owner_doc()
2711 } else {
2712 self.owner_document()
2713 }
2714 };
2715 let fragment = DocumentFragment::new(cx, &context_document);
2716 for child in new_children {
2718 fragment.upcast::<Node>().AppendChild(cx, &child).unwrap();
2719 }
2720 Ok(fragment)
2722 }
2723
2724 pub(crate) fn fragment_parsing_context(
2727 cx: &mut JSContext,
2728 owner_doc: &Document,
2729 element: Option<&Self>,
2730 ) -> DomRoot<Self> {
2731 match element {
2733 Some(elem)
2734 if elem.local_name() != &local_name!("html") ||
2738 !elem.html_element_in_html_document() =>
2739 {
2740 DomRoot::from_ref(elem)
2741 },
2742 _ => Element::create(
2745 cx,
2746 QualName::new(None, ns!(html), local_name!("body")),
2747 None,
2748 owner_doc,
2749 ElementCreator::ScriptCreated,
2750 CustomElementCreationMode::Asynchronous,
2751 None
2752 ),
2753 }
2754 }
2755
2756 pub(crate) fn is_in_same_home_subtree<T>(&self, other: &T) -> bool
2758 where
2759 T: DerivedFrom<Element> + DomObject,
2760 {
2761 let other = other.upcast::<Element>();
2762 self.root_element() == other.root_element()
2763 }
2764
2765 pub(crate) fn get_id(&self) -> Option<Atom> {
2766 self.id_attribute.borrow().clone()
2767 }
2768
2769 pub(crate) fn get_name(&self) -> Option<Atom> {
2770 self.rare_data().as_ref()?.name_attribute.clone()
2771 }
2772
2773 pub(crate) fn get_element_internals(&self) -> Option<DomRoot<ElementInternals>> {
2774 self.rare_data()
2775 .as_ref()?
2776 .element_internals
2777 .as_ref()
2778 .map(|sr| DomRoot::from_ref(&**sr))
2779 }
2780
2781 pub(crate) fn ensure_element_internals(&self, cx: &mut JSContext) -> DomRoot<ElementInternals> {
2782 let Some(element_internals) = self.get_element_internals() else {
2783 let elem = self
2784 .downcast::<HTMLElement>()
2785 .expect("ensure_element_internals should only be called for an HTMLElement");
2786 let internals = ElementInternals::new(cx, elem);
2787 self.ensure_rare_data(cx.no_gc()).element_internals = Some(Dom::from_ref(&*internals));
2788 return internals;
2789 };
2790 element_internals
2791 }
2792
2793 pub(crate) fn outer_html(&self, cx: &mut JSContext) -> Fallible<DOMString> {
2794 match self.GetOuterHTML(cx)? {
2795 TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(str) => Ok(str),
2796 TrustedHTMLOrNullIsEmptyString::TrustedHTML(_) => unreachable!(),
2797 }
2798 }
2799
2800 pub(crate) fn compute_source_position(&self, line_number: u32) -> SourcePosition {
2801 SourcePosition {
2802 source_file: self.owner_global().get_url().to_string(),
2803 line_number: line_number + 2,
2804 column_number: 0,
2805 }
2806 }
2807
2808 pub(crate) fn explicitly_set_tab_index(&self) -> Option<i32> {
2809 if self.has_attribute(&local_name!("tabindex")) {
2810 Some(self.get_int_attribute(&local_name!("tabindex"), 0))
2811 } else {
2812 None
2813 }
2814 }
2815
2816 pub(crate) fn tab_index(&self) -> i32 {
2818 if let Some(tab_index) = self.explicitly_set_tab_index() {
2824 return tab_index;
2825 }
2826
2827 if matches!(
2833 self.upcast::<Node>().type_id(),
2834 NodeTypeId::Element(ElementTypeId::HTMLElement(
2835 HTMLElementTypeId::HTMLAnchorElement |
2836 HTMLElementTypeId::HTMLAreaElement |
2837 HTMLElementTypeId::HTMLButtonElement |
2838 HTMLElementTypeId::HTMLFrameElement |
2839 HTMLElementTypeId::HTMLIFrameElement |
2840 HTMLElementTypeId::HTMLInputElement |
2841 HTMLElementTypeId::HTMLObjectElement |
2842 HTMLElementTypeId::HTMLSelectElement |
2843 HTMLElementTypeId::HTMLTextAreaElement
2844 ))
2845 ) {
2846 return 0;
2847 }
2848 if self
2849 .downcast::<HTMLElement>()
2850 .is_some_and(|html_element| html_element.is_a_summary_for_its_parent_details())
2851 {
2852 return 0;
2853 }
2854
2855 -1
2856 }
2857
2858 #[inline]
2859 fn insert_selector_flags(&self, flags: ElementSelectorFlags) {
2860 self.selector_flags
2861 .fetch_or(flags.bits(), Ordering::Relaxed);
2862 }
2863
2864 #[inline]
2865 fn get_selector_flags(&self) -> ElementSelectorFlags {
2866 ElementSelectorFlags::from_bits_retain(self.selector_flags.load(Ordering::Relaxed))
2867 }
2868
2869 pub(crate) fn needs_preserved_style_attribute_after_change(&self) -> bool {
2874 self.owner_window().get_exists_mut_observer() ||
2881 self.get_custom_element_definition()
2882 .is_some_and(|custom_element_definition| {
2883 custom_element_definition.has_attribute_changed_callback()
2884 })
2885 }
2886
2887 pub(crate) fn register_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2888 if let Some(shadow_root) = self.containing_shadow_root() {
2889 if let Some(ref id) = *self.id_attribute.borrow() {
2890 shadow_root.register_element_id(self, id);
2891 }
2892 } else {
2893 let document = self.owner_document();
2894 if let Some(ref id) = *self.id_attribute.borrow() {
2895 document.register_element_id(cx, self, id);
2896 }
2897 if let Some(ref name) = self.name_attribute() {
2898 document.register_element_name(self, name);
2899 }
2900 }
2901 }
2902
2903 pub(crate) fn unregister_current_id_and_name_attribute(&self, cx: &mut JSContext) {
2904 if let Some(shadow_root) = self.containing_shadow_root() {
2905 if self.upcast::<Node>().is_in_a_shadow_tree() {
2909 return;
2910 }
2911 if let Some(ref id) = *self.id_attribute.borrow() {
2912 shadow_root.unregister_element_id(id);
2913 }
2914 } else {
2915 let document = self.owner_document();
2916 if let Some(ref id) = *self.id_attribute.borrow() {
2917 document.unregister_element_id(cx, id);
2918 }
2919 if let Some(ref name) = self.name_attribute() {
2920 document.unregister_element_name(name);
2921 }
2922 }
2923 }
2924}
2925
2926impl ElementMethods<crate::DomTypeHolder> for Element {
2927 fn GetNamespaceURI(&self) -> Option<DOMString> {
2929 Node::namespace_to_string(self.namespace.clone())
2930 }
2931
2932 fn LocalName(&self) -> DOMString {
2934 DOMString::from(&*self.local_name)
2936 }
2937
2938 fn GetPrefix(&self) -> Option<DOMString> {
2940 self.prefix.borrow().as_ref().map(|p| DOMString::from(&**p))
2941 }
2942
2943 fn TagName(&self) -> DOMString {
2945 let name = self.tag_name.or_init(|| {
2946 let qualified_name = match *self.prefix.borrow() {
2947 Some(ref prefix) => Cow::Owned(format!("{}:{}", &**prefix, &*self.local_name)),
2948 None => Cow::Borrowed(&*self.local_name),
2949 };
2950 if self.html_element_in_html_document() {
2951 LocalName::from(qualified_name.to_ascii_uppercase())
2952 } else {
2953 LocalName::from(qualified_name)
2954 }
2955 });
2956 DOMString::from(&*name)
2957 }
2958
2959 fn Id(&self) -> DOMString {
2963 self.get_string_attribute(&local_name!("id"))
2964 }
2965
2966 fn SetId(&self, cx: &mut JSContext, id: DOMString) {
2968 self.set_atomic_attribute(cx, &local_name!("id"), id);
2969 }
2970
2971 fn ClassName(&self) -> DOMString {
2973 self.get_string_attribute(&local_name!("class"))
2974 }
2975
2976 fn SetClassName(&self, cx: &mut JSContext, class: DOMString) {
2978 self.set_tokenlist_attribute(cx, &local_name!("class"), class);
2979 }
2980
2981 fn ClassList(&self, cx: &mut js::context::JSContext) -> DomRoot<DOMTokenList> {
2983 self.class_list
2984 .or_init(|| DOMTokenList::new(cx, self, &local_name!("class"), None))
2985 }
2986
2987 make_getter!(Slot, "slot");
2989
2990 make_setter!(SetSlot, "slot");
2992
2993 fn Attributes(&self, cx: &mut JSContext) -> DomRoot<NamedNodeMap> {
2995 self.attr_list
2996 .or_init(|| NamedNodeMap::new(cx, &self.owner_window(), self))
2997 }
2998
2999 fn HasAttributes(&self) -> bool {
3001 !self.attrs.borrow().is_empty()
3002 }
3003
3004 fn GetAttributeNames(&self) -> Vec<DOMString> {
3006 self.attrs
3007 .borrow()
3008 .iter()
3009 .map(|attr| DOMString::from(&**attr.name()))
3010 .collect()
3011 }
3012
3013 fn GetAttribute(&self, cx: &mut JSContext, name: DOMString) -> Option<DOMString> {
3015 self.GetAttributeNode(cx, name).map(|s| s.Value())
3016 }
3017
3018 fn GetAttributeNS(
3020 &self,
3021 cx: &mut JSContext,
3022 namespace: Option<DOMString>,
3023 local_name: DOMString,
3024 ) -> Option<DOMString> {
3025 self.GetAttributeNodeNS(cx, namespace, local_name)
3026 .map(|attr| attr.Value())
3027 }
3028
3029 fn GetAttributeNode(&self, cx: &mut JSContext, name: DOMString) -> Option<DomRoot<Attr>> {
3031 self.get_attribute_by_name(cx, name)
3032 }
3033
3034 fn GetAttributeNodeNS(
3036 &self,
3037 cx: &mut JSContext,
3038 namespace: Option<DOMString>,
3039 local_name: DOMString,
3040 ) -> Option<DomRoot<Attr>> {
3041 let namespace = &namespace_from_domstring(namespace);
3042 self.get_attribute_with_namespace(cx, namespace, &LocalName::from(local_name))
3043 }
3044
3045 fn ToggleAttribute(
3047 &self,
3048 cx: &mut JSContext,
3049 name: DOMString,
3050 force: Option<bool>,
3051 ) -> Fallible<bool> {
3052 if !is_valid_attribute_local_name(&name.str()) {
3055 return Err(Error::InvalidCharacter(None));
3056 }
3057
3058 let attribute = self.GetAttribute(cx, name.clone());
3060
3061 let name = self.parsed_name(name);
3063 match attribute {
3064 None => match force {
3066 None | Some(true) => {
3068 self.set_first_matching_attribute(
3069 cx,
3070 name.clone(),
3071 AttrValue::String(String::new()),
3072 name.clone(),
3073 ns!(),
3074 None,
3075 |attr| *attr.name() == name,
3076 );
3077 Ok(true)
3078 },
3079 Some(false) => Ok(false),
3081 },
3082 Some(_index) => match force {
3083 None | Some(false) => {
3085 self.remove_attribute_by_name(cx, &name);
3086 Ok(false)
3087 },
3088 Some(true) => Ok(true),
3090 },
3091 }
3092 }
3093
3094 fn SetAttribute(
3096 &self,
3097 cx: &mut JSContext,
3098 name: DOMString,
3099 value: TrustedTypeOrString,
3100 ) -> ErrorResult {
3101 if !is_valid_attribute_local_name(&name.str()) {
3104 return Err(Error::InvalidCharacter(None));
3105 }
3106
3107 let name = self.parsed_name(name);
3110
3111 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3115 cx,
3116 self.namespace(),
3117 self.local_name(),
3118 &name,
3119 None,
3120 value,
3121 &self.owner_global(),
3122 )?;
3123
3124 let value = self.parse_attribute(&ns!(), &name, value);
3129 self.set_first_matching_attribute(
3130 cx,
3131 name.clone(),
3132 value,
3133 name.clone(),
3134 ns!(),
3135 None,
3136 |attr| *attr.name() == name,
3137 );
3138 Ok(())
3139 }
3140
3141 fn SetAttributeNS(
3143 &self,
3144 cx: &mut JSContext,
3145 namespace: Option<DOMString>,
3146 qualified_name: DOMString,
3147 value: TrustedTypeOrString,
3148 ) -> ErrorResult {
3149 let (namespace, prefix, local_name) =
3151 domname::validate_and_extract(namespace, &qualified_name, domname::Context::Element)?;
3152 let value = TrustedTypePolicyFactory::get_trusted_types_compliant_attribute_value(
3155 cx,
3156 self.namespace(),
3157 self.local_name(),
3158 &local_name,
3159 Some(&namespace),
3160 value,
3161 &self.owner_global(),
3162 )?;
3163 let value = self.parse_attribute(&namespace, &local_name, value);
3165 self.set_attribute_with_namespace(
3166 cx,
3167 local_name,
3168 value,
3169 LocalName::from(qualified_name),
3170 namespace,
3171 prefix,
3172 );
3173 Ok(())
3174 }
3175
3176 fn SetAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<Option<DomRoot<Attr>>> {
3178 self.set_attribute_node(cx, attr)
3179 }
3180
3181 fn SetAttributeNodeNS(
3183 &self,
3184 cx: &mut JSContext,
3185 attr: &Attr,
3186 ) -> Fallible<Option<DomRoot<Attr>>> {
3187 self.set_attribute_node(cx, attr)
3188 }
3189
3190 fn RemoveAttribute(&self, cx: &mut JSContext, name: DOMString) {
3192 let name = self.parsed_name(name);
3193 self.remove_attribute_by_name(cx, &name);
3194 }
3195
3196 fn RemoveAttributeNS(
3198 &self,
3199 cx: &mut JSContext,
3200 namespace: Option<DOMString>,
3201 local_name: DOMString,
3202 ) {
3203 let namespace = namespace_from_domstring(namespace);
3204 let local_name = LocalName::from(local_name);
3205 self.remove_attribute(cx, &namespace, &local_name);
3206 }
3207
3208 fn RemoveAttributeNode(&self, cx: &mut JSContext, attr: &Attr) -> Fallible<DomRoot<Attr>> {
3210 self.remove_first_matching_attribute(cx, |a| a.as_attr().is_some_and(|a| a == attr))
3213 .ok_or(Error::NotFound(None))
3214 }
3215
3216 fn HasAttribute(&self, cx: &mut JSContext, name: DOMString) -> bool {
3218 self.GetAttribute(cx, name).is_some()
3219 }
3220
3221 fn HasAttributeNS(
3223 &self,
3224 cx: &mut JSContext,
3225 namespace: Option<DOMString>,
3226 local_name: DOMString,
3227 ) -> bool {
3228 self.GetAttributeNS(cx, namespace, local_name).is_some()
3229 }
3230
3231 fn GetElementsByTagName(
3233 &self,
3234 cx: &mut JSContext,
3235 localname: DOMString,
3236 ) -> DomRoot<HTMLCollection> {
3237 let window = self.owner_window();
3238 HTMLCollection::by_qualified_name(cx, &window, self.upcast(), LocalName::from(localname))
3239 }
3240
3241 fn GetElementsByTagNameNS(
3243 &self,
3244 cx: &mut JSContext,
3245 maybe_ns: Option<DOMString>,
3246 localname: DOMString,
3247 ) -> DomRoot<HTMLCollection> {
3248 let window = self.owner_window();
3249 HTMLCollection::by_tag_name_ns(cx, &window, self.upcast(), localname, maybe_ns)
3250 }
3251
3252 fn GetElementsByClassName(
3254 &self,
3255 cx: &mut JSContext,
3256 classes: DOMString,
3257 ) -> DomRoot<HTMLCollection> {
3258 let window = self.owner_window();
3259 HTMLCollection::by_class_name(cx, &window, self.upcast(), classes)
3260 }
3261
3262 fn GetClientRects(&self, cx: &mut JSContext) -> DomRoot<DOMRectList> {
3264 let win = self.owner_window();
3265 let raw_rects = self.upcast::<Node>().border_boxes();
3266 let rects: Vec<DomRoot<DOMRect>> = raw_rects
3267 .into_iter()
3268 .map(|rect| {
3269 DOMRect::new(
3270 cx,
3271 win.upcast(),
3272 rect.origin.x.to_f64_px(),
3273 rect.origin.y.to_f64_px(),
3274 rect.size.width.to_f64_px(),
3275 rect.size.height.to_f64_px(),
3276 )
3277 })
3278 .collect();
3279 DOMRectList::new(cx, &win, rects)
3280 }
3281
3282 fn GetBoundingClientRect(&self, cx: &mut JSContext) -> DomRoot<DOMRect> {
3284 let win = self.owner_window();
3285 let rect = self.upcast::<Node>().border_box().unwrap_or_default();
3286 debug_assert!(rect.size.width.to_f64_px() >= 0.0 && rect.size.height.to_f64_px() >= 0.0);
3287 DOMRect::new(
3288 cx,
3289 win.upcast(),
3290 rect.origin.x.to_f64_px(),
3291 rect.origin.y.to_f64_px(),
3292 rect.size.width.to_f64_px(),
3293 rect.size.height.to_f64_px(),
3294 )
3295 }
3296
3297 fn Scroll(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3299 let left = options.left.unwrap_or(self.ScrollLeft());
3301 let top = options.top.unwrap_or(self.ScrollTop());
3302 self.scroll(cx, left, top, options.parent.behavior);
3303 }
3304
3305 fn Scroll_(&self, cx: &mut JSContext, x: f64, y: f64) {
3307 self.scroll(cx, x, y, ScrollBehavior::Auto);
3308 }
3309
3310 fn ScrollTo(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3312 self.Scroll(cx, options);
3313 }
3314
3315 fn ScrollTo_(&self, cx: &mut JSContext, x: f64, y: f64) {
3317 self.Scroll_(cx, x, y);
3318 }
3319
3320 fn ScrollBy(&self, cx: &mut JSContext, options: &ScrollToOptions) {
3322 let delta_left = options.left.unwrap_or(0.0f64);
3324 let delta_top = options.top.unwrap_or(0.0f64);
3325 let left = self.ScrollLeft();
3326 let top = self.ScrollTop();
3327 self.scroll(
3328 cx,
3329 left + delta_left,
3330 top + delta_top,
3331 options.parent.behavior,
3332 );
3333 }
3334
3335 fn ScrollBy_(&self, cx: &mut JSContext, x: f64, y: f64) {
3337 let left = self.ScrollLeft();
3338 let top = self.ScrollTop();
3339 self.scroll(cx, left + x, top + y, ScrollBehavior::Auto);
3340 }
3341
3342 fn ScrollTop(&self) -> f64 {
3344 let node = self.upcast::<Node>();
3345
3346 let doc = node.owner_doc();
3348
3349 if !doc.is_fully_active() {
3351 return 0.0;
3352 }
3353
3354 let win = match doc.GetDefaultView() {
3356 None => return 0.0,
3357 Some(win) => win,
3358 };
3359
3360 if self.is_document_element() {
3362 if doc.quirks_mode() == QuirksMode::Quirks {
3363 return 0.0;
3364 }
3365
3366 return win.ScrollY() as f64;
3368 }
3369
3370 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3372 doc.quirks_mode() == QuirksMode::Quirks &&
3373 !self.is_potentially_scrollable_body()
3374 {
3375 return win.ScrollY() as f64;
3376 }
3377
3378 if !self.has_css_layout_box() {
3380 return 0.0;
3381 }
3382
3383 let point = win.scroll_offset_query(node);
3385 point.y.abs() as f64
3386 }
3387
3388 fn SetScrollTop(&self, cx: &mut JSContext, y_: f64) {
3391 let behavior = ScrollBehavior::Auto;
3392
3393 let y = if y_.is_finite() { y_ } else { 0.0 } as f32;
3395
3396 let node = self.upcast::<Node>();
3397
3398 let doc = node.owner_doc();
3400
3401 if !doc.is_fully_active() {
3403 return;
3404 }
3405
3406 let win = match doc.GetDefaultView() {
3408 None => return,
3409 Some(win) => win,
3410 };
3411
3412 if self.is_document_element() {
3414 if doc.quirks_mode() != QuirksMode::Quirks {
3415 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3416 }
3417
3418 return;
3419 }
3420
3421 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3423 doc.quirks_mode() == QuirksMode::Quirks &&
3424 !self.is_potentially_scrollable_body()
3425 {
3426 win.scroll(cx, win.ScrollX() as f32, y, behavior);
3427 return;
3428 }
3429
3430 if !self.has_scrolling_box(cx.no_gc()) {
3432 return;
3433 }
3434
3435 win.scroll_an_element(cx, self, self.ScrollLeft() as f32, y, behavior);
3437 }
3438
3439 fn ScrollLeft(&self) -> f64 {
3441 let node = self.upcast::<Node>();
3442
3443 let doc = node.owner_doc();
3445
3446 if !doc.is_fully_active() {
3448 return 0.0;
3449 }
3450
3451 let win = match doc.GetDefaultView() {
3453 None => return 0.0,
3454 Some(win) => win,
3455 };
3456
3457 if self.is_document_element() {
3459 if doc.quirks_mode() != QuirksMode::Quirks {
3460 return win.ScrollX() as f64;
3462 }
3463
3464 return 0.0;
3465 }
3466
3467 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3469 doc.quirks_mode() == QuirksMode::Quirks &&
3470 !self.is_potentially_scrollable_body()
3471 {
3472 return win.ScrollX() as f64;
3473 }
3474
3475 if !self.has_css_layout_box() {
3477 return 0.0;
3478 }
3479
3480 let point = win.scroll_offset_query(node);
3482 point.x.abs() as f64
3483 }
3484
3485 fn SetScrollLeft(&self, cx: &mut JSContext, x: f64) {
3487 let behavior = ScrollBehavior::Auto;
3488
3489 let x = if x.is_finite() { x } else { 0.0 } as f32;
3491
3492 let node = self.upcast::<Node>();
3493
3494 let doc = node.owner_doc();
3496
3497 if !doc.is_fully_active() {
3499 return;
3500 }
3501
3502 let win = match doc.GetDefaultView() {
3504 None => return,
3505 Some(win) => win,
3506 };
3507
3508 if self.is_document_element() {
3510 if doc.quirks_mode() == QuirksMode::Quirks {
3511 return;
3512 }
3513
3514 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3515 return;
3516 }
3517
3518 if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
3520 doc.quirks_mode() == QuirksMode::Quirks &&
3521 !self.is_potentially_scrollable_body()
3522 {
3523 win.scroll(cx, x, win.ScrollY() as f32, behavior);
3524 return;
3525 }
3526
3527 if !self.has_scrolling_box(cx.no_gc()) {
3529 return;
3530 }
3531
3532 win.scroll_an_element(cx, self, x, self.ScrollTop() as f32, behavior);
3534 }
3535
3536 fn ScrollIntoView(&self, cx: &mut JSContext, arg: BooleanOrScrollIntoViewOptions) {
3538 let (behavior, block, inline, container) = match arg {
3539 BooleanOrScrollIntoViewOptions::Boolean(true) => (
3541 ScrollBehavior::Auto, ScrollLogicalPosition::Start, ScrollLogicalPosition::Nearest, None, ),
3546 BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
3549 options.parent.behavior,
3550 options.block,
3551 options.inline,
3552 if options.container == ScrollIntoViewContainer::Nearest {
3555 Some(self)
3556 } else {
3557 None
3558 },
3559 ),
3560 BooleanOrScrollIntoViewOptions::Boolean(false) => (
3562 ScrollBehavior::Auto,
3563 ScrollLogicalPosition::End,
3564 ScrollLogicalPosition::Nearest,
3565 None,
3566 ),
3567 };
3568
3569 if !self.has_css_layout_box() {
3572 return;
3573 }
3574
3575 self.scroll_into_view_with_options(
3577 cx,
3578 behavior,
3579 ScrollAxisState::new_always_scroll_position(block),
3580 ScrollAxisState::new_always_scroll_position(inline),
3581 container,
3582 None,
3583 );
3584
3585 }
3588
3589 fn ScrollWidth(&self) -> i32 {
3591 self.upcast::<Node>().scroll_area().size.width
3592 }
3593
3594 fn ScrollHeight(&self) -> i32 {
3596 self.upcast::<Node>().scroll_area().size.height
3597 }
3598
3599 fn ClientTop(&self, no_gc: &NoGC) -> i32 {
3601 self.client_rect(no_gc).origin.y
3602 }
3603
3604 fn ClientLeft(&self, no_gc: &NoGC) -> i32 {
3606 self.client_rect(no_gc).origin.x
3607 }
3608
3609 fn ClientWidth(&self, no_gc: &NoGC) -> i32 {
3611 self.client_rect(no_gc).size.width
3612 }
3613
3614 fn ClientHeight(&self, no_gc: &NoGC) -> i32 {
3616 self.client_rect(no_gc).size.height
3617 }
3618
3619 fn CurrentCSSZoom(&self) -> Finite<f64> {
3621 let window = self.owner_window();
3622 Finite::wrap(window.current_css_zoom_query(self.upcast::<Node>()) as f64)
3623 }
3624
3625 fn SetHTMLUnsafe(
3627 &self,
3628 cx: &mut JSContext,
3629 html: TrustedHTMLOrString,
3630 options: &SetHTMLUnsafeOptions,
3631 ) -> ErrorResult {
3632 let compliant_html = TrustedHTML::get_trusted_type_compliant_string(
3636 cx,
3637 &self.owner_global(),
3638 html,
3639 "Element setHTMLUnsafe",
3640 )?;
3641 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3643 DomRoot::upcast(template.Content(cx))
3644 } else {
3645 DomRoot::from_ref(self.upcast())
3646 };
3647
3648 Sanitizer::set_and_filter_html(cx, &target, self, compliant_html, options, false)?;
3650
3651 Ok(())
3652 }
3653
3654 fn SetHTML(
3656 &self,
3657 cx: &mut JSContext,
3658 html: DOMString,
3659 options: &SetHTMLOptions,
3660 ) -> ErrorResult {
3661 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3663 DomRoot::upcast(template.Content(cx))
3664 } else {
3665 DomRoot::from_ref(self.upcast())
3666 };
3667
3668 Sanitizer::set_and_filter_html(cx, &target, self, html, options, true)
3670 }
3671
3672 fn GetHTML(&self, cx: &mut JSContext, options: &GetHTMLOptions) -> DOMString {
3674 self.upcast::<Node>().html_serialize(
3677 cx,
3678 TraversalScope::ChildrenOnly(None),
3679 options.serializableShadowRoots,
3680 options.shadowRoots.clone(),
3681 )
3682 }
3683
3684 fn GetInnerHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3686 let qname = QualName::new(
3687 self.prefix().clone(),
3688 self.namespace().clone(),
3689 self.local_name().clone(),
3690 );
3691
3692 let result = if self.owner_document().is_html_document() {
3695 self.upcast::<Node>()
3696 .html_serialize(cx, ChildrenOnly(Some(qname)), false, vec![])
3697 } else {
3698 self.upcast::<Node>()
3699 .xml_serialize(XmlChildrenOnly(Some(qname)))?
3700 };
3701
3702 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3703 }
3704
3705 fn SetInnerHTML(
3707 &self,
3708 cx: &mut JSContext,
3709 value: TrustedHTMLOrNullIsEmptyString,
3710 ) -> ErrorResult {
3711 let value = TrustedHTML::get_trusted_type_compliant_string(
3715 cx,
3716 &self.owner_global(),
3717 value.convert(),
3718 "Element innerHTML",
3719 )?;
3720 let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
3722 DomRoot::upcast(template.Content(cx))
3725 } else {
3726 DomRoot::from_ref(self.upcast())
3728 };
3729
3730 if !self.node.has_weird_parser_insertion_mode() &&
3733 value.len() < 100 &&
3734 !value
3735 .as_bytes()
3736 .iter()
3737 .any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
3738 {
3739 return Node::SetTextContent(&target, cx, Some(value));
3740 }
3741
3742 let frag = self.parse_fragment(value, cx)?;
3745
3746 Node::replace_all(cx, Some(frag.upcast()), &target);
3748 Ok(())
3749 }
3750
3751 fn GetOuterHTML(&self, cx: &mut JSContext) -> Fallible<TrustedHTMLOrNullIsEmptyString> {
3753 let result = if self.owner_document().is_html_document() {
3756 self.upcast::<Node>()
3757 .html_serialize(cx, IncludeNode, false, vec![])
3758 } else {
3759 self.upcast::<Node>().xml_serialize(XmlIncludeNode)?
3760 };
3761
3762 Ok(TrustedHTMLOrNullIsEmptyString::NullIsEmptyString(result))
3763 }
3764
3765 fn SetOuterHTML(
3767 &self,
3768 cx: &mut JSContext,
3769 value: TrustedHTMLOrNullIsEmptyString,
3770 ) -> ErrorResult {
3771 let value = TrustedHTML::get_trusted_type_compliant_string(
3775 cx,
3776 &self.owner_global(),
3777 value.convert(),
3778 "Element outerHTML",
3779 )?;
3780 let context_document = self.owner_document();
3781 let context_node = self.upcast::<Node>();
3782 let context_parent = match context_node.GetParentNode() {
3784 None => {
3785 return Ok(());
3788 },
3789 Some(parent) => parent,
3790 };
3791
3792 let parent = match context_parent.type_id() {
3793 NodeTypeId::Document(_) => return Err(Error::NoModificationAllowed(None)),
3795
3796 NodeTypeId::DocumentFragment(_) => {
3799 let body_elem = Element::create(
3800 cx,
3801 QualName::new(None, ns!(html), local_name!("body")),
3802 None,
3803 &context_document,
3804 ElementCreator::ScriptCreated,
3805 CustomElementCreationMode::Synchronous,
3806 None,
3807 );
3808 DomRoot::upcast(body_elem)
3809 },
3810 _ => context_node.GetParentElement().unwrap(),
3811 };
3812
3813 let frag = parent.parse_fragment(value, cx)?;
3816 context_parent.ReplaceChild(cx, frag.upcast(), context_node)?;
3818 Ok(())
3819 }
3820
3821 fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
3823 self.upcast::<Node>()
3824 .preceding_siblings()
3825 .find_map(DomRoot::downcast)
3826 }
3827
3828 fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
3830 self.upcast::<Node>()
3831 .following_siblings()
3832 .find_map(DomRoot::downcast)
3833 }
3834
3835 fn Children(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
3837 let window = self.owner_window();
3838 HTMLCollection::children(cx, &window, self.upcast())
3839 }
3840
3841 fn GetFirstElementChild(&self) -> Option<DomRoot<Element>> {
3843 self.upcast::<Node>().child_elements().next()
3844 }
3845
3846 fn GetLastElementChild(&self) -> Option<DomRoot<Element>> {
3848 self.upcast::<Node>()
3849 .rev_children()
3850 .find_map(DomRoot::downcast::<Element>)
3851 }
3852
3853 fn ChildElementCount(&self) -> u32 {
3855 self.upcast::<Node>().child_elements().count() as u32
3856 }
3857
3858 fn Prepend(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3860 self.upcast::<Node>().prepend(cx, nodes)
3861 }
3862
3863 fn Append(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3865 self.upcast::<Node>().append(cx, nodes)
3866 }
3867
3868 fn ReplaceChildren(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3870 self.upcast::<Node>().replace_children(cx, nodes)
3871 }
3872
3873 fn MoveBefore(&self, cx: &mut JSContext, node: &Node, child: Option<&Node>) -> ErrorResult {
3875 self.upcast::<Node>().move_before(cx, node, child)
3876 }
3877
3878 fn QuerySelector(
3880 &self,
3881 cx: &mut JSContext,
3882 selectors: DOMString,
3883 ) -> Fallible<Option<DomRoot<Element>>> {
3884 let root = self.upcast::<Node>();
3885 root.query_selector(cx.no_gc(), selectors)
3886 }
3887
3888 fn QuerySelectorAll(
3890 &self,
3891 cx: &mut JSContext,
3892 selectors: DOMString,
3893 ) -> Fallible<DomRoot<NodeList>> {
3894 let root = self.upcast::<Node>();
3895 root.query_selector_all(cx, selectors)
3896 }
3897
3898 fn Before(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3900 self.upcast::<Node>().before(cx, nodes)
3901 }
3902
3903 fn After(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3905 self.upcast::<Node>().after(cx, nodes)
3906 }
3907
3908 fn ReplaceWith(&self, cx: &mut JSContext, nodes: Vec<NodeOrString>) -> ErrorResult {
3910 self.upcast::<Node>().replace_with(cx, nodes)
3911 }
3912
3913 fn Remove(&self, cx: &mut JSContext) {
3915 self.upcast::<Node>().remove_self(cx);
3916 }
3917
3918 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3920 fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
3921 let document = self.owner_document();
3922 let url = document.url();
3923 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3924 &selectors.str(),
3925 &UrlExtraData(url.get_arc()),
3926 ) {
3927 Err(_) => {
3928 return Err(Error::Syntax(
3929 format!("'{selectors}' is not a valid selector").into(),
3930 ));
3931 },
3932 Ok(selectors) => selectors,
3933 };
3934
3935 let traced_self = Dom::from_ref(self);
3937 let quirks_mode = document.quirks_mode();
3938 Ok(with_layout_state(|| {
3939 #[expect(unsafe_code)]
3940 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3941 dom_apis::element_matches(
3942 &ServoDangerousStyleElement::from(layout_element.upcast()),
3943 &selectors,
3944 quirks_mode,
3945 )
3946 }))
3947 }
3948
3949 fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
3951 self.Matches(selectors)
3952 }
3953
3954 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
3956 fn Closest(&self, selectors: DOMString) -> Fallible<Option<DomRoot<Element>>> {
3957 let document = self.owner_document();
3958 let url = document.url();
3959 let selectors = match SelectorParser::parse_author_origin_no_namespace(
3960 &selectors.str(),
3961 &UrlExtraData(url.get_arc()),
3962 ) {
3963 Err(_) => return Err(Error::Syntax(None)),
3964 Ok(selectors) => selectors,
3965 };
3966
3967 let traced_self = Dom::from_ref(self);
3969 let quirks_mode = document.quirks_mode();
3970 let closest_element = with_layout_state(|| {
3971 #[expect(unsafe_code)]
3972 let layout_element: LayoutDom<'_, _> = unsafe { traced_self.to_layout() };
3973 dom_apis::element_closest(
3974 ServoDangerousStyleElement::from(layout_element.upcast()),
3975 &selectors,
3976 quirks_mode,
3977 )
3978 });
3979 Ok(closest_element.map(ServoDangerousStyleElement::rooted))
3980 }
3981
3982 fn InsertAdjacentElement(
3984 &self,
3985 cx: &mut JSContext,
3986 where_: DOMString,
3987 element: &Element,
3988 ) -> Fallible<Option<DomRoot<Element>>> {
3989 let where_ = where_.parse::<AdjacentPosition>()?;
3990 let inserted_node = self.insert_adjacent(cx, where_, element.upcast())?;
3991 Ok(inserted_node.map(|node| DomRoot::downcast(node).unwrap()))
3992 }
3993
3994 fn InsertAdjacentText(
3996 &self,
3997 cx: &mut JSContext,
3998 where_: DOMString,
3999 data: DOMString,
4000 ) -> ErrorResult {
4001 let text = Text::new(cx, data, &self.owner_document());
4003
4004 let where_ = where_.parse::<AdjacentPosition>()?;
4006 self.insert_adjacent(cx, where_, text.upcast()).map(|_| ())
4007 }
4008
4009 fn InsertAdjacentHTML(
4011 &self,
4012 cx: &mut JSContext,
4013 position: DOMString,
4014 text: TrustedHTMLOrString,
4015 ) -> ErrorResult {
4016 let text = TrustedHTML::get_trusted_type_compliant_string(
4020 cx,
4021 &self.owner_global(),
4022 text,
4023 "Element insertAdjacentHTML",
4024 )?;
4025 let position = position.parse::<AdjacentPosition>()?;
4026
4027 let context = match position {
4030 AdjacentPosition::BeforeBegin | AdjacentPosition::AfterEnd => {
4033 match self.upcast::<Node>().GetParentNode() {
4034 Some(ref node) if node.is::<Document>() => {
4036 return Err(Error::NoModificationAllowed(None));
4037 },
4038 None => return Err(Error::NoModificationAllowed(None)),
4039 Some(node) => node,
4041 }
4042 },
4043 AdjacentPosition::AfterBegin | AdjacentPosition::BeforeEnd => {
4046 DomRoot::from_ref(self.upcast::<Node>())
4048 },
4049 };
4050
4051 let context = Element::fragment_parsing_context(
4053 cx,
4054 &context.owner_doc(),
4055 context.downcast::<Element>(),
4056 );
4057
4058 let fragment = context.parse_fragment(text, cx)?;
4061
4062 self.insert_adjacent(cx, position, fragment.upcast())
4064 .map(|_| ())
4065 }
4066
4067 fn EnterFormalActivationState(&self) -> ErrorResult {
4069 match self.as_maybe_activatable() {
4070 Some(a) => {
4071 a.enter_formal_activation_state();
4072 Ok(())
4073 },
4074 None => Err(Error::NotSupported(None)),
4075 }
4076 }
4077
4078 fn ExitFormalActivationState(&self) -> ErrorResult {
4079 match self.as_maybe_activatable() {
4080 Some(a) => {
4081 a.exit_formal_activation_state();
4082 Ok(())
4083 },
4084 None => Err(Error::NotSupported(None)),
4085 }
4086 }
4087
4088 fn RequestFullscreen(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
4090 let doc = self.owner_document();
4091 doc.enter_fullscreen(cx, self)
4092 }
4093
4094 fn SetPointerCapture(&self, pointer_id: i32) -> ErrorResult {
4096 let document = self.owner_document();
4097 let event_handler = document.event_handler();
4098
4099 if !self.upcast::<Node>().is_connected() {
4110 return Err(Error::InvalidState(Some(
4111 "Can't capture pointer on an unconnected element".into(),
4112 )));
4113 }
4114
4115 if !event_handler.is_active_pointer(pointer_id) {
4125 return Ok(());
4126 }
4127
4128 event_handler.set_pending_pointer_capture(pointer_id, self);
4131
4132 Ok(())
4133 }
4134
4135 fn ReleasePointerCapture(&self, pointer_id: i32) -> ErrorResult {
4137 let document = self.owner_document();
4138 let event_handler = document.event_handler();
4139
4140 if !event_handler.is_active_pointer(pointer_id) {
4144 return Err(Error::NotFound(Some(
4145 "Can't release a pointer that is not active".into(),
4146 )));
4147 }
4148
4149 if !event_handler.has_pointer_capture(pointer_id, self) {
4152 return Ok(());
4153 }
4154
4155 event_handler.clear_pending_pointer_capture(pointer_id);
4157
4158 Ok(())
4159 }
4160
4161 fn HasPointerCapture(&self, pointer_id: i32) -> bool {
4163 let document = self.owner_document();
4164 let event_handler = document.event_handler();
4165 event_handler.has_pointer_capture(pointer_id, self)
4166 }
4167
4168 fn AttachShadow(
4170 &self,
4171 cx: &mut JSContext,
4172 init: &ShadowRootInit,
4173 ) -> Fallible<DomRoot<ShadowRoot>> {
4174 let shadow_root = self.attach_shadow(
4177 cx,
4178 IsUserAgentWidget::No,
4179 init.mode,
4180 init.clonable,
4181 init.serializable,
4182 init.delegatesFocus,
4183 init.slotAssignment,
4184 )?;
4185
4186 Ok(shadow_root)
4188 }
4189
4190 fn GetShadowRoot(&self) -> Option<DomRoot<ShadowRoot>> {
4192 let shadow_or_none = self.shadow_root();
4194
4195 let shadow = shadow_or_none?;
4197 if shadow.Mode() == ShadowRootMode::Closed {
4198 return None;
4199 }
4200
4201 Some(shadow)
4203 }
4204
4205 fn GetCustomElementRegistry(&self) -> Option<DomRoot<CustomElementRegistry>> {
4207 self.custom_element_registry()
4209 }
4210
4211 fn GetRole(&self) -> Option<DOMString> {
4213 self.get_nullable_string_attribute(&local_name!("role"))
4214 }
4215
4216 fn SetRole(&self, cx: &mut JSContext, value: Option<DOMString>) {
4218 self.set_nullable_string_attribute(cx, &local_name!("role"), value);
4219 }
4220
4221 fn GetAriaAtomic(&self) -> Option<DOMString> {
4222 self.get_nullable_string_attribute(&local_name!("aria-atomic"))
4223 }
4224
4225 fn SetAriaAtomic(&self, cx: &mut JSContext, value: Option<DOMString>) {
4226 self.set_nullable_string_attribute(cx, &local_name!("aria-atomic"), value);
4227 }
4228
4229 fn GetAriaAutoComplete(&self) -> Option<DOMString> {
4230 self.get_nullable_string_attribute(&local_name!("aria-autocomplete"))
4231 }
4232
4233 fn SetAriaAutoComplete(&self, cx: &mut JSContext, value: Option<DOMString>) {
4234 self.set_nullable_string_attribute(cx, &local_name!("aria-autocomplete"), value);
4235 }
4236
4237 fn GetAriaBrailleLabel(&self) -> Option<DOMString> {
4238 self.get_nullable_string_attribute(&local_name!("aria-braillelabel"))
4239 }
4240
4241 fn SetAriaBrailleLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4242 self.set_nullable_string_attribute(cx, &local_name!("aria-braillelabel"), value);
4243 }
4244
4245 fn GetAriaBrailleRoleDescription(&self) -> Option<DOMString> {
4246 self.get_nullable_string_attribute(&local_name!("aria-brailleroledescription"))
4247 }
4248
4249 fn SetAriaBrailleRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4250 self.set_nullable_string_attribute(cx, &local_name!("aria-brailleroledescription"), value);
4251 }
4252
4253 fn GetAriaBusy(&self) -> Option<DOMString> {
4254 self.get_nullable_string_attribute(&local_name!("aria-busy"))
4255 }
4256
4257 fn SetAriaBusy(&self, cx: &mut JSContext, value: Option<DOMString>) {
4258 self.set_nullable_string_attribute(cx, &local_name!("aria-busy"), value);
4259 }
4260
4261 fn GetAriaChecked(&self) -> Option<DOMString> {
4262 self.get_nullable_string_attribute(&local_name!("aria-checked"))
4263 }
4264
4265 fn SetAriaChecked(&self, cx: &mut JSContext, value: Option<DOMString>) {
4266 self.set_nullable_string_attribute(cx, &local_name!("aria-checked"), value);
4267 }
4268
4269 fn GetAriaColCount(&self) -> Option<DOMString> {
4270 self.get_nullable_string_attribute(&local_name!("aria-colcount"))
4271 }
4272
4273 fn SetAriaColCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4274 self.set_nullable_string_attribute(cx, &local_name!("aria-colcount"), value);
4275 }
4276
4277 fn GetAriaColIndex(&self) -> Option<DOMString> {
4278 self.get_nullable_string_attribute(&local_name!("aria-colindex"))
4279 }
4280
4281 fn SetAriaColIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4282 self.set_nullable_string_attribute(cx, &local_name!("aria-colindex"), value);
4283 }
4284
4285 fn GetAriaColIndexText(&self) -> Option<DOMString> {
4286 self.get_nullable_string_attribute(&local_name!("aria-colindextext"))
4287 }
4288
4289 fn SetAriaColIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4290 self.set_nullable_string_attribute(cx, &local_name!("aria-colindextext"), value);
4291 }
4292
4293 fn GetAriaColSpan(&self) -> Option<DOMString> {
4294 self.get_nullable_string_attribute(&local_name!("aria-colspan"))
4295 }
4296
4297 fn SetAriaColSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4298 self.set_nullable_string_attribute(cx, &local_name!("aria-colspan"), value);
4299 }
4300
4301 fn GetAriaCurrent(&self) -> Option<DOMString> {
4302 self.get_nullable_string_attribute(&local_name!("aria-current"))
4303 }
4304
4305 fn SetAriaCurrent(&self, cx: &mut JSContext, value: Option<DOMString>) {
4306 self.set_nullable_string_attribute(cx, &local_name!("aria-current"), value);
4307 }
4308
4309 fn GetAriaDescription(&self) -> Option<DOMString> {
4310 self.get_nullable_string_attribute(&local_name!("aria-description"))
4311 }
4312
4313 fn SetAriaDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4314 self.set_nullable_string_attribute(cx, &local_name!("aria-description"), value);
4315 }
4316
4317 fn GetAriaDisabled(&self) -> Option<DOMString> {
4318 self.get_nullable_string_attribute(&local_name!("aria-disabled"))
4319 }
4320
4321 fn SetAriaDisabled(&self, cx: &mut JSContext, value: Option<DOMString>) {
4322 self.set_nullable_string_attribute(cx, &local_name!("aria-disabled"), value);
4323 }
4324
4325 fn GetAriaExpanded(&self) -> Option<DOMString> {
4326 self.get_nullable_string_attribute(&local_name!("aria-expanded"))
4327 }
4328
4329 fn SetAriaExpanded(&self, cx: &mut JSContext, value: Option<DOMString>) {
4330 self.set_nullable_string_attribute(cx, &local_name!("aria-expanded"), value);
4331 }
4332
4333 fn GetAriaHasPopup(&self) -> Option<DOMString> {
4334 self.get_nullable_string_attribute(&local_name!("aria-haspopup"))
4335 }
4336
4337 fn SetAriaHasPopup(&self, cx: &mut JSContext, value: Option<DOMString>) {
4338 self.set_nullable_string_attribute(cx, &local_name!("aria-haspopup"), value);
4339 }
4340
4341 fn GetAriaHidden(&self) -> Option<DOMString> {
4342 self.get_nullable_string_attribute(&local_name!("aria-hidden"))
4343 }
4344
4345 fn SetAriaHidden(&self, cx: &mut JSContext, value: Option<DOMString>) {
4346 self.set_nullable_string_attribute(cx, &local_name!("aria-hidden"), value);
4347 }
4348
4349 fn GetAriaInvalid(&self) -> Option<DOMString> {
4350 self.get_nullable_string_attribute(&local_name!("aria-invalid"))
4351 }
4352
4353 fn SetAriaInvalid(&self, cx: &mut JSContext, value: Option<DOMString>) {
4354 self.set_nullable_string_attribute(cx, &local_name!("aria-invalid"), value);
4355 }
4356
4357 fn GetAriaKeyShortcuts(&self) -> Option<DOMString> {
4358 self.get_nullable_string_attribute(&local_name!("aria-keyshortcuts"))
4359 }
4360
4361 fn SetAriaKeyShortcuts(&self, cx: &mut JSContext, value: Option<DOMString>) {
4362 self.set_nullable_string_attribute(cx, &local_name!("aria-keyshortcuts"), value);
4363 }
4364
4365 fn GetAriaLabel(&self) -> Option<DOMString> {
4366 self.get_nullable_string_attribute(&local_name!("aria-label"))
4367 }
4368
4369 fn SetAriaLabel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4370 self.set_nullable_string_attribute(cx, &local_name!("aria-label"), value);
4371 }
4372
4373 fn GetAriaLevel(&self) -> Option<DOMString> {
4374 self.get_nullable_string_attribute(&local_name!("aria-level"))
4375 }
4376
4377 fn SetAriaLevel(&self, cx: &mut JSContext, value: Option<DOMString>) {
4378 self.set_nullable_string_attribute(cx, &local_name!("aria-level"), value);
4379 }
4380
4381 fn GetAriaLive(&self) -> Option<DOMString> {
4382 self.get_nullable_string_attribute(&local_name!("aria-live"))
4383 }
4384
4385 fn SetAriaLive(&self, cx: &mut JSContext, value: Option<DOMString>) {
4386 self.set_nullable_string_attribute(cx, &local_name!("aria-live"), value);
4387 }
4388
4389 fn GetAriaModal(&self) -> Option<DOMString> {
4390 self.get_nullable_string_attribute(&local_name!("aria-modal"))
4391 }
4392
4393 fn SetAriaModal(&self, cx: &mut JSContext, value: Option<DOMString>) {
4394 self.set_nullable_string_attribute(cx, &local_name!("aria-modal"), value);
4395 }
4396
4397 fn GetAriaMultiLine(&self) -> Option<DOMString> {
4398 self.get_nullable_string_attribute(&local_name!("aria-multiline"))
4399 }
4400
4401 fn SetAriaMultiLine(&self, cx: &mut JSContext, value: Option<DOMString>) {
4402 self.set_nullable_string_attribute(cx, &local_name!("aria-multiline"), value);
4403 }
4404
4405 fn GetAriaMultiSelectable(&self) -> Option<DOMString> {
4406 self.get_nullable_string_attribute(&local_name!("aria-multiselectable"))
4407 }
4408
4409 fn SetAriaMultiSelectable(&self, cx: &mut JSContext, value: Option<DOMString>) {
4410 self.set_nullable_string_attribute(cx, &local_name!("aria-multiselectable"), value);
4411 }
4412
4413 fn GetAriaOrientation(&self) -> Option<DOMString> {
4414 self.get_nullable_string_attribute(&local_name!("aria-orientation"))
4415 }
4416
4417 fn SetAriaOrientation(&self, cx: &mut JSContext, value: Option<DOMString>) {
4418 self.set_nullable_string_attribute(cx, &local_name!("aria-orientation"), value);
4419 }
4420
4421 fn GetAriaPlaceholder(&self) -> Option<DOMString> {
4422 self.get_nullable_string_attribute(&local_name!("aria-placeholder"))
4423 }
4424
4425 fn SetAriaPlaceholder(&self, cx: &mut JSContext, value: Option<DOMString>) {
4426 self.set_nullable_string_attribute(cx, &local_name!("aria-placeholder"), value);
4427 }
4428
4429 fn GetAriaPosInSet(&self) -> Option<DOMString> {
4430 self.get_nullable_string_attribute(&local_name!("aria-posinset"))
4431 }
4432
4433 fn SetAriaPosInSet(&self, cx: &mut JSContext, value: Option<DOMString>) {
4434 self.set_nullable_string_attribute(cx, &local_name!("aria-posinset"), value);
4435 }
4436
4437 fn GetAriaPressed(&self) -> Option<DOMString> {
4438 self.get_nullable_string_attribute(&local_name!("aria-pressed"))
4439 }
4440
4441 fn SetAriaPressed(&self, cx: &mut JSContext, value: Option<DOMString>) {
4442 self.set_nullable_string_attribute(cx, &local_name!("aria-pressed"), value);
4443 }
4444
4445 fn GetAriaReadOnly(&self) -> Option<DOMString> {
4446 self.get_nullable_string_attribute(&local_name!("aria-readonly"))
4447 }
4448
4449 fn SetAriaReadOnly(&self, cx: &mut JSContext, value: Option<DOMString>) {
4450 self.set_nullable_string_attribute(cx, &local_name!("aria-readonly"), value);
4451 }
4452
4453 fn GetAriaRelevant(&self) -> Option<DOMString> {
4454 self.get_nullable_string_attribute(&local_name!("aria-relevant"))
4455 }
4456
4457 fn SetAriaRelevant(&self, cx: &mut JSContext, value: Option<DOMString>) {
4458 self.set_nullable_string_attribute(cx, &local_name!("aria-relevant"), value);
4459 }
4460
4461 fn GetAriaRequired(&self) -> Option<DOMString> {
4462 self.get_nullable_string_attribute(&local_name!("aria-required"))
4463 }
4464
4465 fn SetAriaRequired(&self, cx: &mut JSContext, value: Option<DOMString>) {
4466 self.set_nullable_string_attribute(cx, &local_name!("aria-required"), value);
4467 }
4468
4469 fn GetAriaRoleDescription(&self) -> Option<DOMString> {
4470 self.get_nullable_string_attribute(&local_name!("aria-roledescription"))
4471 }
4472
4473 fn SetAriaRoleDescription(&self, cx: &mut JSContext, value: Option<DOMString>) {
4474 self.set_nullable_string_attribute(cx, &local_name!("aria-roledescription"), value);
4475 }
4476
4477 fn GetAriaRowCount(&self) -> Option<DOMString> {
4478 self.get_nullable_string_attribute(&local_name!("aria-rowcount"))
4479 }
4480
4481 fn SetAriaRowCount(&self, cx: &mut JSContext, value: Option<DOMString>) {
4482 self.set_nullable_string_attribute(cx, &local_name!("aria-rowcount"), value);
4483 }
4484
4485 fn GetAriaRowIndex(&self) -> Option<DOMString> {
4486 self.get_nullable_string_attribute(&local_name!("aria-rowindex"))
4487 }
4488
4489 fn SetAriaRowIndex(&self, cx: &mut JSContext, value: Option<DOMString>) {
4490 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindex"), value);
4491 }
4492
4493 fn GetAriaRowIndexText(&self) -> Option<DOMString> {
4494 self.get_nullable_string_attribute(&local_name!("aria-rowindextext"))
4495 }
4496
4497 fn SetAriaRowIndexText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4498 self.set_nullable_string_attribute(cx, &local_name!("aria-rowindextext"), value);
4499 }
4500
4501 fn GetAriaRowSpan(&self) -> Option<DOMString> {
4502 self.get_nullable_string_attribute(&local_name!("aria-rowspan"))
4503 }
4504
4505 fn SetAriaRowSpan(&self, cx: &mut JSContext, value: Option<DOMString>) {
4506 self.set_nullable_string_attribute(cx, &local_name!("aria-rowspan"), value);
4507 }
4508
4509 fn GetAriaSelected(&self) -> Option<DOMString> {
4510 self.get_nullable_string_attribute(&local_name!("aria-selected"))
4511 }
4512
4513 fn SetAriaSelected(&self, cx: &mut JSContext, value: Option<DOMString>) {
4514 self.set_nullable_string_attribute(cx, &local_name!("aria-selected"), value);
4515 }
4516
4517 fn GetAriaSetSize(&self) -> Option<DOMString> {
4518 self.get_nullable_string_attribute(&local_name!("aria-setsize"))
4519 }
4520
4521 fn SetAriaSetSize(&self, cx: &mut JSContext, value: Option<DOMString>) {
4522 self.set_nullable_string_attribute(cx, &local_name!("aria-setsize"), value);
4523 }
4524
4525 fn GetAriaSort(&self) -> Option<DOMString> {
4526 self.get_nullable_string_attribute(&local_name!("aria-sort"))
4527 }
4528
4529 fn SetAriaSort(&self, cx: &mut JSContext, value: Option<DOMString>) {
4530 self.set_nullable_string_attribute(cx, &local_name!("aria-sort"), value);
4531 }
4532
4533 fn GetAriaValueMax(&self) -> Option<DOMString> {
4534 self.get_nullable_string_attribute(&local_name!("aria-valuemax"))
4535 }
4536
4537 fn SetAriaValueMax(&self, cx: &mut JSContext, value: Option<DOMString>) {
4538 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemax"), value);
4539 }
4540
4541 fn GetAriaValueMin(&self) -> Option<DOMString> {
4542 self.get_nullable_string_attribute(&local_name!("aria-valuemin"))
4543 }
4544
4545 fn SetAriaValueMin(&self, cx: &mut JSContext, value: Option<DOMString>) {
4546 self.set_nullable_string_attribute(cx, &local_name!("aria-valuemin"), value);
4547 }
4548
4549 fn GetAriaValueNow(&self) -> Option<DOMString> {
4550 self.get_nullable_string_attribute(&local_name!("aria-valuenow"))
4551 }
4552
4553 fn SetAriaValueNow(&self, cx: &mut JSContext, value: Option<DOMString>) {
4554 self.set_nullable_string_attribute(cx, &local_name!("aria-valuenow"), value);
4555 }
4556
4557 fn GetAriaValueText(&self) -> Option<DOMString> {
4558 self.get_nullable_string_attribute(&local_name!("aria-valuetext"))
4559 }
4560
4561 fn SetAriaValueText(&self, cx: &mut JSContext, value: Option<DOMString>) {
4562 self.set_nullable_string_attribute(cx, &local_name!("aria-valuetext"), value);
4563 }
4564
4565 fn GetAssignedSlot(&self, cx: &JSContext) -> Option<DomRoot<HTMLSlotElement>> {
4567 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4570 slottable.find_a_slot(cx.no_gc(), true)
4571 }
4572
4573 fn Part(&self, cx: &mut JSContext) -> DomRoot<DOMTokenList> {
4575 let Some(part) = self.rare_data().as_ref().and_then(|data| data.part.get()) else {
4576 let part = DOMTokenList::new(cx, self, &local_name!("part"), None);
4577 self.ensure_rare_data(cx.no_gc()).part.set(Some(&*part));
4578 return part;
4579 };
4580 part
4581 }
4582
4583 fn Animate(
4585 &self,
4586 cx: &mut JSContext,
4587 keyframes: *mut JSObject,
4588 options: UnrestrictedDoubleOrKeyframeAnimationOptions,
4589 ) -> DomRoot<Animation> {
4590 let window = self.owner_window();
4591
4592 let target = self;
4594
4595 let parent_options = match options {
4603 UnrestrictedDoubleOrKeyframeAnimationOptions::UnrestrictedDouble(value) => {
4604 UnrestrictedDoubleOrKeyframeEffectOptions::UnrestrictedDouble(value)
4605 },
4606 UnrestrictedDoubleOrKeyframeAnimationOptions::KeyframeAnimationOptions(options) => {
4607 UnrestrictedDoubleOrKeyframeEffectOptions::KeyframeEffectOptions(options.parent)
4608 },
4609 };
4610 let effect =
4611 KeyframeEffect::Constructor(cx, &window, None, Some(target), keyframes, parent_options);
4612
4613 let animation = Animation::Constructor(cx, &window, None, Some(effect.upcast()));
4621
4622 animation
4629 }
4630}
4631
4632impl VirtualMethods for Element {
4633 fn super_type(&self) -> Option<&dyn VirtualMethods> {
4634 Some(self.upcast::<Node>() as &dyn VirtualMethods)
4635 }
4636
4637 fn attribute_affects_presentational_hints(&self, attr: AttrRef<'_>) -> bool {
4638 if attr.local_name() == &local_name!("lang") {
4640 return true;
4641 }
4642
4643 self.super_type()
4644 .unwrap()
4645 .attribute_affects_presentational_hints(attr)
4646 }
4647
4648 fn attribute_mutated(
4649 &self,
4650 cx: &mut JSContext,
4651 attr: AttrRef<'_>,
4652 mutation: AttributeMutation,
4653 ) {
4654 self.super_type()
4655 .unwrap()
4656 .attribute_mutated(cx, attr, mutation);
4657 let node = self.upcast::<Node>();
4658 let doc = node.owner_doc();
4659 match *attr.local_name() {
4660 ref name if name.starts_with("on") && EventTarget::is_content_event_handler(name) => {
4664 let evtarget = self.upcast::<EventTarget>();
4665 let event_name = &name[2..];
4666 match mutation {
4667 AttributeMutation::Set(..) => {
4669 let source = &**attr.value();
4670 let source_line = 1; evtarget.set_event_handler_uncompiled(
4672 cx,
4673 self.owner_window().get_url(),
4674 source_line,
4675 event_name,
4676 source,
4677 );
4678 },
4679 AttributeMutation::Removed => {
4681 evtarget
4682 .set_event_handler_common::<EventHandlerNonNull>(cx, event_name, None);
4683 },
4684 }
4685 },
4686 local_name!("style") => self.update_style_attribute(cx, attr, mutation),
4687 local_name!("id") => {
4688 *self.id_attribute.borrow_mut() = mutation.new_value(attr).and_then(|value| {
4690 let value = value.as_atom();
4691 if value != &atom!("") {
4692 Some(value.clone())
4694 } else {
4695 None
4697 }
4698 });
4699
4700 let containing_shadow_root = self.containing_shadow_root();
4701 if node.is_in_a_document_tree() || node.is_in_a_shadow_tree() {
4702 let value = attr.value().as_atom().clone();
4703 match mutation {
4704 AttributeMutation::Set(old_value, _) => {
4705 if let Some(old_value) = old_value {
4706 let old_value = old_value.as_atom();
4707 if let Some(ref shadow_root) = containing_shadow_root {
4708 shadow_root.unregister_element_id(old_value);
4709 } else {
4710 doc.unregister_element_id(cx, old_value);
4711 }
4712 }
4713 if value != atom!("") {
4714 if let Some(ref shadow_root) = containing_shadow_root {
4715 shadow_root.register_element_id(self, &value);
4716 } else {
4717 doc.register_element_id(cx, self, &value);
4718 }
4719 }
4720 },
4721 AttributeMutation::Removed => {
4722 if value != atom!("") {
4723 if let Some(ref shadow_root) = containing_shadow_root {
4724 shadow_root.unregister_element_id(&value);
4725 } else {
4726 doc.unregister_element_id(cx, &value);
4727 }
4728 }
4729 },
4730 }
4731 }
4732 },
4733 local_name!("name") => {
4734 self.ensure_rare_data(cx.no_gc()).name_attribute =
4736 mutation.new_value(attr).and_then(|value| {
4737 let value = value.as_atom();
4738 if value != &atom!("") {
4739 Some(value.clone())
4740 } else {
4741 None
4742 }
4743 });
4744 if node.is_connected() && node.containing_shadow_root().is_none() {
4747 let value = attr.value().as_atom().clone();
4748 match mutation {
4749 AttributeMutation::Set(old_value, _) => {
4750 if let Some(old_value) = old_value {
4751 doc.unregister_element_name(old_value.as_atom());
4752 }
4753 if value != atom!("") {
4754 doc.register_element_name(self, &value);
4755 }
4756 },
4757 AttributeMutation::Removed => {
4758 if value != atom!("") {
4759 doc.unregister_element_name(&value);
4760 }
4761 },
4762 }
4763 }
4764 },
4765 local_name!("slot") => {
4766 rooted!(&in(cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
4768
4769 if let Some(assigned_slot) = slottable.assigned_slot() {
4771 assigned_slot.assign_slottables(cx);
4772 }
4773 slottable.assign_a_slot(cx);
4774 },
4775 _ => {
4776 if attr.namespace() == &ns!() && attr.local_name() == &local_name!("src") {
4779 node.dirty(cx.no_gc(), NodeDamage::Other);
4780 }
4781 },
4782 };
4783
4784 if self
4787 .upcast::<Node>()
4788 .get_flag(NodeFlags::USES_ATTR_IN_CONTENT_ATTRIBUTE)
4789 {
4790 node.dirty(cx.no_gc(), NodeDamage::ContentOrHeritage);
4791 }
4792
4793 node.rev_version(cx.no_gc());
4797
4798 let window = self.owner_window();
4800 if window.live_devtools_updates() {
4801 let global = window.upcast::<GlobalScope>();
4802 if let Some(sender) = global.devtools_chan() {
4803 let pipeline_id = global.pipeline_id();
4804 if ScriptThread::devtools_want_updates_for_node(pipeline_id, self.upcast()) {
4805 let devtools_message = ScriptToDevtoolsControlMsg::DomMutation(
4806 pipeline_id,
4807 DomMutation::AttributeModified {
4808 node: self.upcast::<Node>().unique_id(pipeline_id),
4809 attribute_name: attr.local_name().to_string(),
4810 new_value: mutation.new_value(attr).map(|value| value.to_string()),
4811 },
4812 );
4813 sender.send(devtools_message).unwrap();
4814 }
4815 }
4816 }
4817 }
4818
4819 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
4820 match *name {
4821 local_name!("id") => AttrValue::Atom(value.into()),
4822 local_name!("name") => AttrValue::Atom(value.into()),
4823 local_name!("class") | local_name!("part") => {
4824 AttrValue::from_serialized_tokenlist(value.into())
4825 },
4826 local_name!("exportparts") => AttrValue::from_shadow_parts(value.into()),
4827 local_name!("tabindex") => AttrValue::from_i32(value.into(), -1),
4828 _ => self
4829 .super_type()
4830 .unwrap()
4831 .parse_plain_attribute(name, value),
4832 }
4833 }
4834
4835 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
4836 if let Some(s) = self.super_type() {
4837 s.bind_to_tree(cx, context);
4838 }
4839
4840 if let Some(f) = self.as_maybe_form_control() {
4841 f.bind_form_control_to_tree(cx);
4842 }
4843
4844 if let Some(ref shadow_root) = self.shadow_root() {
4845 shadow_root.bind_to_tree(cx, context);
4846 }
4847
4848 if !context.is_in_tree() {
4849 return;
4850 }
4851
4852 self.register_current_id_and_name_attribute(cx);
4853 }
4854
4855 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
4856 self.super_type().unwrap().unbind_from_tree(cx, context);
4857
4858 if let Some(f) = self.as_maybe_form_control() {
4859 f.unbind_form_control_from_tree(cx);
4863 }
4864
4865 if !context.tree_is_in_a_document_tree && !context.tree_is_in_a_shadow_tree {
4866 return;
4867 }
4868
4869 let doc = self.owner_document();
4870
4871 let fullscreen = doc.fullscreen_element();
4872 if fullscreen.as_deref() == Some(self) {
4873 doc.exit_fullscreen(cx);
4874 }
4875
4876 self.unregister_current_id_and_name_attribute(cx);
4877 }
4878
4879 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
4880 if let Some(s) = self.super_type() {
4881 s.children_changed(cx, mutation);
4882 }
4883
4884 let flags = self.get_selector_flags();
4885 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
4886 self.upcast::<Node>().dirty(cx.no_gc(), NodeDamage::Other);
4888 } else {
4889 if flags.intersects(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) &&
4890 let Some(next_child) = mutation.next_child()
4891 {
4892 for child in next_child.inclusively_following_siblings_unrooted(cx.no_gc()) {
4893 if child.is::<Element>() {
4894 child.dirty(cx.no_gc(), NodeDamage::Other);
4895 }
4896 }
4897 }
4898 if flags.intersects(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) &&
4899 let Some(child) = mutation.modified_edge_element(cx.no_gc())
4900 {
4901 child.dirty(cx.no_gc(), NodeDamage::Other);
4902 }
4903 }
4904 }
4905
4906 fn adopting_steps(&self, cx: &mut JSContext, old_doc: &Document) {
4907 self.super_type().unwrap().adopting_steps(cx, old_doc);
4908
4909 if self.owner_document().is_html_document() != old_doc.is_html_document() {
4910 self.tag_name.clear();
4911 }
4912 }
4913
4914 fn post_connection_steps(&self, cx: &mut JSContext) {
4915 if let Some(s) = self.super_type() {
4916 s.post_connection_steps(cx);
4917 }
4918
4919 self.update_nonce_post_connection(cx);
4920 }
4921
4922 fn cloning_steps(
4924 &self,
4925 cx: &mut JSContext,
4926 copy: &Node,
4927 maybe_doc: Option<&Document>,
4928 clone_children: CloneChildrenFlag,
4929 ) {
4930 if let Some(s) = self.super_type() {
4931 s.cloning_steps(cx, copy, maybe_doc, clone_children);
4932 }
4933 let elem = copy.downcast::<Element>().unwrap();
4934 if let Some(rare_data) = self.rare_data().as_ref() {
4935 elem.update_nonce_internal_slot(rare_data.cryptographic_nonce.clone(), cx.no_gc());
4936 }
4937 }
4938}
4939impl Element {
4940 pub(crate) fn client_rect(&self, no_gc: &NoGC) -> Rect<i32, CSSPixel> {
4941 let doc = self.node.owner_doc();
4942
4943 if let Some(rect) = self
4944 .rare_data()
4945 .as_ref()
4946 .and_then(|data| data.client_rect.as_ref())
4947 .and_then(|rect| rect.get().ok()) &&
4948 doc.restyle_reason(no_gc).is_empty()
4949 {
4950 return rect;
4951 }
4952
4953 let mut rect = self.upcast::<Node>().client_rect();
4954 let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks;
4955
4956 if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::<HTMLElement>()) ||
4957 (!in_quirks_mode && self.is_document_element())
4958 {
4959 rect.size = doc.window().viewport_details().size.round().to_i32();
4960 }
4961
4962 self.ensure_rare_data(no_gc).client_rect =
4963 Some(self.owner_window().cache_layout_value(rect));
4964 rect
4965 }
4966
4967 pub(crate) fn as_maybe_activatable(&self) -> Option<&dyn Activatable> {
4968 let element = match self.upcast::<Node>().type_id() {
4969 NodeTypeId::Element(ElementTypeId::HTMLElement(
4970 HTMLElementTypeId::HTMLInputElement,
4971 )) => {
4972 let element = self.downcast::<HTMLInputElement>().unwrap();
4973 Some(element as &dyn Activatable)
4974 },
4975 NodeTypeId::Element(ElementTypeId::HTMLElement(
4976 HTMLElementTypeId::HTMLButtonElement,
4977 )) => {
4978 let element = self.downcast::<HTMLButtonElement>().unwrap();
4979 Some(element as &dyn Activatable)
4980 },
4981 NodeTypeId::Element(ElementTypeId::HTMLElement(
4982 HTMLElementTypeId::HTMLAnchorElement,
4983 )) => {
4984 let element = self.downcast::<HTMLAnchorElement>().unwrap();
4985 Some(element as &dyn Activatable)
4986 },
4987 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
4988 let element = self.downcast::<HTMLAreaElement>().unwrap();
4989 Some(element as &dyn Activatable)
4990 },
4991 NodeTypeId::Element(ElementTypeId::HTMLElement(
4992 HTMLElementTypeId::HTMLLabelElement,
4993 )) => {
4994 let element = self.downcast::<HTMLLabelElement>().unwrap();
4995 Some(element as &dyn Activatable)
4996 },
4997 NodeTypeId::Element(ElementTypeId::HTMLElement(
4998 HTMLElementTypeId::HTMLSelectElement,
4999 )) => {
5000 let element = self.downcast::<HTMLSelectElement>().unwrap();
5001 Some(element as &dyn Activatable)
5002 },
5003 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLElement)) => {
5004 let element = self.downcast::<HTMLElement>().unwrap();
5005 Some(element as &dyn Activatable)
5006 },
5007 _ => None,
5008 };
5009 element.filter(|elem| elem.is_instance_activatable())
5010 }
5011
5012 pub(crate) fn as_stylesheet_owner(&self) -> Option<&dyn StylesheetOwner> {
5013 if let Some(s) = self.downcast::<HTMLStyleElement>() {
5014 return Some(s as &dyn StylesheetOwner);
5015 }
5016
5017 if let Some(l) = self.downcast::<HTMLLinkElement>() {
5018 return Some(l as &dyn StylesheetOwner);
5019 }
5020
5021 None
5022 }
5023
5024 pub(crate) fn as_maybe_validatable(&self) -> Option<&dyn Validatable> {
5026 match self.upcast::<Node>().type_id() {
5027 NodeTypeId::Element(ElementTypeId::HTMLElement(
5028 HTMLElementTypeId::HTMLInputElement,
5029 )) => {
5030 let element = self.downcast::<HTMLInputElement>().unwrap();
5031 Some(element as &dyn Validatable)
5032 },
5033 NodeTypeId::Element(ElementTypeId::HTMLElement(
5034 HTMLElementTypeId::HTMLButtonElement,
5035 )) => {
5036 let element = self.downcast::<HTMLButtonElement>().unwrap();
5037 Some(element as &dyn Validatable)
5038 },
5039 NodeTypeId::Element(ElementTypeId::HTMLElement(
5040 HTMLElementTypeId::HTMLObjectElement,
5041 )) => {
5042 let element = self.downcast::<HTMLObjectElement>().unwrap();
5043 Some(element as &dyn Validatable)
5044 },
5045 NodeTypeId::Element(ElementTypeId::HTMLElement(
5046 HTMLElementTypeId::HTMLSelectElement,
5047 )) => {
5048 let element = self.downcast::<HTMLSelectElement>().unwrap();
5049 Some(element as &dyn Validatable)
5050 },
5051 NodeTypeId::Element(ElementTypeId::HTMLElement(
5052 HTMLElementTypeId::HTMLTextAreaElement,
5053 )) => {
5054 let element = self.downcast::<HTMLTextAreaElement>().unwrap();
5055 Some(element as &dyn Validatable)
5056 },
5057 NodeTypeId::Element(ElementTypeId::HTMLElement(
5058 HTMLElementTypeId::HTMLFieldSetElement,
5059 )) => {
5060 let element = self.downcast::<HTMLFieldSetElement>().unwrap();
5061 Some(element as &dyn Validatable)
5062 },
5063 NodeTypeId::Element(ElementTypeId::HTMLElement(
5064 HTMLElementTypeId::HTMLOutputElement,
5065 )) => {
5066 let element = self.downcast::<HTMLOutputElement>().unwrap();
5067 Some(element as &dyn Validatable)
5068 },
5069 _ => None,
5070 }
5071 }
5072
5073 pub(crate) fn is_invalid(&self, cx: &mut JSContext, needs_update: bool) -> bool {
5074 if let Some(validatable) = self.as_maybe_validatable() {
5075 if needs_update {
5076 validatable
5077 .validity_state(cx)
5078 .perform_validation_and_update(cx, ValidationFlags::all());
5079 }
5080 return validatable.is_instance_validatable() && !validatable.satisfies_constraints(cx);
5081 }
5082
5083 if let Some(internals) = self.get_element_internals() {
5084 return internals.is_invalid(cx);
5085 }
5086 false
5087 }
5088
5089 pub(crate) fn is_instance_validatable(&self) -> bool {
5090 if let Some(validatable) = self.as_maybe_validatable() {
5091 return validatable.is_instance_validatable();
5092 }
5093 if let Some(internals) = self.get_element_internals() {
5094 return internals.is_instance_validatable();
5095 }
5096 false
5097 }
5098
5099 pub(crate) fn init_state_for_internals(&self) {
5100 self.set_enabled_state(true);
5101 self.set_state(ElementState::VALID, true);
5102 self.set_state(ElementState::INVALID, false);
5103 }
5104
5105 pub(crate) fn click_in_progress(&self) -> bool {
5106 self.upcast::<Node>().get_flag(NodeFlags::CLICK_IN_PROGRESS)
5107 }
5108
5109 pub(crate) fn set_click_in_progress(&self, click: bool) {
5110 self.upcast::<Node>()
5111 .set_flag(NodeFlags::CLICK_IN_PROGRESS, click)
5112 }
5113
5114 pub fn state(&self) -> ElementState {
5115 self.state.get()
5116 }
5117
5118 pub(crate) fn set_state(&self, which: ElementState, value: bool) {
5119 let mut state = self.state.get();
5120 let previous_state = state;
5121 if value {
5122 state.insert(which);
5123 } else {
5124 state.remove(which);
5125 }
5126
5127 if previous_state == state {
5128 return;
5130 }
5131
5132 {
5135 let document = self.owner_document();
5136 let mut entry = document.ensure_pending_restyle(self);
5137 if entry.snapshot.is_none() {
5138 entry.snapshot = Some(Snapshot::new());
5139 }
5140 let snapshot = entry.snapshot.as_mut().unwrap();
5141 if snapshot.state.is_none() {
5142 snapshot.state = Some(self.state());
5143 }
5144 }
5145
5146 self.state.set(state);
5147 }
5148
5149 pub(crate) fn set_active_state(&self, value: bool) {
5151 self.set_state(ElementState::ACTIVE, value);
5152
5153 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
5154 parent.set_active_state(value);
5155 }
5156 }
5157
5158 pub(crate) fn focus_state(&self) -> bool {
5159 self.state.get().contains(ElementState::FOCUS)
5160 }
5161
5162 pub(crate) fn set_focus_state(&self, value: bool) {
5163 self.set_state(ElementState::FOCUS, value);
5164 }
5165
5166 pub(crate) fn set_hover_state(&self, value: bool) {
5167 self.set_state(ElementState::HOVER, value);
5168 }
5169
5170 pub(crate) fn enabled_state(&self) -> bool {
5171 self.state.get().contains(ElementState::ENABLED)
5172 }
5173
5174 pub(crate) fn set_enabled_state(&self, value: bool) {
5175 self.set_state(ElementState::ENABLED, value)
5176 }
5177
5178 pub(crate) fn disabled_state(&self) -> bool {
5179 self.state.get().contains(ElementState::DISABLED)
5180 }
5181
5182 pub(crate) fn set_disabled_state(&self, value: bool) {
5183 self.set_state(ElementState::DISABLED, value)
5184 }
5185
5186 pub(crate) fn read_write_state(&self) -> bool {
5187 self.state.get().contains(ElementState::READWRITE)
5188 }
5189
5190 pub(crate) fn set_read_write_state(&self, value: bool) {
5191 self.set_state(ElementState::READWRITE, value)
5192 }
5193
5194 pub(crate) fn set_open_state(&self, value: bool) {
5195 self.set_state(ElementState::OPEN, value);
5196 }
5197
5198 pub(crate) fn set_placeholder_shown_state(&self, value: bool) {
5199 self.set_state(ElementState::PLACEHOLDER_SHOWN, value);
5200 }
5201
5202 pub(crate) fn set_modal_state(&self, value: bool) {
5203 self.set_state(ElementState::MODAL, value);
5204 }
5205
5206 pub(crate) fn set_target_state(&self, value: bool) {
5207 self.set_state(ElementState::URLTARGET, value)
5208 }
5209
5210 pub(crate) fn set_fullscreen_state(&self, value: bool) {
5211 self.set_state(ElementState::FULLSCREEN, value)
5212 }
5213
5214 pub(crate) fn is_connected(&self) -> bool {
5216 self.upcast::<Node>().is_connected()
5217 }
5218
5219 pub(crate) fn cannot_navigate(&self) -> bool {
5221 let document = self.owner_document();
5222
5223 !document.is_fully_active() ||
5225 (
5226 !self.is::<HTMLAnchorElement>() && !self.is_connected()
5228 )
5229 }
5230}
5231
5232impl Element {
5233 pub(crate) fn check_ancestors_disabled_state_for_form_control(&self) {
5234 let node = self.upcast::<Node>();
5235 if self.disabled_state() {
5236 return;
5237 }
5238 for ancestor in node.ancestors() {
5239 if !ancestor.is::<HTMLFieldSetElement>() {
5240 continue;
5241 }
5242 if !ancestor.downcast::<Element>().unwrap().disabled_state() {
5243 continue;
5244 }
5245 if ancestor.is_parent_of(node) {
5246 self.set_disabled_state(true);
5247 self.set_enabled_state(false);
5248 return;
5249 }
5250 if let Some(ref legend) = ancestor.children().find(|n| n.is::<HTMLLegendElement>()) {
5251 if node.ancestors().any(|ancestor| ancestor == *legend) {
5253 continue;
5254 }
5255 }
5256 self.set_disabled_state(true);
5257 self.set_enabled_state(false);
5258 return;
5259 }
5260 }
5261
5262 pub(crate) fn check_parent_disabled_state_for_option(&self) {
5263 if self.disabled_state() {
5264 return;
5265 }
5266 let node = self.upcast::<Node>();
5267 if let Some(ref parent) = node.GetParentNode() &&
5268 parent.is::<HTMLOptGroupElement>() &&
5269 parent.downcast::<Element>().unwrap().disabled_state()
5270 {
5271 self.set_disabled_state(true);
5272 self.set_enabled_state(false);
5273 }
5274 }
5275
5276 pub(crate) fn check_disabled_attribute(&self) {
5277 let has_disabled_attrib = self.has_attribute(&local_name!("disabled"));
5278 self.set_disabled_state(has_disabled_attrib);
5279 self.set_enabled_state(!has_disabled_attrib);
5280 }
5281
5282 pub(crate) fn update_read_write_state_from_readonly_attribute(&self) {
5283 let has_readonly_attribute = self.has_attribute(&local_name!("readonly"));
5284 self.set_read_write_state(has_readonly_attribute);
5285 }
5286}
5287
5288#[derive(Clone, Copy, PartialEq)]
5289pub(crate) enum AttributeMutationReason {
5290 ByCloning,
5291 ByParser,
5292 Directly,
5293}
5294
5295#[derive(Clone, Copy)]
5296pub(crate) enum AttributeMutation<'a> {
5297 Set(Option<&'a AttrValue>, AttributeMutationReason),
5300
5301 Removed,
5304}
5305
5306impl AttributeMutation<'_> {
5307 pub(crate) fn is_removal(&self) -> bool {
5308 match *self {
5309 AttributeMutation::Removed => true,
5310 AttributeMutation::Set(..) => false,
5311 }
5312 }
5313
5314 pub(crate) fn new_value<'b>(&self, attr: AttrRef<'b>) -> Option<AttrValueRef<'b>> {
5315 match *self {
5316 AttributeMutation::Set(..) => Some(attr.value()),
5317 AttributeMutation::Removed => None,
5318 }
5319 }
5320
5321 pub(crate) fn old_value(&self, attr: AttrRef<'_>) -> Option<String> {
5322 match *self {
5323 AttributeMutation::Set(old, _) => old.map(|value| value.to_string()),
5324 AttributeMutation::Removed => Some(attr.value().to_string()),
5325 }
5326 }
5327}
5328
5329#[derive(JSTraceable, MallocSizeOf)]
5333struct TagName {
5334 #[no_trace]
5335 ptr: DomRefCell<Option<LocalName>>,
5336}
5337
5338impl TagName {
5339 fn new() -> TagName {
5340 TagName {
5341 ptr: DomRefCell::new(None),
5342 }
5343 }
5344
5345 fn or_init<F>(&self, cb: F) -> LocalName
5348 where
5349 F: FnOnce() -> LocalName,
5350 {
5351 match &mut *self.ptr.borrow_mut() {
5352 &mut Some(ref name) => name.clone(),
5353 ptr => {
5354 let name = cb();
5355 *ptr = Some(name.clone());
5356 name
5357 },
5358 }
5359 }
5360
5361 fn clear(&self) {
5364 *self.ptr.borrow_mut() = None;
5365 }
5366}
5367
5368pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
5370 element
5371 .get_attribute_string_value(&local_name!("crossorigin"))
5372 .map(|value| {
5373 let value = value.to_ascii_lowercase();
5374 if value == "anonymous" || value == "use-credentials" {
5375 DOMString::from(value)
5376 } else {
5377 DOMString::from("anonymous")
5378 }
5379 })
5380}
5381
5382pub(crate) fn set_cross_origin_attribute(
5383 cx: &mut JSContext,
5384 element: &Element,
5385 value: Option<DOMString>,
5386) {
5387 match value {
5388 Some(val) => element.set_string_attribute(cx, &local_name!("crossorigin"), val),
5389 None => {
5390 element.remove_attribute(cx, &ns!(), &local_name!("crossorigin"));
5391 },
5392 }
5393}
5394
5395pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
5397 element
5398 .get_attribute_string_value(&local_name!("referrerpolicy"))
5399 .map(|value| {
5400 let value = value.to_ascii_lowercase();
5401 if value == "no-referrer" ||
5402 value == "no-referrer-when-downgrade" ||
5403 value == "same-origin" ||
5404 value == "origin" ||
5405 value == "strict-origin" ||
5406 value == "origin-when-cross-origin" ||
5407 value == "strict-origin-when-cross-origin" ||
5408 value == "unsafe-url"
5409 {
5410 DOMString::from(value)
5411 } else {
5412 DOMString::new()
5413 }
5414 })
5415 .unwrap_or_default()
5416}
5417
5418pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
5419 element
5420 .get_attribute_string_value(&local_name!("referrerpolicy"))
5421 .map(|value| ReferrerPolicy::from(value.as_ref()))
5422 .unwrap_or(element.owner_document().get_referrer_policy())
5423}
5424
5425pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
5426 element
5427 .get_attribute_string_value(&local_name!("crossorigin"))
5428 .map(|value| CorsSettings::from_enumerated_attribute(value.as_ref()))
5429}
5430
5431pub(crate) fn cors_settings_attribute_credential_mode(element: &Element) -> CredentialsMode {
5433 element
5434 .get_attribute_string_value(&local_name!("crossorigin"))
5435 .map(|value| {
5436 if value.eq_ignore_ascii_case("use-credentials") {
5437 CredentialsMode::Include
5438 } else {
5439 CredentialsMode::CredentialsSameOrigin
5441 }
5442 })
5443 .unwrap_or(CredentialsMode::CredentialsSameOrigin)
5445}
5446
5447pub(crate) fn is_element_affected_by_legacy_background_presentational_hint(
5448 namespace: &Namespace,
5449 local_name: &LocalName,
5450) -> bool {
5451 *namespace == ns!(html) &&
5452 matches!(
5453 *local_name,
5454 local_name!("body") |
5455 local_name!("table") |
5456 local_name!("thead") |
5457 local_name!("tbody") |
5458 local_name!("tfoot") |
5459 local_name!("tr") |
5460 local_name!("td") |
5461 local_name!("th")
5462 )
5463}
5464
5465impl script_bindings::callback::OwnerWindow<crate::DomTypeHolder> for Element {
5466 fn owner_window(&self) -> Option<DomRoot<Window>> {
5467 Some(NodeTraits::owner_window(self))
5468 }
5469}