1use std::fmt::{self, Write};
8
9use super::{
10 registry::PropertyRegistrationData,
11 syntax::{
12 data_type::DataType, Component as SyntaxComponent, ComponentName, Descriptor, Multiplier,
13 },
14};
15use crate::custom_properties::ComputedValue as ComputedPropertyValue;
16use crate::derives::*;
17use crate::parser::{Parse, ParserContext};
18use crate::properties;
19use crate::properties::{CSSWideKeyword, CustomDeclarationValue};
20use crate::properties_and_values::rule::Inherits;
21use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
22use crate::values::{
23 animated::{self, Animate, Procedure},
24 computed::{self, ToComputedValue},
25 specified, CustomIdent,
26};
27use cssparser::{BasicParseErrorKind, ParseErrorKind, Parser as CSSParser, TokenSerializationType};
28use selectors::matching::QuirksMode;
29use servo_arc::Arc;
30use smallvec::SmallVec;
31use style_traits::{
32 owned_str::OwnedStr, CssWriter, ParseError as StyleParseError, ParsingMode,
33 PropertySyntaxParseError, StyleParseErrorKind, ToCss,
34};
35
36pub type ComputedValueComponent = GenericValueComponent<
38 computed::Length,
39 computed::Number,
40 computed::Percentage,
41 computed::LengthPercentage,
42 computed::Color,
43 computed::Image,
44 computed::url::ComputedUrl,
45 computed::Integer,
46 computed::Angle,
47 computed::Time,
48 computed::Resolution,
49 computed::Transform,
50>;
51
52pub type SpecifiedValueComponent = GenericValueComponent<
54 specified::Length,
55 specified::Number,
56 specified::Percentage,
57 specified::LengthPercentage,
58 specified::Color,
59 specified::Image,
60 specified::url::SpecifiedUrl,
61 specified::Integer,
62 specified::Angle,
63 specified::Time,
64 specified::Resolution,
65 specified::Transform,
66>;
67
68impl<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>
69 GenericValueComponent<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>
70{
71 fn serialization_types(&self) -> (TokenSerializationType, TokenSerializationType) {
72 let first_token_type = match self {
73 Self::Length(_) | Self::Angle(_) | Self::Time(_) | Self::Resolution(_) => {
74 TokenSerializationType::Dimension
75 },
76 Self::Number(_) | Self::Integer(_) => TokenSerializationType::Number,
77 Self::Percentage(_) | Self::LengthPercentage(_) => TokenSerializationType::Percentage,
78 Self::Color(_)
79 | Self::Image(_)
80 | Self::Url(_)
81 | Self::TransformFunction(_)
82 | Self::TransformList(_) => TokenSerializationType::Function,
83 Self::CustomIdent(_) => TokenSerializationType::Ident,
84 Self::String(_) => TokenSerializationType::Other,
85 };
86 let last_token_type = if first_token_type == TokenSerializationType::Function {
87 TokenSerializationType::Other
88 } else {
89 first_token_type
90 };
91 (first_token_type, last_token_type)
92 }
93}
94
95#[derive(
97 Animate, Clone, ToCss, ToComputedValue, ToResolvedValue, Debug, MallocSizeOf, PartialEq, ToShmem,
98)]
99#[animation(no_bound(Image, Url))]
100pub enum GenericValueComponent<
101 Length,
102 Number,
103 Percentage,
104 LengthPercentage,
105 Color,
106 Image,
107 Url,
108 Integer,
109 Angle,
110 Time,
111 Resolution,
112 TransformFunction,
113> {
114 Length(Length),
116 Number(Number),
118 Percentage(Percentage),
120 LengthPercentage(LengthPercentage),
122 Color(Color),
124 #[animation(error)]
126 Image(Image),
127 #[animation(error)]
129 Url(Url),
130 Integer(Integer),
132 Angle(Angle),
134 Time(Time),
136 Resolution(Resolution),
138 TransformFunction(TransformFunction),
141 #[animation(error)]
143 CustomIdent(CustomIdent),
144 TransformList(ComponentList<Self>),
147 #[animation(error)]
149 String(OwnedStr),
150}
151
152#[derive(Clone, ToComputedValue, ToResolvedValue, Debug, MallocSizeOf, PartialEq, ToShmem)]
154pub struct ComponentList<Component> {
155 pub multiplier: Multiplier,
157 pub components: crate::OwnedSlice<Component>,
159}
160
161impl<Component: Animate> Animate for ComponentList<Component> {
162 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
163 if self.multiplier != other.multiplier {
164 return Err(());
165 }
166 let components = animated::lists::by_computed_value::animate(
167 &self.components,
168 &other.components,
169 procedure,
170 )?;
171 Ok(Self {
172 multiplier: self.multiplier,
173 components,
174 })
175 }
176}
177
178impl<Component: ToCss> ToCss for ComponentList<Component> {
179 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
180 where
181 W: Write,
182 {
183 let mut iter = self.components.iter();
184 let Some(first) = iter.next() else {
185 return Ok(());
186 };
187 first.to_css(dest)?;
188
189 let separator = match self.multiplier {
191 Multiplier::Space => " ",
193 Multiplier::Comma => ", ",
195 };
196 for component in iter {
197 dest.write_str(separator)?;
198 component.to_css(dest)?;
199 }
200 Ok(())
201 }
202}
203
204#[derive(
207 Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem,
208)]
209pub struct Value<Component> {
210 pub(crate) v: ValueInner<Component>,
212 #[css(skip)]
215 url_data: UrlExtraData,
216}
217
218impl<Component: Animate> Animate for Value<Component> {
219 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
220 let v = self.v.animate(&other.v, procedure)?;
221 Ok(Value {
222 v,
223 url_data: self.url_data.clone(),
224 })
225 }
226}
227
228impl<Component> Value<Component> {
229 pub fn new(v: ValueInner<Component>, url_data: UrlExtraData) -> Self {
231 Self { v, url_data }
232 }
233
234 pub fn universal(var: Arc<ComputedPropertyValue>) -> Self {
236 let url_data = var.url_data.clone();
237 let v = ValueInner::Universal(var);
238 Self { v, url_data }
239 }
240}
241
242impl<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>
243 Value<GenericValueComponent<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>>
244where
245 Self: ToCss,
246{
247 fn serialization_types(&self) -> (TokenSerializationType, TokenSerializationType) {
248 match &self.v {
249 ValueInner::Component(component) => component.serialization_types(),
250 ValueInner::Universal(_) => unreachable!(),
251 ValueInner::List(list) => list
252 .components
253 .first()
254 .map_or(Default::default(), |f| f.serialization_types()),
255 }
256 }
257
258 pub fn to_variable_value(&self) -> ComputedPropertyValue {
260 if let ValueInner::Universal(ref value) = self.v {
261 return (**value).clone();
262 }
263 let serialization_types = self.serialization_types();
264 ComputedPropertyValue::new(
265 self.to_css_string(),
266 &self.url_data,
267 serialization_types.0,
268 serialization_types.1,
269 )
270 }
271}
272
273#[derive(
275 Animate, ToComputedValue, ToResolvedValue, ToCss, Clone, Debug, MallocSizeOf, PartialEq, ToShmem,
276)]
277pub enum ValueInner<Component> {
278 Component(Component),
281 #[animation(error)]
283 Universal(#[ignore_malloc_size_of = "Arc"] Arc<ComputedPropertyValue>),
284 List(#[animation(field_bound)] ComponentList<Component>),
286}
287
288pub type SpecifiedValue = Value<SpecifiedValueComponent>;
290
291pub type ComputedValue = Value<ComputedValueComponent>;
293
294impl SpecifiedValue {
295 pub fn compute<'i, 't>(
298 input: &mut CSSParser<'i, 't>,
299 registration: &PropertyRegistrationData,
300 url_data: &UrlExtraData,
301 context: &computed::Context,
302 allow_computationally_dependent: AllowComputationallyDependent,
303 ) -> Result<ComputedValue, ()> {
304 debug_assert!(!registration.syntax.is_universal(), "Shouldn't be needed");
305 let Ok(value) = Self::parse(
306 input,
307 ®istration.syntax,
308 url_data,
309 allow_computationally_dependent,
310 ) else {
311 return Err(());
312 };
313
314 Ok(value.to_computed_value(context))
315 }
316
317 pub fn parse<'i, 't>(
320 mut input: &mut CSSParser<'i, 't>,
321 syntax: &Descriptor,
322 url_data: &UrlExtraData,
323 allow_computationally_dependent: AllowComputationallyDependent,
324 ) -> Result<Self, StyleParseError<'i>> {
325 if syntax.is_universal() {
326 let parsed = ComputedPropertyValue::parse(&mut input, url_data)?;
327 return Ok(SpecifiedValue {
328 v: ValueInner::Universal(Arc::new(parsed)),
329 url_data: url_data.clone(),
330 });
331 }
332
333 let mut values = SmallComponentVec::new();
334 let mut multiplier = None;
335 {
336 let mut parser = Parser::new(syntax, &mut values, &mut multiplier);
337 parser.parse(&mut input, url_data, allow_computationally_dependent)?;
338 }
339 let v = if let Some(multiplier) = multiplier {
340 ValueInner::List(ComponentList {
341 multiplier,
342 components: values.to_vec().into(),
343 })
344 } else {
345 ValueInner::Component(values[0].clone())
346 };
347 Ok(Self {
348 v,
349 url_data: url_data.clone(),
350 })
351 }
352}
353
354impl ComputedValue {
355 fn to_declared_value(&self) -> properties::CustomDeclarationValue {
356 if let ValueInner::Universal(ref var) = self.v {
357 return properties::CustomDeclarationValue::Unparsed(Arc::clone(var));
358 }
359 properties::CustomDeclarationValue::Parsed(Arc::new(ToComputedValue::from_computed_value(
360 self,
361 )))
362 }
363
364 pub fn as_universal(&self) -> Option<&Arc<ComputedPropertyValue>> {
366 if let ValueInner::Universal(ref var) = self.v {
367 Some(var)
368 } else {
369 None
370 }
371 }
372}
373
374pub enum AllowComputationallyDependent {
379 No,
381 Yes,
383}
384
385type SmallComponentVec = SmallVec<[SpecifiedValueComponent; 1]>;
386
387struct Parser<'a> {
388 syntax: &'a Descriptor,
389 output: &'a mut SmallComponentVec,
390 output_multiplier: &'a mut Option<Multiplier>,
391}
392
393impl<'a> Parser<'a> {
394 fn new(
395 syntax: &'a Descriptor,
396 output: &'a mut SmallComponentVec,
397 output_multiplier: &'a mut Option<Multiplier>,
398 ) -> Self {
399 Self {
400 syntax,
401 output,
402 output_multiplier,
403 }
404 }
405
406 fn parse<'i, 't>(
407 &mut self,
408 input: &mut CSSParser<'i, 't>,
409 url_data: &UrlExtraData,
410 allow_computationally_dependent: AllowComputationallyDependent,
411 ) -> Result<(), StyleParseError<'i>> {
412 use self::AllowComputationallyDependent::*;
413 let parsing_mode = match allow_computationally_dependent {
414 No => ParsingMode::DISALLOW_COMPUTATIONALLY_DEPENDENT,
415 Yes => ParsingMode::DEFAULT,
416 };
417 let ref context = ParserContext::new(
418 Origin::Author,
419 url_data,
420 Some(CssRuleType::Style),
421 parsing_mode,
422 QuirksMode::NoQuirks,
423 Default::default(),
424 None,
425 None,
426 );
427 for component in self.syntax.components.iter() {
428 let result = input.try_parse(|input| {
429 input.parse_entirely(|input| {
430 Self::parse_value(context, input, &component.unpremultiplied())
431 })
432 });
433 let Ok(values) = result else { continue };
434 self.output.extend(values);
435 *self.output_multiplier = component.multiplier();
436 break;
437 }
438 if self.output.is_empty() {
439 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
440 }
441 Ok(())
442 }
443
444 fn parse_value<'i, 't>(
445 context: &ParserContext,
446 input: &mut CSSParser<'i, 't>,
447 component: &SyntaxComponent,
448 ) -> Result<SmallComponentVec, StyleParseError<'i>> {
449 let mut values = SmallComponentVec::new();
450 values.push(Self::parse_component_without_multiplier(
451 context, input, component,
452 )?);
453
454 if let Some(multiplier) = component.multiplier() {
455 loop {
456 let result = Self::expect_multiplier(input, &multiplier);
457 if Self::expect_multiplier_yielded_eof_error(&result) {
458 break;
459 }
460 result?;
461 values.push(Self::parse_component_without_multiplier(
462 context, input, component,
463 )?);
464 }
465 }
466 Ok(values)
467 }
468
469 fn parse_component_without_multiplier<'i, 't>(
470 context: &ParserContext,
471 input: &mut CSSParser<'i, 't>,
472 component: &SyntaxComponent,
473 ) -> Result<SpecifiedValueComponent, StyleParseError<'i>> {
474 let data_type = match component.name() {
475 ComponentName::DataType(ty) => ty,
476 ComponentName::Ident(ref name) => {
477 let ident = CustomIdent::parse(input, &[])?;
478 if ident != *name {
479 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
480 }
481 return Ok(SpecifiedValueComponent::CustomIdent(ident));
482 },
483 };
484
485 let value = match data_type {
486 DataType::Length => {
487 SpecifiedValueComponent::Length(specified::Length::parse(context, input)?)
488 },
489 DataType::Number => {
490 SpecifiedValueComponent::Number(specified::Number::parse(context, input)?)
491 },
492 DataType::Percentage => {
493 SpecifiedValueComponent::Percentage(specified::Percentage::parse(context, input)?)
494 },
495 DataType::LengthPercentage => SpecifiedValueComponent::LengthPercentage(
496 specified::LengthPercentage::parse(context, input)?,
497 ),
498 DataType::Color => {
499 SpecifiedValueComponent::Color(specified::Color::parse(context, input)?)
500 },
501 DataType::Image => {
502 SpecifiedValueComponent::Image(specified::Image::parse(context, input)?)
503 },
504 DataType::Url => {
505 SpecifiedValueComponent::Url(specified::url::SpecifiedUrl::parse(context, input)?)
506 },
507 DataType::Integer => {
508 SpecifiedValueComponent::Integer(specified::Integer::parse(context, input)?)
509 },
510 DataType::Angle => {
511 SpecifiedValueComponent::Angle(specified::Angle::parse(context, input)?)
512 },
513 DataType::Time => {
514 SpecifiedValueComponent::Time(specified::Time::parse(context, input)?)
515 },
516 DataType::Resolution => {
517 SpecifiedValueComponent::Resolution(specified::Resolution::parse(context, input)?)
518 },
519 DataType::TransformFunction => SpecifiedValueComponent::TransformFunction(
520 specified::Transform::parse(context, input)?,
521 ),
522 DataType::CustomIdent => {
523 let name = CustomIdent::parse(input, &[])?;
524 SpecifiedValueComponent::CustomIdent(name)
525 },
526 DataType::TransformList => {
527 let mut values = vec![];
528 let Some(multiplier) = component.unpremultiplied().multiplier() else {
529 debug_assert!(false, "Unpremultiplied <transform-list> had no multiplier?");
530 return Err(
531 input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(
532 PropertySyntaxParseError::UnexpectedEOF,
533 )),
534 );
535 };
536 debug_assert_eq!(multiplier, Multiplier::Space);
537 loop {
538 values.push(SpecifiedValueComponent::TransformFunction(
539 specified::Transform::parse(context, input)?,
540 ));
541 let result = Self::expect_multiplier(input, &multiplier);
542 if Self::expect_multiplier_yielded_eof_error(&result) {
543 break;
544 }
545 result?;
546 }
547 let list = ComponentList {
548 multiplier,
549 components: values.into(),
550 };
551 SpecifiedValueComponent::TransformList(list)
552 },
553 DataType::String => {
554 let string = input.expect_string()?;
555 SpecifiedValueComponent::String(string.as_ref().to_owned().into())
556 },
557 };
558 Ok(value)
559 }
560
561 fn expect_multiplier_yielded_eof_error<'i>(result: &Result<(), StyleParseError<'i>>) -> bool {
562 matches!(
563 result,
564 Err(StyleParseError {
565 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
566 ..
567 })
568 )
569 }
570
571 fn expect_multiplier<'i, 't>(
572 input: &mut CSSParser<'i, 't>,
573 multiplier: &Multiplier,
574 ) -> Result<(), StyleParseError<'i>> {
575 match multiplier {
576 Multiplier::Space => {
577 input.expect_whitespace()?;
578 if input.is_exhausted() {
579 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
581 }
582 Ok(())
583 },
584 Multiplier::Comma => Ok(input.expect_comma()?),
585 }
586 }
587}
588
589#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
591pub struct CustomAnimatedValue {
592 pub(crate) name: crate::custom_properties::Name,
594 pub(crate) value: Option<ComputedValue>,
597}
598
599impl Animate for CustomAnimatedValue {
600 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
601 if self.name != other.name {
602 return Err(());
603 }
604 let value = self.value.animate(&other.value, procedure)?;
605 Ok(Self {
606 name: self.name.clone(),
607 value,
608 })
609 }
610}
611
612impl CustomAnimatedValue {
613 pub(crate) fn from_computed(
614 name: &crate::custom_properties::Name,
615 value: Option<&ComputedValue>,
616 ) -> Self {
617 Self {
618 name: name.clone(),
619 value: value.cloned(),
620 }
621 }
622
623 pub(crate) fn from_declaration(
624 declaration: &properties::CustomDeclaration,
625 context: &mut computed::Context,
626 ) -> Option<Self> {
627 let computed_value = match declaration.value {
628 properties::CustomDeclarationValue::Unparsed(ref value) => Some({
629 debug_assert!(
630 context.builder.stylist.is_some(),
631 "Need a Stylist to get property registration!"
632 );
633 let registration = context
634 .builder
635 .stylist
636 .unwrap()
637 .get_custom_property_registration(&declaration.name);
638 if registration.syntax.is_universal() {
639 ComputedValue {
641 v: ValueInner::Universal(Arc::clone(value)),
642 url_data: value.url_data.clone(),
643 }
644 } else {
645 let mut input = cssparser::ParserInput::new(&value.css);
646 let mut input = CSSParser::new(&mut input);
647 SpecifiedValue::compute(
648 &mut input,
649 registration,
650 &value.url_data,
651 context,
652 AllowComputationallyDependent::Yes,
653 )
654 .unwrap_or_else(|_| ComputedValue {
655 v: ValueInner::Universal(Arc::clone(value)),
656 url_data: value.url_data.clone(),
657 })
658 }
659 }),
660 properties::CustomDeclarationValue::Parsed(ref v) => Some(v.to_computed_value(context)),
661 properties::CustomDeclarationValue::CSSWideKeyword(keyword) => {
662 let stylist = context.builder.stylist.unwrap();
663 let registration = stylist.get_custom_property_registration(&declaration.name);
664 match keyword {
665 CSSWideKeyword::Initial => stylist
666 .get_custom_property_initial_values()
667 .get(registration, &declaration.name),
668 CSSWideKeyword::Inherit => context
669 .builder
670 .inherited_custom_properties()
671 .get(registration, &declaration.name),
672 CSSWideKeyword::Unset => match registration.inherits {
673 Inherits::False => stylist
674 .get_custom_property_initial_values()
675 .get(registration, &declaration.name),
676 Inherits::True => context
677 .builder
678 .inherited_custom_properties()
679 .get(registration, &declaration.name),
680 },
681 CSSWideKeyword::Revert | CSSWideKeyword::RevertLayer => return None,
691 }
692 .cloned()
693 },
694 };
695 Some(Self {
696 name: declaration.name.clone(),
697 value: computed_value,
698 })
699 }
700
701 pub(crate) fn to_declaration(&self) -> properties::PropertyDeclaration {
702 properties::PropertyDeclaration::Custom(properties::CustomDeclaration {
703 name: self.name.clone(),
704 value: match &self.value {
705 Some(value) => value.to_declared_value(),
706 None => CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Initial),
707 },
708 })
709 }
710}