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