use crate::derives::*;
use crate::properties::PropertyDeclarationBlock;
use crate::rule_tree::{CascadeLevel, RuleCascadeFlags, StyleSource};
use crate::shared_lock::Locked;
use crate::stylesheets::layer_rule::LayerOrder;
use servo_arc::Arc;
use smallvec::SmallVec;
pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
const SOURCE_ORDER_BITS: usize = 24;
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct CascadePriority {
cascade_level: CascadeLevel,
flags: RuleCascadeFlags,
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;
}
if self.cascade_level.is_important()
&& !self.layer_order.is_style_attribute_layer()
&& !other.layer_order.is_style_attribute_layer()
{
ordering.reverse()
} else {
ordering
}
})
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RevertKind {
Origin,
Layer,
Rule,
}
impl CascadePriority {
pub fn new(
cascade_level: CascadeLevel,
layer_order: LayerOrder,
flags: RuleCascadeFlags,
) -> Self {
Self {
cascade_level,
flags,
layer_order,
}
}
#[inline]
pub fn flags(&self) -> RuleCascadeFlags {
self.flags
}
#[inline]
pub fn set_flags(&mut self, flags: RuleCascadeFlags) {
self.flags.insert(flags);
}
#[inline]
pub fn layer_order(&self) -> LayerOrder {
self.layer_order
}
#[inline]
pub fn cascade_level(&self) -> CascadeLevel {
self.cascade_level
}
pub fn allows_when_reverted(&self, other: &Self, kind: RevertKind) -> bool {
match kind {
RevertKind::Origin => {
other.cascade_level.origin().origin() < self.cascade_level.origin().origin()
},
RevertKind::Layer => other.unimportant() < self.unimportant(),
RevertKind::Rule => true,
}
}
pub fn unimportant(&self) -> Self {
Self {
cascade_level: self.cascade_level.unimportant(),
flags: self.flags,
layer_order: self.layer_order,
}
}
pub fn important(&self) -> Self {
Self {
cascade_level: self.cascade_level.important(),
flags: self.flags,
layer_order: self.layer_order,
}
}
pub fn same_tree_author_normal_at_root_layer() -> Self {
Self::new(
CascadeLevel::same_tree_author_normal(),
LayerOrder::root(),
RuleCascadeFlags::empty(),
)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct ScopeProximity(u16);
impl PartialOrd for ScopeProximity {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ScopeProximity {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other.0.cmp(&self.0)
}
}
const PROXIMITY_INFINITY: u16 = u16::MAX;
impl ScopeProximity {
pub fn new(proximity: usize) -> Self {
if cfg!(debug_assertions) && proximity >= PROXIMITY_INFINITY as usize {
warn!("Proximity out of bounds");
}
Self(proximity.clamp(0, (PROXIMITY_INFINITY - 1) as usize) as u16)
}
pub fn infinity() -> Self {
Self(PROXIMITY_INFINITY)
}
pub fn get(&self) -> Option<u16> {
(self.0 != PROXIMITY_INFINITY).then(|| self.0)
}
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub struct ApplicableDeclarationBlock {
#[ignore_malloc_size_of = "Arc"]
pub source: StyleSource,
source_order: u32,
pub specificity: u32,
pub scope_proximity: ScopeProximity,
pub cascade_priority: CascadePriority,
}
impl ApplicableDeclarationBlock {
#[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,
scope_proximity: ScopeProximity::infinity(),
cascade_priority: CascadePriority::new(level, layer_order, RuleCascadeFlags::empty()),
}
}
#[inline]
pub fn new(
source: StyleSource,
source_order: u32,
level: CascadeLevel,
specificity: u32,
layer_order: LayerOrder,
scope_proximity: ScopeProximity,
flags: RuleCascadeFlags,
) -> Self {
ApplicableDeclarationBlock {
source,
source_order: source_order & SOURCE_ORDER_MASK,
specificity,
scope_proximity,
cascade_priority: CascadePriority::new(level, layer_order, flags),
}
}
#[inline]
pub fn source_order(&self) -> u32 {
self.source_order
}
#[inline]
pub fn level(&self) -> CascadeLevel {
self.cascade_priority.cascade_level()
}
#[inline]
pub fn layer_order(&self) -> LayerOrder {
self.cascade_priority.layer_order()
}
#[inline]
pub fn scope_proximity(&self) -> ScopeProximity {
self.scope_proximity
}
#[inline]
pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) {
(self.source, self.cascade_priority)
}
#[inline]
pub fn sort_key(&self) -> (LayerOrder, u32, ScopeProximity, u32) {
(
self.layer_order(),
self.specificity,
self.scope_proximity(),
self.source_order(),
)
}
}
size_of_test!(ApplicableDeclarationBlock, 24);