mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Recascade the document when rem units are used and the root font-size changes.
This commit is contained in:
parent
7b61d55421
commit
19b61dfc08
6 changed files with 76 additions and 21 deletions
|
@ -9,7 +9,7 @@ use context::SharedStyleContext;
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint};
|
use restyle_hints::{CascadeHint, HintComputationContext, RestyleReplacements, RestyleHint};
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
||||||
use selectors::matching::VisitedHandlingMode;
|
use selectors::matching::VisitedHandlingMode;
|
||||||
|
@ -414,6 +414,11 @@ impl StoredRestyleHint {
|
||||||
pub fn has_recascade_self(&self) -> bool {
|
pub fn has_recascade_self(&self) -> bool {
|
||||||
self.0.has_recascade_self()
|
self.0.has_recascade_self()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert the specified `CascadeHint`.
|
||||||
|
pub fn insert_cascade_hint(&mut self, cascade_hint: CascadeHint) {
|
||||||
|
self.0.insert_cascade_hint(cascade_hint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StoredRestyleHint {
|
impl Default for StoredRestyleHint {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use parser::ParserContext;
|
||||||
use properties::{ComputedValues, StyleBuilder};
|
use properties::{ComputedValues, StyleBuilder};
|
||||||
use properties::longhands::font_size;
|
use properties::longhands::font_size;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||||
use str::starts_with_ignore_ascii_case;
|
use str::starts_with_ignore_ascii_case;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -47,6 +47,9 @@ pub struct Device {
|
||||||
/// the parent to compute everything else. So it is correct to just use
|
/// the parent to compute everything else. So it is correct to just use
|
||||||
/// a relaxed atomic here.
|
/// a relaxed atomic here.
|
||||||
root_font_size: AtomicIsize,
|
root_font_size: AtomicIsize,
|
||||||
|
/// Whether any styles computed in the document relied on the root font-size
|
||||||
|
/// by using rem units.
|
||||||
|
used_root_font_size: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for Device {}
|
unsafe impl Sync for Device {}
|
||||||
|
@ -61,6 +64,7 @@ impl Device {
|
||||||
default_values: ComputedValues::default_values(unsafe { &*pres_context }),
|
default_values: ComputedValues::default_values(unsafe { &*pres_context }),
|
||||||
viewport_override: None,
|
viewport_override: None,
|
||||||
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious?
|
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious?
|
||||||
|
used_root_font_size: AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +95,7 @@ impl Device {
|
||||||
|
|
||||||
/// Get the font size of the root element (for rem)
|
/// Get the font size of the root element (for rem)
|
||||||
pub fn root_font_size(&self) -> Au {
|
pub fn root_font_size(&self) -> Au {
|
||||||
|
self.used_root_font_size.store(true, Ordering::Relaxed);
|
||||||
Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
|
Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +109,12 @@ impl Device {
|
||||||
// NB: A following stylesheet flush will populate this if appropriate.
|
// NB: A following stylesheet flush will populate this if appropriate.
|
||||||
self.viewport_override = None;
|
self.viewport_override = None;
|
||||||
self.default_values = ComputedValues::default_values(unsafe { &*self.pres_context });
|
self.default_values = ComputedValues::default_values(unsafe { &*self.pres_context });
|
||||||
|
self.used_root_font_size.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether we ever looked up the root font size of the Device.
|
||||||
|
pub fn used_root_font_size(&self) -> bool {
|
||||||
|
self.used_root_font_size.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recreates all the temporary state that the `Device` stores.
|
/// Recreates all the temporary state that the `Device` stores.
|
||||||
|
|
|
@ -78,17 +78,21 @@ pub enum ChildCascadeRequirement {
|
||||||
///
|
///
|
||||||
/// FIXME(heycam) Although this is "must" cascade, in the future we should
|
/// FIXME(heycam) Although this is "must" cascade, in the future we should
|
||||||
/// track whether child elements rely specifically on inheriting particular
|
/// track whether child elements rely specifically on inheriting particular
|
||||||
/// property values. When we do that, we can treat `MustCascade` as "must
|
/// property values. When we do that, we can treat `MustCascadeChildren` as
|
||||||
/// cascade unless we know that changes to these properties can be
|
/// "must cascade unless we know that changes to these properties can be
|
||||||
/// ignored".
|
/// ignored".
|
||||||
MustCascade,
|
MustCascadeChildren,
|
||||||
|
/// The same as `MustCascadeChildren`, but for the entire subtree. This is
|
||||||
|
/// used to handle root font-size updates needing to recascade the whole
|
||||||
|
/// document.
|
||||||
|
MustCascadeDescendants,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StyleChange> for ChildCascadeRequirement {
|
impl From<StyleChange> for ChildCascadeRequirement {
|
||||||
fn from(change: StyleChange) -> ChildCascadeRequirement {
|
fn from(change: StyleChange) -> ChildCascadeRequirement {
|
||||||
match change {
|
match change {
|
||||||
StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade,
|
StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade,
|
||||||
StyleChange::Changed => ChildCascadeRequirement::MustCascade,
|
StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,6 +451,22 @@ trait PrivateMatchMethods: TElement {
|
||||||
old_values.as_ref().map(|v| v.as_ref()),
|
old_values.as_ref().map(|v| v.as_ref()),
|
||||||
&new_values,
|
&new_values,
|
||||||
None);
|
None);
|
||||||
|
|
||||||
|
// Handle root font-size changes.
|
||||||
|
if self.is_root() && !self.is_native_anonymous() {
|
||||||
|
// The new root font-size has already been updated on the Device
|
||||||
|
// in properties::apply_declarations.
|
||||||
|
let device = context.shared.stylist.device();
|
||||||
|
let new_font_size = new_values.get_font().clone_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.
|
||||||
|
if old_values.map_or(false, |v| v.get_font().clone_font_size() != new_font_size) &&
|
||||||
|
device.used_root_font_size() {
|
||||||
|
child_cascade_requirement = ChildCascadeRequirement::MustCascadeDescendants;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new computed values.
|
// Set the new computed values.
|
||||||
|
@ -664,7 +684,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
// Don't accumulate damage if we're in a restyle for reconstruction.
|
// Don't accumulate damage if we're in a restyle for reconstruction.
|
||||||
if shared_context.traversal_flags.for_reconstruct() {
|
if shared_context.traversal_flags.for_reconstruct() {
|
||||||
return ChildCascadeRequirement::MustCascade;
|
return ChildCascadeRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an ancestor is already getting reconstructed by Gecko's top-down
|
// If an ancestor is already getting reconstructed by Gecko's top-down
|
||||||
|
@ -1220,12 +1240,12 @@ pub trait MatchMethods : TElement {
|
||||||
-> ChildCascadeRequirement {
|
-> ChildCascadeRequirement {
|
||||||
let restyle = match restyle {
|
let restyle = match restyle {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => return ChildCascadeRequirement::MustCascade,
|
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||||
};
|
};
|
||||||
|
|
||||||
let old_values = match old_values {
|
let old_values = match old_values {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return ChildCascadeRequirement::MustCascade,
|
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ::before and ::after are element-backed in Gecko, so they do the
|
// ::before and ::after are element-backed in Gecko, so they do the
|
||||||
|
|
|
@ -446,6 +446,12 @@ impl RestyleHint {
|
||||||
self.insert_from(&other)
|
self.insert_from(&other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts the specified `CascadeHint`.
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_cascade_hint(&mut self, cascade_hint: CascadeHint) {
|
||||||
|
self.recascade.insert(cascade_hint);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether this `RestyleHint` represents at least as much restyle
|
/// Returns whether this `RestyleHint` represents at least as much restyle
|
||||||
/// work as the specified one.
|
/// work as the specified one.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -14,7 +14,7 @@ use parser::ParserContext;
|
||||||
use properties::{ComputedValues, StyleBuilder};
|
use properties::{ComputedValues, StyleBuilder};
|
||||||
use properties::longhands::font_size;
|
use properties::longhands::font_size;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||||
use style_traits::{CSSPixel, ToCss};
|
use style_traits::{CSSPixel, ToCss};
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
use values::computed::{self, ToComputedValue};
|
use values::computed::{self, ToComputedValue};
|
||||||
|
@ -41,6 +41,10 @@ pub struct Device {
|
||||||
/// a relaxed atomic here.
|
/// a relaxed atomic here.
|
||||||
#[ignore_heap_size_of = "Pure stack type"]
|
#[ignore_heap_size_of = "Pure stack type"]
|
||||||
root_font_size: AtomicIsize,
|
root_font_size: AtomicIsize,
|
||||||
|
/// Whether any styles computed in the document relied on the root font-size
|
||||||
|
/// by using rem units.
|
||||||
|
#[ignore_heap_size_of = "Pure stack type"]
|
||||||
|
used_root_font_size: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
|
@ -52,6 +56,7 @@ impl Device {
|
||||||
media_type: media_type,
|
media_type: media_type,
|
||||||
viewport_size: viewport_size,
|
viewport_size: viewport_size,
|
||||||
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious?
|
root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious?
|
||||||
|
used_root_font_size: AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +70,7 @@ impl Device {
|
||||||
|
|
||||||
/// Get the font size of the root element (for rem)
|
/// Get the font size of the root element (for rem)
|
||||||
pub fn root_font_size(&self) -> Au {
|
pub fn root_font_size(&self) -> Au {
|
||||||
|
self.used_root_font_size.store(true, Ordering::Relaxed);
|
||||||
Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
|
Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +79,11 @@ impl Device {
|
||||||
self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
|
self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether we ever looked up the root font size of the Device.
|
||||||
|
pub fn used_root_font_size(&self) -> bool {
|
||||||
|
self.used_root_font_size.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the viewport size of the current device in app units, needed,
|
/// Returns the viewport size of the current device in app units, needed,
|
||||||
/// among other things, to resolve viewport units.
|
/// among other things, to resolve viewport units.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -9,7 +9,8 @@ use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
|
||||||
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
||||||
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
||||||
use matching::{ChildCascadeRequirement, MatchMethods};
|
use matching::{ChildCascadeRequirement, MatchMethods};
|
||||||
use restyle_hints::{HintComputationContext, RestyleHint};
|
use restyle_hints::{CascadeHint, HintComputationContext, RECASCADE_SELF};
|
||||||
|
use restyle_hints::{RECASCADE_DESCENDANTS, RestyleHint};
|
||||||
use selector_parser::RestyleDamage;
|
use selector_parser::RestyleDamage;
|
||||||
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
||||||
#[cfg(feature = "servo")] use servo_config::opts;
|
#[cfg(feature = "servo")] use servo_config::opts;
|
||||||
|
@ -672,7 +673,7 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
}), "Should've computed the final hint and handled later_siblings already");
|
}), "Should've computed the final hint and handled later_siblings already");
|
||||||
|
|
||||||
let compute_self = !element.has_current_styles(data);
|
let compute_self = !element.has_current_styles(data);
|
||||||
let mut inherited_style_changed = false;
|
let mut cascade_hint = CascadeHint::empty();
|
||||||
|
|
||||||
debug!("recalc_style_at: {:?} (compute_self={:?}, dirty_descendants={:?}, data={:?})",
|
debug!("recalc_style_at: {:?} (compute_self={:?}, dirty_descendants={:?}, data={:?})",
|
||||||
element, compute_self, element.has_dirty_descendants(), data);
|
element, compute_self, element.has_dirty_descendants(), data);
|
||||||
|
@ -680,8 +681,11 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
// Compute style for this element if necessary.
|
// Compute style for this element if necessary.
|
||||||
if compute_self {
|
if compute_self {
|
||||||
match compute_style(traversal, traversal_data, context, element, data) {
|
match compute_style(traversal, traversal_data, context, element, data) {
|
||||||
ChildCascadeRequirement::MustCascade => {
|
ChildCascadeRequirement::MustCascadeChildren => {
|
||||||
inherited_style_changed = true;
|
cascade_hint |= RECASCADE_SELF;
|
||||||
|
}
|
||||||
|
ChildCascadeRequirement::MustCascadeDescendants => {
|
||||||
|
cascade_hint |= RECASCADE_SELF | RECASCADE_DESCENDANTS;
|
||||||
}
|
}
|
||||||
ChildCascadeRequirement::CanSkipCascade => {}
|
ChildCascadeRequirement::CanSkipCascade => {}
|
||||||
};
|
};
|
||||||
|
@ -708,15 +712,13 @@ pub fn recalc_style_at<E, D>(traversal: &D,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if inherited_style_changed {
|
|
||||||
// FIXME(bholley): Need to handle explicitly-inherited reset properties
|
// FIXME(bholley): Need to handle explicitly-inherited reset properties
|
||||||
// somewhere.
|
// somewhere.
|
||||||
propagated_hint.insert(StoredRestyleHint::recascade_self());
|
propagated_hint.insert_cascade_hint(cascade_hint);
|
||||||
}
|
|
||||||
|
|
||||||
trace!("propagated_hint={:?}, inherited_style_changed={:?}, \
|
trace!("propagated_hint={:?}, cascade_hint={:?}, \
|
||||||
is_display_none={:?}, implementing_pseudo={:?}",
|
is_display_none={:?}, implementing_pseudo={:?}",
|
||||||
propagated_hint, inherited_style_changed,
|
propagated_hint, cascade_hint,
|
||||||
data.styles().is_display_none(),
|
data.styles().is_display_none(),
|
||||||
element.implemented_pseudo_element());
|
element.implemented_pseudo_element());
|
||||||
debug_assert!(element.has_current_styles(data) ||
|
debug_assert!(element.has_current_styles(data) ||
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue