style/dom.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Types and traits used to access the DOM from style calculation.
6
7#![allow(unsafe_code)]
8#![deny(missing_docs)]
9
10use crate::applicable_declarations::ApplicableDeclarationBlock;
11#[cfg(feature = "gecko")]
12use crate::context::UpdateAnimationsTasks;
13use crate::context::{SharedStyleContext, TreeCountingCaches};
14use crate::data::{ElementData, ElementDataMut, ElementDataRef};
15use crate::device::Device;
16use crate::properties::{AnimationDeclarations, ComputedValues, PropertyDeclarationBlock};
17use crate::selector_map::PrecomputedHashMap;
18use crate::selector_parser::{AttrValue, Lang, PseudoElement, RestyleDamage, SelectorImpl};
19use crate::shared_lock::{Locked, SharedRwLock};
20use crate::stylesheets::scope_rule::ImplicitScopeRoot;
21use crate::stylist::CascadeData;
22use crate::values::AtomIdent;
23use crate::values::computed::{Display, TreeCountingResult};
24use crate::{LocalName, Namespace, WeakAtom};
25use dom::ElementState;
26use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
27use selectors::sink::Push;
28use selectors::{Element as SelectorsElement, OpaqueElement};
29use servo_arc::{Arc, ArcBorrow};
30use smallvec::SmallVec;
31use std::fmt;
32use std::fmt::Debug;
33use std::hash::Hash;
34use std::ops::Deref;
35
36pub use style_traits::dom::OpaqueNode;
37
38/// Simple trait to provide basic information about the type of an element.
39///
40/// We avoid exposing the full type id, since computing it in the general case
41/// would be difficult for Gecko nodes.
42pub trait NodeInfo {
43 /// Whether this node is an element.
44 fn is_element(&self) -> bool;
45 /// Whether this node is a text node.
46 fn is_text_node(&self) -> bool;
47}
48
49/// A node iterator that only returns node that don't need layout.
50pub struct LayoutIterator<T>(pub T);
51
52impl<T, N> Iterator for LayoutIterator<T>
53where
54 T: Iterator<Item = N>,
55 N: NodeInfo,
56{
57 type Item = N;
58
59 fn next(&mut self) -> Option<N> {
60 loop {
61 let n = self.0.next()?;
62 // Filter out nodes that layout should ignore.
63 if n.is_text_node() || n.is_element() {
64 return Some(n);
65 }
66 }
67 }
68}
69
70/// An iterator over the DOM children of a node.
71pub struct DomChildren<N>(Option<N>);
72impl<N> Iterator for DomChildren<N>
73where
74 N: TNode,
75{
76 type Item = N;
77
78 fn next(&mut self) -> Option<N> {
79 let n = self.0.take()?;
80 self.0 = n.next_sibling();
81 Some(n)
82 }
83}
84
85/// An iterator over the DOM descendants of a node in pre-order.
86pub struct DomDescendants<N> {
87 previous: Option<N>,
88 scope: N,
89}
90
91impl<N> DomDescendants<N>
92where
93 N: TNode,
94{
95 /// Returns the next element ignoring all of our subtree.
96 #[inline]
97 pub fn next_skipping_children(&mut self) -> Option<N> {
98 let prev = self.previous.take()?;
99 self.previous = prev.next_in_preorder_skipping_children(self.scope);
100 self.previous
101 }
102}
103
104impl<N> Iterator for DomDescendants<N>
105where
106 N: TNode,
107{
108 type Item = N;
109
110 #[inline]
111 fn next(&mut self) -> Option<N> {
112 let prev = self.previous.take()?;
113 self.previous = prev.next_in_preorder(self.scope);
114 self.previous
115 }
116}
117
118/// The `TDocument` trait, to represent a document node.
119pub trait TDocument: Sized + Copy + Clone {
120 /// The concrete `TNode` type.
121 type ConcreteNode: TNode<ConcreteDocument = Self>;
122
123 /// Get this document as a `TNode`.
124 fn as_node(&self) -> Self::ConcreteNode;
125
126 /// Returns whether this document is an HTML document.
127 fn is_html_document(&self) -> bool;
128
129 /// Returns the quirks mode of this document.
130 fn quirks_mode(&self) -> QuirksMode;
131
132 /// Get a list of elements with a given ID in this document, sorted by
133 /// tree position.
134 ///
135 /// Can return an error to signal that this list is not available, or also
136 /// return an empty slice.
137 fn elements_with_id<'a>(
138 &self,
139 _id: &AtomIdent,
140 ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
141 where
142 Self: 'a,
143 {
144 Err(())
145 }
146
147 /// This document's shared lock.
148 fn shared_lock(&self) -> &SharedRwLock;
149}
150
151/// The `TNode` trait. This is the main generic trait over which the style
152/// system can be implemented.
153pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
154 /// The concrete `TElement` type.
155 type ConcreteElement: TElement<ConcreteNode = Self>;
156
157 /// The concrete `TDocument` type.
158 type ConcreteDocument: TDocument<ConcreteNode = Self>;
159
160 /// The concrete `TShadowRoot` type.
161 type ConcreteShadowRoot: TShadowRoot<ConcreteNode = Self>;
162
163 /// Get this node's parent node.
164 fn parent_node(&self) -> Option<Self>;
165
166 /// Get this node's first child.
167 fn first_child(&self) -> Option<Self>;
168
169 /// Get this node's last child.
170 fn last_child(&self) -> Option<Self>;
171
172 /// Get this node's previous sibling.
173 fn prev_sibling(&self) -> Option<Self>;
174
175 /// Get this node's next sibling.
176 fn next_sibling(&self) -> Option<Self>;
177
178 /// Get the owner document of this node.
179 fn owner_doc(&self) -> Self::ConcreteDocument;
180
181 /// Iterate over the DOM children of a node.
182 #[inline(always)]
183 fn dom_children(&self) -> DomChildren<Self> {
184 DomChildren(self.first_child())
185 }
186
187 /// Returns whether the node is attached to a document.
188 fn is_in_document(&self) -> bool;
189
190 /// Iterate over the DOM children of a node, in preorder.
191 #[inline(always)]
192 fn dom_descendants(&self) -> DomDescendants<Self> {
193 DomDescendants {
194 previous: Some(*self),
195 scope: *self,
196 }
197 }
198
199 /// Returns the next node after this one, in a pre-order tree-traversal of
200 /// the subtree rooted at scoped_to.
201 #[inline]
202 fn next_in_preorder(&self, scoped_to: Self) -> Option<Self> {
203 if let Some(c) = self.first_child() {
204 return Some(c);
205 }
206 self.next_in_preorder_skipping_children(scoped_to)
207 }
208
209 /// Returns the next node in tree order, skipping the children of the current node.
210 ///
211 /// This is useful when we know that a subtree cannot contain matches, allowing us
212 /// to skip entire subtrees during traversal.
213 #[inline]
214 fn next_in_preorder_skipping_children(&self, scoped_to: Self) -> Option<Self> {
215 let mut current = *self;
216 loop {
217 if current == scoped_to {
218 return None;
219 }
220
221 if let Some(s) = current.next_sibling() {
222 return Some(s);
223 }
224
225 debug_assert!(
226 current.parent_node().is_some(),
227 "Not a descendant of the scope?"
228 );
229 current = current.parent_node()?;
230 }
231 }
232
233 /// Returns the depth of this node in the DOM.
234 fn depth(&self) -> usize {
235 let mut depth = 0;
236 let mut curr = *self;
237 while let Some(parent) = curr.traversal_parent() {
238 depth += 1;
239 curr = parent.as_node();
240 }
241 depth
242 }
243
244 /// Get this node's parent element from the perspective of a restyle
245 /// traversal.
246 fn traversal_parent(&self) -> Option<Self::ConcreteElement>;
247
248 /// Get this node's parent element if present.
249 fn parent_element(&self) -> Option<Self::ConcreteElement> {
250 self.parent_node().and_then(|n| n.as_element())
251 }
252
253 /// Get this node's parent element, or shadow host if it's a shadow root.
254 fn parent_element_or_host(&self) -> Option<Self::ConcreteElement> {
255 let parent = self.parent_node()?;
256 if let Some(e) = parent.as_element() {
257 return Some(e);
258 }
259 if let Some(root) = parent.as_shadow_root() {
260 return Some(root.host());
261 }
262 None
263 }
264
265 /// Converts self into an `OpaqueNode`.
266 fn opaque(&self) -> OpaqueNode;
267
268 /// A debug id, only useful, mm... for debugging.
269 fn debug_id(self) -> usize;
270
271 /// Get this node as an element, if it's one.
272 fn as_element(&self) -> Option<Self::ConcreteElement>;
273
274 /// Get this node as a document, if it's one.
275 fn as_document(&self) -> Option<Self::ConcreteDocument>;
276
277 /// Get this node as a ShadowRoot, if it's one.
278 fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot>;
279}
280
281/// Wrapper to output the subtree rather than the single node when formatting
282/// for Debug.
283pub struct ShowSubtree<N: TNode>(pub N);
284impl<N: TNode> Debug for ShowSubtree<N> {
285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 writeln!(f, "DOM Subtree:")?;
287 fmt_subtree(f, &|f, n| write!(f, "{:?}", n), self.0, 1)
288 }
289}
290
291/// Wrapper to output the subtree along with the ElementData when formatting
292/// for Debug.
293pub struct ShowSubtreeData<N: TNode>(pub N);
294impl<N: TNode> Debug for ShowSubtreeData<N> {
295 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 writeln!(f, "DOM Subtree:")?;
297 fmt_subtree(f, &|f, n| fmt_with_data(f, n), self.0, 1)
298 }
299}
300
301/// Wrapper to output the subtree along with the ElementData and primary
302/// ComputedValues when formatting for Debug. This is extremely verbose.
303#[cfg(feature = "servo")]
304pub struct ShowSubtreeDataAndPrimaryValues<N: TNode>(pub N);
305#[cfg(feature = "servo")]
306impl<N: TNode> Debug for ShowSubtreeDataAndPrimaryValues<N> {
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 writeln!(f, "DOM Subtree:")?;
309 fmt_subtree(f, &|f, n| fmt_with_data_and_primary_values(f, n), self.0, 1)
310 }
311}
312
313fn fmt_with_data<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
314 if let Some(el) = n.as_element() {
315 write!(
316 f,
317 "{:?} dd={} aodd={} data={:?}",
318 el,
319 el.has_dirty_descendants(),
320 el.has_animation_only_dirty_descendants(),
321 el.borrow_data(),
322 )
323 } else {
324 write!(f, "{:?}", n)
325 }
326}
327
328#[cfg(feature = "servo")]
329fn fmt_with_data_and_primary_values<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
330 if let Some(el) = n.as_element() {
331 let dd = el.has_dirty_descendants();
332 let aodd = el.has_animation_only_dirty_descendants();
333 let data = el.borrow_data();
334 let values = data.as_ref().and_then(|d| d.styles.get_primary());
335 write!(
336 f,
337 "{:?} dd={} aodd={} data={:?} values={:?}",
338 el, dd, aodd, &data, values
339 )
340 } else {
341 write!(f, "{:?}", n)
342 }
343}
344
345fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) -> fmt::Result
346where
347 F: Fn(&mut fmt::Formatter, N) -> fmt::Result,
348{
349 for _ in 0..indent {
350 write!(f, " ")?;
351 }
352 stringify(f, n)?;
353 if let Some(e) = n.as_element() {
354 for kid in e.traversal_children() {
355 writeln!(f)?;
356 fmt_subtree(f, stringify, kid, indent + 1)?;
357 }
358 }
359
360 Ok(())
361}
362
363/// The ShadowRoot trait.
364pub trait TShadowRoot: Sized + Copy + Clone + Debug + PartialEq {
365 /// The concrete node type.
366 type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
367
368 /// Get this ShadowRoot as a node.
369 fn as_node(&self) -> Self::ConcreteNode;
370
371 /// Get the shadow host that hosts this ShadowRoot.
372 fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
373
374 /// Get the style data for this ShadowRoot.
375 fn style_data<'a>(&self) -> Option<&'a CascadeData>
376 where
377 Self: 'a;
378
379 /// Get the list of shadow parts for this shadow root.
380 fn parts<'a>(&self) -> &[<Self::ConcreteNode as TNode>::ConcreteElement]
381 where
382 Self: 'a,
383 {
384 &[]
385 }
386
387 /// Get a list of elements with a given ID in this shadow root, sorted by
388 /// tree position.
389 ///
390 /// Can return an error to signal that this list is not available, or also
391 /// return an empty slice.
392 fn elements_with_id<'a>(
393 &self,
394 _id: &AtomIdent,
395 ) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
396 where
397 Self: 'a,
398 {
399 Err(())
400 }
401
402 /// Get the implicit scope for a stylesheet in given index.
403 fn implicit_scope_for_sheet(&self, _sheet_index: usize) -> Option<ImplicitScopeRoot> {
404 None
405 }
406}
407
408/// The element trait, the main abstraction the style crate acts over.
409pub trait TElement:
410 Eq
411 + PartialEq
412 + Debug
413 + Hash
414 + Sized
415 + Copy
416 + Clone
417 + SelectorsElement<Impl = SelectorImpl>
418 + ElementContext
419{
420 /// The concrete node type.
421 type ConcreteNode: TNode<ConcreteElement = Self>;
422
423 /// A concrete children iterator type in order to iterate over the `Node`s.
424 ///
425 /// TODO(emilio): We should eventually replace this with the `impl Trait`
426 /// syntax.
427 type TraversalChildrenIterator: Iterator<Item = Self::ConcreteNode>;
428
429 /// Get this element as a node.
430 fn as_node(&self) -> Self::ConcreteNode;
431
432 /// A debug-only check that the device's owner doc matches the actual doc
433 /// we're the root of.
434 ///
435 /// Otherwise we may set document-level state incorrectly, like the root
436 /// font-size used for rem units.
437 fn owner_doc_matches_for_testing(&self, _: &Device) -> bool {
438 true
439 }
440
441 /// Whether this element should match user and content rules.
442 ///
443 /// We use this for Native Anonymous Content in Gecko.
444 fn matches_user_and_content_rules(&self) -> bool {
445 true
446 }
447
448 /// Get this node's parent element from the perspective of a restyle
449 /// traversal.
450 fn traversal_parent(&self) -> Option<Self> {
451 self.as_node().traversal_parent()
452 }
453
454 /// Get this node's children from the perspective of a restyle traversal.
455 fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator>;
456
457 /// Returns the parent element we should inherit from.
458 ///
459 /// This is pretty much always the parent element itself, except in the case
460 /// of Gecko's Native Anonymous Content, which uses the traversal parent
461 /// (i.e. the flattened tree parent) and which also may need to find the
462 /// closest non-NAC ancestor.
463 fn inheritance_parent(&self) -> Option<Self> {
464 self.parent_element()
465 }
466
467 /// Execute `f` for each anonymous content child (apart from ::before and
468 /// ::after) whose originating element is `self`.
469 fn each_anonymous_content_child<F>(&self, _f: F)
470 where
471 F: FnMut(Self),
472 {
473 }
474
475 /// Return whether this element is an element in the HTML namespace.
476 fn is_html_element(&self) -> bool;
477
478 /// Return whether this element is an element in the MathML namespace.
479 fn is_mathml_element(&self) -> bool;
480
481 /// Return whether this element is an element in the SVG namespace.
482 fn is_svg_element(&self) -> bool;
483
484 /// Return whether this element is an element in the XUL namespace.
485 fn is_xul_element(&self) -> bool {
486 false
487 }
488
489 /// Return whether this element is an HTML <video> or <audio> element.
490 fn is_html_media_element(&self) -> bool {
491 false
492 }
493
494 /// Return the list of slotted nodes of this node.
495 fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
496 &[]
497 }
498
499 /// Get this element's style attribute.
500 fn style_attribute(&self) -> Option<ArcBorrow<'_, Locked<PropertyDeclarationBlock>>>;
501
502 /// Get this element's SMIL override declarations.
503 fn smil_override(&self) -> Option<ArcBorrow<'_, Locked<PropertyDeclarationBlock>>> {
504 None
505 }
506
507 /// Get the combined animation and transition rules.
508 ///
509 /// FIXME(emilio): Is this really useful?
510 fn animation_declarations(&self, context: &SharedStyleContext) -> AnimationDeclarations {
511 if !self.may_have_animations() {
512 return Default::default();
513 }
514
515 AnimationDeclarations {
516 animations: self.animation_rule(context),
517 transitions: self.transition_rule(context),
518 }
519 }
520
521 /// Get this element's animation rule.
522 fn animation_rule(
523 &self,
524 _: &SharedStyleContext,
525 ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
526
527 /// Get this element's transition rule.
528 fn transition_rule(
529 &self,
530 context: &SharedStyleContext,
531 ) -> Option<Arc<Locked<PropertyDeclarationBlock>>>;
532
533 /// Get this element's state, for non-tree-structural pseudos.
534 fn state(&self) -> ElementState;
535
536 /// Returns whether this element has a `part` attribute.
537 fn has_part_attr(&self) -> bool;
538
539 /// Returns whether this element exports any part from its shadow tree.
540 fn exports_any_part(&self) -> bool;
541
542 /// The ID for this element.
543 fn id(&self) -> Option<&WeakAtom>;
544
545 /// Internal iterator for the classes of this element.
546 fn each_class<F>(&self, callback: F)
547 where
548 F: FnMut(&AtomIdent);
549
550 /// Internal iterator for the classes of this element.
551 fn each_custom_state<F>(&self, callback: F)
552 where
553 F: FnMut(&AtomIdent);
554
555 /// Internal iterator for the part names of this element.
556 fn each_part<F>(&self, _callback: F)
557 where
558 F: FnMut(&AtomIdent),
559 {
560 }
561
562 /// Internal iterator for the attribute names of this element.
563 fn each_attr_name<F>(&self, callback: F)
564 where
565 F: FnMut(&LocalName);
566
567 /// Internal iterator for the part names that this element exports for a
568 /// given part name.
569 fn each_exported_part<F>(&self, _name: &AtomIdent, _callback: F)
570 where
571 F: FnMut(&AtomIdent),
572 {
573 }
574
575 /// Whether a given element may generate a pseudo-element.
576 ///
577 /// This is useful to avoid computing, for example, pseudo styles for
578 /// `::-first-line` or `::-first-letter`, when we know it won't affect us.
579 ///
580 /// TODO(emilio, bz): actually implement the logic for it.
581 fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
582 // ::before/::after are always supported for now, though we could try to
583 // optimize out leaf elements.
584
585 // ::first-letter and ::first-line are only supported for block-inside
586 // things, and only in Gecko, not Servo. Unfortunately, Gecko has
587 // block-inside things that might have any computed display value due to
588 // things like fieldsets, legends, etc. Need to figure out how this
589 // should work.
590 debug_assert!(
591 pseudo.is_eager(),
592 "Someone called may_generate_pseudo with a non-eager pseudo."
593 );
594 true
595 }
596
597 /// Returns true if this element may have a descendant needing style processing.
598 ///
599 /// Note that we cannot guarantee the existence of such an element, because
600 /// it may have been removed from the DOM between marking it for restyle and
601 /// the actual restyle traversal.
602 fn has_dirty_descendants(&self) -> bool;
603
604 /// Returns whether state or attributes that may change style have changed
605 /// on the element, and thus whether the element has been snapshotted to do
606 /// restyle hint computation.
607 fn has_snapshot(&self) -> bool;
608
609 /// Returns whether the current snapshot if present has been handled.
610 fn handled_snapshot(&self) -> bool;
611
612 /// Flags this element as having handled already its snapshot.
613 unsafe fn set_handled_snapshot(&self);
614
615 /// Returns whether the element's styles are up-to-date after traversal
616 /// (i.e. in post traversal).
617 fn has_current_styles(&self, data: &ElementData) -> bool {
618 if self.has_snapshot() && !self.handled_snapshot() {
619 return false;
620 }
621
622 data.has_styles() &&
623 // TODO(hiro): When an animating element moved into subtree of
624 // contenteditable element, there remains animation restyle hints in
625 // post traversal. It's generally harmless since the hints will be
626 // processed in a next styling but ideally it should be processed soon.
627 //
628 // Without this, we get failures in:
629 // layout/style/crashtests/1383319.html
630 // layout/style/crashtests/1383001.html
631 //
632 // https://bugzilla.mozilla.org/show_bug.cgi?id=1389675 tracks fixing
633 // this.
634 !data.hint.has_non_animation_invalidations()
635 }
636
637 /// Flag that this element has a descendant for style processing.
638 ///
639 /// Only safe to call with exclusive access to the element.
640 unsafe fn set_dirty_descendants(&self);
641
642 /// Flag that this element has no descendant for style processing.
643 ///
644 /// Only safe to call with exclusive access to the element.
645 unsafe fn unset_dirty_descendants(&self);
646
647 /// Similar to the dirty_descendants but for representing a descendant of
648 /// the element needs to be updated in animation-only traversal.
649 fn has_animation_only_dirty_descendants(&self) -> bool {
650 false
651 }
652
653 /// Flag that this element has a descendant for animation-only restyle
654 /// processing.
655 ///
656 /// Only safe to call with exclusive access to the element.
657 unsafe fn set_animation_only_dirty_descendants(&self) {}
658
659 /// Flag that this element has no descendant for animation-only restyle processing.
660 ///
661 /// Only safe to call with exclusive access to the element.
662 unsafe fn unset_animation_only_dirty_descendants(&self) {}
663
664 /// Clear all bits related describing the dirtiness of descendants.
665 ///
666 /// In Gecko, this corresponds to the regular dirty descendants bit, the
667 /// animation-only dirty descendants bit, and the lazy frame construction
668 /// descendants bit.
669 unsafe fn clear_descendant_bits(&self) {
670 unsafe {
671 self.unset_dirty_descendants();
672 }
673 }
674
675 /// Returns true if this element is a visited link.
676 ///
677 /// Servo doesn't support visited styles yet.
678 fn is_visited_link(&self) -> bool {
679 false
680 }
681
682 /// Returns the pseudo-element implemented by this element, if any.
683 ///
684 /// Gecko traverses pseudo-elements during the style traversal, and we need
685 /// to know this so we can properly grab the pseudo-element style from the
686 /// parent element.
687 ///
688 /// Note that we still need to compute the pseudo-elements before-hand,
689 /// given otherwise we don't know if we need to create an element or not.
690 fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
691 None
692 }
693
694 /// Atomically stores the number of children of this node that we will
695 /// need to process during bottom-up traversal.
696 fn store_children_to_process(&self, n: isize);
697
698 /// Atomically notes that a child has been processed during bottom-up
699 /// traversal. Returns the number of children left to process.
700 fn did_process_child(&self) -> isize;
701
702 /// Gets a reference to the ElementData container, or creates one.
703 ///
704 /// Unsafe because it can race to allocate and leak if not used with
705 /// exclusive access to the element.
706 unsafe fn ensure_data(&self) -> ElementDataMut<'_>;
707
708 /// Clears the element data reference, if any.
709 ///
710 /// Unsafe following the same reasoning as ensure_data.
711 unsafe fn clear_data(&self);
712
713 /// Whether there is an ElementData container.
714 fn has_data(&self) -> bool;
715
716 /// Immutably borrows the ElementData.
717 fn borrow_data(&self) -> Option<ElementDataRef<'_>>;
718
719 /// Mutably borrows the ElementData.
720 fn mutate_data(&self) -> Option<ElementDataMut<'_>>;
721
722 /// Whether we should skip any root- or item-based display property
723 /// blockification on this element. (This function exists so that Gecko
724 /// native anonymous content can opt out of this style fixup.)
725 fn skip_item_display_fixup(&self) -> bool;
726
727 /// In Gecko, element has a flag that represents the element may have
728 /// any type of animations or not to bail out animation stuff early.
729 /// Whereas Servo doesn't have such flag.
730 fn may_have_animations(&self) -> bool;
731
732 /// Creates a task to update various animation state on a given (pseudo-)element.
733 #[cfg(feature = "gecko")]
734 fn update_animations(
735 &self,
736 before_change_style: Option<Arc<ComputedValues>>,
737 tasks: UpdateAnimationsTasks,
738 );
739
740 /// Returns true if the element has relevant animations. Relevant
741 /// animations are those animations that are affecting the element's style
742 /// or are scheduled to do so in the future.
743 fn has_animations(&self, context: &SharedStyleContext) -> bool;
744
745 /// Returns true if the element has a CSS animation. The `context` and `pseudo_element`
746 /// arguments are only used by Servo, since it stores animations globally and pseudo-elements
747 /// are not in the DOM.
748 fn has_css_animations(
749 &self,
750 context: &SharedStyleContext,
751 pseudo_element: Option<PseudoElement>,
752 ) -> bool;
753
754 /// Returns true if the element has a CSS transition (including running transitions and
755 /// completed transitions). The `context` and `pseudo_element` arguments are only used
756 /// by Servo, since it stores animations globally and pseudo-elements are not in the DOM.
757 fn has_css_transitions(
758 &self,
759 context: &SharedStyleContext,
760 pseudo_element: Option<PseudoElement>,
761 ) -> bool;
762
763 /// Returns true if the element has animation restyle hints.
764 fn has_animation_restyle_hints(&self) -> bool {
765 let data = match self.borrow_data() {
766 Some(d) => d,
767 None => return false,
768 };
769 data.hint.has_animation_hint()
770 }
771
772 /// Called when a highlight pseudo-element (::selection, ::highlight,
773 /// ::target-text) style is invalidated. These pseudos need explicit repaint
774 /// triggering since their styles are resolved lazily during painting.
775 fn note_highlight_pseudo_style_invalidated(&self) {}
776
777 /// The shadow root this element is a host of.
778 fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
779
780 /// The shadow root which roots the subtree this element is contained in.
781 fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
782
783 /// If this element is not a pseudo-element, return self. Otherwise,
784 /// return the ultimate originating element [1]. This is the element
785 /// used to look up rules in the selector maps.
786 /// [1]: https://drafts.csswg.org/selectors-4/#ultimate-originating-element
787 fn ultimate_originating_element(&self) -> Self {
788 let mut cur = *self;
789 while cur.is_pseudo_element() {
790 cur = cur
791 .pseudo_element_originating_element()
792 .expect("Trying to collect rules for a detached pseudo-element")
793 }
794 cur
795 }
796
797 /// Executes the callback for each applicable style rule data which isn't
798 /// the main document's data (which stores UA / author rules).
799 ///
800 /// The element passed to the callback is the containing shadow host for the
801 /// data if it comes from Shadow DOM.
802 ///
803 /// Returns whether normal document author rules should apply.
804 ///
805 /// TODO(emilio): We could separate the invalidation data for elements
806 /// matching in other scopes to avoid over-invalidation.
807 fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
808 where
809 Self: 'a,
810 F: FnMut(&'a CascadeData, Self),
811 {
812 use crate::rule_collector::containing_shadow_ignoring_svg_use;
813
814 let target = self.ultimate_originating_element();
815 let matches_user_and_content_rules = target.matches_user_and_content_rules();
816 let mut doc_rules_apply = matches_user_and_content_rules;
817
818 // Use the same rules to look for the containing host as we do for rule
819 // collection.
820 if let Some(shadow) = containing_shadow_ignoring_svg_use(target) {
821 doc_rules_apply = false;
822 if let Some(data) = shadow.style_data() {
823 f(data, shadow.host());
824 }
825 }
826
827 if let Some(shadow) = target.shadow_root()
828 && let Some(data) = shadow.style_data()
829 {
830 f(data, shadow.host());
831 }
832
833 let mut current = target.assigned_slot();
834 while let Some(slot) = current {
835 // Slots can only have assigned nodes when in a shadow tree.
836 let shadow = slot.containing_shadow().unwrap();
837 if let Some(data) = shadow.style_data()
838 && data.any_slotted_rule()
839 {
840 f(data, shadow.host());
841 }
842 current = slot.assigned_slot();
843 }
844
845 if target.has_part_attr()
846 && let Some(mut inner_shadow) = target.containing_shadow()
847 {
848 loop {
849 let inner_shadow_host = inner_shadow.host();
850 match inner_shadow_host.containing_shadow() {
851 Some(shadow) => {
852 if let Some(data) = shadow.style_data()
853 && data.any_part_rule()
854 {
855 f(data, shadow.host())
856 }
857 // TODO: Could be more granular.
858 if !inner_shadow_host.exports_any_part() {
859 break;
860 }
861 inner_shadow = shadow;
862 },
863 None => {
864 // TODO(emilio): Should probably distinguish with
865 // MatchesDocumentRules::{No,Yes,IfPart} or something so that we could
866 // skip some work.
867 doc_rules_apply = matches_user_and_content_rules;
868 break;
869 },
870 }
871 }
872 }
873
874 doc_rules_apply
875 }
876
877 /// Returns true if one of the transitions needs to be updated on this element. We check all
878 /// the transition properties to make sure that updating transitions is necessary.
879 /// This method should only be called if might_needs_transitions_update returns true when
880 /// passed the same parameters.
881 #[cfg(feature = "gecko")]
882 fn needs_transitions_update(
883 &self,
884 before_change_style: &ComputedValues,
885 after_change_style: &ComputedValues,
886 ) -> bool;
887
888 /// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
889 /// the `lang=""` attribute) on this element.
890 fn lang_attr(&self) -> Option<AttrValue>;
891
892 /// Returns whether this element's language matches the language tag
893 /// `value`. If `override_lang` is not `None`, it specifies the value
894 /// of the `xml:lang=""` or `lang=""` attribute to use in place of
895 /// looking at the element and its ancestors. (This argument is used
896 /// to implement matching of `:lang()` against snapshots.)
897 fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool;
898
899 /// Returns whether this element is the main body element of the HTML
900 /// document it is on.
901 fn is_html_document_body_element(&self) -> bool;
902
903 /// Generate the proper applicable declarations due to presentational hints,
904 /// and insert them into `hints`.
905 fn synthesize_presentational_hints_for_legacy_attributes<V>(
906 &self,
907 visited_handling: VisitedHandlingMode,
908 hints: &mut V,
909 ) where
910 V: Push<ApplicableDeclarationBlock>;
911
912 /// Generate the proper applicable declarations due to view transition dynamic rules, and
913 /// insert them into `rules`.
914 /// https://drafts.csswg.org/css-view-transitions-1/#document-dynamic-view-transition-style-sheet
915 fn synthesize_view_transition_dynamic_rules<V>(&self, _rules: &mut V)
916 where
917 V: Push<ApplicableDeclarationBlock>,
918 {
919 }
920
921 /// Returns element's local name.
922 fn local_name(&self) -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedLocalName;
923
924 /// Returns element's namespace.
925 fn namespace(&self)
926 -> &<SelectorImpl as selectors::parser::SelectorImpl>::BorrowedNamespaceUrl;
927
928 /// Returns the size of the element to be used in container size queries.
929 /// This will usually be the size of the content area of the primary box,
930 /// but can be None if there is no box or if some axis lacks size containment.
931 fn query_container_size(
932 &self,
933 display: &Display,
934 ) -> euclid::default::Size2D<Option<app_units::Au>>;
935
936 /// Returns true if the element has all of specified selector flags.
937 fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
938
939 /// Returns the search direction for relative selector invalidation, if it is on the search path.
940 fn relative_selector_search_direction(&self) -> ElementSelectorFlags;
941
942 /// Returns the implicit scope root for given sheet index and host.
943 fn implicit_scope_for_sheet_in_shadow_root(
944 _opaque_host: OpaqueElement,
945 _sheet_index: usize,
946 ) -> Option<ImplicitScopeRoot> {
947 None
948 }
949
950 /// Compute the damage incurred by the change from the `_old` to `_new`.
951 fn compute_layout_damage(_old: &ComputedValues, _new: &ComputedValues) -> RestyleDamage {
952 Default::default()
953 }
954
955 /// Return the value of the given custom attribute if it exists.
956 fn get_attr(&self, attr: &LocalName, namespace: &Namespace) -> Option<String>;
957
958 /// Traverse the siblings of the element, returning the element's sibling-index()
959 /// and sibling-count(). Also populates `caches` with the sibling-index() and
960 /// sibling-count() values for all siblings of this element.
961 fn get_tree_counting_result(&self, caches: &mut TreeCountingCaches) -> TreeCountingResult {
962 let Some(parent) = self.as_node().parent_node() else {
963 return TreeCountingResult::default();
964 };
965
966 let mut curr = parent.first_child();
967 let mut index = 0u32;
968 let mut count = 0u32;
969 while let Some(node) = curr {
970 if let Some(element) = node.as_element() {
971 count += 1;
972 if *self == element {
973 index = count;
974 }
975 caches.sibling_index.insert(element.opaque(), count);
976 }
977 curr = node.next_sibling();
978 }
979 caches.sibling_count.insert(parent.opaque(), count);
980
981 TreeCountingResult::new(index, count)
982 }
983}
984
985/// Provides element-level context needed during style computation.
986pub trait ElementContext {
987 /// Opaque handle to the element.
988 fn opaque_element(&self) -> Option<OpaqueElement>;
989
990 /// Opaque handle to the element's parent node.
991 fn opaque_parent(&self) -> Option<OpaqueNode>;
992
993 /// Return the value of the given custom attribute if it exists.
994 fn get_attr(&self, attr: &LocalName, namespace: &Namespace) -> Option<String>;
995
996 /// Traverse the siblings of the element, returning the element's sibling-index()
997 /// and sibling-count(). Also populates `caches` with the sibling-index() and
998 /// sibling-count() values for all siblings of this element.
999 fn get_tree_counting_result(&self, caches: &mut TreeCountingCaches) -> TreeCountingResult;
1000}
1001
1002impl<T: TElement> ElementContext for T {
1003 fn opaque_element(&self) -> Option<OpaqueElement> {
1004 Some(self.opaque())
1005 }
1006
1007 fn opaque_parent(&self) -> Option<OpaqueNode> {
1008 self.as_node().parent_node().map(|n| n.opaque())
1009 }
1010
1011 fn get_attr(&self, attr: &LocalName, namespace: &Namespace) -> Option<String> {
1012 TElement::get_attr(self, attr, namespace)
1013 }
1014
1015 fn get_tree_counting_result(&self, caches: &mut TreeCountingCaches) -> TreeCountingResult {
1016 TElement::get_tree_counting_result(self, caches)
1017 }
1018}
1019
1020/// A set of the attributes used to compute a style that uses `attr()`
1021pub type AttributeReferences = Option<Box<PrecomputedHashMap<LocalName, SmallVec<[Namespace; 1]>>>>;
1022
1023/// A data structure to keep track of the names queried from an element.
1024pub struct AttributeTracker<'a> {
1025 /// The element that queries for attributes.
1026 pub context: &'a dyn ElementContext,
1027 /// The set of attributes we have queried.
1028 pub references: AttributeReferences,
1029}
1030
1031impl<'a> AttributeTracker<'a> {
1032 /// Construct a new attribute tracker trivially.
1033 pub fn new(context: &'a dyn ElementContext) -> Self {
1034 Self {
1035 context,
1036 references: None,
1037 }
1038 }
1039
1040 /// Construct a new dummy attribute tracker
1041 pub fn new_dummy() -> Self {
1042 Self {
1043 context: &DummyElementContext {},
1044 references: None,
1045 }
1046 }
1047
1048 /// Extract the queried references and consume self
1049 pub fn finalize(self) -> AttributeReferences {
1050 self.references
1051 }
1052
1053 /// Query the value and save the name of the attribtue.
1054 pub fn query(&mut self, name: &LocalName, namespace: &Namespace) -> Option<String> {
1055 // We need to save namespaces in case we are thinking of sharing this element's
1056 // style with another.
1057 // i.e if elment a has ns1::attr="blue"
1058 // and element b has ns2::attr="blue"
1059 // a and b can only share style if ns1 and ns2 resolve to the same namespace.
1060 self.references
1061 .get_or_insert_default()
1062 .entry_ref(name)
1063 .or_default()
1064 .push(namespace.clone());
1065 self.context.get_attr(name, namespace)
1066 }
1067}
1068
1069/// A dummy ElementContext that returns default values to any query.
1070#[derive(Clone, Debug, PartialEq)]
1071pub struct DummyElementContext;
1072
1073impl ElementContext for DummyElementContext {
1074 fn get_attr(&self, _attr: &LocalName, _namespace: &Namespace) -> Option<String> {
1075 None
1076 }
1077
1078 fn opaque_element(&self) -> Option<OpaqueElement> {
1079 None
1080 }
1081
1082 fn opaque_parent(&self) -> Option<OpaqueNode> {
1083 None
1084 }
1085
1086 fn get_tree_counting_result(&self, _: &mut TreeCountingCaches) -> TreeCountingResult {
1087 TreeCountingResult::default()
1088 }
1089}
1090
1091/// TNode and TElement aren't Send because we want to be careful and explicit
1092/// about our parallel traversal. However, there are certain situations
1093/// (including but not limited to the traversal) where we need to send DOM
1094/// objects to other threads.
1095///
1096/// That's the reason why `SendNode` exists.
1097#[derive(Clone, Debug, PartialEq)]
1098pub struct SendNode<N: TNode>(N);
1099unsafe impl<N: TNode> Send for SendNode<N> {}
1100impl<N: TNode> SendNode<N> {
1101 /// Unsafely construct a SendNode.
1102 pub unsafe fn new(node: N) -> Self {
1103 SendNode(node)
1104 }
1105}
1106impl<N: TNode> Deref for SendNode<N> {
1107 type Target = N;
1108 fn deref(&self) -> &N {
1109 &self.0
1110 }
1111}
1112
1113/// Same reason as for the existence of SendNode, SendElement does the proper
1114/// things for a given `TElement`.
1115#[derive(Debug, Eq, Hash, PartialEq)]
1116pub struct SendElement<E: TElement>(E);
1117unsafe impl<E: TElement> Send for SendElement<E> {}
1118impl<E: TElement> SendElement<E> {
1119 /// Unsafely construct a SendElement.
1120 pub unsafe fn new(el: E) -> Self {
1121 SendElement(el)
1122 }
1123}
1124impl<E: TElement> Deref for SendElement<E> {
1125 type Target = E;
1126 fn deref(&self) -> &E {
1127 &self.0
1128 }
1129}