2015-12-30 07:34:14 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2016-06-28 01:14:55 +03:00
|
|
|
//! Types and traits used to access the DOM from style calculation.
|
|
|
|
|
2015-12-30 07:34:14 +03:00
|
|
|
#![allow(unsafe_code)]
|
2016-12-31 14:19:02 +03:00
|
|
|
#![deny(missing_docs)]
|
2015-12-30 07:34:14 +03:00
|
|
|
|
2018-04-11 04:00:11 +03:00
|
|
|
use {Atom, LocalName, Namespace, WeakAtom};
|
2017-06-12 22:41:39 +03:00
|
|
|
use applicable_declarations::ApplicableDeclarationBlock;
|
2016-11-25 20:00:44 +03:00
|
|
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
2018-04-11 04:00:11 +03:00
|
|
|
#[cfg(feature = "gecko")]
|
|
|
|
use context::PostAnimationTasks;
|
|
|
|
#[cfg(feature = "gecko")]
|
|
|
|
use context::UpdateAnimationsTasks;
|
2016-12-10 04:01:05 +03:00
|
|
|
use data::ElementData;
|
2016-02-03 04:34:11 +03:00
|
|
|
use element_state::ElementState;
|
2017-04-09 14:15:51 +03:00
|
|
|
use font_metrics::FontMetricsProvider;
|
2017-06-22 14:17:04 +03:00
|
|
|
use media_queries::Device;
|
2017-07-18 19:23:03 +03:00
|
|
|
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
2018-09-03 01:54:12 +03:00
|
|
|
use selector_parser::{AttrValue, Lang, PseudoElement, SelectorImpl};
|
2017-10-16 15:32:40 +03:00
|
|
|
use selectors::Element as SelectorsElement;
|
2017-10-26 15:51:21 +03:00
|
|
|
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
|
2017-06-21 19:28:43 +03:00
|
|
|
use selectors::sink::Push;
|
2017-07-19 16:03:17 +03:00
|
|
|
use servo_arc::{Arc, ArcBorrow};
|
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio
<!-- Please describe your changes on the following line: -->
Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1311469
* https://bugzilla.mozilla.org/show_bug.cgi?id=1335941
* https://bugzilla.mozilla.org/show_bug.cgi?id=1339703
This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once.
In Stylo, there is one such lock per process (in a `lazy_static`), used for everything.
I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock.
This was previously #15998, closed accidentally.
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Source-Repo: https://github.com/servo/servo
Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
|
|
|
use shared_lock::Locked;
|
2016-12-13 06:13:03 +03:00
|
|
|
use std::fmt;
|
2016-08-11 05:02:30 +03:00
|
|
|
use std::fmt::Debug;
|
2017-04-13 16:56:03 +03:00
|
|
|
use std::hash::Hash;
|
2016-12-22 23:02:38 +03:00
|
|
|
use std::ops::Deref;
|
2018-02-12 14:03:30 +03:00
|
|
|
use stylist::CascadeData;
|
2017-10-31 02:25:45 +03:00
|
|
|
use traversal_flags::TraversalFlags;
|
2015-12-30 07:34:14 +03:00
|
|
|
|
|
|
|
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
|
|
|
|
/// back into a non-opaque representation. The only safe operation that can be
|
|
|
|
/// performed on this node is to compare it to another opaque handle or to another
|
|
|
|
/// OpaqueNode.
|
|
|
|
///
|
|
|
|
/// Layout and Graphics use this to safely represent nodes for comparison purposes.
|
|
|
|
/// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
|
|
|
|
/// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
|
|
|
|
/// locality reasons. Using `OpaqueNode` enforces this invariant.
|
2017-08-24 01:18:31 +03:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
2018-09-09 17:24:45 +03:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "servo",
|
|
|
|
derive(MallocSizeOf, Deserialize, Serialize)
|
|
|
|
)]
|
2015-12-30 07:34:14 +03:00
|
|
|
pub struct OpaqueNode(pub usize);
|
|
|
|
|
|
|
|
impl OpaqueNode {
|
|
|
|
/// Returns the address of this node, for debugging purposes.
|
|
|
|
#[inline]
|
|
|
|
pub fn id(&self) -> usize {
|
2016-03-28 01:42:31 +03:00
|
|
|
self.0
|
2015-12-30 07:34:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 03:59:52 +03:00
|
|
|
/// Simple trait to provide basic information about the type of an element.
|
|
|
|
///
|
|
|
|
/// We avoid exposing the full type id, since computing it in the general case
|
|
|
|
/// would be difficult for Gecko nodes.
|
|
|
|
pub trait NodeInfo {
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Whether this node is an element.
|
2016-09-22 03:59:52 +03:00
|
|
|
fn is_element(&self) -> bool;
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Whether this node is a text node.
|
2016-09-22 03:59:52 +03:00
|
|
|
fn is_text_node(&self) -> bool;
|
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// A node iterator that only returns node that don't need layout.
|
2016-09-22 03:59:52 +03:00
|
|
|
pub struct LayoutIterator<T>(pub T);
|
2016-12-31 14:19:02 +03:00
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
impl<T, N> Iterator for LayoutIterator<T>
|
|
|
|
where
|
|
|
|
T: Iterator<Item = N>,
|
|
|
|
N: NodeInfo,
|
2016-12-31 14:19:02 +03:00
|
|
|
{
|
2017-10-17 13:18:29 +03:00
|
|
|
type Item = N;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<N> {
|
2016-09-22 03:59:52 +03:00
|
|
|
loop {
|
2017-12-09 19:50:55 +03:00
|
|
|
let n = self.0.next()?;
|
|
|
|
// Filter out nodes that layout should ignore.
|
|
|
|
if n.is_text_node() || n.is_element() {
|
2018-04-11 04:00:11 +03:00
|
|
|
return Some(n);
|
2017-10-17 13:18:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over the DOM children of a node.
|
|
|
|
pub struct DomChildren<N>(Option<N>);
|
|
|
|
impl<N> Iterator for DomChildren<N>
|
|
|
|
where
|
2018-04-11 04:00:11 +03:00
|
|
|
N: TNode,
|
2017-10-17 13:18:29 +03:00
|
|
|
{
|
|
|
|
type Item = N;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<N> {
|
2017-12-09 19:50:55 +03:00
|
|
|
let n = self.0.take()?;
|
|
|
|
self.0 = n.next_sibling();
|
|
|
|
Some(n)
|
2016-09-22 03:59:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 16:14:35 +03:00
|
|
|
/// An iterator over the DOM descendants of a node in pre-order.
|
|
|
|
pub struct DomDescendants<N> {
|
|
|
|
previous: Option<N>,
|
|
|
|
scope: N,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N> Iterator for DomDescendants<N>
|
|
|
|
where
|
2018-04-11 04:00:11 +03:00
|
|
|
N: TNode,
|
2017-10-23 16:14:35 +03:00
|
|
|
{
|
|
|
|
type Item = N;
|
|
|
|
|
2017-11-04 13:36:17 +03:00
|
|
|
#[inline]
|
2017-10-23 16:14:35 +03:00
|
|
|
fn next(&mut self) -> Option<N> {
|
2017-12-09 19:50:55 +03:00
|
|
|
let prev = self.previous.take()?;
|
2017-10-23 16:14:35 +03:00
|
|
|
self.previous = prev.next_in_preorder(Some(self.scope));
|
|
|
|
self.previous
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 15:51:21 +03:00
|
|
|
/// The `TDocument` trait, to represent a document node.
|
2018-04-11 04:00:11 +03:00
|
|
|
pub trait TDocument: Sized + Copy + Clone {
|
2017-10-26 15:51:21 +03:00
|
|
|
/// The concrete `TNode` type.
|
|
|
|
type ConcreteNode: TNode<ConcreteDocument = Self>;
|
|
|
|
|
|
|
|
/// Get this document as a `TNode`.
|
|
|
|
fn as_node(&self) -> Self::ConcreteNode;
|
|
|
|
|
|
|
|
/// Returns whether this document is an HTML document.
|
|
|
|
fn is_html_document(&self) -> bool;
|
|
|
|
|
|
|
|
/// Returns the quirks mode of this document.
|
|
|
|
fn quirks_mode(&self) -> QuirksMode;
|
2017-11-04 13:36:17 +03:00
|
|
|
|
|
|
|
/// Get a list of elements with a given ID in this document, sorted by
|
2018-05-25 17:56:41 +03:00
|
|
|
/// tree position.
|
2017-11-04 13:36:17 +03:00
|
|
|
///
|
|
|
|
/// Can return an error to signal that this list is not available, or also
|
|
|
|
/// return an empty slice.
|
2018-05-25 17:56:41 +03:00
|
|
|
fn elements_with_id<'a>(
|
2017-11-04 13:36:17 +03:00
|
|
|
&self,
|
|
|
|
_id: &Atom,
|
2018-05-25 17:56:41 +03:00
|
|
|
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
|
|
|
|
where
|
|
|
|
Self: 'a,
|
|
|
|
{
|
2017-11-04 13:36:17 +03:00
|
|
|
Err(())
|
|
|
|
}
|
2017-10-26 15:51:21 +03:00
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// The `TNode` trait. This is the main generic trait over which the style
|
|
|
|
/// system can be implemented.
|
2018-04-11 04:00:11 +03:00
|
|
|
pub trait TNode: Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
|
2016-12-31 14:19:02 +03:00
|
|
|
/// The concrete `TElement` type.
|
2016-11-17 21:25:52 +03:00
|
|
|
type ConcreteElement: TElement<ConcreteNode = Self>;
|
2016-12-31 14:19:02 +03:00
|
|
|
|
2017-10-26 15:51:21 +03:00
|
|
|
/// The concrete `TDocument` type.
|
|
|
|
type ConcreteDocument: TDocument<ConcreteNode = Self>;
|
|
|
|
|
2018-03-04 01:53:08 +03:00
|
|
|
/// The concrete `TShadowRoot` type.
|
|
|
|
type ConcreteShadowRoot: TShadowRoot<ConcreteNode = Self>;
|
|
|
|
|
2017-06-09 13:57:36 +03:00
|
|
|
/// Get this node's parent node.
|
|
|
|
fn parent_node(&self) -> Option<Self>;
|
2015-12-30 07:34:14 +03:00
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
/// Get this node's first child.
|
|
|
|
fn first_child(&self) -> Option<Self>;
|
2015-12-30 07:34:14 +03:00
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
/// Get this node's first child.
|
|
|
|
fn last_child(&self) -> Option<Self>;
|
|
|
|
|
|
|
|
/// Get this node's previous sibling.
|
|
|
|
fn prev_sibling(&self) -> Option<Self>;
|
|
|
|
|
|
|
|
/// Get this node's next sibling.
|
|
|
|
fn next_sibling(&self) -> Option<Self>;
|
|
|
|
|
2017-10-26 15:51:21 +03:00
|
|
|
/// Get the owner document of this node.
|
|
|
|
fn owner_doc(&self) -> Self::ConcreteDocument;
|
|
|
|
|
2017-10-23 16:14:35 +03:00
|
|
|
/// Iterate over the DOM children of a node.
|
2017-10-17 13:18:29 +03:00
|
|
|
fn dom_children(&self) -> DomChildren<Self> {
|
|
|
|
DomChildren(self.first_child())
|
|
|
|
}
|
2017-06-09 13:57:36 +03:00
|
|
|
|
2017-11-04 13:36:17 +03:00
|
|
|
/// Returns whether the node is attached to a document.
|
|
|
|
fn is_in_document(&self) -> bool;
|
|
|
|
|
2017-10-23 16:14:35 +03:00
|
|
|
/// Iterate over the DOM children of a node, in preorder.
|
|
|
|
fn dom_descendants(&self) -> DomDescendants<Self> {
|
|
|
|
DomDescendants {
|
|
|
|
previous: Some(*self),
|
|
|
|
scope: *self,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the next children in pre-order, optionally scoped to a subtree
|
|
|
|
/// root.
|
2017-11-04 13:36:17 +03:00
|
|
|
#[inline]
|
2017-10-23 16:14:35 +03:00
|
|
|
fn next_in_preorder(&self, scoped_to: Option<Self>) -> Option<Self> {
|
|
|
|
if let Some(c) = self.first_child() {
|
|
|
|
return Some(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
if Some(*self) == scoped_to {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut current = *self;
|
|
|
|
loop {
|
|
|
|
if let Some(s) = current.next_sibling() {
|
|
|
|
return Some(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
let parent = current.parent_node();
|
|
|
|
if parent == scoped_to {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
current = parent.expect("Not a descendant of the scope?");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-09 13:57:36 +03:00
|
|
|
/// Get this node's parent element from the perspective of a restyle
|
|
|
|
/// traversal.
|
|
|
|
fn traversal_parent(&self) -> Option<Self::ConcreteElement>;
|
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
/// Get this node's parent element if present.
|
|
|
|
fn parent_element(&self) -> Option<Self::ConcreteElement> {
|
|
|
|
self.parent_node().and_then(|n| n.as_element())
|
|
|
|
}
|
2017-06-09 13:57:36 +03:00
|
|
|
|
|
|
|
/// Converts self into an `OpaqueNode`.
|
|
|
|
fn opaque(&self) -> OpaqueNode;
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// A debug id, only useful, mm... for debugging.
|
2015-12-30 07:34:14 +03:00
|
|
|
fn debug_id(self) -> usize;
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Get this node as an element, if it's one.
|
2015-12-30 07:34:14 +03:00
|
|
|
fn as_element(&self) -> Option<Self::ConcreteElement>;
|
|
|
|
|
2017-10-26 15:51:21 +03:00
|
|
|
/// Get this node as a document, if it's one.
|
|
|
|
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
2018-03-04 01:53:08 +03:00
|
|
|
|
|
|
|
/// Get this node as a ShadowRoot, if it's one.
|
|
|
|
fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot>;
|
2016-10-30 01:14:10 +03:00
|
|
|
}
|
|
|
|
|
2016-12-13 06:13:03 +03:00
|
|
|
/// Wrapper to output the subtree rather than the single node when formatting
|
|
|
|
/// for Debug.
|
|
|
|
pub struct ShowSubtree<N: TNode>(pub N);
|
|
|
|
impl<N: TNode> Debug for ShowSubtree<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2017-06-18 15:55:11 +03:00
|
|
|
writeln!(f, "DOM Subtree:")?;
|
2016-12-13 06:13:03 +03:00
|
|
|
fmt_subtree(f, &|f, n| write!(f, "{:?}", n), self.0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper to output the subtree along with the ElementData when formatting
|
|
|
|
/// for Debug.
|
|
|
|
pub struct ShowSubtreeData<N: TNode>(pub N);
|
|
|
|
impl<N: TNode> Debug for ShowSubtreeData<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2017-06-18 15:55:11 +03:00
|
|
|
writeln!(f, "DOM Subtree:")?;
|
2016-12-13 06:13:03 +03:00
|
|
|
fmt_subtree(f, &|f, n| fmt_with_data(f, n), self.0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper to output the subtree along with the ElementData and primary
|
|
|
|
/// ComputedValues when formatting for Debug. This is extremely verbose.
|
2017-10-31 22:09:44 +03:00
|
|
|
#[cfg(feature = "servo")]
|
2016-12-13 06:13:03 +03:00
|
|
|
pub struct ShowSubtreeDataAndPrimaryValues<N: TNode>(pub N);
|
2017-10-31 22:09:44 +03:00
|
|
|
#[cfg(feature = "servo")]
|
2016-12-13 06:13:03 +03:00
|
|
|
impl<N: TNode> Debug for ShowSubtreeDataAndPrimaryValues<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2017-06-18 15:55:11 +03:00
|
|
|
writeln!(f, "DOM Subtree:")?;
|
2016-12-13 06:13:03 +03:00
|
|
|
fmt_subtree(f, &|f, n| fmt_with_data_and_primary_values(f, n), self.0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt_with_data<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
|
|
|
|
if let Some(el) = n.as_element() {
|
2017-08-27 02:13:40 +03:00
|
|
|
write!(
|
2018-04-11 04:00:11 +03:00
|
|
|
f,
|
|
|
|
"{:?} dd={} aodd={} data={:?}",
|
2017-08-27 02:13:40 +03:00
|
|
|
el,
|
|
|
|
el.has_dirty_descendants(),
|
|
|
|
el.has_animation_only_dirty_descendants(),
|
|
|
|
el.borrow_data(),
|
2018-04-11 04:00:11 +03:00
|
|
|
)
|
2016-12-13 06:13:03 +03:00
|
|
|
} else {
|
|
|
|
write!(f, "{:?}", n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 22:09:44 +03:00
|
|
|
#[cfg(feature = "servo")]
|
2016-12-13 06:13:03 +03:00
|
|
|
fn fmt_with_data_and_primary_values<N: TNode>(f: &mut fmt::Formatter, n: N) -> fmt::Result {
|
|
|
|
if let Some(el) = n.as_element() {
|
|
|
|
let dd = el.has_dirty_descendants();
|
2017-08-27 02:13:40 +03:00
|
|
|
let aodd = el.has_animation_only_dirty_descendants();
|
2016-12-13 06:13:03 +03:00
|
|
|
let data = el.borrow_data();
|
2017-06-23 03:46:55 +03:00
|
|
|
let values = data.as_ref().and_then(|d| d.styles.get_primary());
|
2018-04-11 04:00:11 +03:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{:?} dd={} aodd={} data={:?} values={:?}",
|
|
|
|
el, dd, aodd, &data, values
|
|
|
|
)
|
2016-12-13 06:13:03 +03:00
|
|
|
} else {
|
|
|
|
write!(f, "{:?}", n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 04:00:11 +03:00
|
|
|
fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) -> fmt::Result
|
|
|
|
where
|
|
|
|
F: Fn(&mut fmt::Formatter, N) -> fmt::Result,
|
2016-12-13 06:13:03 +03:00
|
|
|
{
|
|
|
|
for _ in 0..indent {
|
2017-06-18 15:55:11 +03:00
|
|
|
write!(f, " ")?;
|
2016-12-13 06:13:03 +03:00
|
|
|
}
|
2017-06-18 15:55:11 +03:00
|
|
|
stringify(f, n)?;
|
2017-10-17 13:18:29 +03:00
|
|
|
if let Some(e) = n.as_element() {
|
|
|
|
for kid in e.traversal_children() {
|
|
|
|
writeln!(f, "")?;
|
|
|
|
fmt_subtree(f, stringify, kid, indent + 1)?;
|
|
|
|
}
|
2016-12-13 06:13:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-03-04 01:53:08 +03:00
|
|
|
/// The ShadowRoot trait.
|
2018-04-11 04:00:11 +03:00
|
|
|
pub trait TShadowRoot: Sized + Copy + Clone + PartialEq {
|
2018-03-04 01:53:08 +03:00
|
|
|
/// The concrete node type.
|
|
|
|
type ConcreteNode: TNode<ConcreteShadowRoot = Self>;
|
|
|
|
|
|
|
|
/// Get this ShadowRoot as a node.
|
|
|
|
fn as_node(&self) -> Self::ConcreteNode;
|
|
|
|
|
|
|
|
/// Get the shadow host that hosts this ShadowRoot.
|
|
|
|
fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
|
2018-03-07 18:06:05 +03:00
|
|
|
|
|
|
|
/// Get the style data for this ShadowRoot.
|
2018-08-30 15:00:00 +03:00
|
|
|
fn style_data<'a>(&self) -> Option<&'a CascadeData>
|
2018-03-07 18:06:05 +03:00
|
|
|
where
|
|
|
|
Self: 'a;
|
2018-05-25 17:56:41 +03:00
|
|
|
|
|
|
|
/// Get a list of elements with a given ID in this shadow root, sorted by
|
|
|
|
/// tree position.
|
|
|
|
///
|
|
|
|
/// Can return an error to signal that this list is not available, or also
|
|
|
|
/// return an empty slice.
|
|
|
|
fn elements_with_id<'a>(
|
|
|
|
&self,
|
|
|
|
_id: &Atom,
|
|
|
|
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
|
|
|
|
where
|
|
|
|
Self: 'a,
|
|
|
|
{
|
|
|
|
Err(())
|
|
|
|
}
|
2018-03-04 01:53:08 +03:00
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// The element trait, the main abstraction the style crate acts over.
|
2018-04-11 04:00:11 +03:00
|
|
|
pub trait TElement:
|
|
|
|
Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + SelectorsElement<Impl = SelectorImpl>
|
2017-10-16 15:32:40 +03:00
|
|
|
{
|
2016-12-31 14:19:02 +03:00
|
|
|
/// The concrete node type.
|
2016-11-17 21:25:52 +03:00
|
|
|
type ConcreteNode: TNode<ConcreteElement = Self>;
|
2016-10-30 01:14:10 +03:00
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
/// A concrete children iterator type in order to iterate over the `Node`s.
|
|
|
|
///
|
|
|
|
/// TODO(emilio): We should eventually replace this with the `impl Trait`
|
|
|
|
/// syntax.
|
|
|
|
type TraversalChildrenIterator: Iterator<Item = Self::ConcreteNode>;
|
|
|
|
|
2017-04-09 14:15:51 +03:00
|
|
|
/// Type of the font metrics provider
|
|
|
|
///
|
|
|
|
/// XXXManishearth It would be better to make this a type parameter on
|
|
|
|
/// ThreadLocalStyleContext and StyleContext
|
2017-07-06 05:29:01 +03:00
|
|
|
type FontMetricsProvider: FontMetricsProvider + Send;
|
2017-04-09 14:15:51 +03:00
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Get this element as a node.
|
2016-10-30 01:14:10 +03:00
|
|
|
fn as_node(&self) -> Self::ConcreteNode;
|
|
|
|
|
2017-06-22 14:17:04 +03:00
|
|
|
/// A debug-only check that the device's owner doc matches the actual doc
|
|
|
|
/// we're the root of.
|
|
|
|
///
|
|
|
|
/// Otherwise we may set document-level state incorrectly, like the root
|
|
|
|
/// font-size used for rem units.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn owner_doc_matches_for_testing(&self, _: &Device) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2017-06-22 14:17:04 +03:00
|
|
|
|
2017-10-16 15:32:40 +03:00
|
|
|
/// Whether this element should match user and author rules.
|
|
|
|
///
|
|
|
|
/// We use this for Native Anonymous Content in Gecko.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn matches_user_and_author_rules(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2017-10-16 15:32:40 +03:00
|
|
|
|
2017-04-09 09:55:09 +03:00
|
|
|
/// Returns the depth of this element in the DOM.
|
|
|
|
fn depth(&self) -> usize {
|
|
|
|
let mut depth = 0;
|
|
|
|
let mut curr = *self;
|
2017-06-09 13:57:36 +03:00
|
|
|
while let Some(parent) = curr.traversal_parent() {
|
2017-04-09 09:55:09 +03:00
|
|
|
depth += 1;
|
|
|
|
curr = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
depth
|
|
|
|
}
|
|
|
|
|
2017-06-09 13:57:36 +03:00
|
|
|
/// Get this node's parent element from the perspective of a restyle
|
|
|
|
/// traversal.
|
|
|
|
fn traversal_parent(&self) -> Option<Self> {
|
|
|
|
self.as_node().traversal_parent()
|
2016-11-25 20:00:44 +03:00
|
|
|
}
|
|
|
|
|
2017-10-17 13:18:29 +03:00
|
|
|
/// Get this node's children from the perspective of a restyle traversal.
|
|
|
|
fn traversal_children(&self) -> LayoutIterator<Self::TraversalChildrenIterator>;
|
|
|
|
|
2017-05-12 15:25:00 +03:00
|
|
|
/// Returns the parent element we should inherit from.
|
|
|
|
///
|
|
|
|
/// This is pretty much always the parent element itself, except in the case
|
2017-06-09 13:57:36 +03:00
|
|
|
/// of Gecko's Native Anonymous Content, which uses the traversal parent
|
|
|
|
/// (i.e. the flattened tree parent) and which also may need to find the
|
|
|
|
/// closest non-NAC ancestor.
|
2017-05-12 15:25:00 +03:00
|
|
|
fn inheritance_parent(&self) -> Option<Self> {
|
|
|
|
self.parent_element()
|
|
|
|
}
|
|
|
|
|
2017-06-20 14:15:57 +03:00
|
|
|
/// The ::before pseudo-element of this element, if it exists.
|
|
|
|
fn before_pseudo_element(&self) -> Option<Self> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The ::after pseudo-element of this element, if it exists.
|
|
|
|
fn after_pseudo_element(&self) -> Option<Self> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Execute `f` for each anonymous content child (apart from ::before and
|
|
|
|
/// ::after) whose originating element is `self`.
|
|
|
|
fn each_anonymous_content_child<F>(&self, _f: F)
|
|
|
|
where
|
|
|
|
F: FnMut(Self),
|
2018-04-11 04:00:11 +03:00
|
|
|
{
|
|
|
|
}
|
2017-06-20 14:15:57 +03:00
|
|
|
|
2018-01-09 16:26:28 +03:00
|
|
|
/// Return whether this element is an element in the HTML namespace.
|
|
|
|
fn is_html_element(&self) -> bool;
|
|
|
|
|
2018-04-14 19:38:29 +03:00
|
|
|
/// Return whether this element is an element in the MathML namespace.
|
|
|
|
fn is_mathml_element(&self) -> bool;
|
|
|
|
|
|
|
|
/// Return whether this element is an element in the SVG namespace.
|
|
|
|
fn is_svg_element(&self) -> bool;
|
|
|
|
|
|
|
|
/// Return whether this element is an element in the XUL namespace.
|
2018-09-09 17:24:45 +03:00
|
|
|
fn is_xul_element(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2018-04-14 19:38:29 +03:00
|
|
|
|
2018-01-09 16:26:28 +03:00
|
|
|
/// Return the list of slotted nodes of this node.
|
|
|
|
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
|
|
|
|
&[]
|
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Get this element's style attribute.
|
2017-07-18 05:44:25 +03:00
|
|
|
fn style_attribute(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>;
|
2016-10-30 01:14:10 +03:00
|
|
|
|
2017-05-31 04:07:26 +03:00
|
|
|
/// Unset the style attribute's dirty bit.
|
|
|
|
/// Servo doesn't need to manage ditry bit for style attribute.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn unset_dirty_style_attribute(&self) {}
|
2017-05-31 04:07:26 +03:00
|
|
|
|
2017-04-27 08:48:21 +03:00
|
|
|
/// Get this element's SMIL override declarations.
|
2018-02-25 01:28:20 +03:00
|
|
|
fn smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
2017-04-17 13:07:23 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2017-07-12 10:28:44 +03:00
|
|
|
/// Get the combined animation and transition rules.
|
2018-02-25 01:28:20 +03:00
|
|
|
///
|
|
|
|
/// FIXME(emilio): Is this really useful?
|
|
|
|
fn animation_rules(&self) -> AnimationRules {
|
2017-07-12 10:28:44 +03:00
|
|
|
if !self.may_have_animations() {
|
2018-04-11 04:00:11 +03:00
|
|
|
return AnimationRules(None, None);
|
2017-07-12 10:28:44 +03:00
|
|
|
}
|
|
|
|
|
2018-02-25 01:28:20 +03:00
|
|
|
AnimationRules(self.animation_rule(), self.transition_rule())
|
2017-07-12 10:28:44 +03:00
|
|
|
}
|
|
|
|
|
2017-03-17 13:09:31 +03:00
|
|
|
/// Get this element's animation rule.
|
2018-02-25 01:28:20 +03:00
|
|
|
fn animation_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
2017-03-17 13:09:31 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get this element's transition rule.
|
2018-02-25 01:28:20 +03:00
|
|
|
fn transition_rule(&self) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
2017-03-17 13:09:31 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Get this element's state, for non-tree-structural pseudos.
|
2018-02-25 01:28:20 +03:00
|
|
|
fn state(&self) -> ElementState;
|
2016-10-30 01:14:10 +03:00
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Whether this element has an attribute with a given namespace.
|
servo: Merge #14043 - Update to string-cache 0.3 (from servo:string-cache-up); r=nox
Previously, `string-cache` defined:
* An string-like `Atom` type,
* An `atom!("foo")` macro that expands to a value of that type, for a set of strings known at compile-time,
* A `struct Namespace(Atom);` type
* A `ns!(html)` macro that maps known prefixed to `Namespace` values with the corresponding namespace URL.
Adding a string to the static set required making a change to the `string-cache` crate.
With 0.3, the `Atom` type is now generic, with a type parameter that provides a set of static strings. We can have multiple such sets, defined in different crates. The `string_cache_codegen` crate, to be used in build scripts, generates code that defines such a set, a new atom type (a type alias for `Atom<_>` with the type parameter set), and an `atom!`-like macro.
The html5ever repository has a new `html5ever_atoms` crate that defines three such types: `Prefix`, `Namespace`, and `LocalName` (with respective `namespace_prefix!`, `namespace_url!`, and `local_name!` macros). It also defines the `ns!` macro like before.
This repository has a new `servo_atoms` crate in `components/atoms` that, for now, defines a single `Atom` type (and `atom!`) macro. (`servo_atoms::Atom` is defined as something like `type Atom = string_cache::Atom<ServoStaticStringSet>;`, so overall there’s now two types named `Atom`.)
In this PR, `servo_atoms::Atom` is used for everything else that was `string_cache::Atom` before. But more atom types can be defined as needed. Two reasons to do this are to auto-generate the set of static strings (I’m planning to do this for CSS property names, which is the motivation for this change), or to have the type system help us avoid mix up unrelated things (this is why we had a `Namespace` type ever before this change).
Introducing new types helped me find a bug: when creating a new attribute `dom::Element::set_style_attr`, would pass `Some(atom!("style"))` instead of `None` (now `Option<html5ever_atoms::Prefix>` instead of `Option<string_cache::Atom>`) to the `prefix` argument of `Attr::new`. I suppose the author of that code confused it with the `local_name` argument.
---
Note that Stylo is not affected by any of this. The `gecko_string_cache` module is unchanged, with a single `Atom` type. The `style` crate conditionally compiles `Prefix` and `LocalName` re-exports for that are both `gecko_string_cache::Atom` on stylo.
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Source-Repo: https://github.com/servo/servo
Source-Revision: 5b4cc9568dbd5c15e5d2fbc62719172f11566ffa
2016-11-03 19:19:44 +03:00
|
|
|
fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
|
2016-12-31 14:19:02 +03:00
|
|
|
|
2017-06-13 01:52:29 +03:00
|
|
|
/// The ID for this element.
|
2018-02-25 01:28:20 +03:00
|
|
|
fn id(&self) -> Option<&WeakAtom>;
|
2017-06-13 01:52:29 +03:00
|
|
|
|
2017-05-19 02:45:20 +03:00
|
|
|
/// Internal iterator for the classes of this element.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn each_class<F>(&self, callback: F)
|
|
|
|
where
|
|
|
|
F: FnMut(&Atom);
|
2017-05-19 02:45:20 +03:00
|
|
|
|
2017-06-01 22:13:43 +03:00
|
|
|
/// Whether a given element may generate a pseudo-element.
|
|
|
|
///
|
|
|
|
/// This is useful to avoid computing, for example, pseudo styles for
|
|
|
|
/// `::-first-line` or `::-first-letter`, when we know it won't affect us.
|
|
|
|
///
|
|
|
|
/// TODO(emilio, bz): actually implement the logic for it.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn may_generate_pseudo(&self, pseudo: &PseudoElement, _primary_style: &ComputedValues) -> bool {
|
2017-06-27 09:46:13 +03:00
|
|
|
// ::before/::after are always supported for now, though we could try to
|
|
|
|
// optimize out leaf elements.
|
|
|
|
|
|
|
|
// ::first-letter and ::first-line are only supported for block-inside
|
|
|
|
// things, and only in Gecko, not Servo. Unfortunately, Gecko has
|
|
|
|
// block-inside things that might have any computed display value due to
|
|
|
|
// things like fieldsets, legends, etc. Need to figure out how this
|
|
|
|
// should work.
|
2018-04-11 04:00:11 +03:00
|
|
|
debug_assert!(
|
|
|
|
pseudo.is_eager(),
|
|
|
|
"Someone called may_generate_pseudo with a non-eager pseudo."
|
|
|
|
);
|
2017-06-01 22:13:43 +03:00
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2016-11-25 20:00:44 +03:00
|
|
|
/// Returns true if this element may have a descendant needing style processing.
|
|
|
|
///
|
|
|
|
/// Note that we cannot guarantee the existence of such an element, because
|
|
|
|
/// it may have been removed from the DOM between marking it for restyle and
|
|
|
|
/// the actual restyle traversal.
|
2015-12-30 07:34:14 +03:00
|
|
|
fn has_dirty_descendants(&self) -> bool;
|
|
|
|
|
2017-05-10 23:08:59 +03:00
|
|
|
/// Returns whether state or attributes that may change style have changed
|
|
|
|
/// on the element, and thus whether the element has been snapshotted to do
|
|
|
|
/// restyle hint computation.
|
|
|
|
fn has_snapshot(&self) -> bool;
|
|
|
|
|
|
|
|
/// Returns whether the current snapshot if present has been handled.
|
|
|
|
fn handled_snapshot(&self) -> bool;
|
|
|
|
|
|
|
|
/// Flags this element as having handled already its snapshot.
|
|
|
|
unsafe fn set_handled_snapshot(&self);
|
|
|
|
|
2017-07-18 14:55:30 +03:00
|
|
|
/// Returns whether the element's styles are up-to-date for |traversal_flags|.
|
2017-07-24 11:09:24 +03:00
|
|
|
fn has_current_styles_for_traversal(
|
|
|
|
&self,
|
|
|
|
data: &ElementData,
|
|
|
|
traversal_flags: TraversalFlags,
|
|
|
|
) -> bool {
|
2017-07-18 14:55:30 +03:00
|
|
|
if traversal_flags.for_animation_only() {
|
|
|
|
// In animation-only restyle we never touch snapshots and don't
|
|
|
|
// care about them. But we can't assert '!self.handled_snapshot()'
|
|
|
|
// here since there are some cases that a second animation-only
|
|
|
|
// restyle which is a result of normal restyle (e.g. setting
|
|
|
|
// animation-name in normal restyle and creating a new CSS
|
|
|
|
// animation in a SequentialTask) is processed after the normal
|
|
|
|
// traversal in that we had elements that handled snapshot.
|
2018-04-11 04:00:11 +03:00
|
|
|
return data.has_styles() && !data.hint.has_animation_hint_or_recascade();
|
2017-07-18 14:55:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.has_snapshot() && !self.handled_snapshot() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-12 21:16:26 +03:00
|
|
|
data.has_styles() && !data.hint.has_non_animation_invalidations()
|
2017-08-12 05:15:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns whether the element's styles are up-to-date after traversal
|
|
|
|
/// (i.e. in post traversal).
|
|
|
|
fn has_current_styles(&self, data: &ElementData) -> bool {
|
|
|
|
if self.has_snapshot() && !self.handled_snapshot() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.has_styles() &&
|
|
|
|
// TODO(hiro): When an animating element moved into subtree of
|
|
|
|
// contenteditable element, there remains animation restyle hints in
|
|
|
|
// post traversal. It's generally harmless since the hints will be
|
|
|
|
// processed in a next styling but ideally it should be processed soon.
|
|
|
|
//
|
|
|
|
// Without this, we get failures in:
|
|
|
|
// layout/style/crashtests/1383319.html
|
|
|
|
// layout/style/crashtests/1383001.html
|
|
|
|
//
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1389675 tracks fixing
|
|
|
|
// this.
|
2017-09-12 21:16:26 +03:00
|
|
|
!data.hint.has_non_animation_invalidations()
|
2017-07-18 14:55:30 +03:00
|
|
|
}
|
|
|
|
|
2016-11-25 20:00:44 +03:00
|
|
|
/// Flag that this element has a descendant for style processing.
|
|
|
|
///
|
|
|
|
/// Only safe to call with exclusive access to the element.
|
2016-10-20 20:40:58 +03:00
|
|
|
unsafe fn set_dirty_descendants(&self);
|
2015-12-30 07:34:14 +03:00
|
|
|
|
2016-11-25 20:00:44 +03:00
|
|
|
/// Flag that this element has no descendant for style processing.
|
|
|
|
///
|
|
|
|
/// Only safe to call with exclusive access to the element.
|
|
|
|
unsafe fn unset_dirty_descendants(&self);
|
|
|
|
|
2017-03-27 07:13:44 +03:00
|
|
|
/// Similar to the dirty_descendants but for representing a descendant of
|
|
|
|
/// the element needs to be updated in animation-only traversal.
|
|
|
|
fn has_animation_only_dirty_descendants(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2017-06-01 22:13:43 +03:00
|
|
|
/// Flag that this element has a descendant for animation-only restyle
|
|
|
|
/// processing.
|
2017-03-27 07:13:44 +03:00
|
|
|
///
|
|
|
|
/// Only safe to call with exclusive access to the element.
|
2018-04-11 04:00:11 +03:00
|
|
|
unsafe fn set_animation_only_dirty_descendants(&self) {}
|
2017-03-27 07:13:44 +03:00
|
|
|
|
|
|
|
/// Flag that this element has no descendant for animation-only restyle processing.
|
|
|
|
///
|
|
|
|
/// Only safe to call with exclusive access to the element.
|
2018-04-11 04:00:11 +03:00
|
|
|
unsafe fn unset_animation_only_dirty_descendants(&self) {}
|
2017-03-27 07:13:44 +03:00
|
|
|
|
2017-08-23 06:04:34 +03:00
|
|
|
/// Clear all bits related describing the dirtiness of descendants.
|
2017-08-16 01:07:20 +03:00
|
|
|
///
|
|
|
|
/// In Gecko, this corresponds to the regular dirty descendants bit, the
|
|
|
|
/// animation-only dirty descendants bit, and the lazy frame construction
|
|
|
|
/// descendants bit.
|
2018-04-11 04:00:11 +03:00
|
|
|
unsafe fn clear_descendant_bits(&self) {
|
|
|
|
self.unset_dirty_descendants();
|
|
|
|
}
|
2017-08-16 01:07:20 +03:00
|
|
|
|
2017-08-23 06:04:34 +03:00
|
|
|
/// Clear all element flags related to dirtiness.
|
|
|
|
///
|
|
|
|
/// In Gecko, this corresponds to the regular dirty descendants bit, the
|
|
|
|
/// animation-only dirty descendants bit, the lazy frame construction bit,
|
|
|
|
/// and the lazy frame construction descendants bit.
|
2018-04-11 04:00:11 +03:00
|
|
|
unsafe fn clear_dirty_bits(&self) {
|
|
|
|
self.unset_dirty_descendants();
|
|
|
|
}
|
2017-08-23 06:04:34 +03:00
|
|
|
|
2017-07-23 14:15:39 +03:00
|
|
|
/// Returns true if this element is a visited link.
|
|
|
|
///
|
|
|
|
/// Servo doesn't support visited styles yet.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn is_visited_link(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2017-07-23 14:15:39 +03:00
|
|
|
|
2018-05-10 19:48:08 +03:00
|
|
|
/// Returns true if this element is in a native anonymous subtree.
|
|
|
|
fn is_in_native_anonymous_subtree(&self) -> bool {
|
2018-04-11 04:00:11 +03:00
|
|
|
false
|
|
|
|
}
|
2017-04-01 22:34:33 +03:00
|
|
|
|
2017-04-27 15:39:42 +03:00
|
|
|
/// Returns the pseudo-element implemented by this element, if any.
|
|
|
|
///
|
|
|
|
/// Gecko traverses pseudo-elements during the style traversal, and we need
|
|
|
|
/// to know this so we can properly grab the pseudo-element style from the
|
|
|
|
/// parent element.
|
|
|
|
///
|
|
|
|
/// Note that we still need to compute the pseudo-elements before-hand,
|
|
|
|
/// given otherwise we don't know if we need to create an element or not.
|
|
|
|
///
|
|
|
|
/// Servo doesn't have to deal with this.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
|
|
|
|
None
|
|
|
|
}
|
2017-04-27 15:39:42 +03:00
|
|
|
|
2016-10-09 09:37:42 +03:00
|
|
|
/// Atomically stores the number of children of this node that we will
|
|
|
|
/// need to process during bottom-up traversal.
|
|
|
|
fn store_children_to_process(&self, n: isize);
|
|
|
|
|
|
|
|
/// Atomically notes that a child has been processed during bottom-up
|
|
|
|
/// traversal. Returns the number of children left to process.
|
|
|
|
fn did_process_child(&self) -> isize;
|
|
|
|
|
2017-07-15 17:44:08 +03:00
|
|
|
/// Gets a reference to the ElementData container, or creates one.
|
|
|
|
///
|
|
|
|
/// Unsafe because it can race to allocate and leak if not used with
|
|
|
|
/// exclusive access to the element.
|
|
|
|
unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData>;
|
|
|
|
|
|
|
|
/// Clears the element data reference, if any.
|
|
|
|
///
|
|
|
|
/// Unsafe following the same reasoning as ensure_data.
|
|
|
|
unsafe fn clear_data(&self);
|
|
|
|
|
2016-11-01 21:05:46 +03:00
|
|
|
/// Gets a reference to the ElementData container.
|
|
|
|
fn get_data(&self) -> Option<&AtomicRefCell<ElementData>>;
|
|
|
|
|
2016-11-25 20:00:44 +03:00
|
|
|
/// Immutably borrows the ElementData.
|
|
|
|
fn borrow_data(&self) -> Option<AtomicRef<ElementData>> {
|
|
|
|
self.get_data().map(|x| x.borrow())
|
|
|
|
}
|
2016-07-28 01:56:26 +03:00
|
|
|
|
2016-11-25 20:00:44 +03:00
|
|
|
/// Mutably borrows the ElementData.
|
|
|
|
fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> {
|
|
|
|
self.get_data().map(|x| x.borrow_mut())
|
2015-12-30 07:34:14 +03:00
|
|
|
}
|
2016-12-07 07:19:21 +03:00
|
|
|
|
|
|
|
/// Whether we should skip any root- or item-based display property
|
|
|
|
/// blockification on this element. (This function exists so that Gecko
|
|
|
|
/// native anonymous content can opt out of this style fixup.)
|
servo: Merge #19842 - style: Cleanup a bit the cascade (from emilio:cascade-cleanup); r=nox,jryans
This makes an element available in StyleAdjuster, and uses it to replace some of our CascadeFlags (the ones that don't represent restrictions on what's actually cascaded, actually).
That fixes handwaviness in the handling of those flags from style reparenting,
and code duplication to handle tricky stuff like :visited.
There are a number of other changes that are worth noticing:
* skip_root_and_item_based_display_fixup is renamed to skip_item_display_fixup:
TElement::is_root() already implies being the document element, which by
definition is not native anonymous and not a pseudo-element.
Thus, you never get fixed-up if your NAC or a pseudo, which is what the code
tried to avoid, so the only fixup with a point is the item one, which is
necessary.
* The pseudo-element probing code was refactored to return early a
Option::<CascadeInputs>::None, which is nicer than what it was doing.
* The visited_links_enabled check has moved to selector-matching time. The rest
of the checks aren't based on whether the element is a link, or are properly
guarded by parent_style.visited_style().is_some() or visited_rules.is_some().
Thus you can transitively infer that no element will end up with a :visited
style, not even from style reparenting.
Anyway, the underlying reason why I want the element in StyleAdjuster is because
we're going to implement an adjustment in there depending on the tag of the
element (converting display: contents to display: none depending on the tag), so
computing that information eagerly, including a hash lookup, wouldn't be nice.
See each commit for details.
Source-Repo: https://github.com/servo/servo
Source-Revision: 02331617b9bd7a379b05f7daa7ad09a44c27504c
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : dceeca4961762c9f7414007c83ceed03e00c720b
2018-01-23 15:30:51 +03:00
|
|
|
fn skip_item_display_fixup(&self) -> bool;
|
2017-02-09 06:33:27 +03:00
|
|
|
|
|
|
|
/// Sets selector flags, which indicate what kinds of selectors may have
|
|
|
|
/// matched on this element and therefore what kind of work may need to
|
|
|
|
/// be performed when DOM state changes.
|
|
|
|
///
|
|
|
|
/// This is unsafe, like all the flag-setting methods, because it's only safe
|
|
|
|
/// to call with exclusive access to the element. When setting flags on the
|
|
|
|
/// parent during parallel traversal, we use SequentialTask to queue up the
|
|
|
|
/// set to run after the threads join.
|
|
|
|
unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags);
|
|
|
|
|
|
|
|
/// Returns true if the element has all the specified selector flags.
|
|
|
|
fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
|
2017-03-10 07:23:21 +03:00
|
|
|
|
2017-05-25 00:08:02 +03:00
|
|
|
/// In Gecko, element has a flag that represents the element may have
|
|
|
|
/// any type of animations or not to bail out animation stuff early.
|
|
|
|
/// Whereas Servo doesn't have such flag.
|
2018-04-11 04:00:11 +03:00
|
|
|
fn may_have_animations(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2017-05-25 00:08:02 +03:00
|
|
|
|
2017-03-27 13:47:47 +03:00
|
|
|
/// Creates a task to update various animation state on a given (pseudo-)element.
|
|
|
|
#[cfg(feature = "gecko")]
|
2018-04-11 04:00:11 +03:00
|
|
|
fn update_animations(
|
|
|
|
&self,
|
|
|
|
before_change_style: Option<Arc<ComputedValues>>,
|
|
|
|
tasks: UpdateAnimationsTasks,
|
|
|
|
);
|
2017-03-27 13:47:47 +03:00
|
|
|
|
2017-08-03 00:27:58 +03:00
|
|
|
/// Creates a task to process post animation on a given element.
|
|
|
|
#[cfg(feature = "gecko")]
|
|
|
|
fn process_post_animation(&self, tasks: PostAnimationTasks);
|
|
|
|
|
2017-03-27 13:47:47 +03:00
|
|
|
/// Returns true if the element has relevant animations. Relevant
|
|
|
|
/// animations are those animations that are affecting the element's style
|
|
|
|
/// or are scheduled to do so in the future.
|
2017-04-27 15:39:42 +03:00
|
|
|
fn has_animations(&self) -> bool;
|
2017-03-10 07:23:21 +03:00
|
|
|
|
|
|
|
/// Returns true if the element has a CSS animation.
|
2017-04-27 15:39:42 +03:00
|
|
|
fn has_css_animations(&self) -> bool;
|
2017-03-27 07:13:44 +03:00
|
|
|
|
2017-04-17 13:07:23 +03:00
|
|
|
/// Returns true if the element has a CSS transition (including running transitions and
|
|
|
|
/// completed transitions).
|
2017-04-27 15:39:42 +03:00
|
|
|
fn has_css_transitions(&self) -> bool;
|
2017-04-17 13:07:23 +03:00
|
|
|
|
2017-03-27 07:13:44 +03:00
|
|
|
/// Returns true if the element has animation restyle hints.
|
|
|
|
fn has_animation_restyle_hints(&self) -> bool {
|
|
|
|
let data = match self.borrow_data() {
|
|
|
|
Some(d) => d,
|
|
|
|
None => return false,
|
|
|
|
};
|
2018-04-11 04:00:11 +03:00
|
|
|
return data.hint.has_animation_hint();
|
2017-03-27 07:13:44 +03:00
|
|
|
}
|
2017-04-17 13:07:23 +03:00
|
|
|
|
2017-06-20 14:15:57 +03:00
|
|
|
/// Returns the anonymous content for the current element's XBL binding,
|
|
|
|
/// given if any.
|
|
|
|
///
|
|
|
|
/// This is used in Gecko for XBL and shadow DOM.
|
|
|
|
fn xbl_binding_anonymous_content(&self) -> Option<Self::ConcreteNode> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2018-03-04 01:53:08 +03:00
|
|
|
/// The shadow root this element is a host of.
|
|
|
|
fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
|
|
|
|
|
|
|
|
/// The shadow root which roots the subtree this element is contained in.
|
|
|
|
fn containing_shadow(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>;
|
|
|
|
|
2018-03-12 23:48:36 +03:00
|
|
|
/// XBL hack for style sharing. :(
|
2018-04-11 04:00:11 +03:00
|
|
|
fn has_same_xbl_proto_binding_as(&self, _other: Self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2018-03-12 23:48:36 +03:00
|
|
|
|
2017-10-28 14:06:56 +03:00
|
|
|
/// Return the element which we can use to look up rules in the selector
|
|
|
|
/// maps.
|
|
|
|
///
|
|
|
|
/// This is always the element itself, except in the case where we are an
|
|
|
|
/// element-backed pseudo-element, in which case we return the originating
|
|
|
|
/// element.
|
2017-06-23 05:53:37 +03:00
|
|
|
fn rule_hash_target(&self) -> Self {
|
2018-01-13 20:52:15 +03:00
|
|
|
if self.implemented_pseudo_element().is_some() {
|
2018-05-10 19:48:08 +03:00
|
|
|
self.pseudo_element_originating_element()
|
2018-01-13 20:52:15 +03:00
|
|
|
.expect("Trying to collect rules for a detached pseudo-element")
|
2017-06-23 05:53:37 +03:00
|
|
|
} else {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 03:02:17 +03:00
|
|
|
/// Implements Gecko's `nsBindingManager::WalkRules`.
|
|
|
|
///
|
2018-03-07 18:06:05 +03:00
|
|
|
/// Returns whether to cut off the binding inheritance, that is, whether
|
|
|
|
/// document rules should _not_ apply.
|
2018-02-12 14:03:30 +03:00
|
|
|
fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
|
2017-06-29 03:02:17 +03:00
|
|
|
where
|
2017-10-23 16:14:35 +03:00
|
|
|
Self: 'a,
|
2018-02-16 17:54:06 +03:00
|
|
|
F: FnMut(&'a CascadeData, QuirksMode),
|
2017-06-29 03:02:17 +03:00
|
|
|
{
|
2017-06-08 10:19:27 +03:00
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2018-01-09 16:26:28 +03:00
|
|
|
/// Executes the callback for each applicable style rule data which isn't
|
|
|
|
/// the main document's data (which stores UA / author rules).
|
|
|
|
///
|
servo: Merge #20597 - style: Implement the non-functional :host selector (from emilio:host); r=xidorn
Kinda tricky because :host only matches rules on the shadow root where the rules
come from. So we need to be careful during invalidation and style sharing.
I didn't use the non_ts_pseudo_class_list bits because as soon as we implement
the :host(..) bits we're going to need to special-case it anyway.
The general schema is the following:
* Rightmost featureless :host selectors are handled inserting them in the
host_rules hashmap. Note that we only insert featureless stuff there. We
could insert all of them and just filter during matching, but that's slightly
annoying.
* The other selectors, like non-featureless :host or what not, are added to the
normal cascade data. This is harmless, since the shadow host rules are never
matched against the host, so we know they'll just never match, and avoids
adding more special-cases.
* Featureless :host selectors to the left of a combinator are handled during
matching, in the special-case of next_element_for_combinator in selectors.
This prevents this from being more invasive, and keeps the usual fast path
slim, but it's a bit hard to match the spec and the implementation.
We could keep a copy of the SelectorIter instead in the matching context to
make the handling of featureless-ness explicit in match_non_ts_pseudo_class,
but we'd still need the special-case anyway, so I'm not fond of it.
* We take advantage of one thing that makes this sound. As you may have
noticed, if you had `root` element which is a ShadowRoot, and you matched
something like `div:host` against it, using a MatchingContext with
current_host == root, we'd incorrectly report a match. But this is impossible
due to the following constraints:
* Shadow root rules aren't matched against the host during styling (except
these featureless selectors).
* DOM APIs' current_host needs to be the _containing_ host, not the element
itself if you're a Shadow host.
Bug: 992245
Reviewed-by: xidorn
MozReview-Commit-ID: KayYNfTXb5h
Source-Repo: https://github.com/servo/servo
Source-Revision: cb754b262747e7cab794411df55588f0f0b30b5e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 2ebbb2578ff9dbadfe905ae501cd52bd61a9fe9a
2018-04-09 13:41:59 +03:00
|
|
|
/// The element passed to the callback is the containing shadow host for the
|
|
|
|
/// data if it comes from Shadow DOM, None if it comes from XBL.
|
|
|
|
///
|
2018-01-09 16:26:28 +03:00
|
|
|
/// Returns whether normal document author rules should apply.
|
|
|
|
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
|
|
|
|
where
|
|
|
|
Self: 'a,
|
servo: Merge #20597 - style: Implement the non-functional :host selector (from emilio:host); r=xidorn
Kinda tricky because :host only matches rules on the shadow root where the rules
come from. So we need to be careful during invalidation and style sharing.
I didn't use the non_ts_pseudo_class_list bits because as soon as we implement
the :host(..) bits we're going to need to special-case it anyway.
The general schema is the following:
* Rightmost featureless :host selectors are handled inserting them in the
host_rules hashmap. Note that we only insert featureless stuff there. We
could insert all of them and just filter during matching, but that's slightly
annoying.
* The other selectors, like non-featureless :host or what not, are added to the
normal cascade data. This is harmless, since the shadow host rules are never
matched against the host, so we know they'll just never match, and avoids
adding more special-cases.
* Featureless :host selectors to the left of a combinator are handled during
matching, in the special-case of next_element_for_combinator in selectors.
This prevents this from being more invasive, and keeps the usual fast path
slim, but it's a bit hard to match the spec and the implementation.
We could keep a copy of the SelectorIter instead in the matching context to
make the handling of featureless-ness explicit in match_non_ts_pseudo_class,
but we'd still need the special-case anyway, so I'm not fond of it.
* We take advantage of one thing that makes this sound. As you may have
noticed, if you had `root` element which is a ShadowRoot, and you matched
something like `div:host` against it, using a MatchingContext with
current_host == root, we'd incorrectly report a match. But this is impossible
due to the following constraints:
* Shadow root rules aren't matched against the host during styling (except
these featureless selectors).
* DOM APIs' current_host needs to be the _containing_ host, not the element
itself if you're a Shadow host.
Bug: 992245
Reviewed-by: xidorn
MozReview-Commit-ID: KayYNfTXb5h
Source-Repo: https://github.com/servo/servo
Source-Revision: cb754b262747e7cab794411df55588f0f0b30b5e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 2ebbb2578ff9dbadfe905ae501cd52bd61a9fe9a
2018-04-09 13:41:59 +03:00
|
|
|
F: FnMut(&'a CascadeData, QuirksMode, Option<Self>),
|
2018-01-09 16:26:28 +03:00
|
|
|
{
|
servo: Merge #20597 - style: Implement the non-functional :host selector (from emilio:host); r=xidorn
Kinda tricky because :host only matches rules on the shadow root where the rules
come from. So we need to be careful during invalidation and style sharing.
I didn't use the non_ts_pseudo_class_list bits because as soon as we implement
the :host(..) bits we're going to need to special-case it anyway.
The general schema is the following:
* Rightmost featureless :host selectors are handled inserting them in the
host_rules hashmap. Note that we only insert featureless stuff there. We
could insert all of them and just filter during matching, but that's slightly
annoying.
* The other selectors, like non-featureless :host or what not, are added to the
normal cascade data. This is harmless, since the shadow host rules are never
matched against the host, so we know they'll just never match, and avoids
adding more special-cases.
* Featureless :host selectors to the left of a combinator are handled during
matching, in the special-case of next_element_for_combinator in selectors.
This prevents this from being more invasive, and keeps the usual fast path
slim, but it's a bit hard to match the spec and the implementation.
We could keep a copy of the SelectorIter instead in the matching context to
make the handling of featureless-ness explicit in match_non_ts_pseudo_class,
but we'd still need the special-case anyway, so I'm not fond of it.
* We take advantage of one thing that makes this sound. As you may have
noticed, if you had `root` element which is a ShadowRoot, and you matched
something like `div:host` against it, using a MatchingContext with
current_host == root, we'd incorrectly report a match. But this is impossible
due to the following constraints:
* Shadow root rules aren't matched against the host during styling (except
these featureless selectors).
* DOM APIs' current_host needs to be the _containing_ host, not the element
itself if you're a Shadow host.
Bug: 992245
Reviewed-by: xidorn
MozReview-Commit-ID: KayYNfTXb5h
Source-Repo: https://github.com/servo/servo
Source-Revision: cb754b262747e7cab794411df55588f0f0b30b5e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 2ebbb2578ff9dbadfe905ae501cd52bd61a9fe9a
2018-04-09 13:41:59 +03:00
|
|
|
let mut doc_rules_apply = !self.each_xbl_cascade_data(|data, quirks_mode| {
|
|
|
|
f(data, quirks_mode, None);
|
|
|
|
});
|
2018-03-07 18:06:05 +03:00
|
|
|
|
|
|
|
if let Some(shadow) = self.containing_shadow() {
|
|
|
|
doc_rules_apply = false;
|
2018-08-30 15:00:00 +03:00
|
|
|
if let Some(data) = shadow.style_data() {
|
|
|
|
f(
|
|
|
|
data,
|
|
|
|
self.as_node().owner_doc().quirks_mode(),
|
|
|
|
Some(shadow.host()),
|
|
|
|
);
|
|
|
|
}
|
2018-04-10 09:16:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(shadow) = self.shadow_root() {
|
2018-08-30 15:00:00 +03:00
|
|
|
if let Some(data) = shadow.style_data() {
|
|
|
|
f(
|
|
|
|
data,
|
|
|
|
self.as_node().owner_doc().quirks_mode(),
|
|
|
|
Some(shadow.host()),
|
|
|
|
);
|
|
|
|
}
|
2018-03-07 18:06:05 +03:00
|
|
|
}
|
2018-01-09 16:26:28 +03:00
|
|
|
|
|
|
|
let mut current = self.assigned_slot();
|
|
|
|
while let Some(slot) = current {
|
2018-03-07 18:06:05 +03:00
|
|
|
// Slots can only have assigned nodes when in a shadow tree.
|
servo: Merge #20597 - style: Implement the non-functional :host selector (from emilio:host); r=xidorn
Kinda tricky because :host only matches rules on the shadow root where the rules
come from. So we need to be careful during invalidation and style sharing.
I didn't use the non_ts_pseudo_class_list bits because as soon as we implement
the :host(..) bits we're going to need to special-case it anyway.
The general schema is the following:
* Rightmost featureless :host selectors are handled inserting them in the
host_rules hashmap. Note that we only insert featureless stuff there. We
could insert all of them and just filter during matching, but that's slightly
annoying.
* The other selectors, like non-featureless :host or what not, are added to the
normal cascade data. This is harmless, since the shadow host rules are never
matched against the host, so we know they'll just never match, and avoids
adding more special-cases.
* Featureless :host selectors to the left of a combinator are handled during
matching, in the special-case of next_element_for_combinator in selectors.
This prevents this from being more invasive, and keeps the usual fast path
slim, but it's a bit hard to match the spec and the implementation.
We could keep a copy of the SelectorIter instead in the matching context to
make the handling of featureless-ness explicit in match_non_ts_pseudo_class,
but we'd still need the special-case anyway, so I'm not fond of it.
* We take advantage of one thing that makes this sound. As you may have
noticed, if you had `root` element which is a ShadowRoot, and you matched
something like `div:host` against it, using a MatchingContext with
current_host == root, we'd incorrectly report a match. But this is impossible
due to the following constraints:
* Shadow root rules aren't matched against the host during styling (except
these featureless selectors).
* DOM APIs' current_host needs to be the _containing_ host, not the element
itself if you're a Shadow host.
Bug: 992245
Reviewed-by: xidorn
MozReview-Commit-ID: KayYNfTXb5h
Source-Repo: https://github.com/servo/servo
Source-Revision: cb754b262747e7cab794411df55588f0f0b30b5e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 2ebbb2578ff9dbadfe905ae501cd52bd61a9fe9a
2018-04-09 13:41:59 +03:00
|
|
|
let shadow = slot.containing_shadow().unwrap();
|
2018-08-30 15:00:00 +03:00
|
|
|
if let Some(data) = shadow.style_data() {
|
|
|
|
f(
|
|
|
|
data,
|
|
|
|
self.as_node().owner_doc().quirks_mode(),
|
|
|
|
Some(shadow.host()),
|
|
|
|
);
|
|
|
|
}
|
2018-01-09 16:26:28 +03:00
|
|
|
current = slot.assigned_slot();
|
|
|
|
}
|
|
|
|
|
2018-03-07 18:06:05 +03:00
|
|
|
doc_rules_apply
|
2018-01-09 16:26:28 +03:00
|
|
|
}
|
|
|
|
|
2017-04-17 13:07:23 +03:00
|
|
|
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
|
|
|
/// will quickly return false for the common case of no transitions specified or running. If
|
|
|
|
/// this returns false, we definitely don't need to update transitions but if it returns true
|
|
|
|
/// we can perform the more thoroughgoing check, needs_transitions_update, to further
|
|
|
|
/// reduce the possibility of false positives.
|
|
|
|
#[cfg(feature = "gecko")]
|
2017-09-16 04:21:25 +03:00
|
|
|
fn might_need_transitions_update(
|
|
|
|
&self,
|
|
|
|
old_values: Option<&ComputedValues>,
|
2018-04-11 04:00:11 +03:00
|
|
|
new_values: &ComputedValues,
|
2017-09-16 04:21:25 +03:00
|
|
|
) -> bool;
|
2017-04-17 13:07:23 +03:00
|
|
|
|
|
|
|
/// Returns true if one of the transitions needs to be updated on this element. We check all
|
|
|
|
/// the transition properties to make sure that updating transitions is necessary.
|
|
|
|
/// This method should only be called if might_needs_transitions_update returns true when
|
|
|
|
/// passed the same parameters.
|
|
|
|
#[cfg(feature = "gecko")]
|
2017-09-16 04:21:25 +03:00
|
|
|
fn needs_transitions_update(
|
|
|
|
&self,
|
|
|
|
before_change_style: &ComputedValues,
|
2018-04-11 04:00:11 +03:00
|
|
|
after_change_style: &ComputedValues,
|
2017-09-16 04:21:25 +03:00
|
|
|
) -> bool;
|
2017-04-17 13:07:23 +03:00
|
|
|
|
2017-06-08 05:00:54 +03:00
|
|
|
/// Returns the value of the `xml:lang=""` attribute (or, if appropriate,
|
|
|
|
/// the `lang=""` attribute) on this element.
|
|
|
|
fn lang_attr(&self) -> Option<AttrValue>;
|
|
|
|
|
|
|
|
/// Returns whether this element's language matches the language tag
|
|
|
|
/// `value`. If `override_lang` is not `None`, it specifies the value
|
|
|
|
/// of the `xml:lang=""` or `lang=""` attribute to use in place of
|
|
|
|
/// looking at the element and its ancestors. (This argument is used
|
|
|
|
/// to implement matching of `:lang()` against snapshots.)
|
2018-09-09 17:24:45 +03:00
|
|
|
fn match_element_lang(&self, override_lang: Option<Option<AttrValue>>, value: &Lang) -> bool;
|
2017-09-16 04:21:25 +03:00
|
|
|
|
|
|
|
/// Returns whether this element is the main body element of the HTML
|
|
|
|
/// document it is on.
|
|
|
|
fn is_html_document_body_element(&self) -> bool;
|
2017-10-26 13:17:39 +03:00
|
|
|
|
|
|
|
/// Generate the proper applicable declarations due to presentational hints,
|
|
|
|
/// and insert them into `hints`.
|
|
|
|
fn synthesize_presentational_hints_for_legacy_attributes<V>(
|
|
|
|
&self,
|
|
|
|
visited_handling: VisitedHandlingMode,
|
|
|
|
hints: &mut V,
|
2018-04-11 04:00:11 +03:00
|
|
|
) where
|
2017-10-26 13:17:39 +03:00
|
|
|
V: Push<ApplicableDeclarationBlock>;
|
2015-12-30 07:34:14 +03:00
|
|
|
}
|
2016-12-22 23:02:38 +03:00
|
|
|
|
|
|
|
/// TNode and TElement aren't Send because we want to be careful and explicit
|
|
|
|
/// about our parallel traversal. However, there are certain situations
|
|
|
|
/// (including but not limited to the traversal) where we need to send DOM
|
|
|
|
/// objects to other threads.
|
2016-12-31 14:19:02 +03:00
|
|
|
///
|
|
|
|
/// That's the reason why `SendNode` exists.
|
2016-12-22 23:02:38 +03:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub struct SendNode<N: TNode>(N);
|
|
|
|
unsafe impl<N: TNode> Send for SendNode<N> {}
|
|
|
|
impl<N: TNode> SendNode<N> {
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Unsafely construct a SendNode.
|
2016-12-22 23:02:38 +03:00
|
|
|
pub unsafe fn new(node: N) -> Self {
|
|
|
|
SendNode(node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<N: TNode> Deref for SendNode<N> {
|
|
|
|
type Target = N;
|
|
|
|
fn deref(&self) -> &N {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Same reason as for the existence of SendNode, SendElement does the proper
|
|
|
|
/// things for a given `TElement`.
|
2017-04-13 16:56:03 +03:00
|
|
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
2016-12-22 23:02:38 +03:00
|
|
|
pub struct SendElement<E: TElement>(E);
|
|
|
|
unsafe impl<E: TElement> Send for SendElement<E> {}
|
|
|
|
impl<E: TElement> SendElement<E> {
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Unsafely construct a SendElement.
|
2016-12-22 23:02:38 +03:00
|
|
|
pub unsafe fn new(el: E) -> Self {
|
|
|
|
SendElement(el)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<E: TElement> Deref for SendElement<E> {
|
|
|
|
type Target = E;
|
|
|
|
fn deref(&self) -> &E {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|