mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #18936 - heycam:document-state, r=emilio
style: Keep track of document state dependencies. Servo half of https://bugzilla.mozilla.org/show_bug.cgi?id=1390694, reviewed there by Emilio. <!-- 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/18936) <!-- Reviewable:end -->
This commit is contained in:
commit
44eeb1999b
5 changed files with 53 additions and 25 deletions
|
@ -144,6 +144,7 @@ bitflags! {
|
||||||
///
|
///
|
||||||
/// NB: Is important for this to remain in sync with Gecko's
|
/// NB: Is important for this to remain in sync with Gecko's
|
||||||
/// dom/base/nsIDocument.h.
|
/// dom/base/nsIDocument.h.
|
||||||
|
#[derive(MallocSizeOf)]
|
||||||
pub flags DocumentState: u64 {
|
pub flags DocumentState: u64 {
|
||||||
/// RTL locale: specific to the XUL localedir attribute
|
/// RTL locale: specific to the XUL localedir attribute
|
||||||
const NS_DOCUMENT_STATE_RTL_LOCALE = 1 << 0,
|
const NS_DOCUMENT_STATE_RTL_LOCALE = 1 << 0,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! Gecko-specific bits for selector-parsing.
|
//! Gecko-specific bits for selector-parsing.
|
||||||
|
|
||||||
use cssparser::{BasicParseError, BasicParseErrorKind, Parser, ToCss, Token, CowRcStr, SourceLocation};
|
use cssparser::{BasicParseError, BasicParseErrorKind, Parser, ToCss, Token, CowRcStr, SourceLocation};
|
||||||
use element_state::ElementState;
|
use element_state::{self, DocumentState, ElementState};
|
||||||
use gecko_bindings::structs::CSSPseudoClassType;
|
use gecko_bindings::structs::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};
|
||||||
|
@ -195,6 +195,15 @@ impl NonTSPseudoClass {
|
||||||
apply_non_ts_list!(pseudo_class_state)
|
apply_non_ts_list!(pseudo_class_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the document state flag associated with a pseudo-class, if any.
|
||||||
|
pub fn document_state_flag(&self) -> DocumentState {
|
||||||
|
match *self {
|
||||||
|
NonTSPseudoClass::MozLocaleDir(..) => element_state::NS_DOCUMENT_STATE_RTL_LOCALE,
|
||||||
|
NonTSPseudoClass::MozWindowInactive => element_state::NS_DOCUMENT_STATE_WINDOW_INACTIVE,
|
||||||
|
_ => DocumentState::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the given pseudoclass should trigger style sharing cache
|
/// Returns true if the given pseudoclass should trigger style sharing cache
|
||||||
/// revalidation.
|
/// revalidation.
|
||||||
pub fn needs_cache_revalidation(&self) -> bool {
|
pub fn needs_cache_revalidation(&self) -> bool {
|
||||||
|
@ -433,13 +442,6 @@ impl SelectorImpl {
|
||||||
fun(pseudo.clone())
|
fun(pseudo.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns the relevant state flag for a given non-tree-structural
|
|
||||||
/// pseudo-class.
|
|
||||||
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
|
||||||
pc.state_flag()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn utf16_to_ascii_lowercase(unit: u16) -> u16 {
|
fn utf16_to_ascii_lowercase(unit: u16) -> u16 {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use {Atom, Prefix, Namespace, LocalName, CaseSensitivityExt};
|
||||||
use attr::{AttrIdentifier, AttrValue};
|
use attr::{AttrIdentifier, AttrValue};
|
||||||
use cssparser::{Parser as CssParser, ToCss, serialize_identifier, CowRcStr, SourceLocation};
|
use cssparser::{Parser as CssParser, ToCss, serialize_identifier, CowRcStr, SourceLocation};
|
||||||
use dom::{OpaqueNode, TElement, TNode};
|
use dom::{OpaqueNode, TElement, TNode};
|
||||||
use element_state::ElementState;
|
use element_state::{DocumentState, ElementState};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use invalidation::element::element_wrapper::ElementSnapshot;
|
use invalidation::element::element_wrapper::ElementSnapshot;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
|
@ -353,6 +353,11 @@ impl NonTSPseudoClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the document state flag associated with a pseudo-class, if any.
|
||||||
|
pub fn document_state_flag(&self) -> DocumentState {
|
||||||
|
DocumentState::empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the given pseudoclass should trigger style sharing cache revalidation.
|
/// Returns true if the given pseudoclass should trigger style sharing cache revalidation.
|
||||||
pub fn needs_cache_revalidation(&self) -> bool {
|
pub fn needs_cache_revalidation(&self) -> bool {
|
||||||
self.state_flag().is_empty()
|
self.state_flag().is_empty()
|
||||||
|
@ -561,12 +566,6 @@ impl SelectorImpl {
|
||||||
fun(PseudoElement::from_eager_index(i));
|
fun(PseudoElement::from_eager_index(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pseudo-class state flag for selector matching.
|
|
||||||
#[inline]
|
|
||||||
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
|
||||||
pc.state_flag()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map from elements to snapshots for the Servo style back-end.
|
/// A map from elements to snapshots for the Servo style back-end.
|
||||||
|
|
|
@ -8,7 +8,7 @@ use {Atom, LocalName, Namespace};
|
||||||
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
||||||
use context::{CascadeInputs, QuirksMode};
|
use context::{CascadeInputs, QuirksMode};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use element_state::ElementState;
|
use element_state::{DocumentState, ElementState};
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
|
use gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
|
||||||
|
@ -625,12 +625,6 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given ElementState bit might be relied upon by a
|
|
||||||
/// selector of some rule in the stylist.
|
|
||||||
pub fn might_have_state_dependency(&self, state: ElementState) -> bool {
|
|
||||||
self.has_state_dependency(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the given ElementState bit is relied upon by a selector
|
/// Returns whether the given ElementState bit is relied upon by a selector
|
||||||
/// of some rule in the stylist.
|
/// of some rule in the stylist.
|
||||||
pub fn has_state_dependency(&self, state: ElementState) -> bool {
|
pub fn has_state_dependency(&self, state: ElementState) -> bool {
|
||||||
|
@ -639,6 +633,14 @@ impl Stylist {
|
||||||
.any(|(d, _)| d.state_dependencies.intersects(state))
|
.any(|(d, _)| d.state_dependencies.intersects(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given DocumentState bit is relied upon by a selector
|
||||||
|
/// of some rule in the stylist.
|
||||||
|
pub fn has_document_state_dependency(&self, state: DocumentState) -> bool {
|
||||||
|
self.cascade_data
|
||||||
|
.iter_origins()
|
||||||
|
.any(|(d, _)| d.document_state_dependencies.intersects(state))
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
/// Computes the style for a given "precomputed" pseudo-element, taking the
|
||||||
/// universal rules and applying them.
|
/// universal rules and applying them.
|
||||||
///
|
///
|
||||||
|
@ -1677,6 +1679,8 @@ struct StylistSelectorVisitor<'a> {
|
||||||
style_attribute_dependency: &'a mut bool,
|
style_attribute_dependency: &'a mut bool,
|
||||||
/// All the states selectors in the page reference.
|
/// All the states selectors in the page reference.
|
||||||
state_dependencies: &'a mut ElementState,
|
state_dependencies: &'a mut ElementState,
|
||||||
|
/// All the document states selectors in the page reference.
|
||||||
|
document_state_dependencies: &'a mut DocumentState,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn component_needs_revalidation(
|
fn component_needs_revalidation(
|
||||||
|
@ -1764,6 +1768,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
|
||||||
match *s {
|
match *s {
|
||||||
Component::NonTSPseudoClass(ref p) => {
|
Component::NonTSPseudoClass(ref p) => {
|
||||||
self.state_dependencies.insert(p.state_flag());
|
self.state_dependencies.insert(p.state_flag());
|
||||||
|
self.document_state_dependencies.insert(p.document_state_flag());
|
||||||
}
|
}
|
||||||
Component::ID(ref id) if !self.passed_rightmost_selector => {
|
Component::ID(ref id) if !self.passed_rightmost_selector => {
|
||||||
// We want to stop storing mapped ids as soon as we've moved off
|
// We want to stop storing mapped ids as soon as we've moved off
|
||||||
|
@ -1832,6 +1837,11 @@ struct CascadeData {
|
||||||
/// when an irrelevant element state bit changes.
|
/// when an irrelevant element state bit changes.
|
||||||
state_dependencies: ElementState,
|
state_dependencies: ElementState,
|
||||||
|
|
||||||
|
/// The document state bits that are relied on by selectors. This is used
|
||||||
|
/// to tell whether we need to restyle the entire document when a document
|
||||||
|
/// state bit changes.
|
||||||
|
document_state_dependencies: DocumentState,
|
||||||
|
|
||||||
/// The ids that appear in the rightmost complex selector of selectors (and
|
/// The ids that appear in the rightmost complex selector of selectors (and
|
||||||
/// hence in our selector maps). Used to determine when sharing styles is
|
/// hence in our selector maps). Used to determine when sharing styles is
|
||||||
/// safe: we disallow style sharing for elements whose id matches this
|
/// safe: we disallow style sharing for elements whose id matches this
|
||||||
|
@ -1873,6 +1883,7 @@ impl CascadeData {
|
||||||
attribute_dependencies: NonCountingBloomFilter::new(),
|
attribute_dependencies: NonCountingBloomFilter::new(),
|
||||||
style_attribute_dependency: false,
|
style_attribute_dependency: false,
|
||||||
state_dependencies: ElementState::empty(),
|
state_dependencies: ElementState::empty(),
|
||||||
|
document_state_dependencies: DocumentState::empty(),
|
||||||
mapped_ids: NonCountingBloomFilter::new(),
|
mapped_ids: NonCountingBloomFilter::new(),
|
||||||
selectors_for_cache_revalidation: SelectorMap::new(),
|
selectors_for_cache_revalidation: SelectorMap::new(),
|
||||||
effective_media_query_results: EffectiveMediaQueryResults::new(),
|
effective_media_query_results: EffectiveMediaQueryResults::new(),
|
||||||
|
@ -2037,6 +2048,7 @@ impl CascadeData {
|
||||||
attribute_dependencies: &mut self.attribute_dependencies,
|
attribute_dependencies: &mut self.attribute_dependencies,
|
||||||
style_attribute_dependency: &mut self.style_attribute_dependency,
|
style_attribute_dependency: &mut self.style_attribute_dependency,
|
||||||
state_dependencies: &mut self.state_dependencies,
|
state_dependencies: &mut self.state_dependencies,
|
||||||
|
document_state_dependencies: &mut self.document_state_dependencies,
|
||||||
mapped_ids: &mut self.mapped_ids,
|
mapped_ids: &mut self.mapped_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2225,6 +2237,7 @@ impl CascadeData {
|
||||||
self.attribute_dependencies.clear();
|
self.attribute_dependencies.clear();
|
||||||
self.style_attribute_dependency = false;
|
self.style_attribute_dependency = false;
|
||||||
self.state_dependencies = ElementState::empty();
|
self.state_dependencies = ElementState::empty();
|
||||||
|
self.document_state_dependencies = DocumentState::empty();
|
||||||
self.mapped_ids.clear();
|
self.mapped_ids.clear();
|
||||||
self.selectors_for_cache_revalidation.clear();
|
self.selectors_for_cache_revalidation.clear();
|
||||||
}
|
}
|
||||||
|
@ -2333,12 +2346,14 @@ pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool {
|
||||||
let mut mapped_ids = NonCountingBloomFilter::new();
|
let mut mapped_ids = NonCountingBloomFilter::new();
|
||||||
let mut style_attribute_dependency = false;
|
let mut style_attribute_dependency = false;
|
||||||
let mut state_dependencies = ElementState::empty();
|
let mut state_dependencies = ElementState::empty();
|
||||||
|
let mut document_state_dependencies = DocumentState::empty();
|
||||||
let mut visitor = StylistSelectorVisitor {
|
let mut visitor = StylistSelectorVisitor {
|
||||||
needs_revalidation: false,
|
needs_revalidation: false,
|
||||||
passed_rightmost_selector: false,
|
passed_rightmost_selector: false,
|
||||||
attribute_dependencies: &mut attribute_dependencies,
|
attribute_dependencies: &mut attribute_dependencies,
|
||||||
style_attribute_dependency: &mut style_attribute_dependency,
|
style_attribute_dependency: &mut style_attribute_dependency,
|
||||||
state_dependencies: &mut state_dependencies,
|
state_dependencies: &mut state_dependencies,
|
||||||
|
document_state_dependencies: &mut document_state_dependencies,
|
||||||
mapped_ids: &mut mapped_ids,
|
mapped_ids: &mut mapped_ids,
|
||||||
};
|
};
|
||||||
s.visit(&mut visitor);
|
s.visit(&mut visitor);
|
||||||
|
|
|
@ -21,7 +21,7 @@ use style::context::ThreadLocalStyleContext;
|
||||||
use style::data::{ElementStyles, self};
|
use style::data::{ElementStyles, self};
|
||||||
use style::dom::{ShowSubtreeData, TElement, TNode};
|
use style::dom::{ShowSubtreeData, TElement, TNode};
|
||||||
use style::driver;
|
use style::driver;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::{DocumentState, ElementState};
|
||||||
use style::error_reporting::{NullReporter, ParseErrorReporter};
|
use style::error_reporting::{NullReporter, ParseErrorReporter};
|
||||||
use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
|
use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
|
||||||
use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
|
use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
|
||||||
|
@ -4090,19 +4090,30 @@ 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.might_have_state_dependency(state);
|
let mut has_dep = data.stylist.has_state_dependency(state);
|
||||||
if !has_dep {
|
if !has_dep {
|
||||||
// TODO(emilio): Consider optimizing this storing attribute
|
// TODO(emilio): Consider optimizing this storing attribute
|
||||||
// dependencies from UA sheets separately, so we could optimize
|
// dependencies from UA sheets separately, so we could optimize
|
||||||
// the above lookup if cut_off_inheritance is true.
|
// the above lookup if cut_off_inheritance is true.
|
||||||
element.each_xbl_stylist(|stylist| {
|
element.each_xbl_stylist(|stylist| {
|
||||||
has_dep = has_dep || stylist.might_have_state_dependency(state);
|
has_dep = has_dep || stylist.has_state_dependency(state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
has_dep
|
has_dep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
|
||||||
|
raw_data: RawServoStyleSetBorrowed,
|
||||||
|
state: u64,
|
||||||
|
) -> bool {
|
||||||
|
let state = DocumentState::from_bits_truncate(state);
|
||||||
|
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
|
||||||
|
|
||||||
|
data.stylist.has_document_state_dependency(state)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_GetCustomPropertyValue(
|
pub extern "C" fn Servo_GetCustomPropertyValue(
|
||||||
computed_values: ServoStyleContextBorrowed,
|
computed_values: ServoStyleContextBorrowed,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue