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(
84 &self,
85 lock: &SharedRwLock,
86 guard: &SharedRwLockReadGuard,
87 ) -> Self {
88 KeyframesRule {
89 name: self.name.clone(),
90 keyframes: self
91 .keyframes
92 .iter()
93 .map(|x| {
94 Arc::new(
95 lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard)),
96 )
97 })
98 .collect(),
99 vendor_prefix: self.vendor_prefix.clone(),
100 source_location: self.source_location.clone(),
101 }
102 }
103}
104
105#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
108pub struct KeyframePercentage(pub f32);
109
110impl ::std::cmp::Ord for KeyframePercentage {
111 #[inline]
112 fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
113 self.0.partial_cmp(&other.0).unwrap()
115 }
116}
117
118impl ::std::cmp::Eq for KeyframePercentage {}
119
120impl ToCss for KeyframePercentage {
121 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
122 where
123 W: Write,
124 {
125 serialize_percentage(self.0, dest)
126 }
127}
128
129impl KeyframePercentage {
130 #[inline]
132 pub fn new(value: f32) -> KeyframePercentage {
133 debug_assert!(value >= 0. && value <= 1.);
134 KeyframePercentage(value)
135 }
136
137 fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
138 let token = input.next()?.clone();
139 match token {
140 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") => {
141 Ok(KeyframePercentage::new(0.))
142 },
143 Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") => {
144 Ok(KeyframePercentage::new(1.))
145 },
146 Token::Percentage {
147 unit_value: percentage,
148 ..
149 } if percentage >= 0. && percentage <= 1. => Ok(KeyframePercentage::new(percentage)),
150 _ => Err(input.new_unexpected_token_error(token)),
151 }
152 }
153}
154
155#[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
158#[css(comma)]
159pub struct KeyframeSelector(#[css(iterable)] Vec<KeyframePercentage>);
160
161impl KeyframeSelector {
162 #[inline]
164 pub fn percentages(&self) -> &[KeyframePercentage] {
165 &self.0
166 }
167
168 pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
170 KeyframeSelector(percentages)
171 }
172
173 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
175 input
176 .parse_comma_separated(KeyframePercentage::parse)
177 .map(KeyframeSelector)
178 }
179}
180
181#[derive(Debug, ToShmem)]
183pub struct Keyframe {
184 pub selector: KeyframeSelector,
186
187 pub block: Arc<Locked<PropertyDeclarationBlock>>,
192
193 pub source_location: SourceLocation,
195}
196
197impl ToCssWithGuard for Keyframe {
198 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
199 self.selector.to_css(&mut CssWriter::new(dest))?;
200 dest.write_str(" { ")?;
201 self.block.read_with(guard).to_css(dest)?;
202 dest.write_str(" }")?;
203 Ok(())
204 }
205}
206
207impl Keyframe {
208 pub fn parse<'i>(
210 css: &'i str,
211 parent_stylesheet_contents: &StylesheetContents,
212 lock: &SharedRwLock,
213 ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
214 let url_data = parent_stylesheet_contents.url_data.read();
215 let namespaces = parent_stylesheet_contents.namespaces.read();
216 let mut context = ParserContext::new(
217 parent_stylesheet_contents.origin,
218 &url_data,
219 Some(CssRuleType::Keyframe),
220 ParsingMode::DEFAULT,
221 parent_stylesheet_contents.quirks_mode,
222 Cow::Borrowed(&*namespaces),
223 None,
224 None,
225 );
226 let mut input = ParserInput::new(css);
227 let mut input = Parser::new(&mut input);
228
229 let mut rule_parser = KeyframeListParser {
230 context: &mut context,
231 shared_lock: &lock,
232 };
233 parse_one_rule(&mut input, &mut rule_parser)
234 }
235}
236
237impl DeepCloneWithLock for Keyframe {
238 fn deep_clone_with_lock(
240 &self,
241 lock: &SharedRwLock,
242 guard: &SharedRwLockReadGuard,
243 ) -> Keyframe {
244 Keyframe {
245 selector: self.selector.clone(),
246 block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
247 source_location: self.source_location.clone(),
248 }
249 }
250}
251
252#[derive(Clone, Debug, MallocSizeOf)]
258pub enum KeyframesStepValue {
259 Declarations {
261 #[cfg_attr(
263 feature = "gecko",
264 ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
265 )]
266 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
267 block: Arc<Locked<PropertyDeclarationBlock>>,
268 },
269 ComputedValues,
272}
273
274#[derive(Clone, Debug, MallocSizeOf)]
276pub struct KeyframesStep {
277 pub start_percentage: KeyframePercentage,
279 pub value: KeyframesStepValue,
282 pub declared_timing_function: bool,
287 pub declared_composition: bool,
292}
293
294impl KeyframesStep {
295 #[inline]
296 fn new(
297 start_percentage: KeyframePercentage,
298 value: KeyframesStepValue,
299 guard: &SharedRwLockReadGuard,
300 ) -> Self {
301 let mut declared_timing_function = false;
302 let mut declared_composition = false;
303 if let KeyframesStepValue::Declarations { ref block } = value {
304 for prop_decl in block.read_with(guard).declarations().iter() {
305 match *prop_decl {
306 PropertyDeclaration::AnimationTimingFunction(..) => {
307 declared_timing_function = true;
308 },
309 PropertyDeclaration::AnimationComposition(..) => {
310 declared_composition = true;
311 },
312 _ => continue,
313 }
314 if declared_timing_function && declared_composition {
316 break;
317 }
318 }
319 }
320
321 KeyframesStep {
322 start_percentage,
323 value,
324 declared_timing_function,
325 declared_composition,
326 }
327 }
328
329 #[inline]
331 fn get_declared_property<'a>(
332 &'a self,
333 guard: &'a SharedRwLockReadGuard,
334 property: LonghandId,
335 ) -> Option<&'a PropertyDeclaration> {
336 match self.value {
337 KeyframesStepValue::Declarations { ref block } => {
338 let guard = block.read_with(guard);
339 let (declaration, _) = guard
340 .get(PropertyDeclarationId::Longhand(property))
341 .unwrap();
342 match *declaration {
343 PropertyDeclaration::CSSWideKeyword(..) => None,
344 PropertyDeclaration::WithVariables(..) => None,
346 _ => Some(declaration),
347 }
348 },
349 KeyframesStepValue::ComputedValues => {
350 panic!("Shouldn't happen to set this property in missing keyframes")
351 },
352 }
353 }
354
355 pub fn get_animation_timing_function(
358 &self,
359 guard: &SharedRwLockReadGuard,
360 ) -> Option<SpecifiedTimingFunction> {
361 if !self.declared_timing_function {
362 return None;
363 }
364
365 self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
366 .map(|decl| {
367 match *decl {
368 PropertyDeclaration::AnimationTimingFunction(ref value) => {
369 value.0[0].clone()
371 },
372 _ => unreachable!("Unexpected PropertyDeclaration"),
373 }
374 })
375 }
376
377 pub fn get_animation_composition(
379 &self,
380 guard: &SharedRwLockReadGuard,
381 ) -> Option<SpecifiedComposition> {
382 if !self.declared_composition {
383 return None;
384 }
385
386 self.get_declared_property(guard, LonghandId::AnimationComposition)
387 .map(|decl| {
388 match *decl {
389 PropertyDeclaration::AnimationComposition(ref value) => {
390 value.0[0].clone()
392 },
393 _ => unreachable!("Unexpected PropertyDeclaration"),
394 }
395 })
396 }
397}
398
399#[derive(Clone, Debug, MallocSizeOf)]
404pub struct KeyframesAnimation {
405 pub steps: Vec<KeyframesStep>,
407 pub properties_changed: PropertyDeclarationIdSet,
409 pub vendor_prefix: Option<VendorPrefix>,
411}
412
413fn get_animated_properties(
415 keyframes: &[Arc<Locked<Keyframe>>],
416 guard: &SharedRwLockReadGuard,
417) -> PropertyDeclarationIdSet {
418 let mut ret = PropertyDeclarationIdSet::default();
419 for keyframe in keyframes {
422 let keyframe = keyframe.read_with(&guard);
423 let block = keyframe.block.read_with(guard);
424 for declaration in block.normal_declaration_iter() {
431 let declaration_id = declaration.id();
432
433 if declaration_id == PropertyDeclarationId::Longhand(LonghandId::Display) {
434 continue;
435 }
436
437 if !declaration_id.is_animatable() {
438 continue;
439 }
440
441 ret.insert(declaration_id);
442 }
443 }
444
445 ret
446}
447
448impl KeyframesAnimation {
449 pub fn from_keyframes(
458 keyframes: &[Arc<Locked<Keyframe>>],
459 vendor_prefix: Option<VendorPrefix>,
460 guard: &SharedRwLockReadGuard,
461 ) -> Self {
462 let mut result = KeyframesAnimation {
463 steps: vec![],
464 properties_changed: PropertyDeclarationIdSet::default(),
465 vendor_prefix,
466 };
467
468 if keyframes.is_empty() {
469 return result;
470 }
471
472 result.properties_changed = get_animated_properties(keyframes, guard);
473 if result.properties_changed.is_empty() {
474 return result;
475 }
476
477 for keyframe in keyframes {
478 let keyframe = keyframe.read_with(&guard);
479 for percentage in keyframe.selector.0.iter() {
480 result.steps.push(KeyframesStep::new(
481 *percentage,
482 KeyframesStepValue::Declarations {
483 block: keyframe.block.clone(),
484 },
485 guard,
486 ));
487 }
488 }
489
490 result.steps.sort_by_key(|step| step.start_percentage);
492
493 if result.steps[0].start_percentage.0 != 0. {
495 result.steps.insert(
496 0,
497 KeyframesStep::new(
498 KeyframePercentage::new(0.),
499 KeyframesStepValue::ComputedValues,
500 guard,
501 ),
502 );
503 }
504
505 if result.steps.last().unwrap().start_percentage.0 != 1. {
506 result.steps.push(KeyframesStep::new(
507 KeyframePercentage::new(1.),
508 KeyframesStepValue::ComputedValues,
509 guard,
510 ));
511 }
512
513 result
514 }
515}
516
517struct KeyframeListParser<'a, 'b> {
526 context: &'a mut ParserContext<'b>,
527 shared_lock: &'a SharedRwLock,
528}
529
530pub fn parse_keyframe_list<'a>(
532 context: &mut ParserContext<'a>,
533 input: &mut Parser,
534 shared_lock: &SharedRwLock,
535) -> Vec<Arc<Locked<Keyframe>>> {
536 let mut parser = KeyframeListParser {
537 context,
538 shared_lock,
539 };
540 RuleBodyParser::new(input, &mut parser)
541 .filter_map(Result::ok)
542 .collect()
543}
544
545impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
546 type Prelude = ();
547 type AtRule = Arc<Locked<Keyframe>>;
548 type Error = StyleParseErrorKind<'i>;
549}
550
551impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
552 type Declaration = Arc<Locked<Keyframe>>;
553 type Error = StyleParseErrorKind<'i>;
554}
555
556impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
557 type Prelude = KeyframeSelector;
558 type QualifiedRule = Arc<Locked<Keyframe>>;
559 type Error = StyleParseErrorKind<'i>;
560
561 fn parse_prelude<'t>(
562 &mut self,
563 input: &mut Parser<'i, 't>,
564 ) -> Result<Self::Prelude, ParseError<'i>> {
565 let start_position = input.position();
566 KeyframeSelector::parse(input).map_err(|e| {
567 let location = e.location;
568 let error = ContextualParseError::InvalidKeyframeRule(
569 input.slice_from(start_position),
570 e.clone(),
571 );
572 self.context.log_css_error(location, error);
573 e
574 })
575 }
576
577 fn parse_block<'t>(
578 &mut self,
579 selector: Self::Prelude,
580 start: &ParserState,
581 input: &mut Parser<'i, 't>,
582 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
583 let block = self.context.nest_for_rule(CssRuleType::Keyframe, |p| {
584 parse_property_declaration_list(&p, input, &[])
585 });
586 Ok(Arc::new(self.shared_lock.wrap(Keyframe {
587 selector,
588 block: Arc::new(self.shared_lock.wrap(block)),
589 source_location: start.source_location(),
590 })))
591 }
592}
593
594impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
595 for KeyframeListParser<'a, 'b>
596{
597 fn parse_qualified(&self) -> bool {
598 true
599 }
600 fn parse_declarations(&self) -> bool {
601 false
602 }
603}