1use crate::derives::*;
8use crate::error_reporting::ContextualParseError;
9use crate::parser::ParserContext;
10use crate::properties::{
11 longhands::{
12 animation_composition::single_value::SpecifiedValue as SpecifiedComposition,
13 transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction,
14 },
15 parse_property_declaration_list, LonghandId, PropertyDeclaration, PropertyDeclarationBlock,
16 PropertyDeclarationId, PropertyDeclarationIdSet,
17};
18use crate::shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
19use crate::shared_lock::{Locked, ToCssWithGuard};
20use crate::stylesheets::rule_parser::VendorPrefix;
21use crate::stylesheets::{CssRuleType, StylesheetContents};
22use crate::values::specified::animation::TimelineRangeName;
23use crate::values::{serialize_percentage, KeyframesName};
24use cssparser::{
25 parse_one_rule, AtRuleParser, DeclarationParser, Parser, ParserInput, ParserState,
26 QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, Token,
27};
28use servo_arc::Arc;
29use std::borrow::Cow;
30use std::fmt::{self, Write};
31use style_traits::{
32 CssStringWriter, CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss,
33};
34
35#[derive(Debug, ToShmem)]
39pub struct KeyframesRule {
40 pub name: KeyframesName,
42 pub keyframes: Vec<Arc<Locked<Keyframe>>>,
44 pub vendor_prefix: Option<VendorPrefix>,
46 pub source_location: SourceLocation,
48}
49
50impl ToCssWithGuard for KeyframesRule {
51 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
53 dest.write_str("@keyframes ")?;
54 self.name.to_css(&mut CssWriter::new(dest))?;
55 dest.write_str(" {")?;
56 let iter = self.keyframes.iter();
57 for lock in iter {
58 dest.write_str("\n")?;
59 let keyframe = lock.read_with(&guard);
60 keyframe.to_css(guard, dest)?;
61 }
62 dest.write_str("\n}")
63 }
64}
65
66impl KeyframesRule {
67 pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
73 let mut input = ParserInput::new(selector);
74 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelectors::parse) {
75 for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
76 if keyframe.read_with(guard).selector == selector {
77 return Some(i);
78 }
79 }
80 }
81 None
82 }
83}
84
85impl DeepCloneWithLock for KeyframesRule {
86 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
87 KeyframesRule {
88 name: self.name.clone(),
89 keyframes: self
90 .keyframes
91 .iter()
92 .map(|x| Arc::new(lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard))))
93 .collect(),
94 vendor_prefix: self.vendor_prefix.clone(),
95 source_location: self.source_location.clone(),
96 }
97 }
98}
99
100#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
103pub struct KeyframePercentage(pub f32);
104
105impl ::std::cmp::Ord for KeyframePercentage {
106 #[inline]
107 fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
108 self.0.partial_cmp(&other.0).unwrap()
110 }
111}
112
113impl ::std::cmp::Eq for KeyframePercentage {}
114
115impl ToCss for KeyframePercentage {
116 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
117 where
118 W: Write,
119 {
120 serialize_percentage(self.0, dest)
121 }
122}
123
124impl KeyframePercentage {
125 #[inline]
127 pub fn new(value: f32) -> KeyframePercentage {
128 KeyframePercentage(value)
129 }
130
131 fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
132 let token = input.next()?.clone();
133 match token {
134 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
135 Ok(KeyframePercentage::new(0.))
136 },
137 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
138 Ok(KeyframePercentage::new(1.))
139 },
140 Token::Percentage {
141 unit_value: percentage,
142 ..
143 } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
144 _ => Err(input.new_unexpected_token_error(token)),
145 }
146 }
147}
148
149#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)]
154pub struct KeyframeSelector {
155 pub range_name: TimelineRangeName,
159 pub percentage: KeyframePercentage,
162}
163
164impl KeyframeSelector {
165 fn from_percentage(percentage: KeyframePercentage) -> Self {
167 debug_assert!(percentage.0 >= 0. && percentage.0 <= 1.);
168 KeyframeSelector {
169 range_name: TimelineRangeName::None,
170 percentage,
171 }
172 }
173
174 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
176 if let Ok(percentage) = input.try_parse(KeyframePercentage::parse) {
178 return Ok(Self::from_percentage(percentage));
179 }
180
181 if !static_prefs::pref!("layout.css.scroll-driven-animations.enabled") {
183 let location = input.current_source_location();
184 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
185 }
186
187 Ok(Self {
190 range_name: TimelineRangeName::parse(input)?,
191 percentage: KeyframePercentage::new(input.expect_percentage()?),
192 })
193 }
194}
195
196#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
198#[css(comma)]
199pub struct KeyframeSelectors(#[css(iterable)] Vec<KeyframeSelector>);
200
201impl KeyframeSelectors {
202 pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelectors {
204 KeyframeSelectors(
205 percentages
206 .into_iter()
207 .map(KeyframeSelector::from_percentage)
208 .collect(),
209 )
210 }
211
212 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
214 input
215 .parse_comma_separated(KeyframeSelector::parse)
216 .map(KeyframeSelectors)
217 }
218}
219
220#[derive(Debug, ToShmem)]
222pub struct Keyframe {
223 pub selector: KeyframeSelectors,
225
226 pub block: Arc<Locked<PropertyDeclarationBlock>>,
231
232 pub source_location: SourceLocation,
234}
235
236impl ToCssWithGuard for Keyframe {
237 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
238 self.selector.to_css(&mut CssWriter::new(dest))?;
239 dest.write_str(" { ")?;
240 self.block.read_with(guard).to_css(dest)?;
241 dest.write_str(" }")?;
242 Ok(())
243 }
244}
245
246impl Keyframe {
247 pub fn parse<'i>(
249 css: &'i str,
250 parent_stylesheet_contents: &StylesheetContents,
251 lock: &SharedRwLock,
252 ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
253 let url_data = &parent_stylesheet_contents.url_data;
254 let namespaces = &parent_stylesheet_contents.namespaces;
255 let mut context = ParserContext::new(
256 parent_stylesheet_contents.origin,
257 &url_data,
258 Some(CssRuleType::Keyframe),
259 ParsingMode::DEFAULT,
260 parent_stylesheet_contents.quirks_mode,
261 Cow::Borrowed(&*namespaces),
262 None,
263 None,
264 Default::default(),
265 );
266 let mut input = ParserInput::new(css);
267 let mut input = Parser::new(&mut input);
268
269 let mut rule_parser = KeyframeListParser {
270 context: &mut context,
271 shared_lock: &lock,
272 };
273 parse_one_rule(&mut input, &mut rule_parser)
274 }
275}
276
277impl DeepCloneWithLock for Keyframe {
278 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Keyframe {
280 Keyframe {
281 selector: self.selector.clone(),
282 block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
283 source_location: self.source_location.clone(),
284 }
285 }
286}
287
288#[derive(Clone, Debug, MallocSizeOf)]
294pub enum KeyframesStepValue {
295 Declarations {
297 #[cfg_attr(
299 feature = "gecko",
300 ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
301 )]
302 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
303 block: Arc<Locked<PropertyDeclarationBlock>>,
304 },
305 ComputedValues,
308}
309
310#[derive(Clone, Debug, MallocSizeOf)]
312pub struct KeyframesStep {
313 pub start_offset: KeyframeSelector,
315 pub value: KeyframesStepValue,
318 pub declared_timing_function: bool,
323 pub declared_composition: bool,
328}
329
330impl KeyframesStep {
331 #[inline]
332 fn new(
333 start_offset: KeyframeSelector,
334 value: KeyframesStepValue,
335 guard: &SharedRwLockReadGuard,
336 ) -> Self {
337 let mut declared_timing_function = false;
338 let mut declared_composition = false;
339 if let KeyframesStepValue::Declarations { ref block } = value {
340 for prop_decl in block.read_with(guard).declarations().iter() {
341 match *prop_decl {
342 PropertyDeclaration::AnimationTimingFunction(..) => {
343 declared_timing_function = true;
344 },
345 PropertyDeclaration::AnimationComposition(..) => {
346 declared_composition = true;
347 },
348 _ => continue,
349 }
350 if declared_timing_function && declared_composition {
352 break;
353 }
354 }
355 }
356
357 KeyframesStep {
358 start_offset,
359 value,
360 declared_timing_function,
361 declared_composition,
362 }
363 }
364
365 #[inline]
367 fn get_declared_property<'a>(
368 &'a self,
369 guard: &'a SharedRwLockReadGuard,
370 property: LonghandId,
371 ) -> Option<&'a PropertyDeclaration> {
372 match self.value {
373 KeyframesStepValue::Declarations { ref block } => {
374 let guard = block.read_with(guard);
375 let (declaration, _) = guard
376 .get(PropertyDeclarationId::Longhand(property))
377 .unwrap();
378 match *declaration {
379 PropertyDeclaration::CSSWideKeyword(..) => None,
380 PropertyDeclaration::WithVariables(..) => None,
382 _ => Some(declaration),
383 }
384 },
385 KeyframesStepValue::ComputedValues => {
386 panic!("Shouldn't happen to set this property in missing keyframes")
387 },
388 }
389 }
390
391 pub fn get_animation_timing_function(
394 &self,
395 guard: &SharedRwLockReadGuard,
396 ) -> Option<SpecifiedTimingFunction> {
397 if !self.declared_timing_function {
398 return None;
399 }
400
401 self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
402 .map(|decl| {
403 match *decl {
404 PropertyDeclaration::AnimationTimingFunction(ref value) => {
405 value.0[0].clone()
407 },
408 _ => unreachable!("Unexpected PropertyDeclaration"),
409 }
410 })
411 }
412
413 pub fn get_animation_composition(
415 &self,
416 guard: &SharedRwLockReadGuard,
417 ) -> Option<SpecifiedComposition> {
418 if !self.declared_composition {
419 return None;
420 }
421
422 self.get_declared_property(guard, LonghandId::AnimationComposition)
423 .map(|decl| {
424 match *decl {
425 PropertyDeclaration::AnimationComposition(ref value) => {
426 value.0[0].clone()
428 },
429 _ => unreachable!("Unexpected PropertyDeclaration"),
430 }
431 })
432 }
433}
434
435#[derive(Clone, Debug, MallocSizeOf)]
440pub struct KeyframesAnimation {
441 pub steps: Vec<KeyframesStep>,
443 pub steps_with_range_name: Vec<KeyframesStep>,
451 pub properties_changed: PropertyDeclarationIdSet,
453 pub vendor_prefix: Option<VendorPrefix>,
455}
456
457fn get_animated_properties(
459 keyframes: &[Arc<Locked<Keyframe>>],
460 guard: &SharedRwLockReadGuard,
461) -> PropertyDeclarationIdSet {
462 let mut ret = PropertyDeclarationIdSet::default();
463 for keyframe in keyframes {
466 let keyframe = keyframe.read_with(&guard);
467 let block = keyframe.block.read_with(guard);
468 for declaration in block.normal_declaration_iter() {
475 let declaration_id = declaration.id();
476
477 if declaration_id == PropertyDeclarationId::Longhand(LonghandId::Display) {
478 continue;
479 }
480
481 if !declaration_id.is_animatable() {
482 continue;
483 }
484
485 ret.insert(declaration_id);
486 }
487 }
488
489 ret
490}
491
492impl KeyframesAnimation {
493 pub fn from_keyframes(
502 keyframes: &[Arc<Locked<Keyframe>>],
503 vendor_prefix: Option<VendorPrefix>,
504 guard: &SharedRwLockReadGuard,
505 ) -> Self {
506 let mut result = KeyframesAnimation {
507 steps: vec![],
508 steps_with_range_name: vec![],
509 properties_changed: PropertyDeclarationIdSet::default(),
510 vendor_prefix,
511 };
512
513 if keyframes.is_empty() {
514 return result;
515 }
516
517 result.properties_changed = get_animated_properties(keyframes, guard);
518 if result.properties_changed.is_empty() {
519 return result;
520 }
521
522 let mut steps = vec![];
524
525 for keyframe in keyframes {
526 let keyframe = keyframe.read_with(&guard);
527 for selector in keyframe.selector.0.iter() {
528 let step = KeyframesStep::new(
529 *selector,
530 KeyframesStepValue::Declarations {
531 block: keyframe.block.clone(),
532 },
533 guard,
534 );
535
536 if !selector.range_name.is_none() {
537 result.steps_with_range_name.push(step);
538 } else {
539 steps.push(step);
540 }
541 }
542 }
543
544 steps.sort_by_key(|step| step.start_offset.percentage);
548
549 if steps.is_empty() || steps[0].start_offset.percentage.0 != 0. {
559 steps.insert(
560 0,
561 KeyframesStep::new(
562 KeyframeSelector::from_percentage(KeyframePercentage::new(0.)),
563 KeyframesStepValue::ComputedValues,
564 guard,
565 ),
566 );
567 }
568
569 if steps.last().unwrap().start_offset.percentage.0 != 1. {
570 steps.push(KeyframesStep::new(
571 KeyframeSelector::from_percentage(KeyframePercentage::new(1.)),
572 KeyframesStepValue::ComputedValues,
573 guard,
574 ));
575 }
576
577 result.steps = steps;
578 result
579 }
580}
581
582struct KeyframeListParser<'a, 'b> {
591 context: &'a mut ParserContext<'b>,
592 shared_lock: &'a SharedRwLock,
593}
594
595pub fn parse_keyframe_list<'a>(
597 context: &mut ParserContext<'a>,
598 input: &mut Parser,
599 shared_lock: &SharedRwLock,
600) -> Vec<Arc<Locked<Keyframe>>> {
601 let mut parser = KeyframeListParser {
602 context,
603 shared_lock,
604 };
605 RuleBodyParser::new(input, &mut parser)
606 .filter_map(Result::ok)
607 .collect()
608}
609
610impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
611 type Prelude = ();
612 type AtRule = Arc<Locked<Keyframe>>;
613 type Error = StyleParseErrorKind<'i>;
614}
615
616impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
617 type Declaration = Arc<Locked<Keyframe>>;
618 type Error = StyleParseErrorKind<'i>;
619}
620
621impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
622 type Prelude = KeyframeSelectors;
623 type QualifiedRule = Arc<Locked<Keyframe>>;
624 type Error = StyleParseErrorKind<'i>;
625
626 fn parse_prelude<'t>(
627 &mut self,
628 input: &mut Parser<'i, 't>,
629 ) -> Result<Self::Prelude, ParseError<'i>> {
630 let start_position = input.position();
631 KeyframeSelectors::parse(input).map_err(|e| {
632 let location = e.location;
633 let error = ContextualParseError::InvalidKeyframeRule(
634 input.slice_from(start_position),
635 e.clone(),
636 );
637 self.context.log_css_error(location, error);
638 e
639 })
640 }
641
642 fn parse_block<'t>(
643 &mut self,
644 selector: Self::Prelude,
645 start: &ParserState,
646 input: &mut Parser<'i, 't>,
647 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
648 let block = self.context.nest_for_rule(CssRuleType::Keyframe, |p| {
649 parse_property_declaration_list(&p, input, &[])
650 });
651 Ok(Arc::new(self.shared_lock.wrap(Keyframe {
652 selector,
653 block: Arc::new(self.shared_lock.wrap(block)),
654 source_location: start.source_location(),
655 })))
656 }
657}
658
659impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
660 for KeyframeListParser<'a, 'b>
661{
662 fn parse_qualified(&self) -> bool {
663 true
664 }
665 fn parse_declarations(&self) -> bool {
666 false
667 }
668}