mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
style: React to font-size changes on query containers
Much like we react to font-size changes on the root. Differential Revision: https://phabricator.services.mozilla.com/D157173
This commit is contained in:
parent
00c9d9d033
commit
f9f5283a65
2 changed files with 78 additions and 60 deletions
|
@ -50,10 +50,11 @@ pub enum StyleChange {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not newly computed values for an element need to be cascade
|
/// Whether or not newly computed values for an element need to be cascaded to
|
||||||
/// to children.
|
/// children (or children might need to be re-matched, e.g., for container
|
||||||
|
/// queries).
|
||||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub enum ChildCascadeRequirement {
|
pub enum ChildRestyleRequirement {
|
||||||
/// Old and new computed values were the same, or we otherwise know that
|
/// Old and new computed values were the same, or we otherwise know that
|
||||||
/// we won't bother recomputing style for children, so we can skip cascading
|
/// we won't bother recomputing style for children, so we can skip cascading
|
||||||
/// the new values into child elements.
|
/// the new values into child elements.
|
||||||
|
@ -68,12 +69,16 @@ pub enum ChildCascadeRequirement {
|
||||||
/// used to handle root font-size updates needing to recascade the whole
|
/// used to handle root font-size updates needing to recascade the whole
|
||||||
/// document.
|
/// document.
|
||||||
MustCascadeDescendants = 3,
|
MustCascadeDescendants = 3,
|
||||||
|
/// We need to re-match the whole subttree. This is used to handle container
|
||||||
|
/// query relative unit changes for example. Container query size changes
|
||||||
|
/// also trigger re-match, but after layout.
|
||||||
|
MustMatchDescendants = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChildCascadeRequirement {
|
impl ChildRestyleRequirement {
|
||||||
/// Whether we can unconditionally skip the cascade.
|
/// Whether we can unconditionally skip the cascade.
|
||||||
pub fn can_skip_cascade(&self) -> bool {
|
pub fn can_skip_cascade(&self) -> bool {
|
||||||
matches!(*self, ChildCascadeRequirement::CanSkipCascade)
|
matches!(*self, ChildRestyleRequirement::CanSkipCascade)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,7 +736,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
old_values: &ComputedValues,
|
old_values: &ComputedValues,
|
||||||
new_values: &ComputedValues,
|
new_values: &ComputedValues,
|
||||||
pseudo: Option<&PseudoElement>,
|
pseudo: Option<&PseudoElement>,
|
||||||
) -> ChildCascadeRequirement {
|
) -> ChildRestyleRequirement {
|
||||||
debug!("accumulate_damage_for: {:?}", self);
|
debug!("accumulate_damage_for: {:?}", self);
|
||||||
debug_assert!(!shared_context
|
debug_assert!(!shared_context
|
||||||
.traversal_flags
|
.traversal_flags
|
||||||
|
@ -750,16 +755,16 @@ trait PrivateMatchMethods: TElement {
|
||||||
" > flags changed: {:?} != {:?}",
|
" > flags changed: {:?} != {:?}",
|
||||||
old_values.flags, new_values.flags
|
old_values.flags, new_values.flags
|
||||||
);
|
);
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
match difference.change {
|
match difference.change {
|
||||||
StyleChange::Unchanged => return ChildCascadeRequirement::CanSkipCascade,
|
StyleChange::Unchanged => return ChildRestyleRequirement::CanSkipCascade,
|
||||||
StyleChange::Changed { reset_only } => {
|
StyleChange::Changed { reset_only } => {
|
||||||
// If inherited properties changed, the best we can do is
|
// If inherited properties changed, the best we can do is
|
||||||
// cascade the children.
|
// cascade the children.
|
||||||
if !reset_only {
|
if !reset_only {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -771,26 +776,26 @@ trait PrivateMatchMethods: TElement {
|
||||||
// If we used to be a display: none element, and no longer are, our
|
// If we used to be a display: none element, and no longer are, our
|
||||||
// children need to be restyled because they're unstyled.
|
// children need to be restyled because they're unstyled.
|
||||||
if old_display == Display::None {
|
if old_display == Display::None {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
// Blockification of children may depend on our display value,
|
// Blockification of children may depend on our display value,
|
||||||
// so we need to actually do the recascade. We could potentially
|
// so we need to actually do the recascade. We could potentially
|
||||||
// do better, but it doesn't seem worth it.
|
// do better, but it doesn't seem worth it.
|
||||||
if old_display.is_item_container() != new_display.is_item_container() {
|
if old_display.is_item_container() != new_display.is_item_container() {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
// We may also need to blockify and un-blockify descendants if our
|
// We may also need to blockify and un-blockify descendants if our
|
||||||
// display goes from / to display: contents, since the "layout
|
// display goes from / to display: contents, since the "layout
|
||||||
// parent style" changes.
|
// parent style" changes.
|
||||||
if old_display.is_contents() || new_display.is_contents() {
|
if old_display.is_contents() || new_display.is_contents() {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
// Line break suppression may also be affected if the display
|
// Line break suppression may also be affected if the display
|
||||||
// type changes from ruby to non-ruby.
|
// type changes from ruby to non-ruby.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
{
|
{
|
||||||
if old_display.is_ruby_type() != new_display.is_ruby_type() {
|
if old_display.is_ruby_type() != new_display.is_ruby_type() {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,12 +818,12 @@ trait PrivateMatchMethods: TElement {
|
||||||
let is_legacy_justify_items = new_justify_items.computed.0.contains(AlignFlags::LEGACY);
|
let is_legacy_justify_items = new_justify_items.computed.0.contains(AlignFlags::LEGACY);
|
||||||
|
|
||||||
if is_legacy_justify_items != was_legacy_justify_items {
|
if is_legacy_justify_items != was_legacy_justify_items {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
if was_legacy_justify_items && old_justify_items.computed != new_justify_items.computed
|
if was_legacy_justify_items && old_justify_items.computed != new_justify_items.computed
|
||||||
{
|
{
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,13 +832,13 @@ trait PrivateMatchMethods: TElement {
|
||||||
// We may need to set or propagate the CAN_BE_FRAGMENTED bit
|
// We may need to set or propagate the CAN_BE_FRAGMENTED bit
|
||||||
// on our children.
|
// on our children.
|
||||||
if old_values.is_multicol() != new_values.is_multicol() {
|
if old_values.is_multicol() != new_values.is_multicol() {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We could prove that, if our children don't inherit reset
|
// We could prove that, if our children don't inherit reset
|
||||||
// properties, we can stop the cascade.
|
// properties, we can stop the cascade.
|
||||||
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle
|
ChildRestyleRequirement::MustCascadeChildrenIfInheritResetStyle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,7 +885,7 @@ pub trait MatchMethods: TElement {
|
||||||
data: &mut ElementData,
|
data: &mut ElementData,
|
||||||
mut new_styles: ResolvedElementStyles,
|
mut new_styles: ResolvedElementStyles,
|
||||||
important_rules_changed: bool,
|
important_rules_changed: bool,
|
||||||
) -> ChildCascadeRequirement {
|
) -> ChildRestyleRequirement {
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
self.process_animations(
|
self.process_animations(
|
||||||
|
@ -896,26 +901,37 @@ pub trait MatchMethods: TElement {
|
||||||
|
|
||||||
let new_primary_style = data.styles.primary.as_ref().unwrap();
|
let new_primary_style = data.styles.primary.as_ref().unwrap();
|
||||||
|
|
||||||
let mut cascade_requirement = ChildCascadeRequirement::CanSkipCascade;
|
let mut restyle_requirement = ChildRestyleRequirement::CanSkipCascade;
|
||||||
if new_primary_style
|
let is_root = new_primary_style.flags.contains(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE);
|
||||||
.flags
|
let is_container = !new_primary_style.get_box().clone_container_type().is_empty();
|
||||||
.contains(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE)
|
if is_root || is_container {
|
||||||
{
|
|
||||||
let device = context.shared.stylist.device();
|
|
||||||
let new_font_size = new_primary_style.get_font().clone_font_size();
|
let new_font_size = new_primary_style.get_font().clone_font_size();
|
||||||
|
let old_font_size = old_styles
|
||||||
if old_styles
|
|
||||||
.primary
|
.primary
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(true, |s| s.get_font().clone_font_size() != new_font_size)
|
.map(|s| s.get_font().clone_font_size());
|
||||||
{
|
|
||||||
debug_assert!(self.owner_doc_matches_for_testing(device));
|
if old_font_size != Some(new_font_size) {
|
||||||
device.set_root_font_size(new_font_size.size().into());
|
if is_root {
|
||||||
// If the root font-size changed since last time, and something
|
let device = context.shared.stylist.device();
|
||||||
// in the document did use rem units, ensure we recascade the
|
debug_assert!(self.owner_doc_matches_for_testing(device));
|
||||||
// entire tree.
|
device.set_root_font_size(new_font_size.size().into());
|
||||||
if device.used_root_font_size() {
|
if device.used_root_font_size() {
|
||||||
cascade_requirement = ChildCascadeRequirement::MustCascadeDescendants;
|
// If the root font-size changed since last time, and something
|
||||||
|
// in the document did use rem units, ensure we recascade the
|
||||||
|
// entire tree.
|
||||||
|
restyle_requirement = ChildRestyleRequirement::MustCascadeDescendants;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_container && old_font_size.is_some() {
|
||||||
|
// TODO(emilio): Maybe only do this if we were matched
|
||||||
|
// against relative font sizes?
|
||||||
|
// Also, maybe we should do this as well for font-family /
|
||||||
|
// etc changes (for ex/ch/ic units to work correctly)? We
|
||||||
|
// should probably do the optimization mentioned above if
|
||||||
|
// so.
|
||||||
|
restyle_requirement = ChildRestyleRequirement::MustMatchDescendants;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -926,7 +942,6 @@ pub trait MatchMethods: TElement {
|
||||||
// changes and before we reach our children the cascade stops,
|
// changes and before we reach our children the cascade stops,
|
||||||
// but we don't track right now whether we use the document body
|
// but we don't track right now whether we use the document body
|
||||||
// color, and nobody else handles that properly anyway.
|
// color, and nobody else handles that properly anyway.
|
||||||
|
|
||||||
let device = context.shared.stylist.device();
|
let device = context.shared.stylist.device();
|
||||||
|
|
||||||
// Needed for the "inherit from body" quirk.
|
// Needed for the "inherit from body" quirk.
|
||||||
|
@ -941,17 +956,17 @@ pub trait MatchMethods: TElement {
|
||||||
.traversal_flags
|
.traversal_flags
|
||||||
.contains(TraversalFlags::FinalAnimationTraversal)
|
.contains(TraversalFlags::FinalAnimationTraversal)
|
||||||
{
|
{
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildRestyleRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also, don't do anything if there was no style.
|
// Also, don't do anything if there was no style.
|
||||||
let old_primary_style = match old_styles.primary {
|
let old_primary_style = match old_styles.primary {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
None => return ChildRestyleRequirement::MustCascadeChildren,
|
||||||
};
|
};
|
||||||
|
|
||||||
cascade_requirement = cmp::max(
|
restyle_requirement = cmp::max(
|
||||||
cascade_requirement,
|
restyle_requirement,
|
||||||
self.accumulate_damage_for(
|
self.accumulate_damage_for(
|
||||||
context.shared,
|
context.shared,
|
||||||
&mut data.damage,
|
&mut data.damage,
|
||||||
|
@ -963,7 +978,7 @@ pub trait MatchMethods: TElement {
|
||||||
|
|
||||||
if data.styles.pseudos.is_empty() && old_styles.pseudos.is_empty() {
|
if data.styles.pseudos.is_empty() && old_styles.pseudos.is_empty() {
|
||||||
// This is the common case; no need to examine pseudos here.
|
// This is the common case; no need to examine pseudos here.
|
||||||
return cascade_requirement;
|
return restyle_requirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pseudo_styles = old_styles
|
let pseudo_styles = old_styles
|
||||||
|
@ -996,13 +1011,13 @@ pub trait MatchMethods: TElement {
|
||||||
old.as_ref().map_or(false, |s| pseudo.should_exist(s));
|
old.as_ref().map_or(false, |s| pseudo.should_exist(s));
|
||||||
if new_pseudo_should_exist != old_pseudo_should_exist {
|
if new_pseudo_should_exist != old_pseudo_should_exist {
|
||||||
data.damage |= RestyleDamage::reconstruct();
|
data.damage |= RestyleDamage::reconstruct();
|
||||||
return cascade_requirement;
|
return restyle_requirement;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cascade_requirement
|
restyle_requirement
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the rule nodes without re-running selector matching, using just
|
/// Updates the rule nodes without re-running selector matching, using just
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::context::{ElementCascadeInputs, SharedStyleContext, StyleContext};
|
||||||
use crate::data::{ElementData, ElementStyles};
|
use crate::data::{ElementData, ElementStyles};
|
||||||
use crate::dom::{NodeInfo, OpaqueNode, TElement, TNode};
|
use crate::dom::{NodeInfo, OpaqueNode, TElement, TNode};
|
||||||
use crate::invalidation::element::restyle_hints::RestyleHint;
|
use crate::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use crate::matching::{ChildCascadeRequirement, MatchMethods};
|
use crate::matching::{ChildRestyleRequirement, MatchMethods};
|
||||||
use crate::selector_parser::PseudoElement;
|
use crate::selector_parser::PseudoElement;
|
||||||
use crate::sharing::StyleSharingTarget;
|
use crate::sharing::StyleSharingTarget;
|
||||||
use crate::style_resolver::{PseudoElementResolution, StyleResolverForElement};
|
use crate::style_resolver::{PseudoElementResolution, StyleResolverForElement};
|
||||||
|
@ -423,19 +423,19 @@ pub fn recalc_style_at<E, D, F>(
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut child_cascade_requirement = ChildCascadeRequirement::CanSkipCascade;
|
let mut child_restyle_requirement = ChildRestyleRequirement::CanSkipCascade;
|
||||||
|
|
||||||
// Compute style for this element if necessary.
|
// Compute style for this element if necessary.
|
||||||
if compute_self {
|
if compute_self {
|
||||||
child_cascade_requirement = compute_style(traversal_data, context, element, data);
|
child_restyle_requirement = compute_style(traversal_data, context, element, data);
|
||||||
|
|
||||||
if element.is_in_native_anonymous_subtree() {
|
if element.is_in_native_anonymous_subtree() {
|
||||||
// We must always cascade native anonymous subtrees, since they
|
// We must always cascade native anonymous subtrees, since they
|
||||||
// may have pseudo-elements underneath that would inherit from the
|
// may have pseudo-elements underneath that would inherit from the
|
||||||
// closest non-NAC ancestor instead of us.
|
// closest non-NAC ancestor instead of us.
|
||||||
child_cascade_requirement = cmp::max(
|
child_restyle_requirement = cmp::max(
|
||||||
child_cascade_requirement,
|
child_restyle_requirement,
|
||||||
ChildCascadeRequirement::MustCascadeChildren,
|
ChildRestyleRequirement::MustCascadeChildren,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,10 +472,10 @@ pub fn recalc_style_at<E, D, F>(
|
||||||
let propagated_hint = data.hint.propagate(&flags);
|
let propagated_hint = data.hint.propagate(&flags);
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"propagated_hint={:?}, cascade_requirement={:?}, \
|
"propagated_hint={:?}, restyle_requirement={:?}, \
|
||||||
is_display_none={:?}, implementing_pseudo={:?}",
|
is_display_none={:?}, implementing_pseudo={:?}",
|
||||||
propagated_hint,
|
propagated_hint,
|
||||||
child_cascade_requirement,
|
child_restyle_requirement,
|
||||||
data.styles.is_display_none(),
|
data.styles.is_display_none(),
|
||||||
element.implemented_pseudo_element()
|
element.implemented_pseudo_element()
|
||||||
);
|
);
|
||||||
|
@ -504,7 +504,7 @@ pub fn recalc_style_at<E, D, F>(
|
||||||
// it's useless to style children.
|
// it's useless to style children.
|
||||||
let mut traverse_children = has_dirty_descendants_for_this_restyle ||
|
let mut traverse_children = has_dirty_descendants_for_this_restyle ||
|
||||||
!propagated_hint.is_empty() ||
|
!propagated_hint.is_empty() ||
|
||||||
!child_cascade_requirement.can_skip_cascade() ||
|
!child_restyle_requirement.can_skip_cascade() ||
|
||||||
is_servo_nonincremental_layout();
|
is_servo_nonincremental_layout();
|
||||||
|
|
||||||
traverse_children = traverse_children && !data.styles.is_display_none();
|
traverse_children = traverse_children && !data.styles.is_display_none();
|
||||||
|
@ -516,7 +516,7 @@ pub fn recalc_style_at<E, D, F>(
|
||||||
element,
|
element,
|
||||||
data,
|
data,
|
||||||
propagated_hint,
|
propagated_hint,
|
||||||
child_cascade_requirement,
|
child_restyle_requirement,
|
||||||
is_initial_style,
|
is_initial_style,
|
||||||
note_child,
|
note_child,
|
||||||
);
|
);
|
||||||
|
@ -549,7 +549,7 @@ fn compute_style<E>(
|
||||||
context: &mut StyleContext<E>,
|
context: &mut StyleContext<E>,
|
||||||
element: E,
|
element: E,
|
||||||
data: &mut ElementData,
|
data: &mut ElementData,
|
||||||
) -> ChildCascadeRequirement
|
) -> ChildRestyleRequirement
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
|
@ -734,7 +734,7 @@ fn note_children<E, D, F>(
|
||||||
element: E,
|
element: E,
|
||||||
data: &ElementData,
|
data: &ElementData,
|
||||||
propagated_hint: RestyleHint,
|
propagated_hint: RestyleHint,
|
||||||
cascade_requirement: ChildCascadeRequirement,
|
restyle_requirement: ChildRestyleRequirement,
|
||||||
is_initial_style: bool,
|
is_initial_style: bool,
|
||||||
mut note_child: F,
|
mut note_child: F,
|
||||||
) where
|
) where
|
||||||
|
@ -771,12 +771,12 @@ fn note_children<E, D, F>(
|
||||||
|
|
||||||
if let Some(ref mut child_data) = child_data {
|
if let Some(ref mut child_data) = child_data {
|
||||||
let mut child_hint = propagated_hint;
|
let mut child_hint = propagated_hint;
|
||||||
match cascade_requirement {
|
match restyle_requirement {
|
||||||
ChildCascadeRequirement::CanSkipCascade => {},
|
ChildRestyleRequirement::CanSkipCascade => {},
|
||||||
ChildCascadeRequirement::MustCascadeDescendants => {
|
ChildRestyleRequirement::MustCascadeDescendants => {
|
||||||
child_hint |= RestyleHint::RECASCADE_SELF | RestyleHint::RECASCADE_DESCENDANTS;
|
child_hint |= RestyleHint::RECASCADE_SELF | RestyleHint::RECASCADE_DESCENDANTS;
|
||||||
},
|
},
|
||||||
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle => {
|
ChildRestyleRequirement::MustCascadeChildrenIfInheritResetStyle => {
|
||||||
use crate::computed_value_flags::ComputedValueFlags;
|
use crate::computed_value_flags::ComputedValueFlags;
|
||||||
if child_data
|
if child_data
|
||||||
.styles
|
.styles
|
||||||
|
@ -787,9 +787,12 @@ fn note_children<E, D, F>(
|
||||||
child_hint |= RestyleHint::RECASCADE_SELF;
|
child_hint |= RestyleHint::RECASCADE_SELF;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChildCascadeRequirement::MustCascadeChildren => {
|
ChildRestyleRequirement::MustCascadeChildren => {
|
||||||
child_hint |= RestyleHint::RECASCADE_SELF;
|
child_hint |= RestyleHint::RECASCADE_SELF;
|
||||||
},
|
},
|
||||||
|
ChildRestyleRequirement::MustMatchDescendants => {
|
||||||
|
child_hint |= RestyleHint::restyle_subtree();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child_data.hint.insert(child_hint);
|
child_data.hint.insert(child_hint);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue