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:
bors-servo 2016-08-03 19:02:26 -05:00 committed by GitHub
commit cbf71a2cf3
19 changed files with 446 additions and 100 deletions

View file

@ -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);
}
}
});

View file

@ -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> {

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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()));
}

View file

@ -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

View file

@ -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,
}
}

View file

@ -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);
}
}

View file

@ -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;