mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Provide container information in computed::Context and use it to resolve the container queries. This still fails a lot of tests because we are not ensuring that layout is up-to-date when we style the container descendants, but that's expected. Differential Revision: https://phabricator.services.mozilla.com/D146478
207 lines
7.3 KiB
Rust
207 lines
7.3 KiB
Rust
/* 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 https://mozilla.org/MPL/2.0/. */
|
|
|
|
//! Applicable declarations management.
|
|
|
|
use crate::properties::PropertyDeclarationBlock;
|
|
use crate::rule_tree::{CascadeLevel, StyleSource};
|
|
use crate::shared_lock::Locked;
|
|
use crate::stylesheets::layer_rule::LayerOrder;
|
|
use servo_arc::Arc;
|
|
use smallvec::SmallVec;
|
|
|
|
/// List of applicable declarations. This is a transient structure that shuttles
|
|
/// declarations between selector matching and inserting into the rule tree, and
|
|
/// therefore we want to avoid heap-allocation where possible.
|
|
///
|
|
/// In measurements on wikipedia, we pretty much never have more than 8 applicable
|
|
/// declarations, so we could consider making this 8 entries instead of 16.
|
|
/// However, it may depend a lot on workload, and stack space is cheap.
|
|
pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
|
|
|
|
/// Blink uses 18 bits to store source order, and does not check overflow [1].
|
|
/// That's a limit that could be reached in realistic webpages, so we use
|
|
/// 24 bits and enforce defined behavior in the overflow case.
|
|
///
|
|
/// Note that right now this restriction could be lifted if wanted (because we
|
|
/// no longer stash the cascade level in the remaining bits), but we keep it in
|
|
/// place in case we come up with a use-case for them, lacking reports of the
|
|
/// current limit being too small.
|
|
///
|
|
/// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/
|
|
/// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
|
|
const SOURCE_ORDER_BITS: usize = 24;
|
|
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
|
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
|
|
|
|
/// The cascade-level+layer order of this declaration.
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
|
|
pub struct CascadePriority {
|
|
cascade_level: CascadeLevel,
|
|
layer_order: LayerOrder,
|
|
}
|
|
|
|
const_assert_eq!(std::mem::size_of::<CascadePriority>(), std::mem::size_of::<u32>());
|
|
|
|
impl PartialOrd for CascadePriority {
|
|
#[inline]
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for CascadePriority {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.cascade_level.cmp(&other.cascade_level).then_with(|| {
|
|
let ordering = self.layer_order.cmp(&other.layer_order);
|
|
if ordering == std::cmp::Ordering::Equal {
|
|
return ordering;
|
|
}
|
|
// https://drafts.csswg.org/css-cascade-5/#cascade-layering
|
|
//
|
|
// Cascade layers (like declarations) are ordered by order
|
|
// of appearance. When comparing declarations that belong to
|
|
// different layers, then for normal rules the declaration
|
|
// whose cascade layer is last wins, and for important rules
|
|
// the declaration whose cascade layer is first wins.
|
|
//
|
|
// But the style attribute layer for some reason is special.
|
|
if self.cascade_level.is_important() &&
|
|
!self.layer_order.is_style_attribute_layer() &&
|
|
!other.layer_order.is_style_attribute_layer()
|
|
{
|
|
ordering.reverse()
|
|
} else {
|
|
ordering
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl CascadePriority {
|
|
/// Construct a new CascadePriority for a given (level, order) pair.
|
|
pub fn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self {
|
|
Self {
|
|
cascade_level,
|
|
layer_order,
|
|
}
|
|
}
|
|
|
|
/// Returns the layer order.
|
|
#[inline]
|
|
pub fn layer_order(&self) -> LayerOrder {
|
|
self.layer_order
|
|
}
|
|
|
|
/// Returns the cascade level.
|
|
#[inline]
|
|
pub fn cascade_level(&self) -> CascadeLevel {
|
|
self.cascade_level
|
|
}
|
|
|
|
/// Whether this declaration should be allowed if `revert` or `revert-layer`
|
|
/// have been specified on a given origin.
|
|
///
|
|
/// `self` is the priority at which the `revert` or `revert-layer` keyword
|
|
/// have been specified.
|
|
pub fn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool {
|
|
if origin_revert {
|
|
other.cascade_level.origin() < self.cascade_level.origin()
|
|
} else {
|
|
other.unimportant() < self.unimportant()
|
|
}
|
|
}
|
|
|
|
/// Convert this priority from "important" to "non-important", if needed.
|
|
pub fn unimportant(&self) -> Self {
|
|
Self::new(self.cascade_level().unimportant(), self.layer_order())
|
|
}
|
|
|
|
/// Convert this priority from "non-important" to "important", if needed.
|
|
pub fn important(&self) -> Self {
|
|
Self::new(self.cascade_level().important(), self.layer_order())
|
|
}
|
|
}
|
|
|
|
/// A property declaration together with its precedence among rules of equal
|
|
/// specificity so that we can sort them.
|
|
///
|
|
/// This represents the declarations in a given declaration block for a given
|
|
/// importance.
|
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
|
|
pub struct ApplicableDeclarationBlock {
|
|
/// The style source, either a style rule, or a property declaration block.
|
|
#[ignore_malloc_size_of = "Arc"]
|
|
pub source: StyleSource,
|
|
/// The bits containing the source order, cascade level, and shadow cascade
|
|
/// order.
|
|
source_order: u32,
|
|
/// The specificity of the selector.
|
|
pub specificity: u32,
|
|
/// The cascade priority of the rule.
|
|
pub cascade_priority: CascadePriority,
|
|
}
|
|
|
|
impl ApplicableDeclarationBlock {
|
|
/// Constructs an applicable declaration block from a given property
|
|
/// declaration block and importance.
|
|
#[inline]
|
|
pub fn from_declarations(
|
|
declarations: Arc<Locked<PropertyDeclarationBlock>>,
|
|
level: CascadeLevel,
|
|
layer_order: LayerOrder,
|
|
) -> Self {
|
|
ApplicableDeclarationBlock {
|
|
source: StyleSource::from_declarations(declarations),
|
|
source_order: 0,
|
|
specificity: 0,
|
|
cascade_priority: CascadePriority::new(level, layer_order),
|
|
}
|
|
}
|
|
|
|
/// Constructs an applicable declaration block from the given components.
|
|
#[inline]
|
|
pub fn new(
|
|
source: StyleSource,
|
|
source_order: u32,
|
|
level: CascadeLevel,
|
|
specificity: u32,
|
|
layer_order: LayerOrder,
|
|
) -> Self {
|
|
ApplicableDeclarationBlock {
|
|
source,
|
|
source_order: source_order & SOURCE_ORDER_MASK,
|
|
specificity,
|
|
cascade_priority: CascadePriority::new(level, layer_order),
|
|
}
|
|
}
|
|
|
|
/// Returns the source order of the block.
|
|
#[inline]
|
|
pub fn source_order(&self) -> u32 {
|
|
self.source_order
|
|
}
|
|
|
|
/// Returns the cascade level of the block.
|
|
#[inline]
|
|
pub fn level(&self) -> CascadeLevel {
|
|
self.cascade_priority.cascade_level()
|
|
}
|
|
|
|
/// Returns the cascade level of the block.
|
|
#[inline]
|
|
pub fn layer_order(&self) -> LayerOrder {
|
|
self.cascade_priority.layer_order()
|
|
}
|
|
|
|
/// Convenience method to consume self and return the right thing for the
|
|
/// rule tree to iterate over.
|
|
#[inline]
|
|
pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) {
|
|
(self.source, self.cascade_priority)
|
|
}
|
|
}
|
|
|
|
// Size of this struct determines sorting and selector-matching performance.
|
|
size_of_test!(ApplicableDeclarationBlock, 24);
|