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