keyframes_rule.rs 20.8 KB
Newer Older
1
2
/* 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
3
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4

5
6
//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes

7
8
9
10
11
12
13
14
15
16
17
18
19
use crate::error_reporting::ContextualParseError;
use crate::parser::ParserContext;
use crate::properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use crate::properties::LonghandIdSet;
use crate::properties::{Importance, PropertyDeclaration};
use crate::properties::{LonghandId, PropertyDeclarationBlock, PropertyId};
use crate::properties::{PropertyDeclarationId, SourcePropertyDeclaration};
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
use crate::shared_lock::{Locked, ToCssWithGuard};
use crate::str::CssStringWriter;
use crate::stylesheets::rule_parser::VendorPrefix;
use crate::stylesheets::{CssRuleType, StylesheetContents};
use crate::values::{serialize_percentage, KeyframesName};
20
use cssparser::{parse_one_rule, DeclarationListParser, DeclarationParser, ParserState, SourceLocation, Token};
21
use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser, RuleListParser};
22
use servo_arc::Arc;
23
use std::fmt::{self, Write};
24
use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
25
26
27
28

/// A [`@keyframes`][keyframes] rule.
///
/// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes
29
#[derive(Debug, ToShmem)]
30
31
32
33
34
35
36
37
38
39
40
41
42
pub struct KeyframesRule {
    /// The name of the current animation.
    pub name: KeyframesName,
    /// The keyframes specified for this CSS rule.
    pub keyframes: Vec<Arc<Locked<Keyframe>>>,
    /// Vendor prefix type the @keyframes has.
    pub vendor_prefix: Option<VendorPrefix>,
    /// The line and column of the rule's source code.
    pub source_location: SourceLocation,
}

impl ToCssWithGuard for KeyframesRule {
    // Serialization of KeyframesRule is not specced.
43
    fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
44
        dest.write_str("@keyframes ")?;
45
        self.name.to_css(&mut CssWriter::new(dest))?;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
        dest.write_str(" {")?;
        let iter = self.keyframes.iter();
        for lock in iter {
            dest.write_str("\n")?;
            let keyframe = lock.read_with(&guard);
            keyframe.to_css(guard, dest)?;
        }
        dest.write_str("\n}")
    }
}

impl KeyframesRule {
    /// Returns the index of the last keyframe that matches the given selector.
    /// If the selector is not valid, or no keyframe is found, returns None.
    ///
    /// Related spec:
62
    /// <https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule>
63
    pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
64
65
        let mut input = ParserInput::new(selector);
        if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
66
67
68
69
70
71
72
73
74
75
76
77
78
79
            for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
                if keyframe.read_with(guard).selector == selector {
                    return Some(i);
                }
            }
        }
        None
    }
}

impl DeepCloneWithLock for KeyframesRule {
    fn deep_clone_with_lock(
        &self,
        lock: &SharedRwLock,
80
81
        guard: &SharedRwLockReadGuard,
        params: &DeepCloneParams,
82
83
84
    ) -> Self {
        KeyframesRule {
            name: self.name.clone(),
85
86
            keyframes: self
                .keyframes
87
                .iter()
88
                .map(|x| {
89
90
91
                    Arc::new(
                        lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard, params)),
                    )
92
93
                })
                .collect(),
94
95
96
97
98
            vendor_prefix: self.vendor_prefix.clone(),
            source_location: self.source_location.clone(),
        }
    }
}
99

100
101
/// A number from 0 to 1, indicating the percentage of the animation when this
/// keyframe should run.
102
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
103
104
105
106
107
108
109
110
111
112
pub struct KeyframePercentage(pub f32);

impl ::std::cmp::Ord for KeyframePercentage {
    #[inline]
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        // We know we have a number from 0 to 1, so unwrap() here is safe.
        self.0.partial_cmp(&other.0).unwrap()
    }
}

113
impl ::std::cmp::Eq for KeyframePercentage {}
114

115
impl ToCss for KeyframePercentage {
116
117
118
119
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
120
        serialize_percentage(self.0, dest)
121
122
123
    }
}

124
impl KeyframePercentage {
125
    /// Trivially constructs a new `KeyframePercentage`.
126
127
128
129
130
131
    #[inline]
    pub fn new(value: f32) -> KeyframePercentage {
        debug_assert!(value >= 0. && value <= 1.);
        KeyframePercentage(value)
    }

132
    fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
133
134
135
136
137
138
139
140
        let token = input.next()?.clone();
        match token {
            Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
                Ok(KeyframePercentage::new(0.))
            },
            Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
                Ok(KeyframePercentage::new(1.))
            },
141
142
143
            Token::Percentage {
                unit_value: percentage,
                ..
144
            } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
145
            _ => Err(input.new_unexpected_token_error(token)),
146
        }
147
148
149
150
151
    }
}

/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
152
#[css(comma)]
153
#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
154
pub struct KeyframeSelector(#[css(iterable)] Vec<KeyframePercentage>);
155

156
impl KeyframeSelector {
157
    /// Return the list of percentages this selector contains.
158
159
160
161
162
163
164
165
166
    #[inline]
    pub fn percentages(&self) -> &[KeyframePercentage] {
        &self.0
    }

    /// A dummy public function so we can write a unit test for this.
    pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
        KeyframeSelector(percentages)
    }
167

168
    /// Parse a keyframe selector from CSS input.
169
    pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
170
171
172
        input
            .parse_comma_separated(KeyframePercentage::parse)
            .map(KeyframeSelector)
173
    }
174
175
176
}

/// A keyframe.
177
#[derive(Debug, ToShmem)]
178
pub struct Keyframe {
179
    /// The selector this keyframe was specified from.
180
181
    pub selector: KeyframeSelector,

182
183
184
185
    /// The declaration block that was declared inside this keyframe.
    ///
    /// Note that `!important` rules in keyframes don't apply, but we keep this
    /// `Arc` just for convenience.
186
    pub block: Arc<Locked<PropertyDeclarationBlock>>,
187
188
189

    /// The line and column of the rule's source code.
    pub source_location: SourceLocation,
190
191
}

192
impl ToCssWithGuard for Keyframe {
193
    fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
194
        self.selector.to_css(&mut CssWriter::new(dest))?;
195
196
197
        dest.write_str(" { ")?;
        self.block.read_with(guard).to_css(dest)?;
        dest.write_str(" }")?;
198
199
200
201
        Ok(())
    }
}

202
impl Keyframe {
203
    /// Parse a CSS keyframe.
204
205
206
207
208
209
    pub fn parse<'i>(
        css: &'i str,
        parent_stylesheet_contents: &StylesheetContents,
        lock: &SharedRwLock,
    ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
        let url_data = parent_stylesheet_contents.url_data.read();
210
211
212
213
214
        let namespaces = parent_stylesheet_contents.namespaces.read();
        let mut context = ParserContext::new(
            parent_stylesheet_contents.origin,
            &url_data,
            Some(CssRuleType::Keyframe),
215
            ParsingMode::DEFAULT,
216
            parent_stylesheet_contents.quirks_mode,
217
            None,
218
            None,
219
220
        );
        context.namespaces = Some(&*namespaces);
221
222
        let mut input = ParserInput::new(css);
        let mut input = Parser::new(&mut input);
223

224
        let mut declarations = SourcePropertyDeclaration::new();
225
226
        let mut rule_parser = KeyframeListParser {
            context: &context,
227
            shared_lock: &lock,
228
            declarations: &mut declarations,
229
230
231
        };
        parse_one_rule(&mut input, &mut rule_parser)
    }
232
}
233

234
impl DeepCloneWithLock for Keyframe {
235
    /// Deep clones this Keyframe.
236
237
238
    fn deep_clone_with_lock(
        &self,
        lock: &SharedRwLock,
239
240
        guard: &SharedRwLockReadGuard,
        _params: &DeepCloneParams,
241
    ) -> Keyframe {
242
243
        Keyframe {
            selector: self.selector.clone(),
244
            block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
245
            source_location: self.source_location.clone(),
246
247
        }
    }
248
249
}

250
251
252
/// 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.
253
254
///
/// TODO: Find a better name for this?
255
#[derive(Clone, Debug, MallocSizeOf)]
256
pub enum KeyframesStepValue {
257
    /// A step formed by a declaration block specified by the CSS.
258
    Declarations {
259
        /// The declaration block per se.
260
261
262
263
        #[cfg_attr(
            feature = "gecko",
            ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
        )]
264
        #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
265
        block: Arc<Locked<PropertyDeclarationBlock>>,
266
    },
267
268
    /// A synthetic step computed from the current computed values at the time
    /// of the animation.
269
270
271
272
    ComputedValues,
}

/// A single step from a keyframe animation.
273
#[derive(Clone, Debug, MallocSizeOf)]
274
275
276
277
278
279
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, or
    /// `ComputedValues` if this is an autogenerated step.
    pub value: KeyframesStepValue,
280
281
282
283
284
    /// Wether a animation-timing-function declaration exists in the list of
    /// declarations.
    ///
    /// This is used to know when to override the keyframe animation style.
    pub declared_timing_function: bool,
285
286
287
288
}

impl KeyframesStep {
    #[inline]
289
290
291
292
293
    fn new(
        percentage: KeyframePercentage,
        value: KeyframesStepValue,
        guard: &SharedRwLockReadGuard,
    ) -> Self {
294
        let declared_timing_function = match value {
295
296
297
298
299
300
301
302
            KeyframesStepValue::Declarations { ref block } => block
                .read_with(guard)
                .declarations()
                .iter()
                .any(|prop_decl| match *prop_decl {
                    PropertyDeclaration::AnimationTimingFunction(..) => true,
                    _ => false,
                }),
303
304
305
            _ => false,
        };

306
307
308
        KeyframesStep {
            start_percentage: percentage,
            value: value,
309
            declared_timing_function: declared_timing_function,
310
311
        }
    }
312
313

    /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
314
315
316
317
    pub fn get_animation_timing_function(
        &self,
        guard: &SharedRwLockReadGuard,
    ) -> Option<SpecifiedTimingFunction> {
318
319
320
321
322
        if !self.declared_timing_function {
            return None;
        }
        match self.value {
            KeyframesStepValue::Declarations { ref block } => {
323
                let guard = block.read_with(guard);
324
325
326
                let (declaration, _) = guard
                    .get(PropertyDeclarationId::Longhand(
                        LonghandId::AnimationTimingFunction,
327
328
                    ))
                    .unwrap();
329
330
                match *declaration {
                    PropertyDeclaration::AnimationTimingFunction(ref value) => {
331
332
                        // Use the first value.
                        Some(value.0[0])
333
                    },
334
335
                    PropertyDeclaration::CSSWideKeyword(..) => None,
                    PropertyDeclaration::WithVariables(..) => None,
336
337
338
339
340
341
342
343
                    _ => panic!(),
                }
            },
            KeyframesStepValue::ComputedValues => {
                panic!("Shouldn't happen to set animation-timing-function in missing keyframes")
            },
        }
    }
344
345
346
347
348
349
}

/// This structure represents a list of animation steps computed from the list
/// of keyframes, in order.
///
/// It only takes into account animable properties.
350
#[derive(Clone, Debug, MallocSizeOf)]
351
pub struct KeyframesAnimation {
352
    /// The difference steps of the animation.
353
354
    pub steps: Vec<KeyframesStep>,
    /// The properties that change in this animation.
355
    pub properties_changed: LonghandIdSet,
356
357
    /// Vendor prefix type the @keyframes has.
    pub vendor_prefix: Option<VendorPrefix>,
358
359
}

360
/// Get all the animated properties in a keyframes animation.
361
362
fn get_animated_properties(
    keyframes: &[Arc<Locked<Keyframe>>],
363
    guard: &SharedRwLockReadGuard,
364
365
) -> LonghandIdSet {
    let mut ret = LonghandIdSet::new();
366
367
    // NB: declarations are already deduplicated, so we don't have to check for
    // it here.
368
    for keyframe in keyframes {
369
370
        let keyframe = keyframe.read_with(&guard);
        let block = keyframe.block.read_with(guard);
371
372
373
374
375
376
377
        // CSS Animations spec clearly defines that properties with !important
        // in keyframe rules are invalid and ignored, but it's still ambiguous
        // whether we should drop the !important properties or retain the
        // properties when they are set via CSSOM. So we assume there might
        // be properties with !important in keyframe rules here.
        // See the spec issue https://github.com/w3c/csswg-drafts/issues/1824
        for declaration in block.normal_declaration_iter() {
378
379
380
381
382
383
384
385
386
387
388
            let longhand_id = match declaration.id() {
                PropertyDeclarationId::Longhand(id) => id,
                _ => continue,
            };

            if longhand_id == LonghandId::Display {
                continue;
            }

            if !longhand_id.is_animatable() {
                continue;
389
            }
390
391

            ret.insert(longhand_id);
392
393
394
395
396
397
398
        }
    }

    ret
}

impl KeyframesAnimation {
399
400
    /// Create a keyframes animation from a given list of keyframes.
    ///
401
402
    /// This will return a keyframe animation with empty steps and
    /// properties_changed if the list of keyframes is empty, or there are no
403
    /// animated properties obtained from the keyframes.
404
405
406
    ///
    /// Otherwise, this will compute and sort the steps used for the animation,
    /// and return the animation object.
407
408
409
410
411
    pub fn from_keyframes(
        keyframes: &[Arc<Locked<Keyframe>>],
        vendor_prefix: Option<VendorPrefix>,
        guard: &SharedRwLockReadGuard,
    ) -> Self {
412
413
        let mut result = KeyframesAnimation {
            steps: vec![],
414
415
            properties_changed: LonghandIdSet::new(),
            vendor_prefix,
416
417
        };

418
        if keyframes.is_empty() {
419
            return result;
420
421
        }

422
        result.properties_changed = get_animated_properties(keyframes, guard);
423
424
        if result.properties_changed.is_empty() {
            return result;
425
426
427
        }

        for keyframe in keyframes {
428
            let keyframe = keyframe.read_with(&guard);
429
            for percentage in keyframe.selector.0.iter() {
430
431
432
433
434
435
436
                result.steps.push(KeyframesStep::new(
                    *percentage,
                    KeyframesStepValue::Declarations {
                        block: keyframe.block.clone(),
                    },
                    guard,
                ));
437
438
439
440
            }
        }

        // Sort by the start percentage, so we can easily find a frame.
441
        result.steps.sort_by_key(|step| step.start_percentage);
442
443

        // Prepend autogenerated keyframes if appropriate.
444
        if result.steps[0].start_percentage.0 != 0. {
445
446
447
448
449
450
451
452
            result.steps.insert(
                0,
                KeyframesStep::new(
                    KeyframePercentage::new(0.),
                    KeyframesStepValue::ComputedValues,
                    guard,
                ),
            );
453
454
        }

455
        if result.steps.last().unwrap().start_percentage.0 != 1. {
456
457
458
459
460
            result.steps.push(KeyframesStep::new(
                KeyframePercentage::new(1.),
                KeyframesStepValue::ComputedValues,
                guard,
            ));
461
462
        }

463
        result
464
465
466
467
468
469
470
471
472
473
474
    }
}

/// Parses a keyframes list, like:
/// 0%, 50% {
///     width: 50%;
/// }
///
/// 40%, 60%, 100% {
///     width: 100%;
/// }
475
struct KeyframeListParser<'a> {
476
    context: &'a ParserContext<'a>,
477
    shared_lock: &'a SharedRwLock,
478
    declarations: &'a mut SourcePropertyDeclaration,
479
480
}

481
/// Parses a keyframe list from CSS input.
482
pub fn parse_keyframe_list(
483
484
    context: &ParserContext,
    input: &mut Parser,
485
    shared_lock: &SharedRwLock,
486
) -> Vec<Arc<Locked<Keyframe>>> {
487
488
489
490
    debug_assert!(
        context.namespaces.is_some(),
        "Parsing a keyframe list from a context without namespaces?"
    );
491

492
    let mut declarations = SourcePropertyDeclaration::new();
493
494
495
496
497
498
499
    RuleListParser::new_for_nested_rule(
        input,
        KeyframeListParser {
            context: context,
            shared_lock: shared_lock,
            declarations: &mut declarations,
        },
500
501
    )
    .filter_map(Result::ok)
502
    .collect()
503
504
}

505
impl<'a, 'i> AtRuleParser<'i> for KeyframeListParser<'a> {
506
507
    type PreludeNoBlock = ();
    type PreludeBlock = ();
508
    type AtRule = Arc<Locked<Keyframe>>;
509
    type Error = StyleParseErrorKind<'i>;
510
511
}

512
impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
513
    type Prelude = KeyframeSelector;
514
    type QualifiedRule = Arc<Locked<Keyframe>>;
515
    type Error = StyleParseErrorKind<'i>;
516

517
518
519
520
    fn parse_prelude<'t>(
        &mut self,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self::Prelude, ParseError<'i>> {
521
        let start_position = input.position();
522
523
524
525
526
        KeyframeSelector::parse(input).map_err(|e| {
            let location = e.location;
            let error = ContextualParseError::InvalidKeyframeRule(
                input.slice_from(start_position),
                e.clone(),
527
            );
528
529
530
            self.context.log_css_error(location, error);
            e
        })
531
532
    }

533
534
    fn parse_block<'t>(
        &mut self,
535
        selector: Self::Prelude,
536
        start: &ParserState,
537
538
539
540
541
542
543
        input: &mut Parser<'i, 't>,
    ) -> Result<Self::QualifiedRule, ParseError<'i>> {
        let context = ParserContext::new_with_rule_type(
            self.context,
            CssRuleType::Keyframe,
            self.context.namespaces.unwrap(),
        );
544

545
        let parser = KeyframeDeclarationParser {
546
            context: &context,
547
            declarations: self.declarations,
548
549
        };
        let mut iter = DeclarationListParser::new(input, parser);
550
        let mut block = PropertyDeclarationBlock::new();
551
552
        while let Some(declaration) = iter.next() {
            match declaration {
553
                Ok(()) => {
554
                    block.extend(iter.parser.declarations.drain(), Importance::Normal);
555
                },
556
                Err((error, slice)) => {
557
                    iter.parser.declarations.clear();
558
                    let location = error.location;
559
560
                    let error =
                        ContextualParseError::UnsupportedKeyframePropertyDeclaration(slice, error);
561
                    context.log_css_error(location, error);
562
                },
563
564
565
            }
            // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
        }
566
        Ok(Arc::new(self.shared_lock.wrap(Keyframe {
567
            selector,
568
            block: Arc::new(self.shared_lock.wrap(block)),
569
            source_location: start.source_location(),
570
        })))
571
572
    }
}
573
574
575

struct KeyframeDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
576
    declarations: &'a mut SourcePropertyDeclaration,
577
578
579
}

/// Default methods reject all at rules.
580
impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeDeclarationParser<'a, 'b> {
581
582
    type PreludeNoBlock = ();
    type PreludeBlock = ();
583
    type AtRule = ();
584
    type Error = StyleParseErrorKind<'i>;
585
586
}

587
impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> {
588
    type Declaration = ();
589
    type Error = StyleParseErrorKind<'i>;
590

591
592
593
594
595
    fn parse_value<'t>(
        &mut self,
        name: CowRcStr<'i>,
        input: &mut Parser<'i, 't>,
    ) -> Result<(), ParseError<'i>> {
596
597
        let id = match PropertyId::parse(&name, self.context) {
            Ok(id) => id,
598
            Err(()) => {
599
                return Err(input.new_custom_error(StyleParseErrorKind::UnknownProperty(name)));
600
            },
601
        };
602
603

        // TODO(emilio): Shouldn't this use parse_entirely?
604
        PropertyDeclaration::parse_into(self.declarations, id, self.context, input)?;
605
606
607
608
609
610

        // In case there is still unparsed text in the declaration, we should
        // roll back.
        input.expect_exhausted()?;

        Ok(())
611
612
    }
}