mirror of
https://github.com/servo/servo.git
synced 2025-07-30 18:50:36 +01: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 = [
|
dependencies = [
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -1721,7 +1721,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 = [
|
dependencies = [
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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 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 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 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 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 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"
|
"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())
|
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>>> {
|
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc())
|
(*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.
|
/// Consumes the builder, producing a Selector.
|
||||||
#[inline(always)]
|
#[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.
|
// Compute the specificity and flags.
|
||||||
let mut spec = SpecificityAndFlags(specificity(self.simple_selectors.iter()));
|
let mut spec = SpecificityAndFlags(specificity(self.simple_selectors.iter()));
|
||||||
if parsed_pseudo {
|
if parsed_pseudo {
|
||||||
spec.0 |= HAS_PSEUDO_BIT;
|
spec.0 |= HAS_PSEUDO_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if parsed_slotted {
|
||||||
|
spec.0 |= HAS_SLOTTED_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
self.build_with_specificity_and_flags(spec)
|
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_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)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct SpecificityAndFlags(pub u32);
|
pub struct SpecificityAndFlags(pub u32);
|
||||||
|
|
||||||
impl SpecificityAndFlags {
|
impl SpecificityAndFlags {
|
||||||
|
#[inline]
|
||||||
pub fn specificity(&self) -> u32 {
|
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 {
|
pub fn has_pseudo_element(&self) -> bool {
|
||||||
(self.0 & HAS_PSEUDO_BIT) != 0
|
(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;
|
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>>);
|
pub struct Selector<Impl: SelectorImpl>(ThinArc<SpecificityAndFlags, Component<Impl>>);
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Selector<Impl> {
|
impl<Impl: SelectorImpl> Selector<Impl> {
|
||||||
|
#[inline]
|
||||||
pub fn specificity(&self) -> u32 {
|
pub fn specificity(&self) -> u32 {
|
||||||
self.0.header.header.specificity()
|
self.0.header.header.specificity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn has_pseudo_element(&self) -> bool {
|
pub fn has_pseudo_element(&self) -> bool {
|
||||||
self.0.header.header.has_pseudo_element()
|
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> {
|
pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
|
||||||
if !self.has_pseudo_element() {
|
if !self.has_pseudo_element() {
|
||||||
return None
|
return None
|
||||||
|
@ -1219,7 +1227,7 @@ where
|
||||||
builder.push_combinator(combinator);
|
builder.push_combinator(combinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Selector(builder.build(has_pseudo_element)))
|
Ok(Selector(builder.build(has_pseudo_element, slotted)))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Selector<Impl> {
|
impl<Impl: SelectorImpl> Selector<Impl> {
|
||||||
|
|
|
@ -263,7 +263,9 @@ impl ElementData {
|
||||||
|
|
||||||
let mut xbl_stylists = SmallVec::<[_; 3]>::new();
|
let mut xbl_stylists = SmallVec::<[_; 3]>::new();
|
||||||
let cut_off_inheritance =
|
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(
|
let mut processor = StateAndAttrInvalidationProcessor::new(
|
||||||
shared_context,
|
shared_context,
|
||||||
|
|
|
@ -31,7 +31,7 @@ use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use stylist::Stylist;
|
use stylist::{StyleRuleCascadeData, Stylist};
|
||||||
use traversal_flags::TraversalFlags;
|
use traversal_flags::TraversalFlags;
|
||||||
|
|
||||||
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
|
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
|
||||||
|
@ -416,6 +416,20 @@ pub trait TElement
|
||||||
F: FnMut(Self),
|
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
|
/// For a given NAC element, return the closest non-NAC ancestor, which is
|
||||||
/// guaranteed to exist.
|
/// guaranteed to exist.
|
||||||
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {
|
fn closest_non_native_anonymous_ancestor(&self) -> Option<Self> {
|
||||||
|
@ -760,6 +774,41 @@ pub trait TElement
|
||||||
false
|
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.
|
/// Gets the current existing CSS transitions, by |property, end value| pairs in a FnvHashMap.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn get_css_transitions_info(&self)
|
fn get_css_transitions_info(&self)
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
use Atom;
|
use Atom;
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use dom::{TDocument, TElement, TNode};
|
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::{Element, NthIndexCache, SelectorList};
|
||||||
use selectors::attr::CaseSensitivity;
|
use selectors::attr::CaseSensitivity;
|
||||||
use selectors::matching::{self, MatchingContext, MatchingMode};
|
use selectors::matching::{self, MatchingContext, MatchingMode};
|
||||||
|
@ -143,7 +144,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
element: E,
|
element: E,
|
||||||
self_invalidations: &mut InvalidationVector<'a>,
|
self_invalidations: &mut InvalidationVector<'a>,
|
||||||
descendant_invalidations: &mut InvalidationVector<'a>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
||||||
_sibling_invalidations: &mut InvalidationVector<'a>,
|
_sibling_invalidations: &mut InvalidationVector<'a>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// TODO(emilio): If the element is not a root element, and
|
// TODO(emilio): If the element is not a root element, and
|
||||||
|
@ -163,7 +164,7 @@ where
|
||||||
|
|
||||||
let target_vector =
|
let target_vector =
|
||||||
if self.matching_context.scope_element.is_some() {
|
if self.matching_context.scope_element.is_some() {
|
||||||
descendant_invalidations
|
&mut descendant_invalidations.dom_descendants
|
||||||
} else {
|
} else {
|
||||||
self_invalidations
|
self_invalidations
|
||||||
};
|
};
|
||||||
|
|
|
@ -2276,8 +2276,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms9rectangleE"]
|
#[link_name = "_ZN9nsGkAtoms9rectangleE"]
|
||||||
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
|
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms3refE"]
|
|
||||||
pub static nsGkAtoms_ref: *mut nsStaticAtom;
|
|
||||||
#[link_name = "_ZN9nsGkAtoms7refreshE"]
|
#[link_name = "_ZN9nsGkAtoms7refreshE"]
|
||||||
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms3relE"]
|
#[link_name = "_ZN9nsGkAtoms3relE"]
|
||||||
|
@ -2312,8 +2310,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms10resolutionE"]
|
#[link_name = "_ZN9nsGkAtoms10resolutionE"]
|
||||||
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
|
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms8resourceE"]
|
|
||||||
pub static nsGkAtoms_resource: *mut nsStaticAtom;
|
|
||||||
#[link_name = "_ZN9nsGkAtoms9resourcesE"]
|
#[link_name = "_ZN9nsGkAtoms9resourcesE"]
|
||||||
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms6resultE"]
|
#[link_name = "_ZN9nsGkAtoms6resultE"]
|
||||||
|
@ -2486,14 +2482,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms10sortLockedE"]
|
#[link_name = "_ZN9nsGkAtoms10sortLockedE"]
|
||||||
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
|
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"]
|
#[link_name = "_ZN9nsGkAtoms6sourceE"]
|
||||||
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms5spaceE"]
|
#[link_name = "_ZN9nsGkAtoms5spaceE"]
|
||||||
|
@ -4374,8 +4362,8 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms19forcemessagemanagerE"]
|
#[link_name = "_ZN9nsGkAtoms19forcemessagemanagerE"]
|
||||||
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms16isPreloadBrowserE"]
|
#[link_name = "_ZN9nsGkAtoms14preloadedStateE"]
|
||||||
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
|
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms24scrollbar_start_backwardE"]
|
#[link_name = "_ZN9nsGkAtoms24scrollbar_start_backwardE"]
|
||||||
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
||||||
#[link_name = "_ZN9nsGkAtoms23scrollbar_start_forwardE"]
|
#[link_name = "_ZN9nsGkAtoms23scrollbar_start_forwardE"]
|
||||||
|
@ -7463,8 +7451,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
||||||
#[link_name = "?rectangle@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?rectangle@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
|
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
|
||||||
#[link_name = "?ref@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
|
||||||
pub static nsGkAtoms_ref: *mut nsStaticAtom;
|
|
||||||
#[link_name = "?refresh@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?refresh@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
||||||
#[link_name = "?rel@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?rel@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
|
@ -7499,8 +7485,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
||||||
#[link_name = "?resolution@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?resolution@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
|
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
|
||||||
#[link_name = "?resource@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
|
||||||
pub static nsGkAtoms_resource: *mut nsStaticAtom;
|
|
||||||
#[link_name = "?resources@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?resources@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
||||||
#[link_name = "?result@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?result@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
|
@ -7673,14 +7657,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
||||||
#[link_name = "?sortLocked@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?sortLocked@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
|
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"]
|
#[link_name = "?source@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
||||||
#[link_name = "?space@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?space@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
|
@ -9561,8 +9537,8 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
||||||
#[link_name = "?forcemessagemanager@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?forcemessagemanager@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
||||||
#[link_name = "?isPreloadBrowser@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?preloadedState@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
|
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
|
||||||
#[link_name = "?scrollbar_start_backward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?scrollbar_start_backward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
||||||
#[link_name = "?scrollbar_start_forward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
#[link_name = "?scrollbar_start_forward@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
|
||||||
|
@ -12650,8 +12626,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
pub static nsGkAtoms_rect: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?rectangle@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?rectangle@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_rectangle: *mut nsStaticAtom;
|
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"]
|
#[link_name = "\x01?refresh@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
pub static nsGkAtoms_refresh: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?rel@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?rel@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
|
@ -12686,8 +12660,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
pub static nsGkAtoms_resizer: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?resolution@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?resolution@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_resolution: *mut nsStaticAtom;
|
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"]
|
#[link_name = "\x01?resources@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
pub static nsGkAtoms_resources: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?result@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?result@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
|
@ -12860,14 +12832,6 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
pub static nsGkAtoms_sorthints: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?sortLocked@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?sortLocked@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_sortLocked: *mut nsStaticAtom;
|
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"]
|
#[link_name = "\x01?source@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
pub static nsGkAtoms_source: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?space@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?space@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
|
@ -14748,8 +14712,8 @@ cfg_if! {
|
||||||
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?forcemessagemanager@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?forcemessagemanager@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
pub static nsGkAtoms_forcemessagemanager: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?isPreloadBrowser@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?preloadedState@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_isPreloadBrowser: *mut nsStaticAtom;
|
pub static nsGkAtoms_preloadedState: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?scrollbar_start_backward@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[link_name = "\x01?scrollbar_start_backward@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
||||||
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
pub static nsGkAtoms_scrollbar_start_backward: *mut nsStaticAtom;
|
||||||
#[link_name = "\x01?scrollbar_start_forward@nsGkAtoms@@2PAVnsStaticAtom@@A"]
|
#[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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("preloadedState") =>
|
||||||
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_isPreloadBrowser as *mut _) } }};
|
{{ #[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") =>
|
("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 _) } }};
|
{{ #[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") =>
|
("scrollbar-start-forward") =>
|
||||||
|
|
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 cssparser::{BasicParseError, BasicParseErrorKind, Parser, ToCss, Token, CowRcStr, SourceLocation};
|
||||||
use element_state::{DocumentState, ElementState};
|
use element_state::{DocumentState, ElementState};
|
||||||
use gecko_bindings::structs::CSSPseudoClassType;
|
use gecko_bindings::structs::{self, CSSPseudoClassType};
|
||||||
use gecko_bindings::structs::RawServoSelectorList;
|
use gecko_bindings::structs::RawServoSelectorList;
|
||||||
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
|
||||||
use selector_parser::{Direction, SelectorParser};
|
use selector_parser::{Direction, SelectorParser};
|
||||||
|
@ -333,6 +333,13 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
type Impl = SelectorImpl;
|
type Impl = SelectorImpl;
|
||||||
type Error = StyleParseErrorKind<'i>;
|
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 {
|
fn pseudo_element_allows_single_colon(name: &str) -> bool {
|
||||||
// FIXME: -moz-tree check should probably be ascii-case-insensitive.
|
// FIXME: -moz-tree check should probably be ascii-case-insensitive.
|
||||||
::selectors::parser::is_css2_pseudo_element(name) ||
|
::selectors::parser::is_css2_pseudo_element(name) ||
|
||||||
|
|
|
@ -610,10 +610,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
self.as_node().node_info().mInner.mNamespaceID
|
self.as_node().node_info().mInner.mNamespaceID
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_html_element(&self) -> bool {
|
#[inline]
|
||||||
self.namespace_id() == (structs::root::kNameSpaceID_XHTML as i32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_xul_element(&self) -> bool {
|
fn is_xul_element(&self) -> bool {
|
||||||
self.namespace_id() == (structs::root::kNameSpaceID_XUL as i32)
|
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()
|
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
|
/// Execute `f` for each anonymous content child element (apart from
|
||||||
/// ::before and ::after) whose originating element is `self`.
|
/// ::before and ::after) whose originating element is `self`.
|
||||||
fn each_anonymous_content_child<F>(&self, mut f: F)
|
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())
|
parent_node.and_then(|n| n.as_element())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||||
debug_assert!(self.implemented_pseudo_element().is_some());
|
debug_assert!(self.implemented_pseudo_element().is_some());
|
||||||
self.closest_non_native_anonymous_ancestor()
|
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]
|
#[inline]
|
||||||
fn first_child_element(&self) -> Option<Self> {
|
fn first_child_element(&self) -> Option<Self> {
|
||||||
let mut child = self.as_node().first_child();
|
let mut child = self.as_node().first_child();
|
||||||
|
|
|
@ -13,7 +13,8 @@ use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
|
||||||
use invalidation::element::invalidation_map::*;
|
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 invalidation::element::restyle_hints::RestyleHint;
|
||||||
use selector_map::SelectorMap;
|
use selector_map::SelectorMap;
|
||||||
use selector_parser::Snapshot;
|
use selector_parser::Snapshot;
|
||||||
|
@ -23,7 +24,7 @@ use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
|
||||||
use selectors::matching::matches_selector;
|
use selectors::matching::matches_selector;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use stylesheets::origin::{Origin, OriginSet};
|
use stylesheets::origin::{Origin, OriginSet};
|
||||||
use stylist::Stylist;
|
use stylist::StyleRuleCascadeData;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum VisitedDependent {
|
enum VisitedDependent {
|
||||||
|
@ -47,7 +48,7 @@ where
|
||||||
classes_removed: &'a SmallVec<[Atom; 8]>,
|
classes_removed: &'a SmallVec<[Atom; 8]>,
|
||||||
classes_added: &'a SmallVec<[Atom; 8]>,
|
classes_added: &'a SmallVec<[Atom; 8]>,
|
||||||
state_changes: ElementState,
|
state_changes: ElementState,
|
||||||
descendant_invalidations: &'a mut InvalidationVector<'selectors>,
|
descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
|
||||||
sibling_invalidations: &'a mut InvalidationVector<'selectors>,
|
sibling_invalidations: &'a mut InvalidationVector<'selectors>,
|
||||||
invalidates_self: bool,
|
invalidates_self: bool,
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,7 @@ where
|
||||||
/// changes.
|
/// changes.
|
||||||
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
xbl_stylists: &'a [AtomicRef<'b, Stylist>],
|
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
|
||||||
cut_off_inheritance: bool,
|
cut_off_inheritance: bool,
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
|
@ -67,7 +68,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
||||||
/// Creates a new StateAndAttrInvalidationProcessor.
|
/// Creates a new StateAndAttrInvalidationProcessor.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
shared_context: &'a SharedStyleContext<'b>,
|
shared_context: &'a SharedStyleContext<'b>,
|
||||||
xbl_stylists: &'a [AtomicRef<'b, Stylist>],
|
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
|
||||||
cut_off_inheritance: bool,
|
cut_off_inheritance: bool,
|
||||||
element: E,
|
element: E,
|
||||||
data: &'a mut ElementData,
|
data: &'a mut ElementData,
|
||||||
|
@ -83,7 +84,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
shared_context,
|
shared_context,
|
||||||
xbl_stylists,
|
shadow_rule_datas,
|
||||||
cut_off_inheritance,
|
cut_off_inheritance,
|
||||||
element,
|
element,
|
||||||
data,
|
data,
|
||||||
|
@ -109,7 +110,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
element: E,
|
element: E,
|
||||||
_self_invalidations: &mut InvalidationVector<'a>,
|
_self_invalidations: &mut InvalidationVector<'a>,
|
||||||
descendant_invalidations: &mut InvalidationVector<'a>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'a>,
|
sibling_invalidations: &mut InvalidationVector<'a>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
debug_assert!(element.has_snapshot(), "Why bothering?");
|
debug_assert!(element.has_snapshot(), "Why bothering?");
|
||||||
|
@ -210,20 +211,18 @@ where
|
||||||
OriginSet::all()
|
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()) {
|
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 {
|
for &(ref data, quirks_mode) in self.shadow_rule_datas {
|
||||||
// FIXME(emilio): Replace with assert / remove when we
|
// FIXME(emilio): Replace with assert / remove when we figure
|
||||||
// figure out what to do with the quirks mode mismatches
|
// out what to do with the quirks mode mismatches
|
||||||
// (that is, when bug 1406875 is properly fixed).
|
// (that is, when bug 1406875 is properly fixed).
|
||||||
collector.quirks_mode = stylist.quirks_mode();
|
collector.quirks_mode = quirks_mode;
|
||||||
stylist.each_invalidation_map(|invalidation_map, _| {
|
collector.collect_dependencies_in_invalidation_map(data.invalidation_map());
|
||||||
collector.collect_dependencies_in_invalidation_map(invalidation_map);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.invalidates_self
|
collector.invalidates_self
|
||||||
|
@ -236,7 +235,10 @@ where
|
||||||
//
|
//
|
||||||
// This number is completely made-up, but the page that made us add this
|
// This number is completely made-up, but the page that made us add this
|
||||||
// code generated 1960+ invalidations (bug 1420741).
|
// 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);
|
self.data.hint.insert(RestyleHint::RESTYLE_DESCENDANTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,36 +511,52 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note_dependency(&mut self, dependency: &'selectors Dependency) {
|
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;
|
self.invalidates_self = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if dependency.affects_descendants() {
|
|
||||||
debug_assert_ne!(dependency.selector_offset, 0);
|
debug_assert_ne!(dependency.selector_offset, 0);
|
||||||
debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
|
debug_assert_ne!(
|
||||||
debug_assert!(!dependency.affects_later_siblings());
|
dependency.selector_offset,
|
||||||
self.descendant_invalidations.push(Invalidation::new(
|
dependency.selector.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let invalidation = Invalidation::new(
|
||||||
&dependency.selector,
|
&dependency.selector,
|
||||||
dependency.selector.len() - dependency.selector_offset + 1,
|
dependency.selector.len() - dependency.selector_offset + 1,
|
||||||
));
|
);
|
||||||
} else if dependency.affects_later_siblings() {
|
|
||||||
debug_assert_ne!(dependency.selector_offset, 0);
|
match invalidation_kind {
|
||||||
debug_assert_ne!(dependency.selector_offset, dependency.selector.len());
|
DependencyInvalidationKind::Element => unreachable!(),
|
||||||
self.sibling_invalidations.push(Invalidation::new(
|
DependencyInvalidationKind::ElementAndDescendants => {
|
||||||
&dependency.selector,
|
self.invalidates_self = true;
|
||||||
dependency.selector.len() - dependency.selector_offset + 1,
|
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
|
/// Returns whether `dependency` may cause us to invalidate the style of
|
||||||
/// more elements than what we've already invalidated.
|
/// more elements than what we've already invalidated.
|
||||||
fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool {
|
fn dependency_may_be_relevant(&self, dependency: &Dependency) -> bool {
|
||||||
if dependency.affects_descendants() || dependency.affects_later_siblings() {
|
match dependency.invalidation_kind() {
|
||||||
return true;
|
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))
|
.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 {
|
fn blocks_ancestor_combinators(&self) -> bool {
|
||||||
self.element.blocks_ancestor_combinators()
|
self.element.blocks_ancestor_combinators()
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,25 @@ pub struct Dependency {
|
||||||
pub selector_offset: usize,
|
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 {
|
impl Dependency {
|
||||||
/// Returns the combinator to the right of the partial selector this
|
/// Returns the combinator to the right of the partial selector this
|
||||||
/// dependency represents.
|
/// dependency represents.
|
||||||
|
@ -76,28 +95,19 @@ impl Dependency {
|
||||||
Some(self.selector.combinator_at_match_order(self.selector_offset - 1))
|
Some(self.selector.combinator_at_match_order(self.selector_offset - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this dependency affects the style of the element.
|
/// The kind of invalidation that this would generate.
|
||||||
///
|
pub fn invalidation_kind(&self) -> DependencyInvalidationKind {
|
||||||
/// NOTE(emilio): pseudo-elements need to be here to account for eager
|
match self.combinator() {
|
||||||
/// pseudos, since they just grab the style from the originating element.
|
None => DependencyInvalidationKind::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::Child) |
|
||||||
Some(Combinator::Descendant))
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
element: E,
|
element: E,
|
||||||
self_invalidations: &mut InvalidationVector<'a>,
|
self_invalidations: &mut InvalidationVector<'a>,
|
||||||
descendant_invalidations: &mut InvalidationVector<'a>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'a>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'a>,
|
sibling_invalidations: &mut InvalidationVector<'a>,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
|
@ -58,6 +58,25 @@ where
|
||||||
fn invalidated_descendants(&mut self, element: E, child: E);
|
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
|
/// The struct that takes care of encapsulating all the logic on where and how
|
||||||
/// element styles need to be invalidated.
|
/// element styles need to be invalidated.
|
||||||
pub struct TreeStyleInvalidator<'a, 'b, E, P: 'a>
|
pub struct TreeStyleInvalidator<'a, 'b, E, P: 'a>
|
||||||
|
@ -75,13 +94,22 @@ where
|
||||||
/// A vector of invalidations, optimized for small invalidation sets.
|
/// A vector of invalidations, optimized for small invalidation sets.
|
||||||
pub type InvalidationVector<'a> = SmallVec<[Invalidation<'a>; 10]>;
|
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.
|
/// The kind of invalidation we're processing.
|
||||||
///
|
///
|
||||||
/// We can use this to avoid pushing invalidations of the same kind to our
|
/// We can use this to avoid pushing invalidations of the same kind to our
|
||||||
/// descendants or siblings.
|
/// descendants or siblings.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum InvalidationKind {
|
enum InvalidationKind {
|
||||||
Descendant,
|
Descendant(DescendantInvalidationKind),
|
||||||
Sibling,
|
Sibling,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,21 +154,27 @@ impl<'a> Invalidation<'a> {
|
||||||
//
|
//
|
||||||
// We should be able to do better here!
|
// We should be able to do better here!
|
||||||
match self.selector.combinator_at_parse_order(self.offset - 1) {
|
match self.selector.combinator_at_parse_order(self.offset - 1) {
|
||||||
|
Combinator::Descendant |
|
||||||
|
Combinator::LaterSibling |
|
||||||
|
Combinator::PseudoElement => true,
|
||||||
|
Combinator::SlotAssignment |
|
||||||
Combinator::NextSibling |
|
Combinator::NextSibling |
|
||||||
Combinator::Child => false,
|
Combinator::Child => false,
|
||||||
_ => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kind(&self) -> InvalidationKind {
|
fn kind(&self) -> InvalidationKind {
|
||||||
if self.offset == 0 {
|
if self.offset == 0 {
|
||||||
return InvalidationKind::Descendant;
|
return InvalidationKind::Descendant(DescendantInvalidationKind::Dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.selector.combinator_at_parse_order(self.offset - 1).is_ancestor() {
|
match self.selector.combinator_at_parse_order(self.offset - 1) {
|
||||||
InvalidationKind::Descendant
|
Combinator::Child |
|
||||||
} else {
|
Combinator::Descendant |
|
||||||
InvalidationKind::Sibling
|
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);
|
debug!("StyleTreeInvalidator::invalidate({:?})", self.element);
|
||||||
|
|
||||||
let mut self_invalidations = InvalidationVector::new();
|
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 sibling_invalidations = InvalidationVector::new();
|
||||||
|
|
||||||
let mut invalidated_self = self.processor.collect_invalidations(
|
let mut invalidated_self = self.processor.collect_invalidations(
|
||||||
|
@ -242,7 +276,7 @@ where
|
||||||
|
|
||||||
debug!("Collected invalidations (self: {}): ", invalidated_self);
|
debug!("Collected invalidations (self: {}): ", invalidated_self);
|
||||||
debug!(" > self: {}, {:?}", self_invalidations.len(), self_invalidations);
|
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);
|
debug!(" > siblings: {}, {:?}", sibling_invalidations.len(), sibling_invalidations);
|
||||||
|
|
||||||
let invalidated_self_from_collection = invalidated_self;
|
let invalidated_self_from_collection = invalidated_self;
|
||||||
|
@ -251,6 +285,7 @@ where
|
||||||
&self_invalidations,
|
&self_invalidations,
|
||||||
&mut descendant_invalidations,
|
&mut descendant_invalidations,
|
||||||
&mut sibling_invalidations,
|
&mut sibling_invalidations,
|
||||||
|
DescendantInvalidationKind::Dom,
|
||||||
);
|
);
|
||||||
|
|
||||||
if invalidated_self && !invalidated_self_from_collection {
|
if invalidated_self && !invalidated_self_from_collection {
|
||||||
|
@ -260,7 +295,11 @@ where
|
||||||
let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
|
let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
|
||||||
let invalidated_siblings = self.invalidate_siblings(&mut sibling_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
|
/// Go through later DOM siblings, invalidating style as needed using the
|
||||||
|
@ -286,7 +325,8 @@ where
|
||||||
self.processor,
|
self.processor,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut invalidations_for_descendants = InvalidationVector::new();
|
let mut invalidations_for_descendants =
|
||||||
|
DescendantInvalidationLists::default();
|
||||||
let invalidated_sibling =
|
let invalidated_sibling =
|
||||||
sibling_invalidator.process_sibling_invalidations(
|
sibling_invalidator.process_sibling_invalidations(
|
||||||
&mut invalidations_for_descendants,
|
&mut invalidations_for_descendants,
|
||||||
|
@ -301,7 +341,7 @@ where
|
||||||
|
|
||||||
any_invalidated |=
|
any_invalidated |=
|
||||||
sibling_invalidator.invalidate_descendants(
|
sibling_invalidator.invalidate_descendants(
|
||||||
&invalidations_for_descendants
|
&invalidations_for_descendants,
|
||||||
);
|
);
|
||||||
|
|
||||||
if sibling_invalidations.is_empty() {
|
if sibling_invalidations.is_empty() {
|
||||||
|
@ -324,7 +364,8 @@ where
|
||||||
let result = self.invalidate_child(
|
let result = self.invalidate_child(
|
||||||
child,
|
child,
|
||||||
invalidations,
|
invalidations,
|
||||||
&mut sibling_invalidations
|
&mut sibling_invalidations,
|
||||||
|
DescendantInvalidationKind::Dom,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Roots of NAC subtrees can indeed generate sibling invalidations, but
|
// Roots of NAC subtrees can indeed generate sibling invalidations, but
|
||||||
|
@ -344,8 +385,10 @@ where
|
||||||
child: E,
|
child: E,
|
||||||
invalidations: &[Invalidation<'b>],
|
invalidations: &[Invalidation<'b>],
|
||||||
sibling_invalidations: &mut InvalidationVector<'b>,
|
sibling_invalidations: &mut InvalidationVector<'b>,
|
||||||
|
descendant_invalidation_kind: DescendantInvalidationKind,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut invalidations_for_descendants = InvalidationVector::new();
|
let mut invalidations_for_descendants =
|
||||||
|
DescendantInvalidationLists::default();
|
||||||
|
|
||||||
let mut invalidated_child = false;
|
let mut invalidated_child = false;
|
||||||
let invalidated_descendants = {
|
let invalidated_descendants = {
|
||||||
|
@ -366,13 +409,16 @@ where
|
||||||
invalidations,
|
invalidations,
|
||||||
&mut invalidations_for_descendants,
|
&mut invalidations_for_descendants,
|
||||||
sibling_invalidations,
|
sibling_invalidations,
|
||||||
|
descendant_invalidation_kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
if invalidated_child {
|
if invalidated_child {
|
||||||
child_invalidator.processor.invalidated_self(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,
|
// 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
|
// This probably needs a shadow root check on `child` here, and
|
||||||
// recursing if that's the case.
|
// 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() {
|
let child = match child.as_element() {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => continue,
|
None => continue,
|
||||||
|
@ -431,15 +473,14 @@ where
|
||||||
child,
|
child,
|
||||||
invalidations,
|
invalidations,
|
||||||
&mut sibling_invalidations,
|
&mut sibling_invalidations,
|
||||||
|
DescendantInvalidationKind::Dom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
any_descendant
|
any_descendant
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a descendant invalidation list, go through the current element's
|
fn invalidate_slotted_elements(
|
||||||
/// descendants, and invalidate style on them.
|
|
||||||
fn invalidate_descendants(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
invalidations: &[Invalidation<'b>],
|
invalidations: &[Invalidation<'b>],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -447,6 +488,83 @@ where
|
||||||
return false;
|
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({:?})",
|
debug!("StyleTreeInvalidator::invalidate_descendants({:?})",
|
||||||
self.element);
|
self.element);
|
||||||
debug!(" > {:?}", invalidations);
|
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;
|
let mut any_descendant = false;
|
||||||
|
|
||||||
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
|
|
||||||
any_descendant |=
|
any_descendant |=
|
||||||
self.invalidate_dom_descendants_of(anon_content, invalidations);
|
self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
|
||||||
}
|
|
||||||
|
|
||||||
// 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 |=
|
any_descendant |=
|
||||||
self.invalidate_pseudo_element_or_nac(before, invalidations);
|
self.invalidate_slotted_elements(&invalidations.slotted_descendants);
|
||||||
}
|
|
||||||
|
|
||||||
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
|
any_descendant
|
||||||
}
|
}
|
||||||
|
@ -511,7 +606,7 @@ where
|
||||||
/// Returns whether invalidated the current element's style.
|
/// Returns whether invalidated the current element's style.
|
||||||
fn process_sibling_invalidations(
|
fn process_sibling_invalidations(
|
||||||
&mut self,
|
&mut self,
|
||||||
descendant_invalidations: &mut InvalidationVector<'b>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'b>,
|
sibling_invalidations: &mut InvalidationVector<'b>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -547,8 +642,9 @@ where
|
||||||
fn process_descendant_invalidations(
|
fn process_descendant_invalidations(
|
||||||
&mut self,
|
&mut self,
|
||||||
invalidations: &[Invalidation<'b>],
|
invalidations: &[Invalidation<'b>],
|
||||||
descendant_invalidations: &mut InvalidationVector<'b>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'b>,
|
sibling_invalidations: &mut InvalidationVector<'b>,
|
||||||
|
descendant_invalidation_kind: DescendantInvalidationKind,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut invalidated = false;
|
let mut invalidated = false;
|
||||||
|
|
||||||
|
@ -557,14 +653,19 @@ where
|
||||||
invalidation,
|
invalidation,
|
||||||
descendant_invalidations,
|
descendant_invalidations,
|
||||||
sibling_invalidations,
|
sibling_invalidations,
|
||||||
InvalidationKind::Descendant,
|
InvalidationKind::Descendant(descendant_invalidation_kind),
|
||||||
);
|
);
|
||||||
|
|
||||||
invalidated |= result.invalidated_self;
|
invalidated |= result.invalidated_self;
|
||||||
if invalidation.effective_for_next() {
|
if invalidation.effective_for_next() {
|
||||||
let mut invalidation = invalidation.clone();
|
let mut invalidation = invalidation.clone();
|
||||||
invalidation.matched_by_any_previous |= result.matched;
|
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(
|
fn process_invalidation(
|
||||||
&mut self,
|
&mut self,
|
||||||
invalidation: &Invalidation<'b>,
|
invalidation: &Invalidation<'b>,
|
||||||
descendant_invalidations: &mut InvalidationVector<'b>,
|
descendant_invalidations: &mut DescendantInvalidationLists<'b>,
|
||||||
sibling_invalidations: &mut InvalidationVector<'b>,
|
sibling_invalidations: &mut InvalidationVector<'b>,
|
||||||
invalidation_kind: InvalidationKind,
|
invalidation_kind: InvalidationKind,
|
||||||
) -> SingleInvalidationResult {
|
) -> SingleInvalidationResult {
|
||||||
|
@ -732,8 +833,11 @@ where
|
||||||
already been matched before");
|
already been matched before");
|
||||||
} else {
|
} else {
|
||||||
match next_invalidation_kind {
|
match next_invalidation_kind {
|
||||||
InvalidationKind::Descendant => {
|
InvalidationKind::Descendant(DescendantInvalidationKind::Dom) => {
|
||||||
descendant_invalidations.push(next_invalidation);
|
descendant_invalidations.dom_descendants.push(next_invalidation);
|
||||||
|
}
|
||||||
|
InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => {
|
||||||
|
descendant_invalidations.slotted_descendants.push(next_invalidation);
|
||||||
}
|
}
|
||||||
InvalidationKind::Sibling => {
|
InvalidationKind::Sibling => {
|
||||||
sibling_invalidations.push(next_invalidation);
|
sibling_invalidations.push(next_invalidation);
|
||||||
|
|
|
@ -106,6 +106,13 @@ pub struct SelectorMap<T: 'static> {
|
||||||
pub count: usize,
|
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
|
// FIXME(Manishearth) the 'static bound can be removed when
|
||||||
// our HashMap fork (hashglobe) is able to use NonZero,
|
// our HashMap fork (hashglobe) is able to use NonZero,
|
||||||
// or when stdlib gets fallible collections
|
// or when stdlib gets fallible collections
|
||||||
|
|
|
@ -668,6 +668,17 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
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() {
|
if *target.get_local_name() != *candidate.element.get_local_name() {
|
||||||
trace!("Miss: Local Name");
|
trace!("Miss: Local Name");
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -133,6 +133,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of rebuild that we need to do for a given stylesheet.
|
/// The type of rebuild that we need to do for a given stylesheet.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum SheetRebuildKind {
|
pub enum SheetRebuildKind {
|
||||||
/// A full rebuild, of both cascade data and invalidation data.
|
/// A full rebuild, of both cascade data and invalidation data.
|
||||||
Full,
|
Full,
|
||||||
|
|
|
@ -36,6 +36,7 @@ use selectors::visitor::SelectorVisitor;
|
||||||
use servo_arc::{Arc, ArcBorrow};
|
use servo_arc::{Arc, ArcBorrow};
|
||||||
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use smallbitvec::SmallBitVec;
|
use smallbitvec::SmallBitVec;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
|
@ -132,7 +133,7 @@ impl UserAgentCascadeDataCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[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);
|
sizes.mOther += self.entries.shallow_size_of(ops);
|
||||||
for arc in self.entries.iter() {
|
for arc in self.entries.iter() {
|
||||||
// These are primary Arc references that can be measured
|
// These are primary Arc references that can be measured
|
||||||
|
@ -465,27 +466,30 @@ impl Stylist {
|
||||||
/// Returns the number of revalidation_selectors.
|
/// Returns the number of revalidation_selectors.
|
||||||
pub fn num_revalidation_selectors(&self) -> usize {
|
pub fn num_revalidation_selectors(&self) -> usize {
|
||||||
self.cascade_data.iter_origins()
|
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.
|
/// Returns the number of entries in invalidation maps.
|
||||||
pub fn num_invalidations(&self) -> usize {
|
pub fn num_invalidations(&self) -> usize {
|
||||||
self.cascade_data.iter_origins()
|
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.
|
/// Returns whether the given DocumentState bit is relied upon by a selector
|
||||||
///
|
/// of some rule.
|
||||||
/// NOTE(heycam) This might be better as an `iter_invalidation_maps`, once
|
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
|
||||||
/// we have `impl trait` and can return that easily without bothering to
|
self.cascade_data.iter_origins()
|
||||||
/// create a whole new iterator type.
|
.any(|(d, _)| {
|
||||||
pub fn each_invalidation_map<'a, F>(&'a self, mut f: F)
|
d.normal_rule_data.has_document_state_dependency(state)
|
||||||
where
|
})
|
||||||
F: FnMut(&'a InvalidationMap, Origin)
|
|
||||||
{
|
|
||||||
for (data, origin) in self.cascade_data.iter_origins() {
|
|
||||||
f(&data.invalidation_map, origin)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flush the list of stylesheets if they changed, ensuring the stylist is
|
/// 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)
|
self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given attribute might appear in an attribute
|
/// Executes `f` on each of the normal rule cascade datas in this styleset.
|
||||||
/// selector of some rule in the stylist.
|
pub fn each_normal_rule_cascade_data<'a, F>(&'a self, mut f: F)
|
||||||
pub fn might_have_attribute_dependency(
|
where
|
||||||
&self,
|
F: FnMut(&'a StyleRuleCascadeData, Origin),
|
||||||
local_name: &LocalName,
|
{
|
||||||
) -> bool {
|
for (data, origin) in self.cascade_data.iter_origins() {
|
||||||
if *local_name == local_name!("style") {
|
f(&data.normal_rule_data, origin);
|
||||||
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())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given ElementState bit is relied upon by a selector
|
/// Returns whether for any of the applicable style rule data a given
|
||||||
/// of some rule in the stylist.
|
/// condition is true.
|
||||||
pub fn has_state_dependency(&self, state: ElementState) -> bool {
|
pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
|
||||||
self.cascade_data
|
where
|
||||||
.iter_origins()
|
E: TElement,
|
||||||
.any(|(d, _)| d.state_dependencies.intersects(state))
|
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
|
let mut maybe = false;
|
||||||
/// of some rule in the stylist.
|
|
||||||
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
|
let cut_off = element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
||||||
self.cascade_data
|
maybe = maybe || f(&*data, quirks_mode);
|
||||||
.iter_origins()
|
});
|
||||||
.any(|(d, _)| d.document_state_dependencies.intersects(state))
|
|
||||||
|
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
|
/// 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();
|
rule_hash_target.matches_user_and_author_rules();
|
||||||
|
|
||||||
// Step 1: Normal user-agent 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(
|
map.get_all_matching_rules(
|
||||||
element,
|
element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
|
@ -1270,7 +1273,7 @@ impl Stylist {
|
||||||
// Which may be more what you would probably expect.
|
// Which may be more what you would probably expect.
|
||||||
if matches_user_and_author_rules {
|
if matches_user_and_author_rules {
|
||||||
// Step 3a: User normal 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(
|
map.get_all_matching_rules(
|
||||||
element,
|
element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
|
@ -1281,15 +1284,47 @@ impl Stylist {
|
||||||
CascadeLevel::UserNormal,
|
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| {
|
let cut_off_inheritance = element.each_xbl_stylist(|stylist| {
|
||||||
// ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets
|
// ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets
|
||||||
// under eAuthorSheetFeatures level.
|
// 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
|
// NOTE(emilio): This is needed because the XBL stylist may
|
||||||
// think it has a different quirks mode than the document.
|
// think it has a different quirks mode than the document.
|
||||||
//
|
//
|
||||||
|
@ -1320,7 +1355,7 @@ impl Stylist {
|
||||||
!cut_off_inheritance
|
!cut_off_inheritance
|
||||||
{
|
{
|
||||||
// Step 3c: Author normal rules.
|
// 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(
|
map.get_all_matching_rules(
|
||||||
element,
|
element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
|
@ -1331,8 +1366,6 @@ impl Stylist {
|
||||||
CascadeLevel::AuthorNormal
|
CascadeLevel::AuthorNormal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
debug!("skipping author normal rules");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !only_default_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();
|
let hash = id.get_hash();
|
||||||
for (data, _) in self.cascade_data.iter_origins() {
|
self.any_applicable_rule_data(element, |data, _| {
|
||||||
if data.mapped_ids.might_contain_hash(hash) {
|
data.mapped_ids.might_contain_hash(hash)
|
||||||
return true;
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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| {
|
/// Returns the cascade data for the slotted rules in this scope, if any.
|
||||||
xbl_rules_may_contain = xbl_rules_may_contain ||
|
#[inline]
|
||||||
stylist.cascade_data.author.mapped_ids.might_contain_hash(hash)
|
pub fn slotted_author_cascade_data(&self) -> Option<&StyleRuleCascadeData> {
|
||||||
});
|
self.cascade_data.author.slotted_rule_data.as_ref().map(|d| &**d)
|
||||||
|
|
||||||
xbl_rules_may_contain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the registered `@keyframes` animation for the specified name.
|
/// Returns the registered `@keyframes` animation for the specified name.
|
||||||
|
///
|
||||||
|
/// FIXME(emilio): This needs to account for the element rules.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> {
|
pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> {
|
||||||
self.cascade_data
|
self.cascade_data
|
||||||
|
@ -1466,7 +1498,7 @@ impl Stylist {
|
||||||
// this in the caller by asserting that the bitvecs are same-length.
|
// this in the caller by asserting that the bitvecs are same-length.
|
||||||
let mut results = SmallBitVec::new();
|
let mut results = SmallBitVec::new();
|
||||||
for (data, _) in self.cascade_data.iter_origins() {
|
for (data, _) in self.cascade_data.iter_origins() {
|
||||||
data.selectors_for_cache_revalidation.lookup(
|
data.normal_rule_data.selectors_for_cache_revalidation.lookup(
|
||||||
element,
|
element,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
|selector_and_hashes| {
|
|selector_and_hashes| {
|
||||||
|
@ -1483,10 +1515,10 @@ impl Stylist {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
element.each_xbl_stylist(|stylist| {
|
element.each_applicable_non_document_style_rule_data(|data, quirks_mode| {
|
||||||
stylist.cascade_data.author.selectors_for_cache_revalidation.lookup(
|
data.selectors_for_cache_revalidation.lookup(
|
||||||
element,
|
element,
|
||||||
stylist.quirks_mode,
|
quirks_mode,
|
||||||
|selector_and_hashes| {
|
|selector_and_hashes| {
|
||||||
results.push(matches_selector(
|
results.push(matches_selector(
|
||||||
&selector_and_hashes.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
|
/// A set of rules for element and pseudo-elements.
|
||||||
/// origin.
|
#[derive(Debug, Default)]
|
||||||
///
|
|
||||||
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
|
|
||||||
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
|
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
#[derive(Debug)]
|
struct ElementAndPseudoRules {
|
||||||
struct CascadeData {
|
|
||||||
/// Rules from stylesheets at this `CascadeData`'s origin.
|
/// Rules from stylesheets at this `CascadeData`'s origin.
|
||||||
element_map: SelectorMap<Rule>,
|
element_map: SelectorMap<Rule>,
|
||||||
|
|
||||||
|
@ -1859,12 +1887,65 @@ struct CascadeData {
|
||||||
/// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for
|
/// Figure out a good way to do a `PerNonAnonBox` and `PerAnonBox` (for
|
||||||
/// `precomputed_values_for_pseudo`) without duplicating a lot of code.
|
/// `precomputed_values_for_pseudo`) without duplicating a lot of code.
|
||||||
pseudos_map: PerPseudoElementMap<Box<SelectorMap<Rule>>>,
|
pseudos_map: PerPseudoElementMap<Box<SelectorMap<Rule>>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A map with all the animations at this `CascadeData`'s origin, indexed
|
impl ElementAndPseudoRules {
|
||||||
/// by name.
|
#[inline(always)]
|
||||||
animations: PrecomputedHashMap<Atom, KeyframesAnimation>,
|
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,
|
invalidation_map: InvalidationMap,
|
||||||
|
|
||||||
/// The attribute local names that appear in attribute selectors. Used
|
/// The attribute local names that appear in attribute selectors. Used
|
||||||
|
@ -1904,6 +1985,146 @@ struct CascadeData {
|
||||||
/// tree-structural state like child index and pseudos).
|
/// tree-structural state like child index and pseudos).
|
||||||
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
|
||||||
selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
|
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 cached from the last rebuild.
|
||||||
effective_media_query_results: EffectiveMediaQueryResults,
|
effective_media_query_results: EffectiveMediaQueryResults,
|
||||||
|
@ -1925,17 +2146,10 @@ struct CascadeData {
|
||||||
impl CascadeData {
|
impl CascadeData {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
element_map: SelectorMap::new(),
|
normal_rule_data: StyleRuleCascadeData::new(),
|
||||||
pseudos_map: PerPseudoElementMap::default(),
|
slotted_rule_data: None,
|
||||||
animations: Default::default(),
|
animations: Default::default(),
|
||||||
extra_data: ExtraStyleData::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(),
|
effective_media_query_results: EffectiveMediaQueryResults::new(),
|
||||||
rules_source_order: 0,
|
rules_source_order: 0,
|
||||||
num_selectors: 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`.
|
/// Collects all the applicable media query results into `results`.
|
||||||
///
|
///
|
||||||
/// This duplicates part of the logic in `add_stylesheet`, which is
|
/// This duplicates part of the logic in `add_stylesheet`, which is
|
||||||
|
@ -2015,8 +2239,10 @@ impl CascadeData {
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector in &style_rule.selectors.0 {
|
||||||
self.num_selectors += 1;
|
self.num_selectors += 1;
|
||||||
|
|
||||||
let map = match selector.pseudo_element() {
|
let pseudo_element = selector.pseudo_element();
|
||||||
Some(pseudo) if pseudo.is_precomputed() => {
|
|
||||||
|
if let Some(pseudo) = pseudo_element {
|
||||||
|
if pseudo.is_precomputed() {
|
||||||
debug_assert!(selector.is_universal());
|
debug_assert!(selector.is_universal());
|
||||||
debug_assert!(matches!(origin, Origin::UserAgent));
|
debug_assert!(matches!(origin, Origin::UserAgent));
|
||||||
|
|
||||||
|
@ -2030,51 +2256,36 @@ impl CascadeData {
|
||||||
CascadeLevel::UANormal,
|
CascadeLevel::UANormal,
|
||||||
selector.specificity()
|
selector.specificity()
|
||||||
));
|
));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
None => &mut self.element_map,
|
|
||||||
Some(pseudo) => {
|
|
||||||
self.pseudos_map
|
|
||||||
.get_or_insert_with(&pseudo.canonical(), || Box::new(SelectorMap::new()))
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let hashes =
|
let hashes =
|
||||||
AncestorHashes::new(&selector, quirks_mode);
|
AncestorHashes::new(&selector, quirks_mode);
|
||||||
|
|
||||||
let rule = Rule::new(
|
let rule = Rule::new(
|
||||||
selector.clone(),
|
selector.clone(),
|
||||||
hashes.clone(),
|
hashes,
|
||||||
locked.clone(),
|
locked.clone(),
|
||||||
self.rules_source_order
|
self.rules_source_order
|
||||||
);
|
);
|
||||||
|
|
||||||
map.insert(rule, quirks_mode)?;
|
let style_rule_cascade_data = if selector.is_slotted() {
|
||||||
|
if self.slotted_rule_data.is_none() {
|
||||||
if rebuild_kind.should_rebuild_invalidation() {
|
self.slotted_rule_data = Some(Box::new(StyleRuleCascadeData::new()));
|
||||||
self.invalidation_map
|
}
|
||||||
.note_selector(selector, quirks_mode)?;
|
self.slotted_rule_data.as_mut().unwrap()
|
||||||
let mut visitor = StylistSelectorVisitor {
|
} else {
|
||||||
needs_revalidation: false,
|
&mut self.normal_rule_data
|
||||||
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);
|
style_rule_cascade_data.insert(
|
||||||
|
rule,
|
||||||
if visitor.needs_revalidation {
|
pseudo_element,
|
||||||
self.selectors_for_cache_revalidation.insert(
|
quirks_mode,
|
||||||
RevalidationSelectorAndHashes::new(selector.clone(), hashes),
|
rebuild_kind,
|
||||||
quirks_mode
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
self.rules_source_order += 1;
|
self.rules_source_order += 1;
|
||||||
}
|
}
|
||||||
CssRule::Import(ref lock) => {
|
CssRule::Import(ref lock) => {
|
||||||
|
@ -2223,18 +2434,12 @@ impl CascadeData {
|
||||||
true
|
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.
|
/// Clears the cascade data, but not the invalidation data.
|
||||||
fn clear_cascade_data(&mut self) {
|
fn clear_cascade_data(&mut self) {
|
||||||
self.element_map.clear();
|
self.normal_rule_data.clear_cascade_data();
|
||||||
self.pseudos_map.clear();
|
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
|
||||||
|
slotted_rule_data.clear_cascade_data();
|
||||||
|
}
|
||||||
self.animations.clear();
|
self.animations.clear();
|
||||||
self.extra_data.clear();
|
self.extra_data.clear();
|
||||||
self.rules_source_order = 0;
|
self.rules_source_order = 0;
|
||||||
|
@ -2244,33 +2449,21 @@ impl CascadeData {
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.clear_cascade_data();
|
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.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.
|
/// Measures heap usage.
|
||||||
#[cfg(feature = "gecko")]
|
#[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.mElementAndPseudosMaps += self.element_map.size_of(ops);
|
self.normal_rule_data.add_size_of(ops, sizes);
|
||||||
|
if let Some(ref slotted_rules) = self.slotted_rule_data {
|
||||||
for elem in self.pseudos_map.iter() {
|
slotted_rules.add_size_of(ops, sizes);
|
||||||
if let Some(ref elem) = *elem {
|
|
||||||
sizes.mElementAndPseudosMaps += <Box<_> as MallocSizeOf>::size_of(elem, ops);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sizes.mOther += self.animations.size_of(ops);
|
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.effective_media_query_results.size_of(ops);
|
||||||
sizes.mOther += self.extra_data.size_of(ops);
|
sizes.mOther += self.extra_data.size_of(ops);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4326,25 +4326,14 @@ pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
||||||
let element = GeckoElement(element);
|
let element = GeckoElement(element);
|
||||||
let mut has_dep = false;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Atom::with(local_name, |atom| {
|
Atom::with(local_name, |atom| {
|
||||||
has_dep = data.stylist.might_have_attribute_dependency(atom);
|
data.stylist.any_applicable_rule_data(element, |data, _| {
|
||||||
|
data.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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
has_dep
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -4358,17 +4347,9 @@ pub extern "C" fn Servo_StyleSet_HasStateDependency(
|
||||||
let state = ElementState::from_bits_truncate(state);
|
let state = ElementState::from_bits_truncate(state);
|
||||||
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
||||||
|
|
||||||
let mut has_dep = data.stylist.has_state_dependency(state);
|
data.stylist.any_applicable_rule_data(element, |data, _| {
|
||||||
if !has_dep {
|
data.has_state_dependency(state)
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue