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::{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::{
31 CssStringWriter, CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss,
32};
33
34#[derive(Debug, ToShmem)]
38pub struct KeyframesRule {
39 pub name: KeyframesName,
41 pub keyframes: Vec<Arc<Locked<Keyframe>>>,
43 pub vendor_prefix: Option<VendorPrefix>,
45 pub source_location: SourceLocation,
47}
48
49impl ToCssWithGuard for KeyframesRule {
50 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
52 dest.write_str("@keyframes ")?;
53 self.name.to_css(&mut CssWriter::new(dest))?;
54 dest.write_str(" {")?;
55 let iter = self.keyframes.iter();
56 for lock in iter {
57 dest.write_str("\n")?;
58 let keyframe = lock.read_with(&guard);
59 keyframe.to_css(guard, dest)?;
60 }
61 dest.write_str("\n}")
62 }
63}
64
65impl KeyframesRule {
66 pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
72 let mut input = ParserInput::new(selector);
73 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
74 for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
75 if keyframe.read_with(guard).selector == selector {
76 return Some(i);
77 }
78 }
79 }
80 None
81 }
82}
83
84impl DeepCloneWithLock for KeyframesRule {
85 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
86 KeyframesRule {
87 name: self.name.clone(),
88 keyframes: self
89 .keyframes
90 .iter()
91 .map(|x| Arc::new(lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard))))
92 .collect(),
93 vendor_prefix: self.vendor_prefix.clone(),
94 source_location: self.source_location.clone(),
95 }
96 }
97}
98
99#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)]
102pub struct KeyframePercentage(pub f32);
103
104impl ::std::cmp::Ord for KeyframePercentage {
105 #[inline]
106 fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
107 self.0.partial_cmp(&other.0).unwrap()
109 }
110}
111
112impl ::std::cmp::Eq for KeyframePercentage {}
113
114impl ToCss for KeyframePercentage {
115 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
116 where
117 W: Write,
118 {
119 serialize_percentage(self.0, dest)
120 }
121}
122
123impl KeyframePercentage {
124 #[inline]
126 pub fn new(value: f32) -> KeyframePercentage {
127 debug_assert!(value >= 0. && value <= 1.);
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, Debug, Eq, PartialEq, ToCss, ToShmem)]
152#[css(comma)]
153pub struct KeyframeSelector(#[css(iterable)] Vec<KeyframePercentage>);
154
155impl KeyframeSelector {
156 #[inline]
158 pub fn percentages(&self) -> &[KeyframePercentage] {
159 &self.0
160 }
161
162 pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
164 KeyframeSelector(percentages)
165 }
166
167 pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
169 input
170 .parse_comma_separated(KeyframePercentage::parse)
171 .map(KeyframeSelector)
172 }
173}
174
175#[derive(Debug, ToShmem)]
177pub struct Keyframe {
178 pub selector: KeyframeSelector,
180
181 pub block: Arc<Locked<PropertyDeclarationBlock>>,
186
187 pub source_location: SourceLocation,
189}
190
191impl ToCssWithGuard for Keyframe {
192 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
193 self.selector.to_css(&mut CssWriter::new(dest))?;
194 dest.write_str(" { ")?;
195 self.block.read_with(guard).to_css(dest)?;
196 dest.write_str(" }")?;
197 Ok(())
198 }
199}
200
201impl Keyframe {
202 pub fn parse<'i>(
204 css: &'i str,
205 parent_stylesheet_contents: &StylesheetContents,
206 lock: &SharedRwLock,
207 ) -> Result<Arc<Locked<Self>>, ParseError<'i>> {
208 let url_data = &parent_stylesheet_contents.url_data;
209 let namespaces = &parent_stylesheet_contents.namespaces;
210 let mut context = ParserContext::new(
211 parent_stylesheet_contents.origin,
212 &url_data,
213 Some(CssRuleType::Keyframe),
214 ParsingMode::DEFAULT,
215 parent_stylesheet_contents.quirks_mode,
216 Cow::Borrowed(&*namespaces),
217 None,
218 None,
219 );
220 let mut input = ParserInput::new(css);
221 let mut input = Parser::new(&mut input);
222
223 let mut rule_parser = KeyframeListParser {
224 context: &mut context,
225 shared_lock: &lock,
226 };
227 parse_one_rule(&mut input, &mut rule_parser)
228 }
229}
230
231impl DeepCloneWithLock for Keyframe {
232 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Keyframe {
234 Keyframe {
235 selector: self.selector.clone(),
236 block: Arc::new(lock.wrap(self.block.read_with(guard).clone())),
237 source_location: self.source_location.clone(),
238 }
239 }
240}
241
242#[derive(Clone, Debug, MallocSizeOf)]
248pub enum KeyframesStepValue {
249 Declarations {
251 #[cfg_attr(
253 feature = "gecko",
254 ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile"
255 )]
256 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
257 block: Arc<Locked<PropertyDeclarationBlock>>,
258 },
259 ComputedValues,
262}
263
264#[derive(Clone, Debug, MallocSizeOf)]
266pub struct KeyframesStep {
267 pub start_percentage: KeyframePercentage,
269 pub value: KeyframesStepValue,
272 pub declared_timing_function: bool,
277 pub declared_composition: bool,
282}
283
284impl KeyframesStep {
285 #[inline]
286 fn new(
287 start_percentage: KeyframePercentage,
288 value: KeyframesStepValue,
289 guard: &SharedRwLockReadGuard,
290 ) -> Self {
291 let mut declared_timing_function = false;
292 let mut declared_composition = false;
293 if let KeyframesStepValue::Declarations { ref block } = value {
294 for prop_decl in block.read_with(guard).declarations().iter() {
295 match *prop_decl {
296 PropertyDeclaration::AnimationTimingFunction(..) => {
297 declared_timing_function = true;
298 },
299 PropertyDeclaration::AnimationComposition(..) => {
300 declared_composition = true;
301 },
302 _ => continue,
303 }
304 if declared_timing_function && declared_composition {
306 break;
307 }
308 }
309 }
310
311 KeyframesStep {
312 start_percentage,
313 value,
314 declared_timing_function,
315 declared_composition,
316 }
317 }
318
319 #[inline]
321 fn get_declared_property<'a>(
322 &'a self,
323 guard: &'a SharedRwLockReadGuard,
324 property: LonghandId,
325 ) -> Option<&'a PropertyDeclaration> {
326 match self.value {
327 KeyframesStepValue::Declarations { ref block } => {
328 let guard = block.read_with(guard);
329 let (declaration, _) = guard
330 .get(PropertyDeclarationId::Longhand(property))
331 .unwrap();
332 match *declaration {
333 PropertyDeclaration::CSSWideKeyword(..) => None,
334 PropertyDeclaration::WithVariables(..) => None,
336 _ => Some(declaration),
337 }
338 },
339 KeyframesStepValue::ComputedValues => {
340 panic!("Shouldn't happen to set this property in missing keyframes")
341 },
342 }
343 }
344
345 pub fn get_animation_timing_function(
348 &self,
349 guard: &SharedRwLockReadGuard,
350 ) -> Option<SpecifiedTimingFunction> {
351 if !self.declared_timing_function {
352 return None;
353 }
354
355 self.get_declared_property(guard, LonghandId::AnimationTimingFunction)
356 .map(|decl| {
357 match *decl {
358 PropertyDeclaration::AnimationTimingFunction(ref value) => {
359 value.0[0].clone()
361 },
362 _ => unreachable!("Unexpected PropertyDeclaration"),
363 }
364 })
365 }
366
367 pub fn get_animation_composition(
369 &self,
370 guard: &SharedRwLockReadGuard,
371 ) -> Option<SpecifiedComposition> {
372 if !self.declared_composition {
373 return None;
374 }
375
376 self.get_declared_property(guard, LonghandId::AnimationComposition)
377 .map(|decl| {
378 match *decl {
379 PropertyDeclaration::AnimationComposition(ref value) => {
380 value.0[0].clone()
382 },
383 _ => unreachable!("Unexpected PropertyDeclaration"),
384 }
385 })
386 }
387}
388
389#[derive(Clone, Debug, MallocSizeOf)]
394pub struct KeyframesAnimation {
395 pub steps: Vec<KeyframesStep>,
397 pub properties_changed: PropertyDeclarationIdSet,
399 pub vendor_prefix: Option<VendorPrefix>,
401}
402
403fn get_animated_properties(
405 keyframes: &[Arc<Locked<Keyframe>>],
406 guard: &SharedRwLockReadGuard,
407) -> PropertyDeclarationIdSet {
408 let mut ret = PropertyDeclarationIdSet::default();
409 for keyframe in keyframes {
412 let keyframe = keyframe.read_with(&guard);
413 let block = keyframe.block.read_with(guard);
414 for declaration in block.normal_declaration_iter() {
421 let declaration_id = declaration.id();
422
423 if declaration_id == PropertyDeclarationId::Longhand(LonghandId::Display) {
424 continue;
425 }
426
427 if !declaration_id.is_animatable() {
428 continue;
429 }
430
431 ret.insert(declaration_id);
432 }
433 }
434
435 ret
436}
437
438impl KeyframesAnimation {
439 pub fn from_keyframes(
448 keyframes: &[Arc<Locked<Keyframe>>],
449 vendor_prefix: Option<VendorPrefix>,
450 guard: &SharedRwLockReadGuard,
451 ) -> Self {
452 let mut result = KeyframesAnimation {
453 steps: vec![],
454 properties_changed: PropertyDeclarationIdSet::default(),
455 vendor_prefix,
456 };
457
458 if keyframes.is_empty() {
459 return result;
460 }
461
462 result.properties_changed = get_animated_properties(keyframes, guard);
463 if result.properties_changed.is_empty() {
464 return result;
465 }
466
467 for keyframe in keyframes {
468 let keyframe = keyframe.read_with(&guard);
469 for percentage in keyframe.selector.0.iter() {
470 result.steps.push(KeyframesStep::new(
471 *percentage,
472 KeyframesStepValue::Declarations {
473 block: keyframe.block.clone(),
474 },
475 guard,
476 ));
477 }
478 }
479
480 result.steps.sort_by_key(|step| step.start_percentage);
482
483 if result.steps[0].start_percentage.0 != 0. {
485 result.steps.insert(
486 0,
487 KeyframesStep::new(
488 KeyframePercentage::new(0.),
489 KeyframesStepValue::ComputedValues,
490 guard,
491 ),
492 );
493 }
494
495 if result.steps.last().unwrap().start_percentage.0 != 1. {
496 result.steps.push(KeyframesStep::new(
497 KeyframePercentage::new(1.),
498 KeyframesStepValue::ComputedValues,
499 guard,
500 ));
501 }
502
503 result
504 }
505}
506
507struct KeyframeListParser<'a, 'b> {
516 context: &'a mut ParserContext<'b>,
517 shared_lock: &'a SharedRwLock,
518}
519
520pub fn parse_keyframe_list<'a>(
522 context: &mut ParserContext<'a>,
523 input: &mut Parser,
524 shared_lock: &SharedRwLock,
525) -> Vec<Arc<Locked<Keyframe>>> {
526 let mut parser = KeyframeListParser {
527 context,
528 shared_lock,
529 };
530 RuleBodyParser::new(input, &mut parser)
531 .filter_map(Result::ok)
532 .collect()
533}
534
535impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
536 type Prelude = ();
537 type AtRule = Arc<Locked<Keyframe>>;
538 type Error = StyleParseErrorKind<'i>;
539}
540
541impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
542 type Declaration = Arc<Locked<Keyframe>>;
543 type Error = StyleParseErrorKind<'i>;
544}
545
546impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
547 type Prelude = KeyframeSelector;
548 type QualifiedRule = Arc<Locked<Keyframe>>;
549 type Error = StyleParseErrorKind<'i>;
550
551 fn parse_prelude<'t>(
552 &mut self,
553 input: &mut Parser<'i, 't>,
554 ) -> Result<Self::Prelude, ParseError<'i>> {
555 let start_position = input.position();
556 KeyframeSelector::parse(input).map_err(|e| {
557 let location = e.location;
558 let error = ContextualParseError::InvalidKeyframeRule(
559 input.slice_from(start_position),
560 e.clone(),
561 );
562 self.context.log_css_error(location, error);
563 e
564 })
565 }
566
567 fn parse_block<'t>(
568 &mut self,
569 selector: Self::Prelude,
570 start: &ParserState,
571 input: &mut Parser<'i, 't>,
572 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
573 let block = self.context.nest_for_rule(CssRuleType::Keyframe, |p| {
574 parse_property_declaration_list(&p, input, &[])
575 });
576 Ok(Arc::new(self.shared_lock.wrap(Keyframe {
577 selector,
578 block: Arc::new(self.shared_lock.wrap(block)),
579 source_location: start.source_location(),
580 })))
581 }
582}
583
584impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>>
585 for KeyframeListParser<'a, 'b>
586{
587 fn parse_qualified(&self) -> bool {
588 true
589 }
590 fn parse_declarations(&self) -> bool {
591 false
592 }
593}