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