1use crate::error_reporting::ContextualParseError;
8use crate::parser::ParserContext;
9use crate::properties::{
10 longhands::{
11 animation_composition::single_value::SpecifiedValue as SpecifiedComposition,
12 transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction,
13 },
14 parse_property_declaration_list, LonghandId, PropertyDeclaration, PropertyDeclarationBlock,
15 PropertyDeclarationId, PropertyDeclarationIdSet,
16};
17use crate::shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard};
18use crate::shared_lock::{Locked, ToCssWithGuard};
19use crate::str::CssStringWriter;
20use crate::stylesheets::rule_parser::VendorPrefix;
21use crate::stylesheets::{CssRuleType, StylesheetContents};
22use crate::values::{serialize_percentage, KeyframesName};
23use cssparser::{
24 parse_one_rule, AtRuleParser, DeclarationParser, Parser, ParserInput, ParserState,
25 QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, Token,
26};
27use servo_arc::Arc;
28use std::borrow::Cow;
29use std::fmt::{self, Write};
30use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
31
32#[derive(Debug, ToShmem)]
36pub struct KeyframesRule {
37 pub name: KeyframesName,
39 pub keyframes: Vec<Arc<Locked<Keyframe>>>,
41 pub vendor_prefix: Option<VendorPrefix>,
43 pub source_location: SourceLocation,
45}
46
47impl ToCssWithGuard for KeyframesRule {
48 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
50 dest.write_str("@keyframes ")?;
51 self.name.to_css(&mut CssWriter::new(dest))?;
52 dest.write_str(" {")?;
53 let iter = self.keyframes.iter();
54 for lock in iter {
55 dest.write_str("\n")?;
56 let keyframe = lock.read_with(&guard);
57 keyframe.to_css(guard, dest)?;
58 }
59 dest.write_str("\n}")
60 }
61}
62
63impl KeyframesRule {
64 pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
70 let mut input = ParserInput::new(selector);
71 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
72 for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
73 if keyframe.read_with(guard).selector == selector {
74 return Some(i);
75 }
76 }
77 }
78 None
79 }
80}
81
82impl DeepCloneWithLock for KeyframesRule {
83 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
84 KeyframesRule {
85 name: self.name.clone(),
86 keyframes: self
87 .keyframes
88 .iter()
89 .map(|x| Arc::new(lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard))))
90 .collect(),
91 vendor_prefix: self.vendor_prefix.clone(),
92 source_location: self.source_location.clone(),
93 }
94 }
95}
96
97#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
100pub struct KeyframePercentage(pub f32);
101
102impl ::std::cmp::Ord for KeyframePercentage {
103 #[inline]
104 fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
105 self.0.partial_cmp(&other.0).unwrap()
107 }
108}
109
110impl ::std::cmp::Eq for KeyframePercentage {}
111
112impl ToCss for KeyframePercentage {
113 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
114 where
115 W: Write,
116 {
117 serialize_percentage(self.0, dest)
118 }
119}
120
121impl KeyframePercentage {
122 #[inline]
124 pub fn new(value: f32) -> KeyframePercentage {
125 debug_assert!(value >= 0. && value <= 1.);
126 KeyframePercentage(value)
127 }
128
129 fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
130 let token = input.next()?.clone();
131 match token {
132 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
133 Ok(KeyframePercentage::new(0.))
134 },
135 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
136 Ok(KeyframePercentage::new(1.))
137 },
138 Token::Percentage {
139 unit_value: percentage,
140 ..
141 } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
142 _ => Err(input.new_unexpected_token_error(token)),
143 }
144 }
145}
146
147#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
150#[css(comma)]
151pub struct KeyframeSelector(#[css(iterable)] Vec<KeyframePercentage>);
152
153impl KeyframeSelector {
154 #[inline]
156 pub fn percentages(&self) -> &[KeyframePercentage] {
157 &self.0
158 }
159
160 pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
162 KeyframeSelector(percentages)
163 }
164
165 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
167 input
168 .parse_comma_separated(KeyframePercentage::parse)
169 .map(KeyframeSelector)
170 }
171}
172
173#[derive(Debug, ToShmem)]
175pub struct Keyframe {
176 pub selector: KeyframeSelector,
178
179 pub block: Arc<Locked<PropertyDeclarationBlock>>,
184
185 pub source_location: SourceLocation,
187}
188
189impl ToCssWithGuard for Keyframe {
190 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
191 self.selector.to_css(&mut CssWriter::new(dest))?;
192 dest.write_str(" { ")?;
193 self.block.read_with(guard).to_css(dest)?;
194 dest.write_str(" }")?;
195 Ok(())
196 }
197}
198
199impl Keyframe {
200 pub fn parse<'i>(
202 css: &'i str,
203 parent_stylesheet_contents: &StylesheetContents,
204 lock: &SharedRwLock,
205 ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
206 let url_data = parent_stylesheet_contents.url_data.read();
207 let namespaces = parent_stylesheet_contents.namespaces.read();
208 let mut context = ParserContext::new(
209 parent_stylesheet_contents.origin,
210 &url_data,
211 Some(CssRuleType::Keyframe),
212 ParsingMode::DEFAULT,
213 parent_stylesheet_contents.quirks_mode,
214 Cow::Borrowed(&*namespaces),
215 None,
216 None,
217 );
218 let mut input = ParserInput::new(css);
219 let mut input = Parser::new(&mut input);
220
221 let mut rule_parser = KeyframeListParser {
222 context: &mut context,
223 shared_lock: &lock,
224 };
225 parse_one_rule(&mut input, &mut rule_parser)
226 }
227}
228
229impl DeepCloneWithLock for Keyframe {
230 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Keyframe {
232 Keyframe {
233 selector: self.selector.clone(),
234 block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
235 source_location: self.source_location.clone(),
236 }
237 }
238}
239
240#[derive(Clone, Debug, MallocSizeOf)]
246pub enum KeyframesStepValue {
247 Declarations {
249 #[cfg_attr(
251 feature = "gecko",
252 ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
253 )]
254 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
255 block: Arc<Locked<PropertyDeclarationBlock>>,
256 },
257 ComputedValues,
260}
261
262#[derive(Clone, Debug, MallocSizeOf)]
264pub struct KeyframesStep {
265 pub start_percentage: KeyframePercentage,
267 pub value: KeyframesStepValue,
270 pub declared_timing_function: bool,
275 pub declared_composition: bool,
280}
281
282impl KeyframesStep {
283 #[inline]
284 fn new(
285 start_percentage: KeyframePercentage,
286 value: KeyframesStepValue,
287 guard: &SharedRwLockReadGuard,
288 ) -> Self {
289 let mut declared_timing_function = false;
290 let mut declared_composition = false;
291 if let KeyframesStepValue::Declarations { ref block } = value {
292 for prop_decl in block.read_with(guard).declarations().iter() {
293 match *prop_decl {
294 PropertyDeclaration::AnimationTimingFunction(..) => {
295 declared_timing_function = true;
296 },
297 PropertyDeclaration::AnimationComposition(..) => {
298 declared_composition = true;
299 },
300 _ => continue,
301 }
302 if declared_timing_function && declared_composition {
304 break;
305 }
306 }
307 }
308
309 KeyframesStep {
310 start_percentage,
311 value,
312 declared_timing_function,
313 declared_composition,
314 }
315 }
316
317 #[inline]
319 fn get_declared_property<'a>(
320 &'a self,
321 guard: &'a SharedRwLockReadGuard,
322 property: LonghandId,
323 ) -> Option<&'a PropertyDeclaration> {
324 match self.value {
325 KeyframesStepValue::Declarations { ref block } => {
326 let guard = block.read_with(guard);
327 let (declaration, _) = guard
328 .get(PropertyDeclarationId::Longhand(property))
329 .unwrap();
330 match *declaration {
331 PropertyDeclaration::CSSWideKeyword(..) => None,
332 PropertyDeclaration::WithVariables(..) => None,
334 _ => Some(declaration),
335 }
336 },
337 KeyframesStepValue::ComputedValues => {
338 panic!("Shouldn't happen to set this property in missing keyframes")
339 },
340 }
341 }
342
343 pub fn get_animation_timing_function(
346 &self,
347 guard: &SharedRwLockReadGuard,
348 ) -> Option<SpecifiedTimingFunction> {
349 if !self.declared_timing_function {
350 return None;
351 }
352
353 self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
354 .map(|decl| {
355 match *decl {
356 PropertyDeclaration::AnimationTimingFunction(ref value) => {
357 value.0[0].clone()
359 },
360 _ => unreachable!("Unexpected PropertyDeclaration"),
361 }
362 })
363 }
364
365 pub fn get_animation_composition(
367 &self,
368 guard: &SharedRwLockReadGuard,
369 ) -> Option<SpecifiedComposition> {
370 if !self.declared_composition {
371 return None;
372 }
373
374 self.get_declared_property(guard, LonghandId::AnimationComposition)
375 .map(|decl| {
376 match *decl {
377 PropertyDeclaration::AnimationComposition(ref value) => {
378 value.0[0].clone()
380 },
381 _ => unreachable!("Unexpected PropertyDeclaration"),
382 }
383 })
384 }
385}
386
387#[derive(Clone, Debug, MallocSizeOf)]
392pub struct KeyframesAnimation {
393 pub steps: Vec<KeyframesStep>,
395 pub properties_changed: PropertyDeclarationIdSet,
397 pub vendor_prefix: Option<VendorPrefix>,
399}
400
401fn get_animated_properties(
403 keyframes: &[Arc<Locked<Keyframe>>],
404 guard: &SharedRwLockReadGuard,
405) -> PropertyDeclarationIdSet {
406 let mut ret = PropertyDeclarationIdSet::default();
407 for keyframe in keyframes {
410 let keyframe = keyframe.read_with(&guard);
411 let block = keyframe.block.read_with(guard);
412 for declaration in block.normal_declaration_iter() {
419 let declaration_id = declaration.id();
420
421 if declaration_id == PropertyDeclarationId::Longhand(LonghandId::Display) {
422 continue;
423 }
424
425 if !declaration_id.is_animatable() {
426 continue;
427 }
428
429 ret.insert(declaration_id);
430 }
431 }
432
433 ret
434}
435
436impl KeyframesAnimation {
437 pub fn from_keyframes(
446 keyframes: &[Arc<Locked<Keyframe>>],
447 vendor_prefix: Option<VendorPrefix>,
448 guard: &SharedRwLockReadGuard,
449 ) -> Self {
450 let mut result = KeyframesAnimation {
451 steps: vec![],
452 properties_changed: PropertyDeclarationIdSet::default(),
453 vendor_prefix,
454 };
455
456 if keyframes.is_empty() {
457 return result;
458 }
459
460 result.properties_changed = get_animated_properties(keyframes, guard);
461 if result.properties_changed.is_empty() {
462 return result;
463 }
464
465 for keyframe in keyframes {
466 let keyframe = keyframe.read_with(&guard);
467 for percentage in keyframe.selector.0.iter() {
468 result.steps.push(KeyframesStep::new(
469 *percentage,
470 KeyframesStepValue::Declarations {
471 block: keyframe.block.clone(),
472 },
473 guard,
474 ));
475 }
476 }
477
478 result.steps.sort_by_key(|step| step.start_percentage);
480
481 if result.steps[0].start_percentage.0 != 0. {
483 result.steps.insert(
484 0,
485 KeyframesStep::new(
486 KeyframePercentage::new(0.),
487 KeyframesStepValue::ComputedValues,
488 guard,
489 ),
490 );
491 }
492
493 if result.steps.last().unwrap().start_percentage.0 != 1. {
494 result.steps.push(KeyframesStep::new(
495 KeyframePercentage::new(1.),
496 KeyframesStepValue::ComputedValues,
497 guard,
498 ));
499 }
500
501 result
502 }
503}
504
505struct KeyframeListParser<'a, 'b> {
514 context: &'a mut ParserContext<'b>,
515 shared_lock: &'a SharedRwLock,
516}
517
518pub fn parse_keyframe_list<'a>(
520 context: &mut ParserContext<'a>,
521 input: &mut Parser,
522 shared_lock: &SharedRwLock,
523) -> Vec<Arc<Locked<Keyframe>>> {
524 let mut parser = KeyframeListParser {
525 context,
526 shared_lock,
527 };
528 RuleBodyParser::new(input, &mut parser)
529 .filter_map(Result::ok)
530 .collect()
531}
532
533impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
534 type Prelude = ();
535 type AtRule = Arc<Locked<Keyframe>>;
536 type Error = StyleParseErrorKind<'i>;
537}
538
539impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
540 type Declaration = Arc<Locked<Keyframe>>;
541 type Error = StyleParseErrorKind<'i>;
542}
543
544impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
545 type Prelude = KeyframeSelector;
546 type QualifiedRule = Arc<Locked<Keyframe>>;
547 type Error = StyleParseErrorKind<'i>;
548
549 fn parse_prelude<'t>(
550 &mut self,
551 input: &mut Parser<'i, 't>,
552 ) -> Result<Self::Prelude, ParseError<'i>> {
553 let start_position = input.position();
554 KeyframeSelector::parse(input).map_err(|e| {
555 let location = e.location;
556 let error = ContextualParseError::InvalidKeyframeRule(
557 input.slice_from(start_position),
558 e.clone(),
559 );
560 self.context.log_css_error(location, error);
561 e
562 })
563 }
564
565 fn parse_block<'t>(
566 &mut self,
567 selector: Self::Prelude,
568 start: &ParserState,
569 input: &mut Parser<'i, 't>,
570 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
571 let block = self.context.nest_for_rule(CssRuleType::Keyframe, |p| {
572 parse_property_declaration_list(&p, input, &[])
573 });
574 Ok(Arc::new(self.shared_lock.wrap(Keyframe {
575 selector,
576 block: Arc::new(self.shared_lock.wrap(block)),
577 source_location: start.source_location(),
578 })))
579 }
580}
581
582impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
583 for KeyframeListParser<'a, 'b>
584{
585 fn parse_qualified(&self) -> bool {
586 true
587 }
588 fn parse_declarations(&self) -> bool {
589 false
590 }
591}