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