mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
style: Refactor to pass animations cleanly, land animation-name parsing as experimental
This commit is contained in:
parent
c1fd7432e9
commit
60192bb830
12 changed files with 152 additions and 30 deletions
|
@ -327,4 +327,7 @@ partial interface CSSStyleDeclaration {
|
|||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString flex-shrink;
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString alignSelf;
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString align-self;
|
||||
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animation-name;
|
||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString animationName;
|
||||
};
|
||||
|
|
|
@ -817,7 +817,7 @@ fn can_interpolate_list(from_list: &[TransformOperation],
|
|||
fn interpolate_transform_list(from_list: &[TransformOperation],
|
||||
to_list: &[TransformOperation],
|
||||
time: f64) -> TransformList {
|
||||
let mut result = vec!();
|
||||
let mut result = vec![];
|
||||
|
||||
if can_interpolate_list(from_list, to_list) {
|
||||
for (from, to) in from_list.iter().zip(to_list) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use animation::{self, Animation};
|
||||
use context::SharedStyleContext;
|
||||
use animation;
|
||||
use context::{SharedStyleContext, LocalStyleContext};
|
||||
use data::PrivateStyleData;
|
||||
use dom::{TElement, TNode, TRestyleDamage};
|
||||
use properties::{ComputedValues, PropertyDeclaration, cascade};
|
||||
|
@ -21,8 +21,7 @@ use smallvec::SmallVec;
|
|||
use std::collections::HashMap;
|
||||
use std::hash::{BuildHasherDefault, Hash, Hasher};
|
||||
use std::slice::Iter;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use util::arc_ptr_eq;
|
||||
use util::cache::{LRUCache, SimpleHashCache};
|
||||
|
@ -366,6 +365,10 @@ pub enum StyleSharingResult<ConcreteRestyleDamage: TRestyleDamage> {
|
|||
|
||||
trait PrivateMatchMethods: TNode
|
||||
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt {
|
||||
/// Actually cascades style for a node or a pseudo-element of a node.
|
||||
///
|
||||
/// Note that animations only apply to nodes or ::before or ::after
|
||||
/// pseudo-elements.
|
||||
fn cascade_node_pseudo_element(&self,
|
||||
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>,
|
||||
parent_style: Option<&Arc<Self::ConcreteComputedValues>>,
|
||||
|
@ -373,13 +376,14 @@ trait PrivateMatchMethods: TNode
|
|||
mut style: Option<&mut Arc<Self::ConcreteComputedValues>>,
|
||||
applicable_declarations_cache:
|
||||
&mut ApplicableDeclarationsCache<Self::ConcreteComputedValues>,
|
||||
new_animations_sender: &Mutex<Sender<Animation>>,
|
||||
shareable: bool,
|
||||
animate_properties: bool)
|
||||
-> (Self::ConcreteRestyleDamage, Arc<Self::ConcreteComputedValues>) {
|
||||
let mut cacheable = true;
|
||||
let mut animations = None;
|
||||
if animate_properties {
|
||||
cacheable = !self.update_animations_for_cascade(context, &mut style) && cacheable;
|
||||
animations = Some(context.stylist.animations())
|
||||
}
|
||||
|
||||
let mut this_style;
|
||||
|
@ -387,14 +391,16 @@ trait PrivateMatchMethods: TNode
|
|||
Some(ref parent_style) => {
|
||||
let cache_entry = applicable_declarations_cache.find(applicable_declarations);
|
||||
let cached_computed_values = match cache_entry {
|
||||
None => None,
|
||||
Some(ref style) => Some(&**style),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let (the_style, is_cacheable) = cascade(context.viewport_size,
|
||||
applicable_declarations,
|
||||
shareable,
|
||||
Some(&***parent_style),
|
||||
cached_computed_values,
|
||||
animations,
|
||||
context.error_reporter.clone());
|
||||
cacheable = cacheable && is_cacheable;
|
||||
this_style = the_style
|
||||
|
@ -405,6 +411,7 @@ trait PrivateMatchMethods: TNode
|
|||
shareable,
|
||||
None,
|
||||
None,
|
||||
animations,
|
||||
context.error_reporter.clone());
|
||||
cacheable = cacheable && is_cacheable;
|
||||
this_style = the_style
|
||||
|
@ -417,7 +424,7 @@ trait PrivateMatchMethods: TNode
|
|||
if let Some(ref style) = style {
|
||||
let animations_started =
|
||||
animation::start_transitions_if_applicable::<Self::ConcreteComputedValues>(
|
||||
new_animations_sender,
|
||||
&context.new_animations_sender,
|
||||
self.opaque(),
|
||||
&**style,
|
||||
&mut this_style);
|
||||
|
@ -641,11 +648,9 @@ pub trait MatchMethods : TNode {
|
|||
|
||||
unsafe fn cascade_node(&self,
|
||||
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>,
|
||||
local_context: &LocalStyleContext<Self::ConcreteComputedValues>,
|
||||
parent: Option<Self>,
|
||||
applicable_declarations: &ApplicableDeclarations<<Self::ConcreteElement as Element>::Impl>,
|
||||
applicable_declarations_cache:
|
||||
&mut ApplicableDeclarationsCache<Self::ConcreteComputedValues>,
|
||||
new_animations_sender: &Mutex<Sender<Animation>>)
|
||||
applicable_declarations: &ApplicableDeclarations<<Self::ConcreteElement as Element>::Impl>)
|
||||
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt {
|
||||
// Get our parent's style. This must be unsafe so that we don't touch the parent's
|
||||
// borrow flags.
|
||||
|
@ -653,13 +658,16 @@ pub trait MatchMethods : TNode {
|
|||
// FIXME(pcwalton): Isolate this unsafety into the `wrapper` module to allow
|
||||
// enforced safe, race-free access to the parent style.
|
||||
let parent_style = match parent {
|
||||
None => None,
|
||||
Some(parent_node) => {
|
||||
let parent_style = (*parent_node.borrow_data_unchecked().unwrap()).style.as_ref().unwrap();
|
||||
Some(parent_style)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut applicable_declarations_cache =
|
||||
local_context.applicable_declarations_cache.borrow_mut();
|
||||
|
||||
let damage;
|
||||
if self.is_text_node() {
|
||||
let mut data_ref = self.mutate_data().unwrap();
|
||||
|
@ -677,8 +685,7 @@ pub trait MatchMethods : TNode {
|
|||
parent_style,
|
||||
&applicable_declarations.normal,
|
||||
data.style.as_mut(),
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
&mut applicable_declarations_cache,
|
||||
applicable_declarations.normal_shareable,
|
||||
true);
|
||||
|
||||
|
@ -690,15 +697,18 @@ pub trait MatchMethods : TNode {
|
|||
|
||||
|
||||
if !applicable_declarations_for_this_pseudo.is_empty() {
|
||||
// NB: Transitions and animations should only work for
|
||||
// pseudo-elements ::before and ::after
|
||||
let should_animate_properties =
|
||||
<Self::ConcreteElement as Element>::Impl::pseudo_is_before_or_after(&pseudo);
|
||||
let (new_damage, style) = self.cascade_node_pseudo_element(
|
||||
context,
|
||||
Some(data.style.as_ref().unwrap()),
|
||||
&*applicable_declarations_for_this_pseudo,
|
||||
data.per_pseudo.get_mut(&pseudo),
|
||||
applicable_declarations_cache,
|
||||
new_animations_sender,
|
||||
&mut applicable_declarations_cache,
|
||||
false,
|
||||
false);
|
||||
should_animate_properties);
|
||||
data.per_pseudo.insert(pseudo, style);
|
||||
|
||||
damage = damage | new_damage;
|
||||
|
|
|
@ -795,6 +795,77 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", need_clone=
|
|||
pub use properties::longhands::transition_duration::{get_initial_value, parse, parse_one};
|
||||
</%helpers:longhand>
|
||||
|
||||
<%helpers:longhand name="animation-name" experimental="True">
|
||||
use cssparser::ToCss;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
pub mod computed_value {
|
||||
use cssparser::ToCss;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||
pub struct T(pub Vec<String>);
|
||||
|
||||
impl ToCss for T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
for (i, name) in self.0.iter().enumerate() {
|
||||
if i != 0 {
|
||||
try!(dest.write_str(", "));
|
||||
}
|
||||
try!(dest.write_str(&name));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use Cows? Probably more codegen work would be needed, and this
|
||||
// could not be that worth it (animations arent *that* used).
|
||||
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||
pub struct SpecifiedValue(Vec<String>);
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
for (i, name) in self.0.iter().enumerate() {
|
||||
if i != 0 {
|
||||
try!(dest.write_str(", "));
|
||||
}
|
||||
try!(dest.write_str(&name));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T(vec![])
|
||||
}
|
||||
|
||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
Ok(SpecifiedValue(try!(input.parse_comma_separated(|input| {
|
||||
input.expect_ident().map(Cow::into_owned)
|
||||
}))))
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value<Cx: TContext>(&self, context: &Cx) -> computed_value::T {
|
||||
let mut ret = vec![];
|
||||
if let Some(animations) = context.animations() {
|
||||
for name in self.0.iter() {
|
||||
if animations.contains_key(&**name) {
|
||||
ret.push(name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
computed_value::T(ret)
|
||||
}
|
||||
}
|
||||
</%helpers:longhand>
|
||||
|
||||
// CSSOM View Module
|
||||
// https://www.w3.org/TR/cssom-view-1/
|
||||
${helpers.single_keyword("scroll-behavior",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::boxed::Box as StdBox;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::sync::Arc;
|
||||
|
@ -22,6 +22,7 @@ use cssparser::Color as CSSParserColor;
|
|||
use cssparser::{Parser, RGBA, AtRuleParser, DeclarationParser, Delimiter,
|
||||
DeclarationListParser, parse_important, ToCss, TokenSerializationType};
|
||||
use error_reporting::ParseErrorReporter;
|
||||
use keyframes::Keyframe;
|
||||
use url::Url;
|
||||
use euclid::side_offsets::SideOffsets2D;
|
||||
use euclid::size::Size2D;
|
||||
|
@ -1594,12 +1595,14 @@ fn cascade_with_cached_declarations<C: ComputedValues>(
|
|||
parent_style: &C,
|
||||
cached_style: &C,
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
animations: Option<<&HashMap<String, Vec<Keyframe>>>,
|
||||
mut error_reporter: StdBox<ParseErrorReporter + Send>)
|
||||
-> C {
|
||||
let mut context = computed::Context {
|
||||
is_root_element: false,
|
||||
viewport_size: viewport_size,
|
||||
inherited_style: parent_style,
|
||||
animations: animations,
|
||||
style: C::new(
|
||||
custom_properties,
|
||||
shareable,
|
||||
|
@ -1739,6 +1742,7 @@ pub fn cascade<C: ComputedValues>(
|
|||
shareable: bool,
|
||||
parent_style: Option<<&C>,
|
||||
cached_style: Option<<&C>,
|
||||
animations: Option<<&HashMap<String, Vec<Keyframe>>>,
|
||||
mut error_reporter: StdBox<ParseErrorReporter + Send>)
|
||||
-> (C, bool) {
|
||||
use properties::style_struct_traits::{Border, Box, Font, Outline};
|
||||
|
@ -1774,6 +1778,7 @@ pub fn cascade<C: ComputedValues>(
|
|||
parent_style,
|
||||
cached_style,
|
||||
custom_properties,
|
||||
animations,
|
||||
error_reporter);
|
||||
return (style, false)
|
||||
}
|
||||
|
@ -1782,6 +1787,7 @@ pub fn cascade<C: ComputedValues>(
|
|||
is_root_element: is_root_element,
|
||||
viewport_size: viewport_size,
|
||||
inherited_style: inherited_style,
|
||||
animations: animations,
|
||||
style: C::new(
|
||||
custom_properties,
|
||||
shareable,
|
||||
|
|
|
@ -90,6 +90,7 @@ pub trait SelectorImplExt : SelectorImpl + Sized {
|
|||
})
|
||||
}
|
||||
|
||||
fn pseudo_is_before_or_after(pseudo: &Self::PseudoElement) -> bool;
|
||||
|
||||
fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState;
|
||||
|
||||
|
@ -109,6 +110,15 @@ pub enum PseudoElement {
|
|||
}
|
||||
|
||||
impl PseudoElement {
|
||||
#[inline]
|
||||
pub fn is_before_or_after(&self) -> bool {
|
||||
match *self {
|
||||
PseudoElement::Before |
|
||||
PseudoElement::After => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cascade_type(&self) -> PseudoElementCascadeType {
|
||||
match *self {
|
||||
|
@ -249,6 +259,11 @@ impl SelectorImplExt for ServoSelectorImpl {
|
|||
pc.state_flag()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
||||
pseudo.is_before_or_after()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>] {
|
||||
&*USER_OR_USER_AGENT_STYLESHEETS
|
||||
|
|
|
@ -128,9 +128,7 @@ pub struct Stylist<Impl: SelectorImplExt> {
|
|||
BuildHasherDefault<::fnv::FnvHasher>>,
|
||||
|
||||
/// A map with all the animations indexed by name.
|
||||
animations: HashMap<String,
|
||||
Vec<Keyframe>,
|
||||
BuildHasherDefault<::fnv::FnvHasher>>,
|
||||
animations: HashMap<String, Vec<Keyframe>>,
|
||||
|
||||
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
|
||||
/// These are eagerly computed once, and then used to resolve the new
|
||||
|
@ -290,7 +288,8 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
|||
let (computed, _) =
|
||||
properties::cascade(self.device.au_viewport_size(),
|
||||
&declarations, false,
|
||||
parent.map(|p| &**p), None,
|
||||
parent.map(|p| &**p),
|
||||
None, None,
|
||||
Box::new(StdoutErrorReporter));
|
||||
Some(Arc::new(computed))
|
||||
} else {
|
||||
|
@ -323,7 +322,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
|||
let (computed, _) =
|
||||
properties::cascade(self.device.au_viewport_size(),
|
||||
&declarations, false,
|
||||
Some(&**parent), None,
|
||||
Some(&**parent), None, None,
|
||||
Box::new(StdoutErrorReporter));
|
||||
Some(Arc::new(computed))
|
||||
}
|
||||
|
@ -457,6 +456,11 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
|||
pub fn is_device_dirty(&self) -> bool {
|
||||
self.is_device_dirty
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn animations(&self) -> &HashMap<String, Vec<Keyframe>> {
|
||||
&self.animations
|
||||
}
|
||||
}
|
||||
|
||||
/// Map that contains the CSS rules for a given origin.
|
||||
|
|
|
@ -278,7 +278,6 @@ pub mod rule_filter {
|
|||
|
||||
impl<'a, I, Impl: SelectorImpl + 'a> $variant<'a, I>
|
||||
where I: Iterator<Item=&'a CSSRule<Impl>> {
|
||||
|
||||
#[inline]
|
||||
pub fn new(iter: I) -> $variant<'a, I> {
|
||||
$variant {
|
||||
|
|
|
@ -219,10 +219,9 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C,
|
|||
// Perform the CSS cascade.
|
||||
unsafe {
|
||||
node.cascade_node(&context.shared_context(),
|
||||
&context.local_context(),
|
||||
parent_opt,
|
||||
&applicable_declarations,
|
||||
&mut context.local_context().applicable_declarations_cache.borrow_mut(),
|
||||
&context.shared_context().new_animations_sender);
|
||||
&applicable_declarations);
|
||||
}
|
||||
|
||||
// Add ourselves to the LRU cache.
|
||||
|
|
|
@ -1561,8 +1561,10 @@ pub mod specified {
|
|||
pub mod computed {
|
||||
use app_units::Au;
|
||||
use euclid::size::Size2D;
|
||||
use keyframes::Keyframe;
|
||||
use properties::ComputedValues;
|
||||
use properties::style_struct_traits::Font;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use super::LocalToCss;
|
||||
use super::specified::AngleOrCorner;
|
||||
|
@ -1578,6 +1580,7 @@ pub mod computed {
|
|||
fn inherited_style(&self) -> &Self::ConcreteComputedValues;
|
||||
fn style(&self) -> &Self::ConcreteComputedValues;
|
||||
fn mutate_style(&mut self) -> &mut Self::ConcreteComputedValues;
|
||||
fn animations(&self) -> Option<&HashMap<String, Vec<Keyframe>>>;
|
||||
}
|
||||
|
||||
pub struct Context<'a, C: ComputedValues> {
|
||||
|
@ -1585,6 +1588,7 @@ pub mod computed {
|
|||
pub viewport_size: Size2D<Au>,
|
||||
pub inherited_style: &'a C,
|
||||
|
||||
pub animations: Option<&'a HashMap<String, Vec<Keyframe>>>,
|
||||
/// Values access through this need to be in the properties "computed early":
|
||||
/// color, text-decoration, font-size, display, position, float, border-*-style, outline-style
|
||||
pub style: C,
|
||||
|
@ -1597,6 +1601,7 @@ pub mod computed {
|
|||
fn inherited_style(&self) -> &C { &self.inherited_style }
|
||||
fn style(&self) -> &C { &self.style }
|
||||
fn mutate_style(&mut self) -> &mut C { &mut self.style }
|
||||
fn animations(&self) -> Option<&HashMap<String, Vec<Keyframe>>> { self.animations }
|
||||
}
|
||||
|
||||
pub trait ToComputedValue {
|
||||
|
|
|
@ -648,6 +648,7 @@ impl MaybeNew for ViewportConstraints {
|
|||
viewport_size: initial_viewport,
|
||||
inherited_style: ServoComputedValues::initial_values(),
|
||||
style: ServoComputedValues::initial_values().clone(),
|
||||
animations: None,
|
||||
};
|
||||
|
||||
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
||||
|
|
|
@ -379,6 +379,15 @@ impl SelectorImplExt for GeckoSelectorImpl {
|
|||
fun(AnonBox(MozSVGText));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
||||
match *pseudo {
|
||||
PseudoElement::Before |
|
||||
PseudoElement::After => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
||||
pc.state_flag()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue