servo: Merge #19790 - style: Work from multiple bugs (from emilio:fix-all-the-bugs); r=heycam,xidorn

Bug: 1429846,1429248,1430608,1409672
Reviewed-by: xidorn,heycam
Source-Repo: https://github.com/servo/servo
Source-Revision: 7d685d4baa0b107e3dd95eeba8076bfb9e07ba0e

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 3a5287b8cba06111d931ce0d4c9ac8b346bed8c0
This commit is contained in:
Emilio Cobos Álvarez 2018-01-17 13:55:03 -06:00
Родитель 817545f74a
Коммит 3b5da0d9e2
11 изменённых файлов: 249 добавлений и 258 удалений

Просмотреть файл

@ -31,7 +31,7 @@ use std::fmt;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
use stylist::{StyleRuleCascadeData, Stylist};
use stylist::{CascadeData, Stylist};
use traversal_flags::TraversalFlags;
/// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed
@ -772,12 +772,12 @@ pub trait TElement
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
where
Self: 'a,
F: FnMut(AtomicRef<'a, StyleRuleCascadeData>, QuirksMode),
F: FnMut(AtomicRef<'a, CascadeData>, 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()),
AtomicRef::map(stylist, |stylist| stylist.author_cascade_data()),
quirks_mode,
)
});
@ -786,12 +786,10 @@ pub trait TElement
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,
)
}
f(
AtomicRef::map(stylist, |stylist| stylist.author_cascade_data()),
quirks_mode,
)
});
current = slot.assigned_slot();

Просмотреть файл

@ -2216,8 +2216,6 @@ cfg_if! {
pub static nsGkAtoms_prefix: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms7preloadE"]
pub static nsGkAtoms_preload: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms11prerenderedE"]
pub static nsGkAtoms_prerendered: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms15mozpresentationE"]
pub static nsGkAtoms_mozpresentation: *mut nsStaticAtom;
#[link_name = "_ZN9nsGkAtoms8preserveE"]
@ -7391,8 +7389,6 @@ cfg_if! {
pub static nsGkAtoms_prefix: *mut nsStaticAtom;
#[link_name = "?preload@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_preload: *mut nsStaticAtom;
#[link_name = "?prerendered@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_prerendered: *mut nsStaticAtom;
#[link_name = "?mozpresentation@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
pub static nsGkAtoms_mozpresentation: *mut nsStaticAtom;
#[link_name = "?preserve@nsGkAtoms@@2PEAVnsStaticAtom@@EA"]
@ -12566,8 +12562,6 @@ cfg_if! {
pub static nsGkAtoms_prefix: *mut nsStaticAtom;
#[link_name = "\x01?preload@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_preload: *mut nsStaticAtom;
#[link_name = "\x01?prerendered@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_prerendered: *mut nsStaticAtom;
#[link_name = "\x01?mozpresentation@nsGkAtoms@@2PAVnsStaticAtom@@A"]
pub static nsGkAtoms_mozpresentation: *mut nsStaticAtom;
#[link_name = "\x01?preserve@nsGkAtoms@@2PAVnsStaticAtom@@A"]
@ -17744,8 +17738,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_prefix as *mut _) } }};
("preload") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_preload as *mut _) } }};
("prerendered") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_prerendered as *mut _) } }};
("mozpresentation") =>
{{ #[allow(unsafe_code)] #[allow(unused_unsafe)]unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_mozpresentation as *mut _) } }};
("preserve") =>

Просмотреть файл

@ -501,8 +501,6 @@ extern "C" {
pub fn Servo_SourceSizeList_Drop ( ptr : RawServoSourceSizeListOwned , ) ;
} extern "C" {
pub fn Gecko_RecordTraversalStatistics ( total : u32 , parallel : u32 , total_t : u32 , parallel_t : u32 , total_s : u32 , parallel_s : u32 , ) ;
} extern "C" {
pub fn Gecko_IsInDocument ( node : RawGeckoNodeBorrowed , ) -> bool ;
} extern "C" {
pub fn Gecko_IsSignificantChild ( node : RawGeckoNodeBorrowed , text_is_significant : bool , whitespace_is_significant : bool , ) -> bool ;
} extern "C" {
@ -753,8 +751,6 @@ extern "C" {
pub fn Gecko_CalcStyleDifference ( old_style : ServoStyleContextBorrowed , new_style : ServoStyleContextBorrowed , any_style_changed : * mut bool , reset_only_changed : * mut bool , ) -> u32 ;
} extern "C" {
pub fn Gecko_GetElementSnapshot ( table : * const ServoElementSnapshotTable , element : RawGeckoElementBorrowed , ) -> * const ServoElementSnapshot ;
} extern "C" {
pub fn Gecko_DropElementSnapshot ( snapshot : ServoElementSnapshotOwned , ) ;
} extern "C" {
pub fn Gecko_HaveSeenPtr ( table : * mut SeenPtrs , ptr : * const :: std :: os :: raw :: c_void , ) -> bool ;
} extern "C" {
@ -977,8 +973,6 @@ extern "C" {
pub fn Gecko_IsDocumentBody ( element : RawGeckoElementBorrowed , ) -> bool ;
} extern "C" {
pub fn Gecko_GetLookAndFeelSystemColor ( color_id : i32 , pres_context : RawGeckoPresContextBorrowed , ) -> nscolor ;
} extern "C" {
pub fn Gecko_MatchStringArgPseudo ( element : RawGeckoElementBorrowed , type_ : CSSPseudoClassType , ident : * const u16 , ) -> bool ;
} extern "C" {
pub fn Gecko_AddPropertyToSet ( arg1 : nsCSSPropertyIDSetBorrowedMut , arg2 : nsCSSPropertyID , ) ;
} extern "C" {
@ -1157,6 +1151,8 @@ extern "C" {
pub fn Servo_Element_IsDisplayNone ( element : RawGeckoElementBorrowed , ) -> bool ;
} extern "C" {
pub fn Servo_Element_IsPrimaryStyleReusedViaRuleNode ( element : RawGeckoElementBorrowed , ) -> bool ;
} extern "C" {
pub fn Servo_InvalidateStyleForDocStateChanges ( root : RawGeckoElementBorrowed , sets : * const nsTArray < RawServoStyleSetBorrowed > , aStatesChanged : u64 , ) ;
} extern "C" {
pub fn Servo_StyleSheet_FromUTF8Bytes ( loader : * mut Loader , gecko_stylesheet : * mut ServoStyleSheet , data : * const u8 , data_len : usize , parsing_mode : SheetParsingMode , extra_data : * mut RawGeckoURLExtraData , line_number_offset : u32 , quirks_mode : nsCompatibility , reusable_sheets : * mut LoaderReusableStyleSheets , ) -> RawServoStyleSheetContentsStrong ;
} extern "C" {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -684,9 +684,11 @@ impl Expression {
pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
let mut css_value = nsCSSValue::null();
unsafe {
(self.feature.mGetter.unwrap())(device.pres_context,
self.feature,
&mut css_value)
(self.feature.mGetter.unwrap())(
device.pres_context().mDocument.raw::<structs::nsIDocument>(),
self.feature,
&mut css_value,
)
};
let value = match MediaExpressionValue::from_css_value(self, &css_value) {

Просмотреть файл

@ -10,7 +10,7 @@ use invalidation::element::invalidator::{DescendantInvalidationLists, Invalidati
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
use invalidation::element::state_and_attributes;
use selectors::matching::{MatchingContext, MatchingMode, QuirksMode, VisitedHandlingMode};
use stylist::StyleRuleCascadeData;
use stylist::CascadeData;
/// A struct holding the members necessary to invalidate document state
/// selectors.
@ -30,20 +30,20 @@ impl Default for InvalidationMatchingData {
/// An invalidation processor for style changes due to state and attribute
/// changes.
pub struct DocumentStateInvalidationProcessor<'a, E: TElement> {
pub struct DocumentStateInvalidationProcessor<'a, E: TElement, I> {
// TODO(emilio): We might want to just run everything for every possible
// binding along with the document data, or just apply the XBL stuff to the
// bound subtrees.
rules: &'a StyleRuleCascadeData,
rules: I,
matching_context: MatchingContext<'a, E::Impl>,
document_states_changed: DocumentState,
}
impl<'a, E: TElement> DocumentStateInvalidationProcessor<'a, E> {
impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
/// Creates a new DocumentStateInvalidationProcessor.
#[inline]
pub fn new(
rules: &'a StyleRuleCascadeData,
rules: I,
document_states_changed: DocumentState,
quirks_mode: QuirksMode,
) -> Self {
@ -63,7 +63,11 @@ impl<'a, E: TElement> DocumentStateInvalidationProcessor<'a, E> {
}
}
impl<'a, E: TElement> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E> {
impl<'a, E, I> InvalidationProcessor<'a, E> for DocumentStateInvalidationProcessor<'a, E, I>
where
E: TElement,
I: Iterator<Item = &'a CascadeData>,
{
fn collect_invalidations(
&mut self,
_element: E,
@ -71,14 +75,15 @@ impl<'a, E: TElement> InvalidationProcessor<'a, E> for DocumentStateInvalidation
_descendant_invalidations: &mut DescendantInvalidationLists<'a>,
_sibling_invalidations: &mut InvalidationVector<'a>,
) -> bool {
let map = self.rules.invalidation_map();
for cascade_data in &mut self.rules {
let map = cascade_data.invalidation_map();
for dependency in &map.document_state_selectors {
if !dependency.state.intersects(self.document_states_changed) {
continue;
}
for dependency in &map.document_state_selectors {
if !dependency.state.intersects(self.document_states_changed) {
continue;
self_invalidations.push(Invalidation::new(&dependency.selector, 0));
}
self_invalidations.push(Invalidation::new(&dependency.selector, 0));
}
false

Просмотреть файл

@ -534,6 +534,20 @@ where
let mut any_descendant = false;
// NOTE(emilio): This should not be needed for Shadow DOM for normal
// element state / attribute invalidations (it's needed for XBL though,
// due to the weird way the anon content there works (it doesn't block
// combinators)).
//
// However, it's needed as of right now for document state invalidation,
// were we rely on iterating every element that ends up in the composed
// doc.
//
// Also, we could avoid having that special-case for document state
// invalidations if we invalidate for document state changes per
// subtree, though that's kind of annoying because we need to invalidate
// the shadow host subtree (to handle :host and ::slotted), and the
// actual shadow tree (to handle all other rules in the ShadowRoot).
if let Some(anon_content) = self.element.xbl_binding_anonymous_content() {
any_descendant |=
self.invalidate_dom_descendants_of(anon_content, invalidations);

Просмотреть файл

@ -24,7 +24,7 @@ use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::matching::matches_selector;
use smallvec::SmallVec;
use stylesheets::origin::{Origin, OriginSet};
use stylist::StyleRuleCascadeData;
use stylist::CascadeData;
#[derive(Debug, PartialEq)]
enum VisitedDependent {
@ -57,7 +57,7 @@ where
/// changes.
pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
shared_context: &'a SharedStyleContext<'b>,
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
shadow_rule_datas: &'a [(AtomicRef<'b, CascadeData>, QuirksMode)],
cut_off_inheritance: bool,
element: E,
data: &'a mut ElementData,
@ -68,7 +68,7 @@ impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
/// Creates a new StateAndAttrInvalidationProcessor.
pub fn new(
shared_context: &'a SharedStyleContext<'b>,
shadow_rule_datas: &'a [(AtomicRef<'b, StyleRuleCascadeData>, QuirksMode)],
shadow_rule_datas: &'a [(AtomicRef<'b, CascadeData>, QuirksMode)],
cut_off_inheritance: bool,
element: E,
data: &'a mut ElementData,
@ -255,11 +255,11 @@ where
OriginSet::all()
};
self.shared_context.stylist.each_normal_rule_cascade_data(|cascade_data, origin| {
for (cascade_data, origin) in self.shared_context.stylist.iter_origins() {
if document_origins.contains(origin.into()) {
collector.collect_dependencies_in_invalidation_map(cascade_data.invalidation_map());
}
});
}
for &(ref data, quirks_mode) in self.shadow_rule_datas {
// FIXME(emilio): Replace with assert / remove when we figure

Просмотреть файл

@ -680,7 +680,36 @@ impl LonghandId {
/// Returns true if the property is one that is ignored when document
/// colors are disabled.
fn is_ignored_when_document_colors_disabled(&self) -> bool {
fn is_ignored_when_document_colors_disabled(
&self,
cascade_level: CascadeLevel,
pseudo: Option<<&PseudoElement>,
) -> bool {
let is_ua_or_user_rule = matches!(
cascade_level,
CascadeLevel::UANormal |
CascadeLevel::UserNormal |
CascadeLevel::UserImportant |
CascadeLevel::UAImportant
);
if is_ua_or_user_rule {
return false;
}
let is_style_attribute = matches!(
cascade_level,
CascadeLevel::StyleAttributeNormal |
CascadeLevel::StyleAttributeImportant
);
// Don't override colors on pseudo-element's style attributes. The
// background-color on ::-moz-color-swatch is an example. Those are set
// as an author style (via the style attribute), but it's pretty
// important for it to show up for obvious reasons :)
if pseudo.is_some() && is_style_attribute {
return false;
}
matches!(*self,
${" | ".join([("LonghandId::" + p.camel_case)
for p in data.longhands if p.ignored_when_colors_disabled])}
@ -3383,12 +3412,11 @@ where
// marked as ignored in that mode, unless they come from a UA or
// user style sheet.
if ignore_colors &&
longhand_id.is_ignored_when_document_colors_disabled() &&
!matches!(cascade_level,
CascadeLevel::UANormal |
CascadeLevel::UserNormal |
CascadeLevel::UserImportant |
CascadeLevel::UAImportant) {
longhand_id.is_ignored_when_document_colors_disabled(
cascade_level,
context.builder.pseudo
)
{
let non_transparent_background = match *declaration {
PropertyDeclaration::BackgroundColor(ref color) => {
// Treat background-color a bit differently. If the specified

Просмотреть файл

@ -188,7 +188,8 @@ struct DocumentCascadeData {
per_origin: PerOrigin<()>,
}
struct DocumentCascadeDataIter<'a> {
/// An iterator over the cascade data of a given document.
pub struct DocumentCascadeDataIter<'a> {
iter: PerOriginIter<'a, ()>,
cascade_data: &'a DocumentCascadeData,
}
@ -436,6 +437,18 @@ impl Stylist {
}
}
/// Returns the cascade data for the author level.
#[inline]
pub fn author_cascade_data(&self) -> &CascadeData {
&self.cascade_data.author
}
/// Iterate through all the cascade datas from the document.
#[inline]
pub fn iter_origins(&self) -> DocumentCascadeDataIter {
self.cascade_data.iter_origins()
}
/// Iterate over the extra data in origin order.
#[inline]
pub fn iter_extra_data_origins(&self) -> ExtraStyleDataIterator {
@ -466,30 +479,22 @@ impl Stylist {
/// Returns the number of revalidation_selectors.
pub fn num_revalidation_selectors(&self) -> usize {
self.cascade_data.iter_origins()
.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()
.map(|(data, _)| data.selectors_for_cache_revalidation.len())
.sum()
}
/// Returns the number of entries in invalidation maps.
pub fn num_invalidations(&self) -> usize {
self.cascade_data.iter_origins()
.map(|(data, _)| {
data.normal_rule_data.invalidation_map.len() +
data.slotted_rule_data.as_ref().map_or(0, |d| d.invalidation_map.len())
}).sum()
.map(|(data, _)| data.invalidation_map.len())
.sum()
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule.
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.cascade_data.iter_origins()
.any(|(d, _)| {
d.normal_rule_data.has_document_state_dependency(state)
})
.any(|(d, _)| d.document_state_dependencies.intersects(state))
}
/// Flush the list of stylesheets if they changed, ensuring the stylist is
@ -605,24 +610,14 @@ impl Stylist {
self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard)
}
/// Executes `f` on each of the normal rule cascade datas in this styleset.
pub fn each_normal_rule_cascade_data<'a, F>(&'a self, mut f: F)
where
F: FnMut(&'a StyleRuleCascadeData, Origin),
{
for (data, origin) in self.cascade_data.iter_origins() {
f(&data.normal_rule_data, origin);
}
}
/// Returns whether for any of the applicable style rule data a given
/// condition is true.
pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
where
E: TElement,
F: FnMut(&StyleRuleCascadeData, QuirksMode) -> bool,
F: FnMut(&CascadeData, QuirksMode) -> bool,
{
if f(&self.cascade_data.user_agent.cascade_data.normal_rule_data, self.quirks_mode()) {
if f(&self.cascade_data.user_agent.cascade_data, self.quirks_mode()) {
return true;
}
@ -636,8 +631,8 @@ impl Stylist {
return maybe;
}
f(&self.cascade_data.author.normal_rule_data, self.quirks_mode()) ||
f(&self.cascade_data.user.normal_rule_data, self.quirks_mode())
f(&self.cascade_data.author, self.quirks_mode()) ||
f(&self.cascade_data.user, self.quirks_mode())
}
/// Computes the style for a given "precomputed" pseudo-element, taking the
@ -1446,18 +1441,6 @@ impl Stylist {
})
}
/// Returns the cascade data for the normal rules.
#[inline]
pub fn normal_author_cascade_data(&self) -> &StyleRuleCascadeData {
&self.cascade_data.author.normal_rule_data
}
/// Returns the cascade data for the slotted rules in this scope, if any.
#[inline]
pub fn slotted_author_cascade_data(&self) -> Option<&StyleRuleCascadeData> {
self.cascade_data.author.slotted_rule_data.as_ref().map(|d| &**d)
}
/// Returns the registered `@keyframes` animation for the specified name.
///
/// FIXME(emilio): This needs to account for the element rules.
@ -1498,7 +1481,7 @@ impl Stylist {
// this in the caller by asserting that the bitvecs are same-length.
let mut results = SmallBitVec::new();
for (data, _) in self.cascade_data.iter_origins() {
data.normal_rule_data.selectors_for_cache_revalidation.lookup(
data.selectors_for_cache_revalidation.lookup(
element,
self.quirks_mode,
|selector_and_hashes| {
@ -1918,7 +1901,7 @@ impl ElementAndPseudoRules {
}
#[inline]
fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
fn rules(&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),
@ -1938,12 +1921,26 @@ impl ElementAndPseudoRules {
}
}
/// Cascade data generated from style rules.
#[derive(Debug)]
/// 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))]
pub struct StyleRuleCascadeData {
/// The actual style rules.
rules: ElementAndPseudoRules,
#[derive(Debug)]
pub struct CascadeData {
/// The data coming from normal style rules that apply to elements at this
/// cascade level.
normal_rules: ElementAndPseudoRules,
/// 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_rules: Option<Box<ElementAndPseudoRules>>,
/// The invalidation map for these rules.
invalidation_map: InvalidationMap,
@ -1985,142 +1982,6 @@ pub struct StyleRuleCascadeData {
/// tree-structural state like child index and pseudos).
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
}
impl StyleRuleCascadeData {
#[inline(always)]
fn insert(
&mut self,
rule: Rule,
pseudo_element: Option<&PseudoElement>,
quirks_mode: QuirksMode,
rebuild_kind: SheetRebuildKind,
) -> Result<(), FailedAllocationError> {
if rebuild_kind.should_rebuild_invalidation() {
self.invalidation_map.note_selector(&rule.selector, quirks_mode)?;
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
};
rule.selector.visit(&mut visitor);
if visitor.needs_revalidation {
self.selectors_for_cache_revalidation.insert(
RevalidationSelectorAndHashes::new(
rule.selector.clone(),
rule.hashes.clone(),
),
quirks_mode
)?;
}
}
self.rules.insert(rule, pseudo_element, quirks_mode)
}
/// Returns the invalidation map.
#[inline]
pub fn invalidation_map(&self) -> &InvalidationMap {
&self.invalidation_map
}
#[cfg(feature = "gecko")]
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.rules.add_size_of(ops, sizes);
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
}
fn clear_cascade_data(&mut self) {
self.rules.clear();
}
fn clear(&mut self) {
self.clear_cascade_data();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
self.selectors_for_cache_revalidation.clear();
}
/// Returns whether the given attribute might appear in an attribute
/// selector of some rule.
#[inline]
pub fn might_have_attribute_dependency(
&self,
local_name: &LocalName,
) -> bool {
if *local_name == local_name!("style") {
return self.style_attribute_dependency
}
self.attribute_dependencies.might_contain_hash(local_name.get_hash())
}
/// Returns whether the given ElementState bit is relied upon by a selector
/// of some rule.
#[inline]
pub fn has_state_dependency(&self, state: ElementState) -> bool {
self.state_dependencies.intersects(state)
}
/// Returns whether the given DocumentState bit is relied upon by a selector
/// of some rule in the stylist.
#[inline]
fn has_document_state_dependency(&self, state: DocumentState) -> bool {
self.document_state_dependencies.intersects(state)
}
}
impl StyleRuleCascadeData {
fn new() -> Self {
Self {
rules: ElementAndPseudoRules::default(),
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
selectors_for_cache_revalidation: SelectorMap::new(),
}
}
#[inline]
fn rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.rules.borrow_for_pseudo(pseudo)
}
}
/// Data resulting from performing the CSS cascade that is specific to a given
/// origin.
///
/// FIXME(emilio): Consider renaming and splitting in `CascadeData` and
/// `InvalidationData`? That'd make `clear_cascade_data()` clearer.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Debug)]
struct CascadeData {
/// The data coming from normal style rules that apply to elements at this
/// cascade level.
normal_rule_data: StyleRuleCascadeData,
/// The data coming from ::slotted() pseudo-element rules.
///
/// We need to store them separately because an element needs to match
/// ::slotted() pseudo-element rules in different shadow roots.
///
/// In particular, we need to go through all the style data in all the
/// containing style scopes starting from the closest assigned slot.
slotted_rule_data: Option<Box<StyleRuleCascadeData>>,
/// A map with all the animations at this `CascadeData`'s origin, indexed
/// by name.
@ -2146,8 +2007,15 @@ struct CascadeData {
impl CascadeData {
fn new() -> Self {
Self {
normal_rule_data: StyleRuleCascadeData::new(),
slotted_rule_data: None,
normal_rules: ElementAndPseudoRules::default(),
slotted_rules: None,
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(),
animations: Default::default(),
extra_data: ExtraStyleData::default(),
effective_media_query_results: EffectiveMediaQueryResults::new(),
@ -2157,14 +2025,39 @@ impl CascadeData {
}
}
/// Returns the invalidation map.
pub fn invalidation_map(&self) -> &InvalidationMap {
&self.invalidation_map
}
/// 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 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())
}
#[inline]
fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.normal_rule_data.rules(pseudo)
self.normal_rules.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))
self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo))
}
/// Collects all the applicable media query results into `results`.
@ -2270,19 +2163,43 @@ impl CascadeData {
self.rules_source_order
);
let style_rule_cascade_data = if selector.is_slotted() {
self.slotted_rule_data.get_or_insert_with(|| {
Box::new(StyleRuleCascadeData::new())
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
)?;
}
}
let rules = if selector.is_slotted() {
self.slotted_rules.get_or_insert_with(|| {
Box::new(Default::default())
})
} else {
&mut self.normal_rule_data
&mut self.normal_rules
};
style_rule_cascade_data.insert(
rules.insert(
rule,
pseudo_element,
quirks_mode,
rebuild_kind,
)?;
}
self.rules_source_order += 1;
@ -2435,9 +2352,9 @@ impl CascadeData {
/// Clears the cascade data, but not the invalidation data.
fn clear_cascade_data(&mut self) {
self.normal_rule_data.clear_cascade_data();
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear_cascade_data();
self.normal_rules.clear();
if let Some(ref mut slotted_rules) = self.slotted_rules {
slotted_rules.clear();
}
self.animations.clear();
self.extra_data.clear();
@ -2448,20 +2365,25 @@ impl CascadeData {
fn clear(&mut self) {
self.clear_cascade_data();
self.normal_rule_data.clear();
if let Some(ref mut slotted_rule_data) = self.slotted_rule_data {
slotted_rule_data.clear();
}
self.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();
self.effective_media_query_results.clear();
}
/// Measures heap usage.
#[cfg(feature = "gecko")]
fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
self.normal_rule_data.add_size_of(ops, sizes);
if let Some(ref slotted_rules) = self.slotted_rule_data {
self.normal_rules.add_size_of(ops, sizes);
if let Some(ref slotted_rules) = self.slotted_rules {
slotted_rules.add_size_of(ops, sizes);
}
sizes.mInvalidationMap += self.invalidation_map.size_of(ops);
sizes.mRevalidationSelectors += self.selectors_for_cache_revalidation.size_of(ops);
sizes.mOther += self.animations.size_of(ops);
sizes.mOther += self.effective_media_query_results.size_of(ops);
sizes.mOther += self.extra_data.size_of(ops);

Просмотреть файл

@ -9,6 +9,7 @@ use malloc_size_of::MallocSizeOfOps;
use selectors::{Element, NthIndexCache};
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec;
use std::cell::RefCell;
use std::env;
use std::fmt::Write;
@ -1774,7 +1775,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
content_list: *mut structs::nsSimpleContentList,
may_use_invalidation: bool,
) {
use smallvec::SmallVec;
use std::borrow::Borrow;
use style::dom_apis::{self, MayUseInvalidation, QueryAll};
@ -2391,10 +2391,10 @@ pub extern "C" fn Servo_ComputedValues_EqualCustomProperties(
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoStyleContextBorrowed,
rules: RawGeckoServoStyleRuleListBorrowedMut) {
use smallvec::SmallVec;
pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
values: ServoStyleContextBorrowed,
rules: RawGeckoServoStyleRuleListBorrowedMut,
) {
let rule_node = match values.rules {
Some(ref r) => r,
None => return,
@ -4930,6 +4930,40 @@ pub extern "C" fn Servo_ParseCounterStyleName(
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
root: RawGeckoElementBorrowed,
raw_style_sets: *const nsTArray<RawServoStyleSetBorrowed>,
states_changed: u64,
) {
use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
use style::invalidation::element::invalidator::TreeStyleInvalidator;
let mut borrows = SmallVec::<[_; 20]>::with_capacity((*raw_style_sets).len());
for style_set in &**raw_style_sets {
borrows.push(PerDocumentStyleData::from_ffi(*style_set).borrow());
}
let root = GeckoElement(root);
let mut processor = DocumentStateInvalidationProcessor::new(
borrows.iter().flat_map(|b| b.stylist.iter_origins().map(|(data, _origin)| data)),
DocumentState::from_bits_truncate(states_changed),
root.as_node().owner_doc().quirks_mode(),
);
let result = TreeStyleInvalidator::new(
root,
/* stack_limit_checker = */ None,
&mut processor,
).invalidate();
debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
if result.has_invalidated_descendants() {
bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
} else if result.has_invalidated_self() {
bindings::Gecko_NoteDirtyElement(root.0);
}
}
#[no_mangle]
pub extern "C" fn Servo_ParseCounterStyleDescriptor(
descriptor: nsCSSCounterDesc,