mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +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
|
||||
/// to children.
|
||||
/// Whether or not newly computed values for an element need to be cascaded to
|
||||
/// children (or children might need to be re-matched, e.g., for container
|
||||
/// queries).
|
||||
#[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
|
||||
/// we won't bother recomputing style for children, so we can skip cascading
|
||||
/// 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
|
||||
/// document.
|
||||
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.
|
||||
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,
|
||||
new_values: &ComputedValues,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
) -> ChildCascadeRequirement {
|
||||
) -> ChildRestyleRequirement {
|
||||
debug!("accumulate_damage_for: {:?}", self);
|
||||
debug_assert!(!shared_context
|
||||
.traversal_flags
|
||||
|
@ -750,16 +755,16 @@ trait PrivateMatchMethods: TElement {
|
|||
" > flags changed: {:?} != {:?}",
|
||||
old_values.flags, new_values.flags
|
||||
);
|
||||
return ChildCascadeRequirement::MustCascadeChildren;
|
||||
return ChildRestyleRequirement::MustCascadeChildren;
|
||||
}
|
||||
|
||||
match difference.change {
|
||||
StyleChange::Unchanged => return ChildCascadeRequirement::CanSkipCascade,
|
||||
StyleChange::Unchanged => return ChildRestyleRequirement::CanSkipCascade,
|
||||
StyleChange::Changed { reset_only } => {
|
||||
// If inherited properties changed, the best we can do is
|
||||
// cascade the children.
|
||||
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
|
||||
// children need to be restyled because they're unstyled.
|
||||
if old_display == Display::None {
|
||||
return ChildCascadeRequirement::MustCascadeChildren;
|
||||
return ChildRestyleRequirement::MustCascadeChildren;
|
||||
}
|
||||
// Blockification of children may depend on our display value,
|
||||
// so we need to actually do the recascade. We could potentially
|
||||
// do better, but it doesn't seem worth it.
|
||||
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
|
||||
// display goes from / to display: contents, since the "layout
|
||||
// parent style" changes.
|
||||
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
|
||||
// type changes from ruby to non-ruby.
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
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);
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
// on our children.
|
||||
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
|
||||
// properties, we can stop the cascade.
|
||||
ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle
|
||||
ChildRestyleRequirement::MustCascadeChildrenIfInheritResetStyle
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -880,7 +885,7 @@ pub trait MatchMethods: TElement {
|
|||
data: &mut ElementData,
|
||||
mut new_styles: ResolvedElementStyles,
|
||||
important_rules_changed: bool,
|
||||
) -> ChildCascadeRequirement {
|
||||
) -> ChildRestyleRequirement {
|
||||
use std::cmp;
|
||||
|
||||
self.process_animations(
|
||||
|
@ -896,26 +901,37 @@ pub trait MatchMethods: TElement {
|
|||
|
||||
let new_primary_style = data.styles.primary.as_ref().unwrap();
|
||||
|
||||
let mut cascade_requirement = ChildCascadeRequirement::CanSkipCascade;
|
||||
if new_primary_style
|
||||
.flags
|
||||
.contains(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE)
|
||||
{
|
||||
let device = context.shared.stylist.device();
|
||||
let mut restyle_requirement = ChildRestyleRequirement::CanSkipCascade;
|
||||
let is_root = new_primary_style.flags.contains(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE);
|
||||
let is_container = !new_primary_style.get_box().clone_container_type().is_empty();
|
||||
if is_root || is_container {
|
||||
let new_font_size = new_primary_style.get_font().clone_font_size();
|
||||
|
||||
if old_styles
|
||||
let old_font_size = old_styles
|
||||
.primary
|
||||
.as_ref()
|
||||
.map_or(true, |s| s.get_font().clone_font_size() != new_font_size)
|
||||
{
|
||||
debug_assert!(self.owner_doc_matches_for_testing(device));
|
||||
device.set_root_font_size(new_font_size.size().into());
|
||||
// If the root font-size changed since last time, and something
|
||||
// in the document did use rem units, ensure we recascade the
|
||||
// entire tree.
|
||||
if device.used_root_font_size() {
|
||||
cascade_requirement = ChildCascadeRequirement::MustCascadeDescendants;
|
||||
.map(|s| s.get_font().clone_font_size());
|
||||
|
||||
if old_font_size != Some(new_font_size) {
|
||||
if is_root {
|
||||
let device = context.shared.stylist.device();
|
||||
debug_assert!(self.owner_doc_matches_for_testing(device));
|
||||
device.set_root_font_size(new_font_size.size().into());
|
||||
if device.used_root_font_size() {
|
||||
// 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,
|
||||
// but we don't track right now whether we use the document body
|
||||
// color, and nobody else handles that properly anyway.
|
||||
|
||||
let device = context.shared.stylist.device();
|
||||
|
||||
// Needed for the "inherit from body" quirk.
|
||||
|
@ -941,17 +956,17 @@ pub trait MatchMethods: TElement {
|
|||
.traversal_flags
|
||||
.contains(TraversalFlags::FinalAnimationTraversal)
|
||||
{
|
||||
return ChildCascadeRequirement::MustCascadeChildren;
|
||||
return ChildRestyleRequirement::MustCascadeChildren;
|
||||
}
|
||||
|
||||
// Also, don't do anything if there was no style.
|
||||
let old_primary_style = match old_styles.primary {
|
||||
Some(s) => s,
|
||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||
None => return ChildRestyleRequirement::MustCascadeChildren,
|
||||
};
|
||||
|
||||
cascade_requirement = cmp::max(
|
||||
cascade_requirement,
|
||||
restyle_requirement = cmp::max(
|
||||
restyle_requirement,
|
||||
self.accumulate_damage_for(
|
||||
context.shared,
|
||||
&mut data.damage,
|
||||
|
@ -963,7 +978,7 @@ pub trait MatchMethods: TElement {
|
|||
|
||||
if data.styles.pseudos.is_empty() && old_styles.pseudos.is_empty() {
|
||||
// This is the common case; no need to examine pseudos here.
|
||||
return cascade_requirement;
|
||||
return restyle_requirement;
|
||||
}
|
||||
|
||||
let pseudo_styles = old_styles
|
||||
|
@ -996,13 +1011,13 @@ pub trait MatchMethods: TElement {
|
|||
old.as_ref().map_or(false, |s| pseudo.should_exist(s));
|
||||
if new_pseudo_should_exist != old_pseudo_should_exist {
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue