mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
style: Move ANCHORS_RELATIVE_SELECTOR
out of nsINode flags
Move the flag to ComputedValueFlags, like `CONSIDERED_RELATIVE_SELECTOR`. Differential Revision: https://phabricator.services.mozilla.com/D180726
This commit is contained in:
parent
9321265b38
commit
ae5e0d49d8
7 changed files with 59 additions and 43 deletions
|
@ -99,6 +99,21 @@ impl QuirksMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this matching considered relative selector.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum RelativeSelectorMatchingState {
|
||||||
|
/// Was not considered for any relative selector.
|
||||||
|
None,
|
||||||
|
/// Relative selector was considered for a match, but the element to be
|
||||||
|
/// under matching would not anchor the relative selector. i.e. The
|
||||||
|
/// relative selector was not part of the first compound selector (in match
|
||||||
|
/// order).
|
||||||
|
Considered,
|
||||||
|
/// Same as above, but the relative selector was part of the first compound
|
||||||
|
/// selector (in match order).
|
||||||
|
ConsideredAnchor,
|
||||||
|
}
|
||||||
|
|
||||||
/// Data associated with the matching process for a element. This context is
|
/// Data associated with the matching process for a element. This context is
|
||||||
/// used across many selectors for an element, so it's not appropriate for
|
/// used across many selectors for an element, so it's not appropriate for
|
||||||
/// transient data that applies to only a single selector.
|
/// transient data that applies to only a single selector.
|
||||||
|
@ -146,7 +161,7 @@ where
|
||||||
|
|
||||||
/// The current element we're anchoring on for evaluating the relative selector.
|
/// The current element we're anchoring on for evaluating the relative selector.
|
||||||
current_relative_selector_anchor: Option<OpaqueElement>,
|
current_relative_selector_anchor: Option<OpaqueElement>,
|
||||||
pub considered_relative_selector: bool,
|
pub considered_relative_selector: RelativeSelectorMatchingState,
|
||||||
|
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
needs_selector_flags: NeedsSelectorFlags,
|
needs_selector_flags: NeedsSelectorFlags,
|
||||||
|
@ -200,7 +215,7 @@ where
|
||||||
pseudo_element_matching_fn: None,
|
pseudo_element_matching_fn: None,
|
||||||
extra_data: Default::default(),
|
extra_data: Default::default(),
|
||||||
current_relative_selector_anchor: None,
|
current_relative_selector_anchor: None,
|
||||||
considered_relative_selector: false,
|
considered_relative_selector: RelativeSelectorMatchingState::None,
|
||||||
_impl: ::std::marker::PhantomData,
|
_impl: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,12 +344,14 @@ where
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> R,
|
F: FnOnce(&mut Self) -> R,
|
||||||
{
|
{
|
||||||
// TODO(dshin): Nesting should be rejected at parse time.
|
debug_assert!(
|
||||||
let original_relative_selector_anchor = self.current_relative_selector_anchor.take();
|
self.current_relative_selector_anchor.is_none(),
|
||||||
|
"Nesting should've been rejected at parse time"
|
||||||
|
);
|
||||||
self.current_relative_selector_anchor = Some(anchor);
|
self.current_relative_selector_anchor = Some(anchor);
|
||||||
|
self.considered_relative_selector = RelativeSelectorMatchingState::Considered;
|
||||||
let result = self.nest(f);
|
let result = self.nest(f);
|
||||||
self.current_relative_selector_anchor = original_relative_selector_anchor;
|
self.current_relative_selector_anchor = None;
|
||||||
self.considered_relative_selector = true;
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,18 +60,13 @@ bitflags! {
|
||||||
/// The element has an empty selector, so when a child is appended we
|
/// The element has an empty selector, so when a child is appended we
|
||||||
/// might need to restyle the parent completely.
|
/// might need to restyle the parent completely.
|
||||||
const HAS_EMPTY_SELECTOR = 1 << 4;
|
const HAS_EMPTY_SELECTOR = 1 << 4;
|
||||||
|
|
||||||
/// This element has a relative selector that anchors to it, or may do so
|
|
||||||
/// if its descendants or its later siblings change.
|
|
||||||
const ANCHORS_RELATIVE_SELECTOR = 1 << 5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementSelectorFlags {
|
impl ElementSelectorFlags {
|
||||||
/// Returns the subset of flags that apply to the element.
|
/// Returns the subset of flags that apply to the element.
|
||||||
pub fn for_self(self) -> ElementSelectorFlags {
|
pub fn for_self(self) -> ElementSelectorFlags {
|
||||||
self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR |
|
self & ElementSelectorFlags::HAS_EMPTY_SELECTOR
|
||||||
ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the subset of flags that apply to the parent.
|
/// Returns the subset of flags that apply to the parent.
|
||||||
|
@ -370,12 +365,10 @@ fn matches_relative_selectors<E: Element>(
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext<E::Impl>,
|
context: &mut MatchingContext<E::Impl>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if context.needs_selector_flags() {
|
// If we've considered anchoring `:has()` selector while trying to match this element,
|
||||||
// If we've considered anchoring `:has()` selector while trying to match this element,
|
// mark it as such, as it has implications on style sharing (See style sharing
|
||||||
// mark it as such, as it has implications on style sharing (See style sharing
|
// code for further information).
|
||||||
// code for further information).
|
context.considered_relative_selector = RelativeSelectorMatchingState::ConsideredAnchor;
|
||||||
element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
|
|
||||||
}
|
|
||||||
for RelativeSelector {
|
for RelativeSelector {
|
||||||
match_hint,
|
match_hint,
|
||||||
selector,
|
selector,
|
||||||
|
|
|
@ -900,10 +900,6 @@ pub trait TElement:
|
||||||
&self,
|
&self,
|
||||||
display: &Display,
|
display: &Display,
|
||||||
) -> euclid::default::Size2D<Option<app_units::Au>>;
|
) -> euclid::default::Size2D<Option<app_units::Au>>;
|
||||||
|
|
||||||
/// Returns true if this element anchors a relative selector, now or after
|
|
||||||
/// a DOM mutation.
|
|
||||||
fn anchors_relative_selector(&self) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TNode and TElement aren't Send because we want to be careful and explicit
|
/// TNode and TElement aren't Send because we want to be careful and explicit
|
||||||
|
|
|
@ -894,9 +894,6 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
|
||||||
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
|
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
|
||||||
gecko_flags |= NODE_HAS_EMPTY_SELECTOR;
|
gecko_flags |= NODE_HAS_EMPTY_SELECTOR;
|
||||||
}
|
}
|
||||||
if flags.contains(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR) {
|
|
||||||
gecko_flags |= NODE_ANCHORS_RELATIVE_SELECTOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
gecko_flags
|
gecko_flags
|
||||||
}
|
}
|
||||||
|
@ -1730,11 +1727,6 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn anchors_relative_selector(&self) -> bool {
|
|
||||||
use crate::gecko_bindings::structs::NODE_ANCHORS_RELATIVE_SELECTOR;
|
|
||||||
self.flags() & NODE_ANCHORS_RELATIVE_SELECTOR != 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> PartialEq for GeckoElement<'le> {
|
impl<'le> PartialEq for GeckoElement<'le> {
|
||||||
|
|
|
@ -121,6 +121,10 @@ bitflags! {
|
||||||
|
|
||||||
/// Whether the style evaluated any relative selector.
|
/// Whether the style evaluated any relative selector.
|
||||||
const CONSIDERED_RELATIVE_SELECTOR = 1 << 24;
|
const CONSIDERED_RELATIVE_SELECTOR = 1 << 24;
|
||||||
|
|
||||||
|
/// Whether the style evaluated the matched element to be an anchor of
|
||||||
|
/// a relative selector.
|
||||||
|
const ANCHORS_RELATIVE_SELECTOR = 1 << 25;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +157,9 @@ impl ComputedValueFlags {
|
||||||
/// Flags that are an input to the cascade.
|
/// Flags that are an input to the cascade.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cascade_input_flags() -> Self {
|
fn cascade_input_flags() -> Self {
|
||||||
Self::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES | Self::CONSIDERED_RELATIVE_SELECTOR
|
Self::USES_VIEWPORT_UNITS_ON_CONTAINER_QUERIES |
|
||||||
|
Self::CONSIDERED_RELATIVE_SELECTOR |
|
||||||
|
Self::ANCHORS_RELATIVE_SELECTOR
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the flags that are always propagated to descendants.
|
/// Returns the flags that are always propagated to descendants.
|
||||||
|
|
|
@ -632,7 +632,11 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
// matching `.foo`, even if `:has()` may not even be used. Ideally we'd
|
// matching `.foo`, even if `:has()` may not even be used. Ideally we'd
|
||||||
// have something like `RelativeSelectorConsidered::RightMost`, but the
|
// have something like `RelativeSelectorConsidered::RightMost`, but the
|
||||||
// element flag is required for invalidation, and this reduces more tracking.
|
// element flag is required for invalidation, and this reduces more tracking.
|
||||||
if element.anchors_relative_selector() {
|
if style
|
||||||
|
.style
|
||||||
|
.0
|
||||||
|
.flags
|
||||||
|
.intersects(ComputedValueFlags::ANCHORS_RELATIVE_SELECTOR) {
|
||||||
debug!("Failing to insert to the cache: may anchor relative selector");
|
debug!("Failing to insert to the cache: may anchor relative selector");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::rule_tree::StrongRuleNode;
|
||||||
use crate::selector_parser::{PseudoElement, SelectorImpl};
|
use crate::selector_parser::{PseudoElement, SelectorImpl};
|
||||||
use crate::stylist::RuleInclusion;
|
use crate::stylist::RuleInclusion;
|
||||||
use log::Level::Trace;
|
use log::Level::Trace;
|
||||||
use selectors::matching::{MatchingContext, NeedsSelectorFlags};
|
use selectors::matching::{MatchingContext, NeedsSelectorFlags, RelativeSelectorMatchingState};
|
||||||
use selectors::matching::{MatchingMode, VisitedHandlingMode};
|
use selectors::matching::{MatchingMode, VisitedHandlingMode};
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
|
||||||
|
@ -503,16 +503,24 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// This is a bit awkward - ideally, the flag is set directly where `considered_relative_selector`
|
||||||
if matching_context.considered_relative_selector {
|
// is; however, in that context, the implementation detail of `extra_data` is not visible, so
|
||||||
// This is a bit awkward - ideally, the flag is set directly where `considered_relative_selector`
|
// it's done here. A trait for manipulating the flags is an option, but not worth it for a single flag.
|
||||||
// is; however, in that context, the implementation detail of `extra_data` is not visible, so
|
match matching_context.considered_relative_selector {
|
||||||
// it's done here. A trait for manipulating the flags is an option, but not worth it for a single flag.
|
RelativeSelectorMatchingState::None => (),
|
||||||
matching_context
|
RelativeSelectorMatchingState::Considered => {
|
||||||
.extra_data
|
matching_context
|
||||||
.cascade_input_flags
|
.extra_data
|
||||||
.insert(ComputedValueFlags::CONSIDERED_RELATIVE_SELECTOR);
|
.cascade_input_flags
|
||||||
}
|
.insert(ComputedValueFlags::CONSIDERED_RELATIVE_SELECTOR);
|
||||||
|
},
|
||||||
|
RelativeSelectorMatchingState::ConsideredAnchor => {
|
||||||
|
matching_context.extra_data.cascade_input_flags.insert(
|
||||||
|
ComputedValueFlags::ANCHORS_RELATIVE_SELECTOR |
|
||||||
|
ComputedValueFlags::CONSIDERED_RELATIVE_SELECTOR,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
MatchingResults {
|
MatchingResults {
|
||||||
rule_node,
|
rule_node,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue