mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #12645 - emilio:stylo, r=bholley
stylo: Allow computing change hints during the traversal. <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors <!-- Either: --> - [x] These changes do not require tests because geckolib :-( <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> r? @bholley cc @heycam <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12645) <!-- Reviewable:end -->
This commit is contained in:
commit
cbf71a2cf3
19 changed files with 446 additions and 100 deletions
|
@ -14,6 +14,7 @@ use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
|
|||
use std::collections::HashMap;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use style::animation::{Animation, update_style_for_animation};
|
||||
use style::dom::TRestyleDamage;
|
||||
use style::timer::Timer;
|
||||
|
||||
/// Processes any new animations that were discovered after style recalculation.
|
||||
|
@ -130,10 +131,11 @@ pub fn recalc_style_for_animations(context: &SharedLayoutContext,
|
|||
flow.mutate_fragments(&mut |fragment| {
|
||||
if let Some(ref animations) = animations.get(&fragment.node) {
|
||||
for animation in animations.iter() {
|
||||
let old_style = fragment.style.clone();
|
||||
update_style_for_animation(&context.style_context,
|
||||
animation,
|
||||
&mut fragment.style,
|
||||
Some(&mut damage));
|
||||
&mut fragment.style);
|
||||
damage |= RestyleDamage::compute(Some(&old_style), &fragment.style);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -51,6 +51,7 @@ use selectors::matching::{DeclarationBlock, ElementFlags};
|
|||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{transmute, transmute_copy};
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
|
||||
use style::attr::AttrValue;
|
||||
use style::computed_values::display;
|
||||
|
@ -58,7 +59,7 @@ use style::context::SharedStyleContext;
|
|||
use style::data::PrivateStyleData;
|
||||
use style::dom::{PresentationalHintsSynthetizer, OpaqueNode, TDocument, TElement, TNode, UnsafeNode};
|
||||
use style::element_state::*;
|
||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use style::properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use style::refcell::{Ref, RefCell, RefMut};
|
||||
use style::selector_impl::{ElementSnapshot, NonTSPseudoClass, ServoSelectorImpl};
|
||||
use style::sink::Push;
|
||||
|
@ -262,6 +263,13 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
|||
self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn existing_style_for_restyle_damage<'a>(&'a self,
|
||||
current_cv: Option<&'a Arc<ComputedValues>>)
|
||||
-> Option<&'a Arc<ComputedValues>> {
|
||||
current_cv
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
|
||||
|
|
|
@ -44,21 +44,28 @@ bitflags! {
|
|||
}
|
||||
|
||||
impl TRestyleDamage for RestyleDamage {
|
||||
fn compute(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) ->
|
||||
RestyleDamage { compute_damage(old, new) }
|
||||
/// For Servo the style source is always the computed values.
|
||||
type PreExistingComputedValues = Arc<ServoComputedValues>;
|
||||
|
||||
/// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed.
|
||||
fn compute(old: Option<&Arc<ServoComputedValues>>,
|
||||
new: &Arc<ServoComputedValues>) -> RestyleDamage {
|
||||
compute_damage(old, new)
|
||||
}
|
||||
|
||||
/// Returns a bitmask that represents a flow that needs to be rebuilt and
|
||||
/// reflowed.
|
||||
///
|
||||
/// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
|
||||
/// unnecessary sequential resolution of generated content.
|
||||
/// Use this instead of `RestyleDamage::all()` because
|
||||
/// `RestyleDamage::all()` will result in unnecessary sequential resolution
|
||||
/// of generated content.
|
||||
fn rebuild_and_reflow() -> RestyleDamage {
|
||||
REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
|
||||
}
|
||||
}
|
||||
|
||||
impl RestyleDamage {
|
||||
/// Supposing a flow has the given `position` property and this damage, returns the damage that
|
||||
/// we should add to the *parent* of this flow.
|
||||
/// Supposing a flow has the given `position` property and this damage,
|
||||
/// returns the damage that we should add to the *parent* of this flow.
|
||||
pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
|
||||
if child_is_absolutely_positioned {
|
||||
self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
|
||||
|
@ -143,7 +150,8 @@ macro_rules! add_if_not_equal(
|
|||
})
|
||||
);
|
||||
|
||||
fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) -> RestyleDamage {
|
||||
fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &Arc<ServoComputedValues>) -> RestyleDamage {
|
||||
let new = &**new;
|
||||
let old: &ServoComputedValues = match old {
|
||||
None => return RestyleDamage::rebuild_and_reflow(),
|
||||
Some(cv) => &**cv,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use bezier::Bezier;
|
||||
use context::SharedStyleContext;
|
||||
use dom::{OpaqueNode, TRestyleDamage};
|
||||
use dom::OpaqueNode;
|
||||
use euclid::point::Point2D;
|
||||
use keyframes::{KeyframesStep, KeyframesStepValue};
|
||||
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
|
||||
|
@ -490,13 +490,12 @@ pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
|
|||
}
|
||||
/// Updates a single animation and associated style based on the current time.
|
||||
/// If `damage` is provided, inserts the appropriate restyle damage.
|
||||
pub fn update_style_for_animation<Damage>(context: &SharedStyleContext,
|
||||
animation: &Animation,
|
||||
style: &mut Arc<ComputedValues>,
|
||||
damage: Option<&mut Damage>)
|
||||
where Damage: TRestyleDamage {
|
||||
pub fn update_style_for_animation(context: &SharedStyleContext,
|
||||
animation: &Animation,
|
||||
style: &mut Arc<ComputedValues>) {
|
||||
debug!("update_style_for_animation: entering");
|
||||
debug_assert!(!animation.is_expired());
|
||||
|
||||
match *animation {
|
||||
Animation::Transition(_, start_time, ref frame, _) => {
|
||||
debug!("update_style_for_animation: transition found");
|
||||
|
@ -506,10 +505,6 @@ where Damage: TRestyleDamage {
|
|||
now, start_time,
|
||||
frame);
|
||||
if updated_style {
|
||||
if let Some(damage) = damage {
|
||||
*damage = *damage | Damage::compute(Some(style), &new_style);
|
||||
}
|
||||
|
||||
*style = new_style
|
||||
}
|
||||
}
|
||||
|
@ -660,10 +655,6 @@ where Damage: TRestyleDamage {
|
|||
}
|
||||
|
||||
debug!("update_style_for_animation: got style change in animation \"{}\"", name);
|
||||
if let Some(damage) = damage {
|
||||
*damage = *damage | Damage::compute(Some(style), &new_style);
|
||||
}
|
||||
|
||||
*style = new_style;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,19 @@ impl OpaqueNode {
|
|||
}
|
||||
|
||||
pub trait TRestyleDamage : BitOr<Output=Self> + Copy {
|
||||
fn compute(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -> Self;
|
||||
/// The source for our current computed values in the cascade. This is a
|
||||
/// ComputedValues in Servo and a StyleContext in Gecko.
|
||||
///
|
||||
/// This is needed because Gecko has a few optimisations for the calculation
|
||||
/// of the difference depending on which values have been used during
|
||||
/// layout.
|
||||
///
|
||||
/// This should be obtained via TNode::existing_style_for_restyle_damage
|
||||
type PreExistingComputedValues;
|
||||
|
||||
fn compute(old: Option<&Self::PreExistingComputedValues>,
|
||||
new: &Arc<ComputedValues>) -> Self;
|
||||
|
||||
fn rebuild_and_reflow() -> Self;
|
||||
}
|
||||
|
||||
|
@ -159,6 +171,13 @@ pub trait TNode : Sized + Copy + Clone {
|
|||
fn unstyle(self) {
|
||||
self.mutate_data().unwrap().style = None;
|
||||
}
|
||||
|
||||
/// XXX: It's a bit unfortunate we need to pass the current computed values
|
||||
/// as an argument here, but otherwise Servo would crash due to double
|
||||
/// borrows to return it.
|
||||
fn existing_style_for_restyle_damage<'a>(&'a self,
|
||||
current_computed_values: Option<&'a Arc<ComputedValues>>)
|
||||
-> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage>::PreExistingComputedValues>;
|
||||
}
|
||||
|
||||
pub trait TDocument : Sized + Copy + Clone {
|
||||
|
|
|
@ -13,7 +13,6 @@ pub struct ArcHelpers<GeckoType, ServoType> {
|
|||
phantom2: PhantomData<ServoType>,
|
||||
}
|
||||
|
||||
|
||||
impl<GeckoType, ServoType> ArcHelpers<GeckoType, ServoType> {
|
||||
pub fn with<F, Output>(raw: *mut GeckoType, cb: F) -> Output
|
||||
where F: FnOnce(&Arc<ServoType>) -> Output {
|
||||
|
@ -47,6 +46,15 @@ impl<GeckoType, ServoType> ArcHelpers<GeckoType, ServoType> {
|
|||
unsafe { transmute(owned) }
|
||||
}
|
||||
|
||||
pub fn borrow<F, Output>(borrowed: &Arc<ServoType>, cb: F) -> Output
|
||||
where F: FnOnce(&mut GeckoType) -> Output
|
||||
{
|
||||
let borrowed_gecko_type: *const &mut GeckoType =
|
||||
unsafe { transmute(borrowed) };
|
||||
|
||||
unsafe { cb(*borrowed_gecko_type) }
|
||||
}
|
||||
|
||||
pub unsafe fn addref(ptr: *mut GeckoType) {
|
||||
Self::with(ptr, |arc| forget(arc.clone()));
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use animation::{self, Animation};
|
||||
use animation;
|
||||
use arc_ptr_eq;
|
||||
use cache::{LRUCache, SimpleHashCache};
|
||||
use context::{StyleContext, SharedStyleContext};
|
||||
|
@ -442,8 +442,13 @@ trait PrivateMatchMethods: TNode
|
|||
cacheable = cacheable && !animations_started
|
||||
}
|
||||
|
||||
|
||||
let existing_style =
|
||||
self.existing_style_for_restyle_damage(style.map(|s| &*s));
|
||||
|
||||
// Calculate style difference.
|
||||
let damage = Self::ConcreteRestyleDamage::compute(style.map(|s| &*s), &*this_style);
|
||||
let damage =
|
||||
Self::ConcreteRestyleDamage::compute(existing_style, &this_style);
|
||||
|
||||
// Cache the resolved style if it was cacheable.
|
||||
if cacheable {
|
||||
|
@ -490,8 +495,9 @@ trait PrivateMatchMethods: TNode
|
|||
// See #12171 and the associated PR for an example where this
|
||||
// happened while debugging other release panic.
|
||||
if !running_animation.is_expired() {
|
||||
animation::update_style_for_animation::<Self::ConcreteRestyleDamage>(
|
||||
context, running_animation, style, None);
|
||||
animation::update_style_for_animation(context,
|
||||
running_animation,
|
||||
style);
|
||||
running_animation.mark_as_expired();
|
||||
}
|
||||
}
|
||||
|
@ -585,9 +591,17 @@ pub trait ElementMatchMethods : TElement {
|
|||
if let Some(shared_style) = self.share_style_with_candidate_if_possible(parent.clone(), candidate) {
|
||||
// Yay, cache hit. Share the style.
|
||||
let node = self.as_node();
|
||||
|
||||
let style = &mut node.mutate_data().unwrap().style;
|
||||
let damage = <<Self as TElement>::ConcreteNode as TNode>
|
||||
::ConcreteRestyleDamage::compute((*style).as_ref(), &*shared_style);
|
||||
|
||||
let damage = {
|
||||
let source =
|
||||
node.existing_style_for_restyle_damage((*style).as_ref());
|
||||
let damage = <<Self as TElement>::ConcreteNode as TNode>
|
||||
::ConcreteRestyleDamage::compute(source, &shared_style);
|
||||
damage
|
||||
};
|
||||
|
||||
*style = Some(shared_style);
|
||||
return StyleSharingResult::StyleWasShared(i, damage)
|
||||
}
|
||||
|
@ -675,8 +689,14 @@ pub trait MatchMethods : TNode {
|
|||
let mut data_ref = self.mutate_data().unwrap();
|
||||
let mut data = &mut *data_ref;
|
||||
let cloned_parent_style = ComputedValues::style_for_child_text_node(parent_style.unwrap());
|
||||
damage = Self::ConcreteRestyleDamage::compute(data.style.as_ref(),
|
||||
&*cloned_parent_style);
|
||||
|
||||
{
|
||||
let existing_style =
|
||||
self.existing_style_for_restyle_damage(data.style.as_ref());
|
||||
damage = Self::ConcreteRestyleDamage::compute(existing_style,
|
||||
&cloned_parent_style);
|
||||
}
|
||||
|
||||
data.style = Some(cloned_parent_style);
|
||||
} else {
|
||||
damage = {
|
||||
|
@ -697,7 +717,6 @@ pub trait MatchMethods : TNode {
|
|||
let applicable_declarations_for_this_pseudo =
|
||||
applicable_declarations.per_pseudo.get(&pseudo).unwrap();
|
||||
|
||||
|
||||
if !applicable_declarations_for_this_pseudo.is_empty() {
|
||||
// NB: Transitions and animations should only work for
|
||||
// pseudo-elements ::before and ::after
|
||||
|
|
|
@ -28,7 +28,7 @@ bitflags! {
|
|||
// of a good reason for that.
|
||||
const RESTYLE_DESCENDANTS = 0x02,
|
||||
#[doc = "Rerun selector matching on all later siblings of the element and all of their descendants."]
|
||||
const RESTYLE_LATER_SIBLINGS = 0x04,
|
||||
const RESTYLE_LATER_SIBLINGS = 0x08,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn traverse_dom<N, C>(root: N,
|
|||
|
||||
for kid in node.children() {
|
||||
context.pre_process_child_hook(node, kid);
|
||||
if context.should_process(node) {
|
||||
if context.should_process(kid) {
|
||||
doit::<N, C>(context, kid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use selector_impl::SelectorImplExt;
|
|||
use selectors::Element;
|
||||
use selectors::bloom::BloomFilter;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use tid::tid;
|
||||
use util::opts;
|
||||
use values::HasViewportPercentage;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue