Auto merge of #19721 - emilio:slotted, r=heycam

style: Support ::slotted better.

This allows to selector-match ::slotted, though we still don't parse it.

Bug: 1425834, 1424607, 1425755
Reviewed-by: heycam
MozReview-Commit-ID: ItELHkf2PMl

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19721)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-01-09 07:26:28 -06:00 committed by GitHub
commit bb34b7f54a
21 changed files with 842 additions and 404 deletions

8
Cargo.lock generated
View file

@ -1246,7 +1246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"markup5ever 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"markup5ever 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1721,7 +1721,7 @@ dependencies = [
[[package]]
name = "markup5ever"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3740,7 +3740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"markup5ever 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"markup5ever 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -3885,7 +3885,7 @@ dependencies = [
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum markup5ever 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bccd18e4fab95f4410dc4d714163c2e88dd80e39a2a013998e345f337a569ab"
"checksum markup5ever 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c220b3a3d75543b76e5c1fcab6635a8430ab5f9bfa011d003c3787ae0abf4ffa"
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum metadeps 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2"

View file

@ -363,6 +363,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
LayoutIterator(self.as_node().dom_children())
}
fn is_html_element(&self) -> bool {
unsafe { self.element.is_html_element() }
}
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
unsafe {
(*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc())

View file

@ -98,13 +98,21 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
/// Consumes the builder, producing a Selector.
#[inline(always)]
pub fn build(&mut self, parsed_pseudo: bool) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
pub fn build(
&mut self,
parsed_pseudo: bool,
parsed_slotted: bool,
) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
// Compute the specificity and flags.
let mut spec = SpecificityAndFlags(specificity(self.simple_selectors.iter()));
if parsed_pseudo {
spec.0 |= HAS_PSEUDO_BIT;
}
if parsed_slotted {
spec.0 |= HAS_SLOTTED_BIT;
}
self.build_with_specificity_and_flags(spec)
}
@ -188,18 +196,28 @@ fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
}
pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
pub const HAS_SLOTTED_BIT: u32 = 1 << 31;
/// We use ten bits for each specificity kind (id, class, element), and the two
/// high bits for the pseudo and slotted flags.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpecificityAndFlags(pub u32);
impl SpecificityAndFlags {
#[inline]
pub fn specificity(&self) -> u32 {
self.0 & !HAS_PSEUDO_BIT
self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
}
#[inline]
pub fn has_pseudo_element(&self) -> bool {
(self.0 & HAS_PSEUDO_BIT) != 0
}
#[inline]
pub fn is_slotted(&self) -> bool {
(self.0 & HAS_SLOTTED_BIT) != 0
}
}
const MAX_10BIT: u32 = (1u32 << 10) - 1;

View file

@ -445,14 +445,22 @@ pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
pub struct Selector<Impl: SelectorImpl>(ThinArc<SpecificityAndFlags, Component<Impl>>);
impl<Impl: SelectorImpl> Selector<Impl> {
#[inline]
pub fn specificity(&self) -> u32 {
self.0.header.header.specificity()
}
#[inline]
pub fn has_pseudo_element(&self) -> bool {
self.0.header.header.has_pseudo_element()
}
#[inline]
pub fn is_slotted(&self) -> bool {
self.0.header.header.is_slotted()
}
#[inline]
pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
if !self.has_pseudo_element() {
return None
@ -1219,7 +1227,7 @@ where
builder.push_combinator(combinator);
}
Ok(Selector(builder.build(has_pseudo_element)))
Ok(Selector(builder.build(has_pseudo_element, slotted)))
}
impl<Impl: SelectorImpl> Selector<Impl> {

View file

@ -263,7 +263,9 @@ impl ElementData {
let mut xbl_stylists = SmallVec::<[_; 3]>::new();
let cut_off_inheritance =
element.each_xbl_stylist(|s| xbl_stylists.push(s));
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
xbl_stylists.push((data, quirks_mode))
});
let mut processor = StateAndAttrInvalidationProcessor::new(
shared_context,

View file

@ -31,7 +31,7 @@ use std::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
use stylist::Stylist;
use stylist::{StyleRuleCascadeData, Stylist};
use traversal_flags::TraversalFlags;
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
@ -416,6 +416,20 @@ pub trait TElement
F: FnMut(Self),
{}
/// Return whether this element is an element in the HTML namespace.
fn is_html_element(&self) -> bool;
/// Returns whether this element is a <html:slot> element.
fn is_html_slot_element(&self) -> bool {
self.get_local_name() == &*local_name!("slot") &&
self.is_html_element()
}
/// Return the list of slotted nodes of this node.
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
&[]
}
/// 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> {
@ -760,6 +774,41 @@ pub trait TElement
false
}
/// Executes the callback for each applicable style rule data which isn't
/// the main document's data (which stores UA / author rules).
///
/// 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,
F: FnMut(AtomicRef<'a, StyleRuleCascadeData>, QuirksMode),
{
let cut_off_inheritance = self.each_xbl_stylist(|stylist| {
let quirks_mode = stylist.quirks_mode();
f(
AtomicRef::map(stylist, |stylist| stylist.normal_author_cascade_data()),
quirks_mode,
)
});
let mut current = self.assigned_slot();
while let Some(slot) = current {
slot.each_xbl_stylist(|stylist| {
let quirks_mode = stylist.quirks_mode();
if stylist.slotted_author_cascade_data().is_some() {
f(
AtomicRef::map(stylist, |stylist| stylist.slotted_author_cascade_data().unwrap()),
quirks_mode,
)
}
});
current = slot.assigned_slot();
}
cut_off_inheritance
}
/// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap.
#[cfg(feature = "gecko")]
fn get_css_transitions_info(&self)

View file

@ -8,7 +8,8 @@
use Atom;
use context::QuirksMode;
use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
use invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation};
use invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList};
use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode};
@ -143,7 +144,7 @@ where
&mut self,
element: E,
self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
_sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool {
// TODO(emilio): If the element is not a root element, and
@ -163,7 +164,7 @@ where
let target_vector =
if self.matching_context.scope_element.is_some() {
descendant_invalidations
&mut descendant_invalidations.dom_descendants
} else {
self_invalidations
};

View file

@ -2276,8 +2276,6 @@ cfg_if! {
pub static nsGkAtoms_rect: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms9rectangleE"]
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms3refE"]
pub static nsGkAtoms_ref: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms7refreshE"]
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms3relE"]
@ -2312,8 +2310,6 @@ cfg_if! {
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms10resolutionE"]
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms8resourceE"]
pub static nsGkAtoms_resource: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms9resourcesE"]
pub static nsGkAtoms_resources: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms6resultE"]
@ -2486,14 +2482,6 @@ cfg_if! {
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms10sortLockedE"]
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms12sortResourceE"]
pub static nsGkAtoms_sortResource: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms13sortResource2E"]
pub static nsGkAtoms_sortResource2: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms14sortSeparatorsE"]
pub static nsGkAtoms_sortSeparators: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms15sortStaticsLastE"]
pub static nsGkAtoms_sortStaticsLast: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms6sourceE"]
pub static nsGkAtoms_source: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms5spaceE"]
@ -4374,8 +4362,8 @@ cfg_if! {
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms19forcemessagemanagerE"]
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms16isPreloadBrowserE"]
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms14preloadedStateE"]
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms24scrollbar_start_backwardE"]
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms23scrollbar_start_forwardE"]
@ -7463,8 +7451,6 @@ cfg_if! {
pub static nsGkAtoms_rect: *mut nsStaticAtom;
#[link_name = "?rectangle@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
#[link_name = "?ref@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_ref: *mut nsStaticAtom;
#[link_name = "?refresh@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
#[link_name = "?rel@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
@ -7499,8 +7485,6 @@ cfg_if! {
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
#[link_name = "?resolution@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
#[link_name = "?resource@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_resource: *mut nsStaticAtom;
#[link_name = "?resources@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_resources: *mut nsStaticAtom;
#[link_name = "?result@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
@ -7673,14 +7657,6 @@ cfg_if! {
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
#[link_name = "?sortLocked@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
#[link_name = "?sortResource@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_sortResource: *mut nsStaticAtom;
#[link_name = "?sortResource2@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_sortResource2: *mut nsStaticAtom;
#[link_name = "?sortSeparators@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_sortSeparators: *mut nsStaticAtom;
#[link_name = "?sortStaticsLast@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_sortStaticsLast: *mut nsStaticAtom;
#[link_name = "?source@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_source: *mut nsStaticAtom;
#[link_name = "?space@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
@ -9561,8 +9537,8 @@ cfg_if! {
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
#[link_name = "?forcemessagemanager@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
#[link_name = "?isPreloadBrowser@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
#[link_name = "?preloadedState@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
#[link_name = "?scrollbar_start_backward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
#[link_name = "?scrollbar_start_forward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
@ -12650,8 +12626,6 @@ cfg_if! {
pub static nsGkAtoms_rect: *mut nsStaticAtom;
#[link_name = "\x01?rectangle@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
#[link_name = "\x01?ref@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_ref: *mut nsStaticAtom;
#[link_name = "\x01?refresh@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
#[link_name = "\x01?rel@nsGkAtoms@@2PAVnsStaticAtom@@A"]
@ -12686,8 +12660,6 @@ cfg_if! {
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
#[link_name = "\x01?resolution@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
#[link_name = "\x01?resource@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_resource: *mut nsStaticAtom;
#[link_name = "\x01?resources@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_resources: *mut nsStaticAtom;
#[link_name = "\x01?result@nsGkAtoms@@2PAVnsStaticAtom@@A"]
@ -12860,14 +12832,6 @@ cfg_if! {
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
#[link_name = "\x01?sortLocked@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
#[link_name = "\x01?sortResource@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_sortResource: *mut nsStaticAtom;
#[link_name = "\x01?sortResource2@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_sortResource2: *mut nsStaticAtom;
#[link_name = "\x01?sortSeparators@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_sortSeparators: *mut nsStaticAtom;
#[link_name = "\x01?sortStaticsLast@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_sortStaticsLast: *mut nsStaticAtom;
#[link_name = "\x01?source@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_source: *mut nsStaticAtom;
#[link_name = "\x01?space@nsGkAtoms@@2PAVnsStaticAtom@@A"]
@ -14748,8 +14712,8 @@ cfg_if! {
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
#[link_name = "\x01?forcemessagemanager@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
#[link_name = "\x01?isPreloadBrowser@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
#[link_name = "\x01?preloadedState@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
#[link_name = "\x01?scrollbar_start_backward@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
#[link_name = "\x01?scrollbar_start_forward@nsGkAtoms@@2PAVnsStaticAtom@@A"]
@ -17840,8 +17804,6 @@ macro_rules! atom {
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_rect as *mut _) } }};
("rectangle") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_rectangle as *mut _) } }};
("ref") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_ref as *mut _) } }};
("refresh") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_refresh as *mut _) } }};
("rel") =>
@ -17876,8 +17838,6 @@ macro_rules! atom {
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_resizer as *mut _) } }};
("resolution") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_resolution as *mut _) } }};
("resource") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_resource as *mut _) } }};
("resources") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_resources as *mut _) } }};
("result") =>
@ -18050,14 +18010,6 @@ macro_rules! atom {
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sorthints as *mut _) } }};
("sortLocked") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sortLocked as *mut _) } }};
("sortResource") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sortResource as *mut _) } }};
("sortResource2") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sortResource2 as *mut _) } }};
("sortSeparators") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sortSeparators as *mut _) } }};
("sortStaticsLast") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_sortStaticsLast as *mut _) } }};
("source") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_source as *mut _) } }};
("space") =>
@ -19938,8 +19890,8 @@ macro_rules! atom {
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_AsyncScrollLayerCreationFailed as *mut _) } }};
("forcemessagemanager") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_forcemessagemanager as *mut _) } }};
("isPreloadBrowser") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_isPreloadBrowser as *mut _) } }};
("preloadedState") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_preloadedState as *mut _) } }};
("scrollbar-start-backward") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_scrollbar_start_backward as *mut _) } }};
("scrollbar-start-forward") =>

View file

@ -1597,4 +1597,4 @@ extern "C" {
pub fn Gecko_GetElementsWithId ( aDocument : * const nsIDocument , aId : * mut nsAtom , ) -> * const nsTArray < * mut Element > ;
} extern "C" {
pub fn Gecko_GetBoolPrefValue ( pref_name : * const :: std :: os :: raw :: c_char , ) -> bool ;
}
}

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,7 @@
use cssparser::{BasicParseError, BasicParseErrorKind, Parser, ToCss, Token, CowRcStr, SourceLocation};
use element_state::{DocumentState, ElementState};
use gecko_bindings::structs::CSSPseudoClassType;
use gecko_bindings::structs::{self, CSSPseudoClassType};
use gecko_bindings::structs::RawServoSelectorList;
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use selector_parser::{Direction, SelectorParser};
@ -333,6 +333,13 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
type Impl = SelectorImpl;
type Error = StyleParseErrorKind<'i>;
fn parse_slotted(&self) -> bool {
// NOTE(emilio): Slot assignment and such works per-document, but
// getting a document around here is not trivial, and it's not worth
// anyway to handle this in a per-doc basis.
unsafe { structs::nsContentUtils_sIsWebComponentsEnabled }
}
fn pseudo_element_allows_single_colon(name: &str) -> bool {
// FIXME: -moz-tree check should probably be ascii-case-insensitive.
::selectors::parser::is_css2_pseudo_element(name) ||

View file

@ -610,10 +610,7 @@ impl<'le> GeckoElement<'le> {
self.as_node().node_info().mInner.mNamespaceID
}
fn is_html_element(&self) -> bool {
self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32)
}
#[inline]
fn is_xul_element(&self) -> bool {
self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32)
}
@ -974,6 +971,40 @@ impl<'le> TElement for GeckoElement<'le> {
self.as_node().owner_doc().as_node()
}
#[inline]
fn is_html_element(&self) -> bool {
self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32)
}
/// Return the list of slotted nodes of this node.
#[inline]
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
if !self.is_html_slot_element() || !self.is_in_shadow_tree() {
return &[];
}
let slot: &structs::HTMLSlotElement = unsafe {
mem::transmute(self.0)
};
if cfg!(debug_assertions) {
let base: &RawGeckoElement = &slot._base._base._base._base;
assert_eq!(base as *const _, self.0 as *const _, "Bad cast");
}
let assigned_nodes: &[structs::RefPtr<structs::nsINode>] =
&*slot.mAssignedNodes;
debug_assert_eq!(
mem::size_of::<structs::RefPtr<structs::nsINode>>(),
mem::size_of::<Self::ConcreteNode>(),
"Bad cast!"
);
unsafe { mem::transmute(assigned_nodes) }
}
/// Execute `f` for each anonymous content child element (apart from
/// ::before and ::after) whose originating element is `self`.
fn each_anonymous_content_child<F>(&self, mut f: F)
@ -1795,11 +1826,21 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
parent_node.and_then(|n| n.as_element())
}
#[inline]
fn pseudo_element_originating_element(&self) -> Option<Self> {
debug_assert!(self.implemented_pseudo_element().is_some());
self.closest_non_native_anonymous_ancestor()
}
#[inline]
fn assigned_slot(&self) -> Option<Self> {
let slot = self.get_extended_slots()?._base.mAssignedSlot.mRawPtr;
unsafe {
Some(GeckoElement(&slot.as_ref()?._base._base._base._base))
}
}
#[inline]
fn first_child_element(&self) -> Option<Self> {
let mut child = self.as_node().first_child();

View file

@ -13,7 +13,8 @@ use dom::TElement;
use element_state::ElementState;
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::invalidation_map::*;
use invalidation::element::invalidator::{InvalidationVector, Invalidation, InvalidationProcessor};
use invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
use invalidation::element::restyle_hints::RestyleHint;
use selector_map::SelectorMap;
use selector_parser::Snapshot;
@ -23,7 +24,7 @@ use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::matching::matches_selector;
use smallvec::SmallVec;
use stylesheets::origin::{Origin, OriginSet};
use stylist::Stylist;
use stylist::StyleRuleCascadeData;
#[derive(Debug, PartialEq)]
enum VisitedDependent {
@ -47,7 +48,7 @@ where
classes_removed: &'a SmallVec<[Atom; 8]>,
classes_added: &'a SmallVec<[Atom; 8]>,
state_changes: ElementState,
descendant_invalidations: &'a mut InvalidationVector<'selectors>,
descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
sibling_invalidations: &'a mut InvalidationVector<'selectors>,
invalidates_self: bool,
}
@ -56,7 +57,7 @@ where
/// changes.
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
shared_context: &'a SharedStyleContext<'b>,
xbl_stylists: &'a [AtomicRef<'b, Stylist>],
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
cut_off_inheritance: bool,
element: E,
data: &'a mut ElementData,
@ -67,7 +68,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
/// Creates a new StateAndAttrInvalidationProcessor.
pub fn new(
shared_context: &'a SharedStyleContext<'b>,
xbl_stylists: &'a [AtomicRef<'b, Stylist>],
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
cut_off_inheritance: bool,
element: E,
data: &'a mut ElementData,
@ -83,7 +84,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
Self {
shared_context,
xbl_stylists,
shadow_rule_datas,
cut_off_inheritance,
element,
data,
@ -109,7 +110,7 @@ where
&mut self,
element: E,
_self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool {
debug_assert!(element.has_snapshot(), "Why bothering?");
@ -210,20 +211,18 @@ where
OriginSet::all()
};
self.shared_context.stylist.each_invalidation_map(|invalidation_map, origin| {
self.shared_context.stylist.each_normal_rule_cascade_data(|cascade_data, origin| {
if document_origins.contains(origin.into()) {
collector.collect_dependencies_in_invalidation_map(invalidation_map);
collector.collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
}
});
for stylist in self.xbl_stylists {
// FIXME(emilio): Replace with assert / remove when we
// figure out what to do with the quirks mode mismatches
for &(ref data, quirks_mode) in self.shadow_rule_datas {
// FIXME(emilio): Replace with assert / remove when we figure
// out what to do with the quirks mode mismatches
// (that is, when bug 1406875 is properly fixed).
collector.quirks_mode = stylist.quirks_mode();
stylist.each_invalidation_map(|invalidation_map, _| {
collector.collect_dependencies_in_invalidation_map(invalidation_map);
})
collector.quirks_mode = quirks_mode;
collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
}
collector.invalidates_self
@ -236,7 +235,10 @@ where
//
// This number is completely made-up, but the page that made us add this
// code generated 1960+ invalidations (bug 1420741).
if descendant_invalidations.len() > 150 {
//
// We don't look at slotted_descendants because those don't propagate
// down more than one level anyway.
if descendant_invalidations.dom_descendants.len() > 150 {
self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
}
@ -509,36 +511,52 @@ where
}
fn note_dependency(&mut self, dependency: &'selectors Dependency) {
if dependency.affects_self() {
debug_assert!(self.dependency_may_be_relevant(dependency));
let invalidation_kind = dependency.invalidation_kind();
if matches!(invalidation_kind, DependencyInvalidationKind::Element) {
self.invalidates_self = true;
return;
}
if dependency.affects_descendants() {
debug_assert_ne!(dependency.selector_offset, 0);
debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
debug_assert!(!dependency.affects_later_siblings());
self.descendant_invalidations.push(Invalidation::new(
&dependency.selector,
dependency.selector.len() - dependency.selector_offset + 1,
));
} else if dependency.affects_later_siblings() {
debug_assert_ne!(dependency.selector_offset, 0);
debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
self.sibling_invalidations.push(Invalidation::new(
&dependency.selector,
dependency.selector.len() - dependency.selector_offset + 1,
));
debug_assert_ne!(dependency.selector_offset, 0);
debug_assert_ne!(
dependency.selector_offset,
dependency.selector.len()
);
let invalidation = Invalidation::new(
&dependency.selector,
dependency.selector.len() - dependency.selector_offset + 1,
);
match invalidation_kind {
DependencyInvalidationKind::Element => unreachable!(),
DependencyInvalidationKind::ElementAndDescendants => {
self.invalidates_self = true;
self.descendant_invalidations.dom_descendants.push(invalidation);
}
DependencyInvalidationKind::Descendants => {
self.descendant_invalidations.dom_descendants.push(invalidation);
}
DependencyInvalidationKind::Siblings => {
self.sibling_invalidations.push(invalidation);
}
DependencyInvalidationKind::SlottedElements => {
self.descendant_invalidations.slotted_descendants.push(invalidation);
}
}
}
/// Returns whether `dependency` may cause us to invalidate the style of
/// more elements than what we've already invalidated.
fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool {
if dependency.affects_descendants() || dependency.affects_later_siblings() {
return true;
match dependency.invalidation_kind() {
DependencyInvalidationKind::Element => !self.invalidates_self,
DependencyInvalidationKind::SlottedElements => self.element.is_html_slot_element(),
DependencyInvalidationKind::ElementAndDescendants |
DependencyInvalidationKind::Siblings |
DependencyInvalidationKind::Descendants => true,
}
debug_assert!(dependency.affects_self());
!self.invalidates_self
}
}

View file

@ -351,6 +351,11 @@ impl<'a, E> Element for ElementWrapper<'a, E>
.map(|e| ElementWrapper::new(e, self.snapshot_map))
}
fn assigned_slot(&self) -> Option<Self> {
self.element.assigned_slot()
.map(|e| ElementWrapper::new(e, self.snapshot_map))
}
fn blocks_ancestor_combinators(&self) -> bool {
self.element.blocks_ancestor_combinators()
}

View file

@ -63,6 +63,25 @@ pub struct Dependency {
pub selector_offset: usize,
}
/// The kind of elements down the tree this dependency may affect.
#[derive(Debug, Eq, PartialEq)]
pub enum DependencyInvalidationKind {
/// This dependency may affect the element that changed itself.
Element,
/// This dependency affects the style of the element itself, and also the
/// style of its descendants.
///
/// TODO(emilio): Each time this feels more of a hack for eager pseudos...
ElementAndDescendants,
/// This dependency may affect descendants down the tree.
Descendants,
/// This dependency may affect siblings to the right of the element that
/// changed.
Siblings,
/// This dependency may affect slotted elements of the element that changed.
SlottedElements,
}
impl Dependency {
/// Returns the combinator to the right of the partial selector this
/// dependency represents.
@ -76,28 +95,19 @@ impl Dependency {
Some(self.selector.combinator_at_match_order(self.selector_offset - 1))
}
/// Whether this dependency affects the style of the element.
///
/// NOTE(emilio): pseudo-elements need to be here to account for eager
/// pseudos, since they just grab the style from the originating element.
///
/// TODO(emilio): We could look at the selector itself to see if it's an
/// eager pseudo, and return false here if not.
pub fn affects_self(&self) -> bool {
matches!(self.combinator(), None | Some(Combinator::PseudoElement))
}
/// Whether this dependency may affect style of any of our descendants.
pub fn affects_descendants(&self) -> bool {
matches!(self.combinator(), Some(Combinator::PseudoElement) |
Some(Combinator::Child) |
Some(Combinator::Descendant))
}
/// Whether this dependency may affect style of any of our later siblings.
pub fn affects_later_siblings(&self) -> bool {
matches!(self.combinator(), Some(Combinator::NextSibling) |
Some(Combinator::LaterSibling))
/// The kind of invalidation that this would generate.
pub fn invalidation_kind(&self) -> DependencyInvalidationKind {
match self.combinator() {
None => DependencyInvalidationKind::Element,
Some(Combinator::Child) |
Some(Combinator::Descendant) => DependencyInvalidationKind::Descendants,
Some(Combinator::LaterSibling) |
Some(Combinator::NextSibling) => DependencyInvalidationKind::Siblings,
// TODO(emilio): We could look at the selector itself to see if it's
// an eager pseudo, and return only Descendants here if not.
Some(Combinator::PseudoElement) => DependencyInvalidationKind::ElementAndDescendants,
Some(Combinator::SlotAssignment) => DependencyInvalidationKind::SlottedElements,
}
}
}

View file

@ -39,7 +39,7 @@ where
&mut self,
element: E,
self_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut InvalidationVector<'a>,
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool;
@ -58,6 +58,25 @@ where
fn invalidated_descendants(&mut self, element: E, child: E);
}
/// Different invalidation lists for descendants.
#[derive(Debug, Default)]
pub struct DescendantInvalidationLists<'a> {
/// Invalidations for normal DOM children and pseudo-elements.
///
/// TODO(emilio): Having a list of invalidations just for pseudo-elements
/// may save some work here and there.
pub dom_descendants: InvalidationVector<'a>,
/// Invalidations for slotted children of an element.
pub slotted_descendants: InvalidationVector<'a>,
}
impl<'a> DescendantInvalidationLists<'a> {
fn is_empty(&self) -> bool {
self.dom_descendants.is_empty() &&
self.slotted_descendants.is_empty()
}
}
/// The struct that takes care of encapsulating all the logic on where and how
/// element styles need to be invalidated.
pub struct TreeStyleInvalidator<'a, 'b, E, P: 'a>
@ -75,13 +94,22 @@ where
/// A vector of invalidations, optimized for small invalidation sets.
pub type InvalidationVector<'a> = SmallVec<[Invalidation<'a>; 10]>;
/// The kind of descendant invalidation we're processing.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum DescendantInvalidationKind {
/// A DOM descendant invalidation.
Dom,
/// A ::slotted() descendant invalidation.
Slotted,
}
/// The kind of invalidation we're processing.
///
/// We can use this to avoid pushing invalidations of the same kind to our
/// descendants or siblings.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum InvalidationKind {
Descendant,
Descendant(DescendantInvalidationKind),
Sibling,
}
@ -126,21 +154,27 @@ impl<'a> Invalidation<'a> {
//
// We should be able to do better here!
match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Descendant |
Combinator::LaterSibling |
Combinator::PseudoElement => true,
Combinator::SlotAssignment |
Combinator::NextSibling |
Combinator::Child => false,
_ => true,
}
}
fn kind(&self) -> InvalidationKind {
if self.offset == 0 {
return InvalidationKind::Descendant;
return InvalidationKind::Descendant(DescendantInvalidationKind::Dom);
}
if self.selector.combinator_at_parse_order(self.offset - 1).is_ancestor() {
InvalidationKind::Descendant
} else {
InvalidationKind::Sibling
match self.selector.combinator_at_parse_order(self.offset - 1) {
Combinator::Child |
Combinator::Descendant |
Combinator::PseudoElement => InvalidationKind::Descendant(DescendantInvalidationKind::Dom),
Combinator::SlotAssignment => InvalidationKind::Descendant(DescendantInvalidationKind::Slotted),
Combinator::NextSibling |
Combinator::LaterSibling => InvalidationKind::Sibling,
}
}
}
@ -230,7 +264,7 @@ where
debug!("StyleTreeInvalidator::invalidate({:?})", self.element);
let mut self_invalidations = InvalidationVector::new();
let mut descendant_invalidations = InvalidationVector::new();
let mut descendant_invalidations = DescendantInvalidationLists::default();
let mut sibling_invalidations = InvalidationVector::new();
let mut invalidated_self = self.processor.collect_invalidations(
@ -242,7 +276,7 @@ where
debug!("Collected invalidations (self: {}): ", invalidated_self);
debug!(" > self: {}, {:?}", self_invalidations.len(), self_invalidations);
debug!(" > descendants: {}, {:?}", descendant_invalidations.len(), descendant_invalidations);
debug!(" > descendants: {:?}", descendant_invalidations);
debug!(" > siblings: {}, {:?}", sibling_invalidations.len(), sibling_invalidations);
let invalidated_self_from_collection = invalidated_self;
@ -251,6 +285,7 @@ where
&self_invalidations,
&mut descendant_invalidations,
&mut sibling_invalidations,
DescendantInvalidationKind::Dom,
);
if invalidated_self && !invalidated_self_from_collection {
@ -260,7 +295,11 @@ where
let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
let invalidated_siblings = self.invalidate_siblings(&mut sibling_invalidations);
InvalidationResult { invalidated_self, invalidated_descendants, invalidated_siblings }
InvalidationResult {
invalidated_self,
invalidated_descendants,
invalidated_siblings,
}
}
/// Go through later DOM siblings, invalidating style as needed using the
@ -286,7 +325,8 @@ where
self.processor,
);
let mut invalidations_for_descendants = InvalidationVector::new();
let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let invalidated_sibling =
sibling_invalidator.process_sibling_invalidations(
&mut invalidations_for_descendants,
@ -301,7 +341,7 @@ where
any_invalidated |=
sibling_invalidator.invalidate_descendants(
&invalidations_for_descendants
&invalidations_for_descendants,
);
if sibling_invalidations.is_empty() {
@ -324,7 +364,8 @@ where
let result = self.invalidate_child(
child,
invalidations,
&mut sibling_invalidations
&mut sibling_invalidations,
DescendantInvalidationKind::Dom,
);
// Roots of NAC subtrees can indeed generate sibling invalidations, but
@ -344,8 +385,10 @@ where
child: E,
invalidations: &[Invalidation<'b>],
sibling_invalidations: &mut InvalidationVector<'b>,
descendant_invalidation_kind: DescendantInvalidationKind,
) -> bool {
let mut invalidations_for_descendants = InvalidationVector::new();
let mut invalidations_for_descendants =
DescendantInvalidationLists::default();
let mut invalidated_child = false;
let invalidated_descendants = {
@ -366,13 +409,16 @@ where
invalidations,
&mut invalidations_for_descendants,
sibling_invalidations,
descendant_invalidation_kind,
);
if invalidated_child {
child_invalidator.processor.invalidated_self(child);
}
child_invalidator.invalidate_descendants(&invalidations_for_descendants)
child_invalidator.invalidate_descendants(
&invalidations_for_descendants,
)
};
// The child may not be a flattened tree child of the current element,
@ -418,10 +464,6 @@ where
//
// This probably needs a shadow root check on `child` here, and
// recursing if that's the case.
//
// Also, what's the deal with HTML <content>? We don't need to
// support that for now, though we probably need to recurse into the
// distributed children too.
let child = match child.as_element() {
Some(e) => e,
None => continue,
@ -431,15 +473,14 @@ where
child,
invalidations,
&mut sibling_invalidations,
DescendantInvalidationKind::Dom,
);
}
any_descendant
}
/// Given a descendant invalidation list, go through the current element's
/// descendants, and invalidate style on them.
fn invalidate_descendants(
fn invalidate_slotted_elements(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
@ -447,6 +488,83 @@ where
return false;
}
let mut any = false;
let mut sibling_invalidations = InvalidationVector::new();
let element = self.element;
for node in element.slotted_nodes() {
let element = match node.as_element() {
Some(e) => e,
None => continue,
};
any |= self.invalidate_child(
element,
invalidations,
&mut sibling_invalidations,
DescendantInvalidationKind::Slotted,
);
debug_assert!(
sibling_invalidations.is_empty(),
"::slotted() shouldn't have sibling combinators to the right, \
this makes no sense! {:?}",
sibling_invalidations
);
}
any
}
fn invalidate_non_slotted_descendants(
&mut self,
invalidations: &[Invalidation<'b>],
) -> bool {
if invalidations.is_empty() {
return false;
}
if self.processor.light_tree_only() {
let node = self.element.as_node();
return self.invalidate_dom_descendants_of(node, invalidations);
}
let mut any_descendant = false;
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);
}
if let Some(before) = self.element.before_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(before, invalidations);
}
let node = self.element.as_node();
any_descendant |=
self.invalidate_dom_descendants_of(node, invalidations);
if let Some(after) = self.element.after_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(after, invalidations);
}
any_descendant |= self.invalidate_nac(invalidations);
any_descendant
}
/// Given the descendant invalidation lists, go through the current
/// element's descendants, and invalidate style on them.
fn invalidate_descendants(
&mut self,
invalidations: &DescendantInvalidationLists<'b>,
) -> bool {
if invalidations.is_empty() {
return false;
}
debug!("StyleTreeInvalidator::invalidate_descendants({:?})",
self.element);
debug!(" > {:?}", invalidations);
@ -465,35 +583,12 @@ where
}
}
if self.processor.light_tree_only() {
let node = self.element.as_node();
return self.invalidate_dom_descendants_of(node, invalidations);
}
let mut any_descendant = false;
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);
}
// TODO(emilio): Having a list of invalidations just for pseudo-elements
// may save some work here and there.
if let Some(before) = self.element.before_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(before, invalidations);
}
let node = self.element.as_node();
any_descendant |=
self.invalidate_dom_descendants_of(node, invalidations);
if let Some(after) = self.element.after_pseudo_element() {
any_descendant |=
self.invalidate_pseudo_element_or_nac(after, invalidations);
}
any_descendant |= self.invalidate_nac(invalidations);
self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
any_descendant |=
self.invalidate_slotted_elements(&invalidations.slotted_descendants);
any_descendant
}
@ -511,7 +606,7 @@ where
/// Returns whether invalidated the current element's style.
fn process_sibling_invalidations(
&mut self,
descendant_invalidations: &mut InvalidationVector<'b>,
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>,
) -> bool {
let mut i = 0;
@ -547,8 +642,9 @@ where
fn process_descendant_invalidations(
&mut self,
invalidations: &[Invalidation<'b>],
descendant_invalidations: &mut InvalidationVector<'b>,
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>,
descendant_invalidation_kind: DescendantInvalidationKind,
) -> bool {
let mut invalidated = false;
@ -557,14 +653,19 @@ where
invalidation,
descendant_invalidations,
sibling_invalidations,
InvalidationKind::Descendant,
InvalidationKind::Descendant(descendant_invalidation_kind),
);
invalidated |= result.invalidated_self;
if invalidation.effective_for_next() {
let mut invalidation = invalidation.clone();
invalidation.matched_by_any_previous |= result.matched;
descendant_invalidations.push(invalidation.clone());
debug_assert_eq!(
descendant_invalidation_kind,
DescendantInvalidationKind::Dom,
"Slotted invalidations don't propagate."
);
descendant_invalidations.dom_descendants.push(invalidation);
}
}
@ -580,7 +681,7 @@ where
fn process_invalidation(
&mut self,
invalidation: &Invalidation<'b>,
descendant_invalidations: &mut InvalidationVector<'b>,
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
sibling_invalidations: &mut InvalidationVector<'b>,
invalidation_kind: InvalidationKind,
) -> SingleInvalidationResult {
@ -732,8 +833,11 @@ where
already been matched before");
} else {
match next_invalidation_kind {
InvalidationKind::Descendant => {
descendant_invalidations.push(next_invalidation);
InvalidationKind::Descendant(DescendantInvalidationKind::Dom) => {
descendant_invalidations.dom_descendants.push(next_invalidation);
}
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => {
descendant_invalidations.slotted_descendants.push(next_invalidation);
}
InvalidationKind::Sibling => {
sibling_invalidations.push(next_invalidation);

View file

@ -106,6 +106,13 @@ pub struct SelectorMap<T: 'static> {
pub count: usize,
}
impl<T: 'static> Default for SelectorMap<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
// FIXME(Manishearth) the 'static bound can be removed when
// our HashMap fork (hashglobe) is able to use NonZero,
// or when stdlib gets fallible collections

View file

@ -668,6 +668,17 @@ impl<E: TElement> StyleSharingCache<E> {
return None;
}
// If the elements are not assigned to the same slot they could match
// different ::slotted() rules in the slot scope.
//
// If two elements are assigned to different slots, even within the same
// shadow root, they could match different rules, due to the slot being
// assigned to yet another slot in another shadow root.
if target.element.assigned_slot() != candidate.element.assigned_slot() {
trace!("Miss: Different style scopes");
return None;
}
if *target.get_local_name() != *candidate.element.get_local_name() {
trace!("Miss: Local Name");
return None;

View file

@ -133,6 +133,7 @@ where
}
/// The type of rebuild that we need to do for a given stylesheet.
#[derive(Clone, Copy, Debug)]
pub enum SheetRebuildKind {
/// A full rebuild, of both cascade data and invalidation data.
Full,

View file

@ -36,6 +36,7 @@ use selectors::visitor::SelectorVisitor;
use servo_arc::{Arc, ArcBorrow};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use smallbitvec::SmallBitVec;
use smallvec::SmallVec;
use std::ops;
use std::sync::Mutex;
use style_traits::viewport::ViewportConstraints;
@ -132,7 +133,7 @@ impl UserAgentCascadeDataCache {
}
#[cfg(feature = "gecko")]
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
sizes.mOther += self.entries.shallow_size_of(ops);
for arc in self.entries.iter() {
// These are primary Arc references that can be measured
@ -465,27 +466,30 @@ impl Stylist {
/// Returns the number of revalidation_selectors.
pub fn num_revalidation_selectors(&self) -> usize {
self.cascade_data.iter_origins()
.map(|(d, _)| d.selectors_for_cache_revalidation.len()).sum()
.map(|(data, _)| {
data.normal_rule_data.selectors_for_cache_revalidation.len() +
data.slotted_rule_data.as_ref().map_or(0, |d| {
d.selectors_for_cache_revalidation.len()
})
}).sum()
}
/// Returns the number of entries in invalidation maps.
pub fn num_invalidations(&self) -> usize {
self.cascade_data.iter_origins()
.map(|(d, _)| d.invalidation_map.len()).sum()
.map(|(data, _)| {
data.normal_rule_data.invalidation_map.len() +
data.slotted_rule_data.as_ref().map_or(0, |d| d.invalidation_map.len())
}).sum()
}
/// Invokes `f` with the `InvalidationMap` for each origin.
///
/// NOTE(heycam) This might be better as an `iter_invalidation_maps`, once
/// we have `impl trait` and can return that easily without bothering to
/// create a whole new iterator type.
pub fn each_invalidation_map<'a, F>(&'a self, mut f: F)
where
F: FnMut(&'a InvalidationMap, Origin)
{
for (data, origin) in self.cascade_data.iter_origins() {
f(&data.invalidation_map, origin)
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule.
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.cascade_data.iter_origins()
.any(|(d, _)| {
d.normal_rule_data.has_document_state_dependency(state)
})
}
/// Flush the list of stylesheets if they changed, ensuring the stylist is
@ -601,40 +605,39 @@ impl Stylist {
self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard)
}
/// Returns whether the given attribute might appear in an attribute
/// selector of some rule in the stylist.
pub fn might_have_attribute_dependency(
&self,
local_name: &LocalName,
) -> bool {
if *local_name == local_name!("style") {
self.cascade_data
.iter_origins()
.any(|(d, _)| d.style_attribute_dependency)
} else {
self.cascade_data
.iter_origins()
.any(|(d, _)| {
d.attribute_dependencies
.might_contain_hash(local_name.get_hash())
})
/// Executes `f` on each of the normal rule cascade datas in this styleset.
pub fn each_normal_rule_cascade_data<'a, F>(&'a self, mut f: F)
where
F: FnMut(&'a StyleRuleCascadeData, Origin),
{
for (data, origin) in self.cascade_data.iter_origins() {
f(&data.normal_rule_data, origin);
}
}
/// Returns whether the given ElementState bit is relied upon by a selector
/// of some rule in the stylist.
pub fn has_state_dependency(&self, state: ElementState) -> bool {
self.cascade_data
.iter_origins()
.any(|(d, _)| d.state_dependencies.intersects(state))
}
/// Returns whether for any of the applicable style rule data a given
/// condition is true.
pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
where
E: TElement,
F: FnMut(&StyleRuleCascadeData, QuirksMode) -> bool,
{
if f(&self.cascade_data.user_agent.cascade_data.normal_rule_data, self.quirks_mode()) {
return true;
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule in the stylist.
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.cascade_data
.iter_origins()
.any(|(d, _)| d.document_state_dependencies.intersects(state))
let mut maybe = false;
let cut_off = element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
maybe = maybe || f(&*data, quirks_mode);
});
if maybe || cut_off {
return maybe;
}
f(&self.cascade_data.author.normal_rule_data, self.quirks_mode()) ||
f(&self.cascade_data.user.normal_rule_data, self.quirks_mode())
}
/// Computes the style for a given "precomputed" pseudo-element, taking the
@ -1232,7 +1235,7 @@ impl Stylist {
rule_hash_target.matches_user_and_author_rules();
// Step 1: Normal user-agent rules.
if let Some(map) = self.cascade_data.user_agent.cascade_data.borrow_for_pseudo(pseudo_element) {
if let Some(map) = self.cascade_data.user_agent.cascade_data.normal_rules(pseudo_element) {
map.get_all_matching_rules(
element,
&rule_hash_target,
@ -1270,7 +1273,7 @@ impl Stylist {
// Which may be more what you would probably expect.
if matches_user_and_author_rules {
// Step 3a: User normal rules.
if let Some(map) = self.cascade_data.user.borrow_for_pseudo(pseudo_element) {
if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
map.get_all_matching_rules(
element,
&rule_hash_target,
@ -1281,15 +1284,47 @@ impl Stylist {
CascadeLevel::UserNormal,
);
}
} else {
debug!("skipping user rules");
}
// Step 3b: XBL rules.
// Step 3b: XBL / Shadow DOM rules.
//
// TODO(emilio): Cascade order here is wrong for Shadow DOM. In
// particular, normally document rules override ::slotted() rules, but
// for !important it should be the other way around. So probably we need
// to add some sort of AuthorScoped cascade level or something.
if !only_default_rules {
// Match slotted rules in reverse order, so that the outer slotted
// rules come before the inner rules (and thus have less priority).
let mut slots = SmallVec::<[_; 3]>::new();
let mut current = rule_hash_target.assigned_slot();
while let Some(slot) = current {
slots.push(slot);
current = slot.assigned_slot();
}
for slot in slots.iter().rev() {
slot.each_xbl_stylist(|stylist| {
if let Some(map) = stylist.cascade_data.author.slotted_rules(pseudo_element) {
map.get_all_matching_rules(
element,
&rule_hash_target,
applicable_declarations,
context,
self.quirks_mode,
flags_setter,
CascadeLevel::AuthorNormal
);
}
});
}
}
// FIXME(emilio): It looks very wrong to match XBL / Shadow DOM rules
// even for getDefaultComputedStyle!
let cut_off_inheritance = element.each_xbl_stylist(|stylist| {
// ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets
// under eAuthorSheetFeatures level.
if let Some(map) = stylist.cascade_data.author.borrow_for_pseudo(pseudo_element) {
if let Some(map) = stylist.cascade_data.author.normal_rules(pseudo_element) {
// NOTE(emilio): This is needed because the XBL stylist may
// think it has a different quirks mode than the document.
//
@ -1320,7 +1355,7 @@ impl Stylist {
!cut_off_inheritance
{
// Step 3c: Author normal rules.
if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
map.get_all_matching_rules(
element,
&rule_hash_target,
@ -1331,8 +1366,6 @@ impl Stylist {
CascadeLevel::AuthorNormal
);
}
} else {
debug!("skipping author normal rules");
}
if !only_default_rules {
@ -1368,8 +1401,6 @@ impl Stylist {
)
);
}
} else {
debug!("skipping style attr and SMIL & animation rules");
}
//
@ -1388,8 +1419,6 @@ impl Stylist {
)
);
}
} else {
debug!("skipping transition rules");
}
}
@ -1412,23 +1441,26 @@ impl Stylist {
}
let hash = id.get_hash();
for (data, _) in self.cascade_data.iter_origins() {
if data.mapped_ids.might_contain_hash(hash) {
return true;
}
}
self.any_applicable_rule_data(element, |data, _| {
data.mapped_ids.might_contain_hash(hash)
})
}
let mut xbl_rules_may_contain = false;
/// Returns the cascade data for the normal rules.
#[inline]
pub fn normal_author_cascade_data(&self) -> &StyleRuleCascadeData {
&self.cascade_data.author.normal_rule_data
}
element.each_xbl_stylist(|stylist| {
xbl_rules_may_contain = xbl_rules_may_contain ||
stylist.cascade_data.author.mapped_ids.might_contain_hash(hash)
});
xbl_rules_may_contain
/// Returns the cascade data for the slotted rules in this scope, if any.
#[inline]
pub fn slotted_author_cascade_data(&self) -> Option<&StyleRuleCascadeData> {
self.cascade_data.author.slotted_rule_data.as_ref().map(|d| &**d)
}
/// Returns the registered `@keyframes` animation for the specified name.
///
/// FIXME(emilio): This needs to account for the element rules.
#[inline]
pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> {
self.cascade_data
@ -1466,7 +1498,7 @@ impl Stylist {
// this in the caller by asserting that the bitvecs are same-length.
let mut results = SmallBitVec::new();
for (data, _) in self.cascade_data.iter_origins() {
data.selectors_for_cache_revalidation.lookup(
data.normal_rule_data.selectors_for_cache_revalidation.lookup(
element,
self.quirks_mode,
|selector_and_hashes| {
@ -1483,10 +1515,10 @@ impl Stylist {
);
}
element.each_xbl_stylist(|stylist| {
stylist.cascade_data.author.selectors_for_cache_revalidation.lookup(
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
data.selectors_for_cache_revalidation.lookup(
element,
stylist.quirks_mode,
quirks_mode,
|selector_and_hashes| {
results.push(matches_selector(
&selector_and_hashes.selector,
@ -1841,14 +1873,10 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
}
}
/// Data resulting from performing the CSS cascade that is specific to a given
/// origin.
///
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
/// A set of rules for element and pseudo-elements.
#[derive(Debug, Default)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Debug)]
struct CascadeData {
struct ElementAndPseudoRules {
/// Rules from stylesheets at this `CascadeData`'s origin.
element_map: SelectorMap<Rule>,
@ -1859,12 +1887,65 @@ struct CascadeData {
/// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for
/// `precomputed_values_for_pseudo`) without duplicating a lot of code.
pseudos_map: PerPseudoElementMap<Box<SelectorMap<Rule>>>,
}
/// A map with all the animations at this `CascadeData`'s origin, indexed
/// by name.
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
impl ElementAndPseudoRules {
#[inline(always)]
fn insert(
&mut self,
rule: Rule,
pseudo_element: Option<&PseudoElement>,
quirks_mode: QuirksMode,
) -> Result<(), FailedAllocationError> {
debug_assert!(pseudo_element.map_or(true, |pseudo| !pseudo.is_precomputed()));
/// The invalidation map for the rules at this origin.
let map = match pseudo_element {
None => &mut self.element_map,
Some(pseudo) => {
self.pseudos_map.get_or_insert_with(
&pseudo.canonical(),
|| Box::new(SelectorMap::new())
)
}
};
map.insert(rule, quirks_mode)
}
fn clear(&mut self) {
self.element_map.clear();
self.pseudos_map.clear();
}
#[inline]
fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
match pseudo {
Some(pseudo) => self.pseudos_map.get(&pseudo.canonical()).map(|p| &**p),
None => Some(&self.element_map),
}
}
/// Measures heap usage.
#[cfg(feature = "gecko")]
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
sizes.mElementAndPseudosMaps += self.element_map.size_of(ops);
for elem in self.pseudos_map.iter() {
if let Some(ref elem) = *elem {
sizes.mElementAndPseudosMaps += <Box<_> as MallocSizeOf>::size_of(elem, ops);
}
}
}
}
/// Cascade data generated from style rules.
#[derive(Debug)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct StyleRuleCascadeData {
/// The actual style rules.
rules: ElementAndPseudoRules,
/// The invalidation map for these rules.
invalidation_map: InvalidationMap,
/// The attribute local names that appear in attribute selectors. Used
@ -1904,6 +1985,146 @@ struct CascadeData {
/// tree-structural state like child index and pseudos).
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
}
impl StyleRuleCascadeData {
#[inline(always)]
fn insert(
&mut self,
rule: Rule,
pseudo_element: Option<&PseudoElement>,
quirks_mode: QuirksMode,
rebuild_kind: SheetRebuildKind,
) -> Result<(), FailedAllocationError> {
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map.note_selector(&rule.selector, quirks_mode)?;
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
};
rule.selector.visit(&mut visitor);
if visitor.needs_revalidation {
self.selectors_for_cache_revalidation.insert(
RevalidationSelectorAndHashes::new(
rule.selector.clone(),
rule.hashes.clone(),
),
quirks_mode
)?;
}
}
self.rules.insert(rule, pseudo_element, quirks_mode)
}
/// Returns the invalidation map.
#[inline]
pub fn invalidation_map(&self) -> &InvalidationMap {
&self.invalidation_map
}
#[cfg(feature = "gecko")]
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.rules.add_size_of(ops, sizes);
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
}
fn clear_cascade_data(&mut self) {
self.rules.clear();
}
fn clear(&mut self) {
self.clear_cascade_data();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
self.selectors_for_cache_revalidation.clear();
}
/// Returns whether the given attribute might appear in an attribute
/// selector of some rule.
#[inline]
pub fn might_have_attribute_dependency(
&self,
local_name: &LocalName,
) -> bool {
if *local_name == local_name!("style") {
return self.style_attribute_dependency
}
self.attribute_dependencies.might_contain_hash(local_name.get_hash())
}
/// Returns whether the given ElementState bit is relied upon by a selector
/// of some rule.
#[inline]
pub fn has_state_dependency(&self, state: ElementState) -> bool {
self.state_dependencies.intersects(state)
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule in the stylist.
#[inline]
fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.document_state_dependencies.intersects(state)
}
}
impl StyleRuleCascadeData {
fn new() -> Self {
Self {
rules: ElementAndPseudoRules::default(),
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
selectors_for_cache_revalidation: SelectorMap::new(),
}
}
#[inline]
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.rules.borrow_for_pseudo(pseudo)
}
}
/// Data resulting from performing the CSS cascade that is specific to a given
/// origin.
///
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Debug)]
struct CascadeData {
/// The data coming from normal style rules that apply to elements at this
/// cascade level.
normal_rule_data: StyleRuleCascadeData,
/// The data coming from ::slotted() pseudo-element rules.
///
/// We need to store them separately because an element needs to match
/// ::slotted() pseudo-element rules in different shadow roots.
///
/// In particular, we need to go through all the style data in all the
/// containing style scopes starting from the closest assigned slot.
slotted_rule_data: Option<Box<StyleRuleCascadeData>>,
/// A map with all the animations at this `CascadeData`'s origin, indexed
/// by name.
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
/// Effective media query results cached from the last rebuild.
effective_media_query_results: EffectiveMediaQueryResults,
@ -1925,17 +2146,10 @@ struct CascadeData {
impl CascadeData {
fn new() -> Self {
Self {
element_map: SelectorMap::new(),
pseudos_map: PerPseudoElementMap::default(),
normal_rule_data: StyleRuleCascadeData::new(),
slotted_rule_data: None,
animations: Default::default(),
extra_data: ExtraStyleData::default(),
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
selectors_for_cache_revalidation: SelectorMap::new(),
effective_media_query_results: EffectiveMediaQueryResults::new(),
rules_source_order: 0,
num_selectors: 0,
@ -1943,6 +2157,16 @@ impl CascadeData {
}
}
#[inline]
fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.normal_rule_data.rules(pseudo)
}
#[inline]
fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.slotted_rule_data.as_ref().and_then(|d| d.rules(pseudo))
}
/// Collects all the applicable media query results into `results`.
///
/// This duplicates part of the logic in `add_stylesheet`, which is
@ -2015,8 +2239,10 @@ impl CascadeData {
for selector in &style_rule.selectors.0 {
self.num_selectors += 1;
let map = match selector.pseudo_element() {
Some(pseudo) if pseudo.is_precomputed() => {
let pseudo_element = selector.pseudo_element();
if let Some(pseudo) = pseudo_element {
if pseudo.is_precomputed() {
debug_assert!(selector.is_universal());
debug_assert!(matches!(origin, Origin::UserAgent));
@ -2030,50 +2256,35 @@ impl CascadeData {
CascadeLevel::UANormal,
selector.specificity()
));
continue;
}
None => &mut self.element_map,
Some(pseudo) => {
self.pseudos_map
.get_or_insert_with(&pseudo.canonical(), || Box::new(SelectorMap::new()))
}
};
}
let hashes =
AncestorHashes::new(&selector, quirks_mode);
let rule = Rule::new(
selector.clone(),
hashes.clone(),
hashes,
locked.clone(),
self.rules_source_order
);
map.insert(rule, quirks_mode)?;
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map
.note_selector(selector, quirks_mode)?;
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
};
selector.visit(&mut visitor);
if visitor.needs_revalidation {
self.selectors_for_cache_revalidation.insert(
RevalidationSelectorAndHashes::new(selector.clone(), hashes),
quirks_mode
)?;
let style_rule_cascade_data = if selector.is_slotted() {
if self.slotted_rule_data.is_none() {
self.slotted_rule_data = Some(Box::new(StyleRuleCascadeData::new()));
}
}
self.slotted_rule_data.as_mut().unwrap()
} else {
&mut self.normal_rule_data
};
style_rule_cascade_data.insert(
rule,
pseudo_element,
quirks_mode,
rebuild_kind,
)?;
}
self.rules_source_order += 1;
}
@ -2223,18 +2434,12 @@ impl CascadeData {
true
}
#[inline]
fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
match pseudo {
Some(pseudo) => self.pseudos_map.get(&pseudo.canonical()).map(|p| &**p),
None => Some(&self.element_map),
}
}
/// Clears the cascade data, but not the invalidation data.
fn clear_cascade_data(&mut self) {
self.element_map.clear();
self.pseudos_map.clear();
self.normal_rule_data.clear_cascade_data();
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear_cascade_data();
}
self.animations.clear();
self.extra_data.clear();
self.rules_source_order = 0;
@ -2244,33 +2449,21 @@ impl CascadeData {
fn clear(&mut self) {
self.clear_cascade_data();
self.normal_rule_data.clear();
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear();
}
self.effective_media_query_results.clear();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
self.selectors_for_cache_revalidation.clear();
}
/// Measures heap usage.
#[cfg(feature = "gecko")]
pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
sizes.mElementAndPseudosMaps += self.element_map.size_of(ops);
for elem in self.pseudos_map.iter() {
if let Some(ref elem) = *elem {
sizes.mElementAndPseudosMaps += <Box<_> as MallocSizeOf>::size_of(elem, ops);
}
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.normal_rule_data.add_size_of(ops, sizes);
if let Some(ref slotted_rules) = self.slotted_rule_data {
slotted_rules.add_size_of(ops, sizes);
}
sizes.mOther += self.animations.size_of(ops);
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
sizes.mOther += self.effective_media_query_results.size_of(ops);
sizes.mOther += self.extra_data.size_of(ops);
}

View file

@ -4326,25 +4326,14 @@ pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
) -> bool {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let element = GeckoElement(element);
let mut has_dep = false;
unsafe {
Atom::with(local_name, |atom| {
has_dep = data.stylist.might_have_attribute_dependency(atom);
if !has_dep {
// TODO(emilio): Consider optimizing this storing attribute
// dependencies from UA sheets separately, so we could optimize
// the above lookup if cut_off_inheritance is true.
element.each_xbl_stylist(|stylist| {
has_dep =
has_dep || stylist.might_have_attribute_dependency(atom);
});
}
data.stylist.any_applicable_rule_data(element, |data, _| {
data.might_have_attribute_dependency(atom)
})
})
}
has_dep
}
#[no_mangle]
@ -4358,17 +4347,9 @@ pub extern "C" fn Servo_StyleSet_HasStateDependency(
let state = ElementState::from_bits_truncate(state);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let mut has_dep = data.stylist.has_state_dependency(state);
if !has_dep {
// TODO(emilio): Consider optimizing this storing attribute
// dependencies from UA sheets separately, so we could optimize
// the above lookup if cut_off_inheritance is true.
element.each_xbl_stylist(|stylist| {
has_dep = has_dep || stylist.has_state_dependency(state);
});
}
has_dep
data.stylist.any_applicable_rule_data(element, |data, _| {
data.has_state_dependency(state)
})
}
#[no_mangle]