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
|
|
|
|
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
|
|
|
use {Atom, Namespace, LocalName};
|
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};
|
2017-08-03 00:27:58 +03:00
|
|
|
#[cfg(feature = "gecko")] use context::PostAnimationTasks;
|
2017-03-27 13:47:47 +03:00
|
|
|
#[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};
|
2017-09-29 18:01:52 +03:00
|
|
|
#[cfg(feature = "gecko")] use properties::LonghandId;
|
2017-04-17 13:07:23 +03:00
|
|
|
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValue;
|
|
|
|
use rule_tree::CascadeLevel;
|
2017-10-16 15:32:40 +03:00
|
|
|
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
|
|
|
|
use selectors::Element as SelectorsElement;
|
2017-06-02 23:08:04 +03:00
|
|
|
use selectors::matching::{ElementSelectorFlags, 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;
|
2017-10-04 02:47:46 +03:00
|
|
|
#[cfg(feature = "gecko")] use hash::FnvHashMap;
|
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;
|
2017-06-29 03:02:17 +03:00
|
|
|
use stylist::Stylist;
|
2017-10-20 00:23:30 +03:00
|
|
|
use traversal_flags::{TraversalFlags, self};
|
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)]
|
servo: Merge #18938 - Replace all uses of the `heapsize` crate with `malloc_size_of` (from nnethercote:bug-1409255); r=SimonSapin
Servo currently uses `heapsize`, but Stylo/Gecko use `malloc_size_of`.
`malloc_size_of` is better -- it handles various cases that `heapsize` does not
-- so this patch changes Servo to use `malloc_size_of`.
This patch makes the following changes to the `malloc_size_of` crate.
- Adds `MallocSizeOf` trait implementations for numerous types, some built-in
(e.g. `VecDeque`), some external and Servo-only (e.g. `string_cache`).
- Makes `enclosing_size_of_op` optional, because vanilla jemalloc doesn't
support that operation.
- For `HashSet`/`HashMap`, falls back to a computed estimate when
`enclosing_size_of_op` isn't available.
- Adds an extern "C" `malloc_size_of` function that does the actual heap
measurement; this is based on the same functions from the `heapsize` crate.
This patch makes the following changes elsewhere.
- Converts all the uses of `heapsize` to instead use `malloc_size_of`.
- Disables the "heapsize"/"heap_size" feature for the external crates that
provide it.
- Removes the `HeapSizeOf` implementation from `hashglobe`.
- Adds `ignore` annotations to a few `Rc`/`Arc`, because `malloc_size_of`
doesn't derive those types, unlike `heapsize`.
<!-- Please describe your changes on the following line: -->
---
<!-- 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 https://bugzilla.mozilla.org/show_bug.cgi?id=1409255
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because testing is on the Gecko side.
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- 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: 4c538b642e4bdfbf42c522c5a59c258a6d14546e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : f9a6feed1088d0b0be2b55d7f0c2ec9c594ac33b
2017-10-18 21:56:05 +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-10-17 13:18:29 +03:00
|
|
|
match self.0.next() {
|
|
|
|
Some(n) => {
|
|
|
|
// Filter out nodes that layout should ignore.
|
|
|
|
if n.is_text_node() || n.is_element() {
|
|
|
|
return Some(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over the DOM children of a node.
|
|
|
|
pub struct DomChildren<N>(Option<N>);
|
|
|
|
impl<N> Iterator for DomChildren<N>
|
|
|
|
where
|
|
|
|
N: TNode
|
|
|
|
{
|
|
|
|
type Item = N;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<N> {
|
|
|
|
match self.0.take() {
|
|
|
|
Some(n) => {
|
|
|
|
self.0 = n.next_sibling();
|
|
|
|
Some(n)
|
2016-09-22 03:59:52 +03:00
|
|
|
}
|
2017-10-17 13:18:29 +03:00
|
|
|
None => None,
|
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
|
|
|
|
N: TNode
|
|
|
|
{
|
|
|
|
type Item = N;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<N> {
|
|
|
|
let prev = match self.previous.take() {
|
|
|
|
None => return None,
|
|
|
|
Some(n) => n,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.previous = prev.next_in_preorder(Some(self.scope));
|
|
|
|
self.previous
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2017-10-23 16:14:35 +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-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-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-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.
|
|
|
|
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>;
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Whether this node can be fragmented. This is used for multicol, and only
|
|
|
|
/// for Servo.
|
2016-10-30 01:14:10 +03:00
|
|
|
fn can_be_fragmented(&self) -> bool;
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// Set whether this node can be fragmented.
|
2016-10-30 01:14:10 +03:00
|
|
|
unsafe fn set_can_be_fragmented(&self, value: bool);
|
|
|
|
}
|
|
|
|
|
2016-12-13 06:13:03 +03:00
|
|
|
/// Wrapper to output the ElementData along with the node when formatting for
|
|
|
|
/// Debug.
|
|
|
|
pub struct ShowData<N: TNode>(pub N);
|
|
|
|
impl<N: TNode> Debug for ShowData<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
fmt_with_data(f, self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper to output the primary computed values along with the node when
|
|
|
|
/// formatting for Debug. This is very verbose.
|
|
|
|
pub struct ShowDataAndPrimaryValues<N: TNode>(pub N);
|
|
|
|
impl<N: TNode> Debug for ShowDataAndPrimaryValues<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
fmt_with_data_and_primary_values(f, self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
pub struct ShowSubtreeDataAndPrimaryValues<N: TNode>(pub N);
|
|
|
|
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!(
|
|
|
|
f, "{:?} dd={} aodd={} data={:?}",
|
|
|
|
el,
|
|
|
|
el.has_dirty_descendants(),
|
|
|
|
el.has_animation_only_dirty_descendants(),
|
|
|
|
el.borrow_data(),
|
|
|
|
)
|
2016-12-13 06:13:03 +03:00
|
|
|
} else {
|
|
|
|
write!(f, "{:?}", n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
2017-08-27 02:13:40 +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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
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(())
|
|
|
|
}
|
|
|
|
|
2016-12-31 14:19:02 +03:00
|
|
|
/// The element trait, the main abstraction the style crate acts over.
|
2017-10-16 15:32:40 +03:00
|
|
|
pub trait TElement
|
|
|
|
: Eq
|
|
|
|
+ PartialEq
|
|
|
|
+ Debug
|
|
|
|
+ Hash
|
|
|
|
+ Sized
|
|
|
|
+ Copy
|
|
|
|
+ Clone
|
|
|
|
+ SelectorsElement<Impl = SelectorImpl>
|
|
|
|
{
|
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.
|
|
|
|
fn owner_doc_matches_for_testing(&self, _: &Device) -> bool { true }
|
|
|
|
|
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.
|
|
|
|
fn matches_user_and_author_rules(&self) -> bool { true }
|
|
|
|
|
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),
|
|
|
|
{}
|
|
|
|
|
2017-05-12 15:25:00 +03:00
|
|
|
/// For a given NAC element, return the closest non-NAC ancestor, which is
|
|
|
|
/// guaranteed to exist.
|
|
|
|
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {
|
|
|
|
unreachable!("Servo doesn't know about NAC");
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
fn unset_dirty_style_attribute(&self) {
|
|
|
|
}
|
|
|
|
|
2017-04-27 08:48:21 +03:00
|
|
|
/// Get this element's SMIL override declarations.
|
2017-07-18 05:44:25 +03:00
|
|
|
fn get_smil_override(&self) -> Option<ArcBorrow<Locked<PropertyDeclarationBlock>>> {
|
2017-04-27 08:48:21 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2017-04-17 13:07:23 +03:00
|
|
|
/// Get this element's animation rule by the cascade level.
|
|
|
|
fn get_animation_rule_by_cascade(&self,
|
|
|
|
_cascade_level: CascadeLevel)
|
|
|
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2017-07-12 10:28:44 +03:00
|
|
|
/// Get the combined animation and transition rules.
|
|
|
|
fn get_animation_rules(&self) -> AnimationRules {
|
|
|
|
if !self.may_have_animations() {
|
|
|
|
return AnimationRules(None, None)
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationRules(
|
|
|
|
self.get_animation_rule(),
|
|
|
|
self.get_transition_rule(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2017-03-17 13:09:31 +03:00
|
|
|
/// Get this element's animation rule.
|
2017-04-27 15:39:42 +03:00
|
|
|
fn get_animation_rule(&self)
|
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
|
|
|
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
2017-03-17 13:09:31 +03:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get this element's transition rule.
|
2017-04-27 15:39:42 +03:00
|
|
|
fn get_transition_rule(&self)
|
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
|
|
|
-> 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.
|
2016-10-30 01:14:10 +03:00
|
|
|
fn get_state(&self) -> ElementState;
|
|
|
|
|
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.
|
|
|
|
fn get_id(&self) -> Option<Atom>;
|
|
|
|
|
2017-05-19 02:45:20 +03:00
|
|
|
/// Internal iterator for the classes of this element.
|
|
|
|
fn each_class<F>(&self, callback: F) where F: FnMut(&Atom);
|
|
|
|
|
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.
|
|
|
|
fn may_generate_pseudo(
|
|
|
|
&self,
|
2017-06-27 09:46:13 +03:00
|
|
|
pseudo: &PseudoElement,
|
2017-07-18 19:23:03 +03:00
|
|
|
_primary_style: &ComputedValues,
|
2017-06-01 22:13:43 +03:00
|
|
|
) -> 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.
|
|
|
|
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.
|
|
|
|
return data.has_styles() &&
|
2017-09-12 21:16:26 +03:00
|
|
|
!data.hint.has_animation_hint_or_recascade();
|
2017-07-18 14:55:30 +03:00
|
|
|
}
|
|
|
|
|
2017-10-20 00:23:30 +03:00
|
|
|
if traversal_flags.contains(traversal_flags::UnstyledOnly) {
|
2017-08-12 00:47:12 +03:00
|
|
|
// We don't process invalidations in UnstyledOnly mode.
|
|
|
|
return data.has_styles();
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
unsafe fn set_animation_only_dirty_descendants(&self) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Flag that this element has no descendant for animation-only restyle processing.
|
|
|
|
///
|
|
|
|
/// Only safe to call with exclusive access to the element.
|
|
|
|
unsafe fn unset_animation_only_dirty_descendants(&self) {
|
|
|
|
}
|
|
|
|
|
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.
|
2017-08-26 20:22:33 +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.
|
|
|
|
unsafe fn clear_dirty_bits(&self) { self.unset_dirty_descendants(); }
|
|
|
|
|
2017-07-23 14:15:39 +03:00
|
|
|
/// Returns true if this element is a visited link.
|
|
|
|
///
|
|
|
|
/// Servo doesn't support visited styles yet.
|
|
|
|
fn is_visited_link(&self) -> bool { false }
|
|
|
|
|
2017-04-01 22:34:33 +03:00
|
|
|
/// Returns true if this element is native anonymous (only Gecko has native
|
|
|
|
/// anonymous content).
|
|
|
|
fn is_native_anonymous(&self) -> bool { false }
|
|
|
|
|
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.
|
|
|
|
fn implemented_pseudo_element(&self) -> Option<PseudoElement> { None }
|
|
|
|
|
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.)
|
|
|
|
fn skip_root_and_item_based_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.
|
|
|
|
fn may_have_animations(&self) -> bool { false }
|
|
|
|
|
2017-03-27 13:47:47 +03:00
|
|
|
/// Creates a task to update various animation state on a given (pseudo-)element.
|
|
|
|
#[cfg(feature = "gecko")]
|
2017-04-27 15:39:42 +03:00
|
|
|
fn update_animations(&self,
|
2017-04-17 13:07:23 +03:00
|
|
|
before_change_style: Option<Arc<ComputedValues>>,
|
2017-03-27 13:47:47 +03:00
|
|
|
tasks: UpdateAnimationsTasks);
|
|
|
|
|
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,
|
|
|
|
};
|
2017-09-12 21:16:26 +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
|
|
|
|
}
|
|
|
|
|
2017-06-23 05:53:37 +03:00
|
|
|
/// Returns the rule hash target given an element.
|
|
|
|
fn rule_hash_target(&self) -> Self {
|
|
|
|
let is_implemented_pseudo =
|
|
|
|
self.implemented_pseudo_element().is_some();
|
|
|
|
|
|
|
|
// NB: This causes use to rule has pseudo selectors based on the
|
|
|
|
// properties of the originating element (which is fine, given the
|
|
|
|
// find_first_from_right usage).
|
|
|
|
if is_implemented_pseudo {
|
|
|
|
self.closest_non_native_anonymous_ancestor().unwrap()
|
|
|
|
} else {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 03:02:17 +03:00
|
|
|
/// Implements Gecko's `nsBindingManager::WalkRules`.
|
|
|
|
///
|
|
|
|
/// Returns whether to cut off the inheritance.
|
2017-10-23 16:14:35 +03:00
|
|
|
fn each_xbl_stylist<'a, F>(&self, _: F) -> bool
|
2017-06-29 03:02:17 +03:00
|
|
|
where
|
2017-10-23 16:14:35 +03:00
|
|
|
Self: 'a,
|
|
|
|
F: FnMut(AtomicRef<'a, Stylist>),
|
2017-06-29 03:02:17 +03:00
|
|
|
{
|
2017-06-08 10:19:27 +03:00
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2017-10-04 02:47:46 +03:00
|
|
|
/// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap.
|
2017-04-17 13:07:23 +03:00
|
|
|
#[cfg(feature = "gecko")]
|
2017-04-27 15:39:42 +03:00
|
|
|
fn get_css_transitions_info(&self)
|
2017-10-06 20:56:27 +03:00
|
|
|
-> FnvHashMap<LonghandId, Arc<AnimationValue>>;
|
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>,
|
|
|
|
new_values: &ComputedValues
|
|
|
|
) -> 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,
|
|
|
|
after_change_style: &ComputedValues
|
|
|
|
) -> bool;
|
2017-04-17 13:07:23 +03:00
|
|
|
|
|
|
|
/// Returns true if we need to update transitions for the specified property on this element.
|
|
|
|
#[cfg(feature = "gecko")]
|
2017-09-16 04:21:25 +03:00
|
|
|
fn needs_transitions_update_per_property(
|
|
|
|
&self,
|
2017-09-29 18:01:52 +03:00
|
|
|
property: &LonghandId,
|
2017-09-16 04:21:25 +03:00
|
|
|
combined_duration: f32,
|
|
|
|
before_change_style: &ComputedValues,
|
|
|
|
after_change_style: &ComputedValues,
|
2017-10-06 20:56:27 +03:00
|
|
|
existing_transitions: &FnvHashMap<LonghandId, Arc<AnimationValue>>
|
2017-09-16 04:21:25 +03:00
|
|
|
) -> bool;
|
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.)
|
2017-09-16 04:21:25 +03:00
|
|
|
fn match_element_lang(
|
|
|
|
&self,
|
|
|
|
override_lang: Option<Option<AttrValue>>,
|
|
|
|
value: &PseudoClassStringArg
|
|
|
|
) -> bool;
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
)
|
|
|
|
where
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|