Source code

Revision control

Other Tools

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