mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
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:
commit
bb34b7f54a
21 changed files with 842 additions and 404 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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") =>
|
||||
|
|
|
@ -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
|
@ -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) ||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue