mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
style: Fix parsing and add generated keyframes
This commit is contained in:
parent
46eec45886
commit
2d566ef0ef
10 changed files with 189 additions and 94 deletions
|
@ -14,16 +14,17 @@ 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::selector_impl::{SelectorImplExt, ServoSelectorImpl};
|
||||
use time;
|
||||
|
||||
/// Processes any new animations that were discovered after style recalculation.
|
||||
/// Also expire any old animations that have completed, inserting them into
|
||||
/// `expired_animations`.
|
||||
pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||
running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
|
||||
expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
|
||||
new_animations_receiver: &Receiver<Animation>,
|
||||
pipeline_id: PipelineId) {
|
||||
pub fn update_animation_state<Impl: SelectorImplExt>(constellation_chan: &IpcSender<ConstellationMsg>,
|
||||
running_animations: &mut HashMap<OpaqueNode, Vec<Animation<Impl>>>,
|
||||
expired_animations: &mut HashMap<OpaqueNode, Vec<Animation<Impl>>>,
|
||||
new_animations_receiver: &Receiver<Animation<Impl>>,
|
||||
pipeline_id: PipelineId) {
|
||||
let mut new_running_animations = vec![];
|
||||
while let Ok(animation) = new_animations_receiver.try_recv() {
|
||||
let mut should_push = true;
|
||||
|
@ -118,9 +119,13 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
|||
|
||||
/// Recalculates style for a set of animations. This does *not* run with the DOM
|
||||
/// lock held.
|
||||
// NB: This is specific for ServoSelectorImpl, since the layout context and the
|
||||
// flows are ServoSelectorImpl specific too. If that goes away at some point,
|
||||
// this should be made generic.
|
||||
pub fn recalc_style_for_animations(context: &SharedLayoutContext,
|
||||
flow: &mut Flow,
|
||||
animations: &HashMap<OpaqueNode, Vec<Animation>>) {
|
||||
animations: &HashMap<OpaqueNode,
|
||||
Vec<Animation<ServoSelectorImpl>>>) {
|
||||
let mut damage = RestyleDamage::empty();
|
||||
flow.mutate_fragments(&mut |fragment| {
|
||||
if let Some(ref animations) = animations.get(&fragment.node) {
|
||||
|
|
|
@ -98,7 +98,6 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use std::sync::{Arc, Mutex, MutexGuard, RwLock};
|
||||
use style::animation::Animation;
|
||||
use style::computed_values::{filter, mix_blend_mode};
|
||||
use style::context::ReflowGoal;
|
||||
use style::dom::{TDocument, TElement, TNode};
|
||||
|
@ -109,7 +108,7 @@ use style::parallel::WorkQueueData;
|
|||
use style::properties::ComputedValues;
|
||||
use style::refcell::RefCell;
|
||||
use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS;
|
||||
use style::servo::{SharedStyleContext, Stylesheet, Stylist};
|
||||
use style::servo::{Animation, SharedStyleContext, Stylesheet, Stylist};
|
||||
use style::stylesheets::CSSRuleIteratorExt;
|
||||
use url::Url;
|
||||
use util::geometry::MAX_RECT;
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
|
||||
//! CSS transitions and animations.
|
||||
|
||||
use app_units::Au;
|
||||
use bezier::Bezier;
|
||||
use context::SharedStyleContext;
|
||||
use dom::{OpaqueNode, TRestyleDamage};
|
||||
use euclid::point::Point2D;
|
||||
use keyframes::KeyframesStep;
|
||||
use keyframes::{KeyframesStep, KeyframesStepValue};
|
||||
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
|
||||
use properties::longhands::animation_direction::computed_value::AnimationDirection;
|
||||
use properties::longhands::animation_iteration_count::computed_value::AnimationIterationCount;
|
||||
|
@ -54,7 +53,7 @@ pub enum KeyframesRunningState {
|
|||
/// playing or paused).
|
||||
// TODO: unify the use of f32/f64 in this file.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyframesAnimationState {
|
||||
pub struct KeyframesAnimationState<Impl: SelectorImplExt> {
|
||||
/// The time this animation started at.
|
||||
pub started_at: f64,
|
||||
/// The duration of this animation.
|
||||
|
@ -71,9 +70,12 @@ pub struct KeyframesAnimationState {
|
|||
pub current_direction: AnimationDirection,
|
||||
/// Werther this keyframe animation is outdated due to a restyle.
|
||||
pub expired: bool,
|
||||
/// The original cascade style, needed to compute the generated keyframes of
|
||||
/// the animation.
|
||||
pub cascade_style: Arc<Impl::ComputedValues>,
|
||||
}
|
||||
|
||||
impl KeyframesAnimationState {
|
||||
impl<Impl: SelectorImplExt> KeyframesAnimationState<Impl> {
|
||||
/// Performs a tick in the animation state, i.e., increments the counter of
|
||||
/// the current iteration count, updates times and then toggles the
|
||||
/// direction if appropriate.
|
||||
|
@ -121,7 +123,8 @@ impl KeyframesAnimationState {
|
|||
///
|
||||
/// There are some bits of state we can't just replace, over all taking in
|
||||
/// account times, so here's that logic.
|
||||
pub fn update_from_other(&mut self, other: &Self) {
|
||||
pub fn update_from_other(&mut self, other: &Self)
|
||||
where Self: Clone {
|
||||
use self::KeyframesRunningState::*;
|
||||
|
||||
debug!("KeyframesAnimationState::update_from_other({:?}, {:?})", self, other);
|
||||
|
@ -167,7 +170,7 @@ impl KeyframesAnimationState {
|
|||
|
||||
/// State relating to an animation.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Animation {
|
||||
pub enum Animation<Impl: SelectorImplExt> {
|
||||
/// A transition is just a single frame triggered at a time, with a reflow.
|
||||
///
|
||||
/// the f64 field is the start time as returned by `time::precise_time_s()`.
|
||||
|
@ -176,10 +179,10 @@ pub enum Animation {
|
|||
Transition(OpaqueNode, f64, AnimationFrame, bool),
|
||||
/// A keyframes animation is identified by a name, and can have a
|
||||
/// node-dependent state (i.e. iteration count, etc.).
|
||||
Keyframes(OpaqueNode, Atom, KeyframesAnimationState),
|
||||
Keyframes(OpaqueNode, Atom, KeyframesAnimationState<Impl>),
|
||||
}
|
||||
|
||||
impl Animation {
|
||||
impl<Impl: SelectorImplExt> Animation<Impl> {
|
||||
#[inline]
|
||||
pub fn mark_as_expired(&mut self) {
|
||||
debug_assert!(!self.is_expired());
|
||||
|
@ -344,18 +347,20 @@ impl<T> GetMod for Vec<T> {
|
|||
//
|
||||
// TODO(emilio): Take rid of this mutex splitting SharedLayoutContex into a
|
||||
// cloneable part and a non-cloneable part..
|
||||
pub fn start_transitions_if_applicable<C: ComputedValues>(new_animations_sender: &Mutex<Sender<Animation>>,
|
||||
node: OpaqueNode,
|
||||
old_style: &C,
|
||||
new_style: &mut C)
|
||||
-> bool {
|
||||
pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sender: &Mutex<Sender<Animation<Impl>>>,
|
||||
node: OpaqueNode,
|
||||
old_style: &Impl::ComputedValues,
|
||||
new_style: &mut Arc<Impl::ComputedValues>)
|
||||
-> bool {
|
||||
let mut had_animations = false;
|
||||
for i in 0..new_style.get_box().transition_count() {
|
||||
// Create any property animations, if applicable.
|
||||
let property_animations = PropertyAnimation::from_transition(i, old_style, new_style);
|
||||
let property_animations = PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style));
|
||||
for property_animation in property_animations {
|
||||
// Set the property to the initial value.
|
||||
property_animation.update(new_style, 0.0);
|
||||
// NB: get_mut is guaranteed to succeed since we called make_mut()
|
||||
// above.
|
||||
property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
|
||||
|
||||
// Kick off the animation.
|
||||
let now = time::precise_time_s();
|
||||
|
@ -378,24 +383,33 @@ pub fn start_transitions_if_applicable<C: ComputedValues>(new_animations_sender:
|
|||
|
||||
fn compute_style_for_animation_step<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>,
|
||||
step: &KeyframesStep,
|
||||
old_style: &Impl::ComputedValues) -> Impl::ComputedValues {
|
||||
let declaration_block = DeclarationBlock {
|
||||
declarations: step.declarations.clone(),
|
||||
source_order: 0,
|
||||
specificity: ::std::u32::MAX,
|
||||
};
|
||||
let (computed, _) = properties::cascade(context.viewport_size,
|
||||
&[declaration_block],
|
||||
false,
|
||||
Some(old_style),
|
||||
None,
|
||||
context.error_reporter.clone());
|
||||
computed
|
||||
previous_style: &Impl::ComputedValues,
|
||||
style_from_cascade: &Impl::ComputedValues)
|
||||
-> Impl::ComputedValues {
|
||||
match step.value {
|
||||
// TODO: avoiding this spurious clone might involve having to create
|
||||
// an Arc in the below (more common case).
|
||||
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
|
||||
KeyframesStepValue::Declarations(ref declarations) => {
|
||||
let declaration_block = DeclarationBlock {
|
||||
declarations: declarations.clone(),
|
||||
source_order: 0,
|
||||
specificity: ::std::u32::MAX,
|
||||
};
|
||||
let (computed, _) = properties::cascade(context.viewport_size,
|
||||
&[declaration_block],
|
||||
false,
|
||||
Some(previous_style),
|
||||
None,
|
||||
context.error_reporter.clone());
|
||||
computed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>,
|
||||
node: OpaqueNode,
|
||||
new_style: &Impl::ComputedValues) -> bool
|
||||
new_style: &Arc<Impl::ComputedValues>) -> bool
|
||||
{
|
||||
let mut had_animations = false;
|
||||
|
||||
|
@ -407,8 +421,17 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
|||
continue
|
||||
}
|
||||
|
||||
if context.stylist.animations().get(&name).is_some() {
|
||||
if let Some(ref anim) = context.stylist.animations().get(&name) {
|
||||
debug!("maybe_start_animations: animation {} found", name);
|
||||
|
||||
// If this animation doesn't have any keyframe, we can just continue
|
||||
// without submitting it to the compositor, since both the first and
|
||||
// the second keyframes would be synthetised from the computed
|
||||
// values.
|
||||
if anim.steps.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let delay = box_style.animation_delay.0.get_mod(i).seconds();
|
||||
let now = time::precise_time_s();
|
||||
let animation_start = now + delay as f64;
|
||||
|
@ -444,6 +467,7 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
|
|||
direction: animation_direction,
|
||||
current_direction: initial_direction,
|
||||
expired: false,
|
||||
cascade_style: new_style.clone(),
|
||||
})).unwrap();
|
||||
had_animations = true;
|
||||
}
|
||||
|
@ -474,7 +498,7 @@ pub fn update_style_for_animation_frame<C: ComputedValues>(mut new_style: &mut A
|
|||
/// 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, Impl>(context: &SharedStyleContext<Impl>,
|
||||
animation: &Animation,
|
||||
animation: &Animation<Impl>,
|
||||
style: &mut Arc<Damage::ConcreteComputedValues>,
|
||||
damage: Option<&mut Damage>)
|
||||
where Impl: SelectorImplExt,
|
||||
|
@ -516,6 +540,8 @@ where Impl: SelectorImplExt,
|
|||
Some(animation) => animation,
|
||||
};
|
||||
|
||||
debug_assert!(!animation.steps.is_empty());
|
||||
|
||||
let maybe_index = style.as_servo()
|
||||
.get_box().animation_name.0.iter()
|
||||
.position(|animation_name| name == animation_name);
|
||||
|
@ -579,8 +605,6 @@ where Impl: SelectorImplExt,
|
|||
let target_keyframe = match target_keyframe_position {
|
||||
Some(target) => &animation.steps[target],
|
||||
None => {
|
||||
// TODO: The 0. case falls here, maybe we should just resort
|
||||
// to the first keyframe instead.
|
||||
warn!("update_style_for_animation: No current keyframe found for animation \"{}\" at progress {}",
|
||||
name, total_progress);
|
||||
return;
|
||||
|
@ -605,7 +629,8 @@ where Impl: SelectorImplExt,
|
|||
// TODO: How could we optimise it? Is it such a big deal?
|
||||
let from_style = compute_style_for_animation_step(context,
|
||||
last_keyframe,
|
||||
&**style);
|
||||
&**style,
|
||||
&state.cascade_style);
|
||||
|
||||
// NB: The spec says that the timing function can be overwritten
|
||||
// from the keyframe style.
|
||||
|
@ -616,7 +641,8 @@ where Impl: SelectorImplExt,
|
|||
|
||||
let target_style = compute_style_for_animation_step(context,
|
||||
target_keyframe,
|
||||
&from_style);
|
||||
&from_style,
|
||||
&state.cascade_style);
|
||||
|
||||
let mut new_style = (*style).clone();
|
||||
|
||||
|
|
|
@ -34,16 +34,16 @@ pub struct SharedStyleContext<Impl: SelectorImplExt> {
|
|||
|
||||
/// A channel on which new animations that have been triggered by style recalculation can be
|
||||
/// sent.
|
||||
pub new_animations_sender: Mutex<Sender<Animation>>,
|
||||
pub new_animations_sender: Mutex<Sender<Animation<Impl>>>,
|
||||
|
||||
/// Why is this reflow occurring
|
||||
pub goal: ReflowGoal,
|
||||
|
||||
/// The animations that are currently running.
|
||||
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation<Impl>>>>>,
|
||||
|
||||
/// The list of animations that have expired since the last style recalculation.
|
||||
pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation<Impl>>>>>,
|
||||
|
||||
///The CSS error reporter for all CSS loaded in this layout thread
|
||||
pub error_reporter: Box<ParseErrorReporter + Sync>,
|
||||
|
|
|
@ -2,33 +2,12 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cssparser::{Parser, Delimiter};
|
||||
use parser::ParserContext;
|
||||
use cssparser::{AtRuleParser, Delimiter, Parser, QualifiedRuleParser, RuleListParser};
|
||||
use parser::{ParserContext, log_css_error};
|
||||
use properties::animated_properties::TransitionProperty;
|
||||
use properties::{PropertyDeclaration, parse_property_declaration_list};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Parses a keyframes list, like:
|
||||
/// 0%, 50% {
|
||||
/// width: 50%;
|
||||
/// }
|
||||
///
|
||||
/// 40%, 60%, 100% {
|
||||
/// width: 100%;
|
||||
/// }
|
||||
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Result<Vec<Keyframe>, ()> {
|
||||
let mut keyframes = vec![];
|
||||
while !input.is_exhausted() {
|
||||
keyframes.push(try!(Keyframe::parse(context, input)));
|
||||
}
|
||||
|
||||
if keyframes.len() < 2 {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
Ok(keyframes)
|
||||
}
|
||||
|
||||
/// A number from 1 to 100, indicating the percentage of the animation where
|
||||
/// this keyframe should run.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, HeapSizeOf)]
|
||||
|
@ -57,7 +36,11 @@ impl KeyframePercentage {
|
|||
} else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
|
||||
KeyframePercentage::new(1.)
|
||||
} else {
|
||||
KeyframePercentage::new(try!(input.expect_percentage()))
|
||||
let percentage = try!(input.expect_percentage());
|
||||
if percentage > 1. || percentage < 0. {
|
||||
return Err(());
|
||||
}
|
||||
KeyframePercentage::new(percentage)
|
||||
};
|
||||
|
||||
Ok(percentage)
|
||||
|
@ -100,8 +83,7 @@ impl Keyframe {
|
|||
Ok(parse_property_declaration_list(context, input))
|
||||
}).unwrap();
|
||||
|
||||
// NB: Other browsers seem to ignore important declarations in keyframe
|
||||
// animations too.
|
||||
// NB: Important declarations are explicitely ignored in the spec.
|
||||
Ok(Keyframe {
|
||||
selector: selector,
|
||||
declarations: declarations.normal,
|
||||
|
@ -109,22 +91,33 @@ impl Keyframe {
|
|||
}
|
||||
}
|
||||
|
||||
/// A keyframes step value. This can be a synthetised keyframes animation, that
|
||||
/// is, one autogenerated from the current computed values, or a list of
|
||||
/// declarations to apply.
|
||||
// TODO: Find a better name for this?
|
||||
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||
pub enum KeyframesStepValue {
|
||||
Declarations(Arc<Vec<PropertyDeclaration>>),
|
||||
ComputedValues,
|
||||
}
|
||||
|
||||
/// A single step from a keyframe animation.
|
||||
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||
pub struct KeyframesStep {
|
||||
/// The percentage of the animation duration when this step starts.
|
||||
pub start_percentage: KeyframePercentage,
|
||||
/// Declarations that will determine the final style during the step.
|
||||
pub declarations: Arc<Vec<PropertyDeclaration>>,
|
||||
/// Declarations that will determine the final style during the step, or
|
||||
/// `ComputedValues` if this is an autogenerated step.
|
||||
pub value: KeyframesStepValue,
|
||||
}
|
||||
|
||||
impl KeyframesStep {
|
||||
#[inline]
|
||||
fn new(percentage: KeyframePercentage,
|
||||
declarations: Arc<Vec<PropertyDeclaration>>) -> Self {
|
||||
value: KeyframesStepValue) -> Self {
|
||||
KeyframesStep {
|
||||
start_percentage: percentage,
|
||||
declarations: declarations,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,24 +154,34 @@ fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
|
|||
|
||||
impl KeyframesAnimation {
|
||||
pub fn from_keyframes(keyframes: &[Keyframe]) -> Option<Self> {
|
||||
debug_assert!(keyframes.len() > 1);
|
||||
let mut steps = vec![];
|
||||
|
||||
let animated_properties = get_animated_properties(&keyframes[0]);
|
||||
if animated_properties.is_empty() {
|
||||
if keyframes.is_empty() || animated_properties.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut steps = vec![];
|
||||
|
||||
for keyframe in keyframes {
|
||||
for percentage in keyframe.selector.0.iter() {
|
||||
steps.push(KeyframesStep::new(*percentage,
|
||||
keyframe.declarations.clone()));
|
||||
KeyframesStepValue::Declarations(keyframe.declarations.clone())));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by the start percentage, so we can easily find a frame.
|
||||
steps.sort_by_key(|step| step.start_percentage);
|
||||
|
||||
// Prepend autogenerated keyframes if appropriate.
|
||||
if steps[0].start_percentage.0 != 0. {
|
||||
steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
|
||||
KeyframesStepValue::ComputedValues));
|
||||
}
|
||||
|
||||
if steps.last().unwrap().start_percentage.0 != 1. {
|
||||
steps.push(KeyframesStep::new(KeyframePercentage::new(0.),
|
||||
KeyframesStepValue::ComputedValues));
|
||||
}
|
||||
|
||||
Some(KeyframesAnimation {
|
||||
steps: steps,
|
||||
properties_changed: animated_properties,
|
||||
|
@ -186,3 +189,54 @@ impl KeyframesAnimation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parses a keyframes list, like:
|
||||
/// 0%, 50% {
|
||||
/// width: 50%;
|
||||
/// }
|
||||
///
|
||||
/// 40%, 60%, 100% {
|
||||
/// width: 100%;
|
||||
/// }
|
||||
struct KeyframeListParser<'a> {
|
||||
context: &'a ParserContext<'a>,
|
||||
}
|
||||
|
||||
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Keyframe> {
|
||||
RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
|
||||
.filter_map(Result::ok)
|
||||
.collect()
|
||||
}
|
||||
|
||||
enum Void {}
|
||||
impl<'a> AtRuleParser for KeyframeListParser<'a> {
|
||||
type Prelude = Void;
|
||||
type AtRule = Keyframe;
|
||||
}
|
||||
|
||||
impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
|
||||
type Prelude = KeyframeSelector;
|
||||
type QualifiedRule = Keyframe;
|
||||
|
||||
fn parse_prelude(&self, input: &mut Parser) -> Result<Self::Prelude, ()> {
|
||||
let start = input.position();
|
||||
match input.parse_comma_separated(|input| KeyframePercentage::parse(input)) {
|
||||
Ok(percentages) => Ok(KeyframeSelector(percentages)),
|
||||
Err(()) => {
|
||||
let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
|
||||
log_css_error(input, start, &message, self.context);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_block(&self, prelude: Self::Prelude, input: &mut Parser)
|
||||
-> Result<Self::QualifiedRule, ()> {
|
||||
Ok(Keyframe {
|
||||
selector: prelude,
|
||||
// FIXME: needs parsing different from parse_property_declaration_list:
|
||||
// https://drafts.csswg.org/css-animations/#keyframes
|
||||
// Paragraph "The <declaration-list> inside of <keyframe-block> ..."
|
||||
declarations: parse_property_declaration_list(self.context, input).normal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,7 +386,7 @@ trait PrivateMatchMethods: TNode
|
|||
cacheable = !self.update_animations_for_cascade(context, &mut style) && cacheable;
|
||||
}
|
||||
|
||||
let mut this_style;
|
||||
let this_style;
|
||||
match parent_style {
|
||||
Some(ref parent_style) => {
|
||||
let cache_entry = applicable_declarations_cache.find(applicable_declarations);
|
||||
|
@ -416,6 +416,8 @@ trait PrivateMatchMethods: TNode
|
|||
}
|
||||
};
|
||||
|
||||
let mut this_style = Arc::new(this_style);
|
||||
|
||||
if animate_properties {
|
||||
let this_opaque = self.opaque();
|
||||
// Trigger any present animations if necessary.
|
||||
|
@ -428,7 +430,7 @@ trait PrivateMatchMethods: TNode
|
|||
// to its old value if it did trigger a transition.
|
||||
if let Some(ref style) = style {
|
||||
animations_started |=
|
||||
animation::start_transitions_if_applicable::<Self::ConcreteComputedValues>(
|
||||
animation::start_transitions_if_applicable::<<Self::ConcreteElement as Element>::Impl>(
|
||||
&context.new_animations_sender,
|
||||
this_opaque,
|
||||
&**style,
|
||||
|
@ -439,7 +441,6 @@ trait PrivateMatchMethods: TNode
|
|||
}
|
||||
|
||||
// Calculate style difference.
|
||||
let this_style = Arc::new(this_style);
|
||||
let damage = Self::ConcreteRestyleDamage::compute(style.map(|s| &*s), &*this_style);
|
||||
|
||||
// Cache the resolved style if it was cacheable.
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::ascii::AsciiExt;
|
|||
use std::boxed::Box as StdBox;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{Debug, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
use app_units::Au;
|
||||
|
@ -1069,9 +1069,10 @@ impl PropertyDeclaration {
|
|||
|
||||
pub mod style_struct_traits {
|
||||
use super::longhands;
|
||||
use std::fmt::Debug;
|
||||
|
||||
% for style_struct in data.active_style_structs():
|
||||
pub trait ${style_struct.trait_name}: Clone {
|
||||
pub trait ${style_struct.trait_name}: Debug + Clone {
|
||||
% for longhand in style_struct.longhands:
|
||||
#[allow(non_snake_case)]
|
||||
fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T);
|
||||
|
@ -1100,7 +1101,7 @@ pub mod style_structs {
|
|||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
% else:
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
% endif
|
||||
pub struct ${style_struct.servo_struct_name} {
|
||||
|
@ -1249,7 +1250,7 @@ pub mod style_structs {
|
|||
% endfor
|
||||
}
|
||||
|
||||
pub trait ComputedValues : Clone + Send + Sync + 'static {
|
||||
pub trait ComputedValues : Debug + Clone + Send + Sync + 'static {
|
||||
% for style_struct in data.active_style_structs():
|
||||
type Concrete${style_struct.trait_name}: style_struct_traits::${style_struct.trait_name};
|
||||
% endfor
|
||||
|
@ -1292,7 +1293,7 @@ pub trait ComputedValues : Clone + Send + Sync + 'static {
|
|||
fn is_multicol(&self) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct ServoComputedValues {
|
||||
% for style_struct in data.active_style_structs():
|
||||
|
|
|
@ -9,6 +9,7 @@ use properties::{self, ServoComputedValues};
|
|||
use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET};
|
||||
use selectors::Element;
|
||||
use selectors::parser::{ParserContext, SelectorImpl};
|
||||
use std::fmt::Debug;
|
||||
use stylesheets::Stylesheet;
|
||||
|
||||
/// This function determines if a pseudo-element is eagerly cascaded or not.
|
||||
|
@ -62,7 +63,9 @@ pub trait ElementExt: Element {
|
|||
fn is_link(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait SelectorImplExt : SelectorImpl + Sized {
|
||||
// NB: The `Clone` trait is here for convenience due to:
|
||||
// https://github.com/rust-lang/rust/issues/26925
|
||||
pub trait SelectorImplExt : SelectorImpl + Clone + Debug + Sized {
|
||||
type ComputedValues: properties::ComputedValues;
|
||||
|
||||
fn pseudo_element_cascade_type(pseudo: &Self::PseudoElement) -> PseudoElementCascadeType;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Concrete types for servo Style implementation
|
||||
|
||||
use animation;
|
||||
use context;
|
||||
use data;
|
||||
use properties::ServoComputedValues;
|
||||
|
@ -15,3 +15,4 @@ pub type Stylesheet = stylesheets::Stylesheet<ServoSelectorImpl>;
|
|||
pub type PrivateStyleData = data::PrivateStyleData<ServoSelectorImpl, ServoComputedValues>;
|
||||
pub type Stylist = selector_matching::Stylist<ServoSelectorImpl>;
|
||||
pub type SharedStyleContext = context::SharedStyleContext<ServoSelectorImpl>;
|
||||
pub type Animation = animation::Animation<ServoSelectorImpl>;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! Style sheets and their CSS rules.
|
||||
|
||||
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
|
||||
use cssparser::{AtRuleType, RuleListParser};
|
||||
use cssparser::{AtRuleType, RuleListParser, Token};
|
||||
use encoding::EncodingRef;
|
||||
use error_reporting::ParseErrorReporter;
|
||||
use font_face::{FontFaceRule, parse_font_face_block};
|
||||
|
@ -506,7 +506,12 @@ impl<'a, 'b, Impl: SelectorImpl> AtRuleParser for NestedRuleParser<'a, 'b, Impl>
|
|||
}
|
||||
},
|
||||
"keyframes" => {
|
||||
let name = try!(input.expect_ident());
|
||||
let name = match input.next() {
|
||||
Ok(Token::Ident(ref value)) if value != "none" => Atom::from(&**value),
|
||||
Ok(Token::QuotedString(value)) => Atom::from(&*value),
|
||||
_ => return Err(())
|
||||
};
|
||||
|
||||
Ok(AtRuleType::WithBlock(AtRulePrelude::Keyframes(Atom::from(name))))
|
||||
},
|
||||
_ => Err(())
|
||||
|
@ -530,7 +535,7 @@ impl<'a, 'b, Impl: SelectorImpl> AtRuleParser for NestedRuleParser<'a, 'b, Impl>
|
|||
AtRulePrelude::Keyframes(name) => {
|
||||
Ok(CSSRule::Keyframes(KeyframesRule {
|
||||
name: name,
|
||||
keyframes: try!(parse_keyframe_list(&self.context, input)),
|
||||
keyframes: parse_keyframe_list(&self.context, input),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue