mirror of
https://github.com/servo/servo.git
synced 2025-08-01 03:30:33 +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 properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
||||
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 selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
||||
use selectors::matching::VisitedHandlingMode;
|
||||
|
@ -414,6 +414,11 @@ impl StoredRestyleHint {
|
|||
pub fn has_recascade_self(&self) -> bool {
|
||||
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 {
|
||||
|
|
|
@ -20,7 +20,7 @@ use parser::ParserContext;
|
|||
use properties::{ComputedValues, StyleBuilder};
|
||||
use properties::longhands::font_size;
|
||||
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 string_cache::Atom;
|
||||
use style_traits::ToCss;
|
||||
|
@ -47,6 +47,9 @@ pub struct Device {
|
|||
/// the parent to compute everything else. So it is correct to just use
|
||||
/// a relaxed atomic here.
|
||||
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 {}
|
||||
|
@ -61,6 +64,7 @@ impl Device {
|
|||
default_values: ComputedValues::default_values(unsafe { &*pres_context }),
|
||||
viewport_override: None,
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -104,6 +109,12 @@ impl Device {
|
|||
// NB: A following stylesheet flush will populate this if appropriate.
|
||||
self.viewport_override = None;
|
||||
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.
|
||||
|
|
|
@ -78,17 +78,21 @@ pub enum ChildCascadeRequirement {
|
|||
///
|
||||
/// FIXME(heycam) Although this is "must" cascade, in the future we should
|
||||
/// track whether child elements rely specifically on inheriting particular
|
||||
/// property values. When we do that, we can treat `MustCascade` as "must
|
||||
/// cascade unless we know that changes to these properties can be
|
||||
/// property values. When we do that, we can treat `MustCascadeChildren` as
|
||||
/// "must cascade unless we know that changes to these properties can be
|
||||
/// 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 {
|
||||
fn from(change: StyleChange) -> ChildCascadeRequirement {
|
||||
match change {
|
||||
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()),
|
||||
&new_values,
|
||||
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.
|
||||
|
@ -664,7 +684,7 @@ trait PrivateMatchMethods: TElement {
|
|||
-> ChildCascadeRequirement {
|
||||
// Don't accumulate damage if we're in a restyle for reconstruction.
|
||||
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
|
||||
|
@ -1220,12 +1240,12 @@ pub trait MatchMethods : TElement {
|
|||
-> ChildCascadeRequirement {
|
||||
let restyle = match restyle {
|
||||
Some(r) => r,
|
||||
None => return ChildCascadeRequirement::MustCascade,
|
||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||
};
|
||||
|
||||
let old_values = match old_values {
|
||||
Some(v) => v,
|
||||
None => return ChildCascadeRequirement::MustCascade,
|
||||
None => return ChildCascadeRequirement::MustCascadeChildren,
|
||||
};
|
||||
|
||||
// ::before and ::after are element-backed in Gecko, so they do the
|
||||
|
|
|
@ -446,6 +446,12 @@ impl RestyleHint {
|
|||
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
|
||||
/// work as the specified one.
|
||||
#[inline]
|
||||
|
|
|
@ -14,7 +14,7 @@ use parser::ParserContext;
|
|||
use properties::{ComputedValues, StyleBuilder};
|
||||
use properties::longhands::font_size;
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
||||
use style_traits::{CSSPixel, ToCss};
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use values::computed::{self, ToComputedValue};
|
||||
|
@ -41,6 +41,10 @@ pub struct Device {
|
|||
/// a relaxed atomic here.
|
||||
#[ignore_heap_size_of = "Pure stack type"]
|
||||
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 {
|
||||
|
@ -52,6 +56,7 @@ impl Device {
|
|||
media_type: media_type,
|
||||
viewport_size: viewport_size,
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -73,6 +79,11 @@ impl Device {
|
|||
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,
|
||||
/// among other things, to resolve viewport units.
|
||||
#[inline]
|
||||
|
|
|
@ -9,7 +9,8 @@ use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
|
|||
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
||||
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
||||
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 sharing::{StyleSharingBehavior, StyleSharingTarget};
|
||||
#[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");
|
||||
|
||||
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={:?})",
|
||||
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.
|
||||
if compute_self {
|
||||
match compute_style(traversal, traversal_data, context, element, data) {
|
||||
ChildCascadeRequirement::MustCascade => {
|
||||
inherited_style_changed = true;
|
||||
ChildCascadeRequirement::MustCascadeChildren => {
|
||||
cascade_hint |= RECASCADE_SELF;
|
||||
}
|
||||
ChildCascadeRequirement::MustCascadeDescendants => {
|
||||
cascade_hint |= RECASCADE_SELF | RECASCADE_DESCENDANTS;
|
||||
}
|
||||
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
|
||||
// somewhere.
|
||||
propagated_hint.insert(StoredRestyleHint::recascade_self());
|
||||
}
|
||||
// FIXME(bholley): Need to handle explicitly-inherited reset properties
|
||||
// somewhere.
|
||||
propagated_hint.insert_cascade_hint(cascade_hint);
|
||||
|
||||
trace!("propagated_hint={:?}, inherited_style_changed={:?}, \
|
||||
trace!("propagated_hint={:?}, cascade_hint={:?}, \
|
||||
is_display_none={:?}, implementing_pseudo={:?}",
|
||||
propagated_hint, inherited_style_changed,
|
||||
propagated_hint, cascade_hint,
|
||||
data.styles().is_display_none(),
|
||||
element.implemented_pseudo_element());
|
||||
debug_assert!(element.has_current_styles(data) ||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue