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 debug_assert!(value >= 0. && value <= 1.);
129 KeyframePercentage(value)
130 }
131
132 fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
133 let token = input.next()?.clone();
134 match token {
135 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
136 Ok(KeyframePercentage::new(0.))
137 },
138 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
139 Ok(KeyframePercentage::new(1.))
140 },
141 Token::Percentage {
142 unit_value: percentage,
143 ..
144 } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
145 _ => Err(input.new_unexpected_token_error(token)),
146 }
147 }
148}
149
150#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss, ToShmem)]
155pub struct KeyframeSelector {
156 range_name: TimelineRangeName,
160 percentage: KeyframePercentage,
163}
164
165impl KeyframeSelector {
166 fn new_for_unit_testing(percentage: KeyframePercentage) -> Self {
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 {
179 range_name: TimelineRangeName::None,
180 percentage,
181 });
182 }
183
184 if !static_prefs::pref!("layout.css.scroll-driven-animations.enabled") {
186 let location = input.current_source_location();
187 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
188 }
189
190 Ok(Self {
193 range_name: TimelineRangeName::parse(input)?,
194 percentage: KeyframePercentage::new(input.expect_percentage()?),
195 })
196 }
197}
198
199#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
201#[css(comma)]
202pub struct KeyframeSelectors(#[css(iterable)] Vec<KeyframeSelector>);
203
204impl KeyframeSelectors {
205 pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelectors {
207 KeyframeSelectors(
208 percentages
209 .into_iter()
210 .map(KeyframeSelector::new_for_unit_testing)
211 .collect(),
212 )
213 }
214
215 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
217 input
218 .parse_comma_separated(KeyframeSelector::parse)
219 .map(KeyframeSelectors)
220 }
221}
222
223#[derive(Debug, ToShmem)]
225pub struct Keyframe {
226 pub selector: KeyframeSelectors,
228
229 pub block: Arc<Locked<PropertyDeclarationBlock>>,
234
235 pub source_location: SourceLocation,
237}
238
239impl ToCssWithGuard for Keyframe {
240 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
241 self.selector.to_css(&mut CssWriter::new(dest))?;
242 dest.write_str(" { ")?;
243 self.block.read_with(guard).to_css(dest)?;
244 dest.write_str(" }")?;
245 Ok(())
246 }
247}
248
249impl Keyframe {
250 pub fn parse<'i>(
252 css: &'i str,
253 parent_stylesheet_contents: &StylesheetContents,
254 lock: &SharedRwLock,
255 ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
256 let url_data = &parent_stylesheet_contents.url_data;
257 let namespaces = &parent_stylesheet_contents.namespaces;
258 let mut context = ParserContext::new(
259 parent_stylesheet_contents.origin,
260 &url_data,
261 Some(CssRuleType::Keyframe),
262 ParsingMode::DEFAULT,
263 parent_stylesheet_contents.quirks_mode,
264 Cow::Borrowed(&*namespaces),
265 None,
266 None,
267 Default::default(),
268 );
269 let mut input = ParserInput::new(css);
270 let mut input = Parser::new(&mut input);
271
272 let mut rule_parser = KeyframeListParser {
273 context: &mut context,
274 shared_lock: &lock,
275 };
276 parse_one_rule(&mut input, &mut rule_parser)
277 }
278}
279
280impl DeepCloneWithLock for Keyframe {
281 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Keyframe {
283 Keyframe {
284 selector: self.selector.clone(),
285 block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
286 source_location: self.source_location.clone(),
287 }
288 }
289}
290
291#[derive(Clone, Debug, MallocSizeOf)]
297pub enum KeyframesStepValue {
298 Declarations {
300 #[cfg_attr(
302 feature = "gecko",
303 ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
304 )]
305 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
306 block: Arc<Locked<PropertyDeclarationBlock>>,
307 },
308 ComputedValues,
311}
312
313#[derive(Clone, Debug, MallocSizeOf)]
315pub struct KeyframesStep {
316 pub start_percentage: KeyframePercentage,
318 pub value: KeyframesStepValue,
321 pub declared_timing_function: bool,
326 pub declared_composition: bool,
331}
332
333impl KeyframesStep {
334 #[inline]
335 fn new(
336 start_percentage: KeyframePercentage,
337 value: KeyframesStepValue,
338 guard: &SharedRwLockReadGuard,
339 ) -> Self {
340 let mut declared_timing_function = false;
341 let mut declared_composition = false;
342 if let KeyframesStepValue::Declarations { ref block } = value {
343 for prop_decl in block.read_with(guard).declarations().iter() {
344 match *prop_decl {
345 PropertyDeclaration::AnimationTimingFunction(..) => {
346 declared_timing_function = true;
347 },
348 PropertyDeclaration::AnimationComposition(..) => {
349 declared_composition = true;
350 },
351 _ => continue,
352 }
353 if declared_timing_function && declared_composition {
355 break;
356 }
357 }
358 }
359
360 KeyframesStep {
361 start_percentage,
362 value,
363 declared_timing_function,
364 declared_composition,
365 }
366 }
367
368 #[inline]
370 fn get_declared_property<'a>(
371 &'a self,
372 guard: &'a SharedRwLockReadGuard,
373 property: LonghandId,
374 ) -> Option<&'a PropertyDeclaration> {
375 match self.value {
376 KeyframesStepValue::Declarations { ref block } => {
377 let guard = block.read_with(guard);
378 let (declaration, _) = guard
379 .get(PropertyDeclarationId::Longhand(property))
380 .unwrap();
381 match *declaration {
382 PropertyDeclaration::CSSWideKeyword(..) => None,
383 PropertyDeclaration::WithVariables(..) => None,
385 _ => Some(declaration),
386 }
387 },
388 KeyframesStepValue::ComputedValues => {
389 panic!("Shouldn't happen to set this property in missing keyframes")
390 },
391 }
392 }
393
394 pub fn get_animation_timing_function(
397 &self,
398 guard: &SharedRwLockReadGuard,
399 ) -> Option<SpecifiedTimingFunction> {
400 if !self.declared_timing_function {
401 return None;
402 }
403
404 self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
405 .map(|decl| {
406 match *decl {
407 PropertyDeclaration::AnimationTimingFunction(ref value) => {
408 value.0[0].clone()
410 },
411 _ => unreachable!("Unexpected PropertyDeclaration"),
412 }
413 })
414 }
415
416 pub fn get_animation_composition(
418 &self,
419 guard: &SharedRwLockReadGuard,
420 ) -> Option<SpecifiedComposition> {
421 if !self.declared_composition {
422 return None;
423 }
424
425 self.get_declared_property(guard, LonghandId::AnimationComposition)
426 .map(|decl| {
427 match *decl {
428 PropertyDeclaration::AnimationComposition(ref value) => {
429 value.0[0].clone()
431 },
432 _ => unreachable!("Unexpected PropertyDeclaration"),
433 }
434 })
435 }
436}
437
438#[derive(Clone, Debug, MallocSizeOf)]
443pub struct KeyframesAnimation {
444 pub steps: Vec<KeyframesStep>,
446 pub properties_changed: PropertyDeclarationIdSet,
448 pub vendor_prefix: Option<VendorPrefix>,
450}
451
452fn get_animated_properties(
454 keyframes: &[Arc<Locked<Keyframe>>],
455 guard: &SharedRwLockReadGuard,
456) -> PropertyDeclarationIdSet {
457 let mut ret = PropertyDeclarationIdSet::default();
458 for keyframe in keyframes {
461 let keyframe = keyframe.read_with(&guard);
462 let block = keyframe.block.read_with(guard);
463 for declaration in block.normal_declaration_iter() {
470 let declaration_id = declaration.id();
471
472 if declaration_id == PropertyDeclarationId::Longhand(LonghandId::Display) {
473 continue;
474 }
475
476 if !declaration_id.is_animatable() {
477 continue;
478 }
479
480 ret.insert(declaration_id);
481 }
482 }
483
484 ret
485}
486
487impl KeyframesAnimation {
488 pub fn from_keyframes(
497 keyframes: &[Arc<Locked<Keyframe>>],
498 vendor_prefix: Option<VendorPrefix>,
499 guard: &SharedRwLockReadGuard,
500 ) -> Self {
501 let mut result = KeyframesAnimation {
502 steps: vec![],
503 properties_changed: PropertyDeclarationIdSet::default(),
504 vendor_prefix,
505 };
506
507 if keyframes.is_empty() {
508 return result;
509 }
510
511 result.properties_changed = get_animated_properties(keyframes, guard);
512 if result.properties_changed.is_empty() {
513 return result;
514 }
515
516 for keyframe in keyframes {
517 let keyframe = keyframe.read_with(&guard);
518 for selector in keyframe.selector.0.iter() {
519 if !selector.range_name.is_none() {
521 continue;
522 }
523 result.steps.push(KeyframesStep::new(
524 selector.percentage,
525 KeyframesStepValue::Declarations {
526 block: keyframe.block.clone(),
527 },
528 guard,
529 ));
530 }
531 }
532
533 if result.steps.is_empty() {
538 result.properties_changed = PropertyDeclarationIdSet::default();
540 return result;
541 }
542
543 result.steps.sort_by_key(|step| step.start_percentage);
545
546 if result.steps[0].start_percentage.0 != 0. {
548 result.steps.insert(
549 0,
550 KeyframesStep::new(
551 KeyframePercentage::new(0.),
552 KeyframesStepValue::ComputedValues,
553 guard,
554 ),
555 );
556 }
557
558 if result.steps.last().unwrap().start_percentage.0 != 1. {
559 result.steps.push(KeyframesStep::new(
560 KeyframePercentage::new(1.),
561 KeyframesStepValue::ComputedValues,
562 guard,
563 ));
564 }
565
566 result
567 }
568}
569
570struct KeyframeListParser<'a, 'b> {
579 context: &'a mut ParserContext<'b>,
580 shared_lock: &'a SharedRwLock,
581}
582
583pub fn parse_keyframe_list<'a>(
585 context: &mut ParserContext<'a>,
586 input: &mut Parser,
587 shared_lock: &SharedRwLock,
588) -> Vec<Arc<Locked<Keyframe>>> {
589 let mut parser = KeyframeListParser {
590 context,
591 shared_lock,
592 };
593 RuleBodyParser::new(input, &mut parser)
594 .filter_map(Result::ok)
595 .collect()
596}
597
598impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
599 type Prelude = ();
600 type AtRule = Arc<Locked<Keyframe>>;
601 type Error = StyleParseErrorKind<'i>;
602}
603
604impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
605 type Declaration = Arc<Locked<Keyframe>>;
606 type Error = StyleParseErrorKind<'i>;
607}
608
609impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
610 type Prelude = KeyframeSelectors;
611 type QualifiedRule = Arc<Locked<Keyframe>>;
612 type Error = StyleParseErrorKind<'i>;
613
614 fn parse_prelude<'t>(
615 &mut self,
616 input: &mut Parser<'i, 't>,
617 ) -> Result<Self::Prelude, ParseError<'i>> {
618 let start_position = input.position();
619 KeyframeSelectors::parse(input).map_err(|e| {
620 let location = e.location;
621 let error = ContextualParseError::InvalidKeyframeRule(
622 input.slice_from(start_position),
623 e.clone(),
624 );
625 self.context.log_css_error(location, error);
626 e
627 })
628 }
629
630 fn parse_block<'t>(
631 &mut self,
632 selector: Self::Prelude,
633 start: &ParserState,
634 input: &mut Parser<'i, 't>,
635 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
636 let block = self.context.nest_for_rule(CssRuleType::Keyframe, |p| {
637 parse_property_declaration_list(&p, input, &[])
638 });
639 Ok(Arc::new(self.shared_lock.wrap(Keyframe {
640 selector,
641 block: Arc::new(self.shared_lock.wrap(block)),
642 source_location: start.source_location(),
643 })))
644 }
645}
646
647impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
648 for KeyframeListParser<'a, 'b>
649{
650 fn parse_qualified(&self) -> bool {
651 true
652 }
653 fn parse_declarations(&self) -> bool {
654 false
655 }
656}