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