mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Document a bit better the rule tree code.
This commit is contained in:
parent
277ef70d39
commit
9a8c94b998
1 changed files with 48 additions and 1 deletions
|
@ -3,6 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
//! The rule tree.
|
||||||
|
|
||||||
use arc_ptr_eq;
|
use arc_ptr_eq;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
@ -17,15 +20,40 @@ use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||||
use stylesheets::StyleRule;
|
use stylesheets::StyleRule;
|
||||||
use thread_state;
|
use thread_state;
|
||||||
|
|
||||||
|
/// The rule tree, the structure servo uses to preserve the results of selector
|
||||||
|
/// matching.
|
||||||
|
///
|
||||||
|
/// This is organized as a tree of rules. When a node matches a set of rules,
|
||||||
|
/// they're inserted in order in the tree, starting with the less specific one.
|
||||||
|
///
|
||||||
|
/// When a rule is inserted in the tree, other elements may share the path up to
|
||||||
|
/// a given rule. If that's the case, we don't duplicate child nodes, but share
|
||||||
|
/// them.
|
||||||
|
///
|
||||||
|
/// When the rule node refcount drops to zero, it doesn't get freed. It gets
|
||||||
|
/// instead put into a free list, and it is potentially GC'd after a while in a
|
||||||
|
/// single-threaded fashion.
|
||||||
|
///
|
||||||
|
/// That way, a rule node that represents a likely-to-match-again rule (like a
|
||||||
|
/// :hover rule) can be reused if we haven't GC'd it yet.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct RuleTree {
|
pub struct RuleTree {
|
||||||
root: StrongRuleNode,
|
root: StrongRuleNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A style source for the rule node. It can either be a CSS style rule or a
|
||||||
|
/// declaration block.
|
||||||
|
///
|
||||||
|
/// Note that, even though the declaration block from inside the style rule
|
||||||
|
/// could be enough to implement the rule tree, keeping the whole rule provides
|
||||||
|
/// more debuggability, and also the ability of show those selectors to
|
||||||
|
/// devtools.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum StyleSource {
|
pub enum StyleSource {
|
||||||
|
/// A style rule stable pointer.
|
||||||
Style(Arc<RwLock<StyleRule>>),
|
Style(Arc<RwLock<StyleRule>>),
|
||||||
|
/// A declaration block stable pointer.
|
||||||
Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
|
Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +62,11 @@ type StyleSourceGuardHandle<'a> =
|
||||||
RwLockReadGuard<'a, StyleRule>,
|
RwLockReadGuard<'a, StyleRule>,
|
||||||
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
|
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
|
||||||
|
|
||||||
|
/// A guard for a given style source.
|
||||||
pub enum StyleSourceGuard<'a> {
|
pub enum StyleSourceGuard<'a> {
|
||||||
|
/// A guard for a style rule.
|
||||||
Style(StyleSourceGuardHandle<'a>),
|
Style(StyleSourceGuardHandle<'a>),
|
||||||
|
/// A guard for a declaration block.
|
||||||
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
|
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +102,8 @@ impl StyleSource {
|
||||||
let _ = write!(writer, " -> {:?}", self.read().declarations);
|
let _ = write!(writer, " -> {:?}", self.read().declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the style source guard, and obtain thus read access to the
|
||||||
|
/// underlying property declaration block.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
|
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
|
||||||
use self::StyleSource::*;
|
use self::StyleSource::*;
|
||||||
|
@ -87,15 +120,19 @@ impl StyleSource {
|
||||||
/// This value exists here so a node that pushes itself to the list can know
|
/// This value exists here so a node that pushes itself to the list can know
|
||||||
/// that is in the free list by looking at is next pointer, and comparing it
|
/// that is in the free list by looking at is next pointer, and comparing it
|
||||||
/// with null.
|
/// with null.
|
||||||
|
///
|
||||||
|
/// The root node doesn't have a null pointer in the free list, but this value.
|
||||||
const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
|
const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
|
||||||
|
|
||||||
impl RuleTree {
|
impl RuleTree {
|
||||||
|
/// Construct a new rule tree.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
RuleTree {
|
RuleTree {
|
||||||
root: StrongRuleNode::new(Box::new(RuleNode::root())),
|
root: StrongRuleNode::new(Box::new(RuleNode::root())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the root rule node.
|
||||||
pub fn root(&self) -> StrongRuleNode {
|
pub fn root(&self) -> StrongRuleNode {
|
||||||
self.root.clone()
|
self.root.clone()
|
||||||
}
|
}
|
||||||
|
@ -105,13 +142,16 @@ impl RuleTree {
|
||||||
self.root.get().dump(writer, 0);
|
self.root.get().dump(writer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dump the rule tree to stdout.
|
||||||
pub fn dump_stdout(&self) {
|
pub fn dump_stdout(&self) {
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
self.dump(&mut stdout);
|
self.dump(&mut stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert the given rules, that must be in proper order by specifity, and
|
||||||
|
/// return the corresponding rule node representing the last inserted one.
|
||||||
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
|
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
|
||||||
where I: Iterator<Item=(StyleSource, Importance)>
|
where I: Iterator<Item=(StyleSource, Importance)>,
|
||||||
{
|
{
|
||||||
let mut current = self.root.clone();
|
let mut current = self.root.clone();
|
||||||
for (source, importance) in iter {
|
for (source, importance) in iter {
|
||||||
|
@ -294,6 +334,7 @@ struct WeakRuleNode {
|
||||||
ptr: *mut RuleNode,
|
ptr: *mut RuleNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A strong reference to a rule node.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StrongRuleNode {
|
pub struct StrongRuleNode {
|
||||||
ptr: *mut RuleNode,
|
ptr: *mut RuleNode,
|
||||||
|
@ -412,14 +453,19 @@ impl StrongRuleNode {
|
||||||
unsafe { &*self.ptr }
|
unsafe { &*self.ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the style source corresponding to this rule node. May return `None`
|
||||||
|
/// if it's the root node, which means that the node hasn't matched any
|
||||||
|
/// rules.
|
||||||
pub fn style_source(&self) -> Option<&StyleSource> {
|
pub fn style_source(&self) -> Option<&StyleSource> {
|
||||||
self.get().source.as_ref()
|
self.get().source.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the importance that this rule node represents.
|
||||||
pub fn importance(&self) -> Importance {
|
pub fn importance(&self) -> Importance {
|
||||||
self.get().importance
|
self.get().importance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an iterator for this rule node and its ancestors.
|
||||||
pub fn self_and_ancestors(&self) -> SelfAndAncestors {
|
pub fn self_and_ancestors(&self) -> SelfAndAncestors {
|
||||||
SelfAndAncestors {
|
SelfAndAncestors {
|
||||||
current: Some(self)
|
current: Some(self)
|
||||||
|
@ -527,6 +573,7 @@ impl StrongRuleNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over a rule node and its ancestors.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SelfAndAncestors<'a> {
|
pub struct SelfAndAncestors<'a> {
|
||||||
current: Option<&'a StrongRuleNode>,
|
current: Option<&'a StrongRuleNode>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue