1use std::fmt::{self, Write};
8use crate::derives::*;
9use super::{
10 registry::PropertyRegistrationData,
11 syntax::{
12 data_type::DataType, Component as SyntaxComponent, ComponentName, Descriptor, Multiplier,
13 },
14};
15use crate::parser::{Parse, ParserContext};
16use crate::properties;
17use crate::properties::{CSSWideKeyword, CustomDeclarationValue};
18use crate::properties_and_values::rule::Inherits;
19use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
20use crate::values::{
21 animated::{self, Animate, Procedure},
22 computed::{self, ToComputedValue},
23 specified, CustomIdent,
24};
25use crate::custom_properties::ComputedValue as ComputedPropertyValue;
26use crate::{Namespace, Prefix};
27use cssparser::{BasicParseErrorKind, ParseErrorKind, Parser as CSSParser, TokenSerializationType};
28use rustc_hash::FxHashMap;
29use selectors::matching::QuirksMode;
30use servo_arc::Arc;
31use smallvec::SmallVec;
32use style_traits::{
33 owned_str::OwnedStr, CssWriter, ParseError as StyleParseError, ParsingMode,
34 PropertySyntaxParseError, StyleParseErrorKind, ToCss,
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)]
208pub struct Value<Component> {
209 pub(crate) v: ValueInner<Component>,
211 #[css(skip)]
214 url_data: UrlExtraData,
215}
216
217impl<Component: PartialEq> PartialEq for Value<Component> {
218 fn eq(&self, other: &Self) -> bool {
220 self.v == other.v
221 }
222}
223
224impl<Component: Animate> Animate for Value<Component> {
225 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
226 let v = self.v.animate(&other.v, procedure)?;
227 Ok(Value {
228 v,
229 url_data: self.url_data.clone(),
230 })
231 }
232}
233
234impl<Component> Value<Component> {
235 pub fn new(v: ValueInner<Component>, url_data: UrlExtraData) -> Self {
237 Self { v, url_data }
238 }
239
240 pub fn universal(var: Arc<ComputedPropertyValue>) -> Self {
242 let url_data = var.url_data.clone();
243 let v = ValueInner::Universal(var);
244 Self { v, url_data }
245 }
246}
247
248impl<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>
249 Value<GenericValueComponent<L, N, P, LP, C, Image, U, Integer, A, T, R, Transform>>
250where
251 Self: ToCss,
252{
253 fn serialization_types(&self) -> (TokenSerializationType, TokenSerializationType) {
254 match &self.v {
255 ValueInner::Component(component) => component.serialization_types(),
256 ValueInner::Universal(_) => unreachable!(),
257 ValueInner::List(list) => list
258 .components
259 .first()
260 .map_or(Default::default(), |f| f.serialization_types()),
261 }
262 }
263
264 pub fn to_variable_value(&self) -> ComputedPropertyValue {
266 if let ValueInner::Universal(ref value) = self.v {
267 return (**value).clone();
268 }
269 let serialization_types = self.serialization_types();
270 ComputedPropertyValue::new(
271 self.to_css_string(),
272 &self.url_data,
273 serialization_types.0,
274 serialization_types.1,
275 )
276 }
277}
278
279#[derive(
281 Animate, ToComputedValue, ToResolvedValue, ToCss, Clone, Debug, MallocSizeOf, PartialEq, ToShmem,
282)]
283pub enum ValueInner<Component> {
284 Component(Component),
287 #[animation(error)]
289 Universal(#[ignore_malloc_size_of = "Arc"] Arc<ComputedPropertyValue>),
290 List(#[animation(field_bound)] ComponentList<Component>),
292}
293
294pub type SpecifiedValue = Value<SpecifiedValueComponent>;
296
297pub type ComputedValue = Value<ComputedValueComponent>;
299
300impl SpecifiedValue {
301 pub fn compute<'i, 't>(
304 input: &mut CSSParser<'i, 't>,
305 registration: &PropertyRegistrationData,
306 namespaces: Option<&FxHashMap<Prefix, Namespace>>,
307 url_data: &UrlExtraData,
308 context: &computed::Context,
309 allow_computationally_dependent: AllowComputationallyDependent,
310 ) -> Result<ComputedValue, ()> {
311 debug_assert!(!registration.syntax.is_universal(), "Shouldn't be needed");
312 let Ok(value) = Self::parse(
313 input,
314 ®istration.syntax,
315 url_data,
316 namespaces,
317 allow_computationally_dependent,
318 ) else {
319 return Err(());
320 };
321
322 Ok(value.to_computed_value(context))
323 }
324
325 pub fn parse<'i, 't>(
328 mut input: &mut CSSParser<'i, 't>,
329 syntax: &Descriptor,
330 url_data: &UrlExtraData,
331 namespaces: Option<&FxHashMap<Prefix, Namespace>>,
332 allow_computationally_dependent: AllowComputationallyDependent,
333 ) -> Result<Self, StyleParseError<'i>> {
334 if syntax.is_universal() {
335 let parsed = ComputedPropertyValue::parse(&mut input, namespaces, url_data)?;
336 return Ok(SpecifiedValue {
337 v: ValueInner::Universal(Arc::new(parsed)),
338 url_data: url_data.clone(),
339 });
340 }
341
342 let mut values = SmallComponentVec::new();
343 let mut multiplier = None;
344 {
345 let mut parser = Parser::new(syntax, &mut values, &mut multiplier);
346 parser.parse(&mut input, url_data, allow_computationally_dependent)?;
347 }
348 let v = if let Some(multiplier) = multiplier {
349 ValueInner::List(ComponentList {
350 multiplier,
351 components: values.to_vec().into(),
352 })
353 } else {
354 ValueInner::Component(values[0].clone())
355 };
356 Ok(Self {
357 v,
358 url_data: url_data.clone(),
359 })
360 }
361}
362
363impl ComputedValue {
364 fn to_declared_value(&self) -> properties::CustomDeclarationValue {
365 if let ValueInner::Universal(ref var) = self.v {
366 return properties::CustomDeclarationValue::Unparsed(Arc::clone(var));
367 }
368 properties::CustomDeclarationValue::Parsed(Arc::new(ToComputedValue::from_computed_value(
369 self,
370 )))
371 }
372
373 pub fn as_universal(&self) -> Option<&Arc<ComputedPropertyValue>> {
375 if let ValueInner::Universal(ref var) = self.v {
376 Some(var)
377 } else {
378 None
379 }
380 }
381}
382
383pub enum AllowComputationallyDependent {
388 No,
390 Yes,
392}
393
394type SmallComponentVec = SmallVec<[SpecifiedValueComponent; 1]>;
395
396struct Parser<'a> {
397 syntax: &'a Descriptor,
398 output: &'a mut SmallComponentVec,
399 output_multiplier: &'a mut Option<Multiplier>,
400}
401
402impl<'a> Parser<'a> {
403 fn new(
404 syntax: &'a Descriptor,
405 output: &'a mut SmallComponentVec,
406 output_multiplier: &'a mut Option<Multiplier>,
407 ) -> Self {
408 Self {
409 syntax,
410 output,
411 output_multiplier,
412 }
413 }
414
415 fn parse<'i, 't>(
416 &mut self,
417 input: &mut CSSParser<'i, 't>,
418 url_data: &UrlExtraData,
419 allow_computationally_dependent: AllowComputationallyDependent,
420 ) -> Result<(), StyleParseError<'i>> {
421 use self::AllowComputationallyDependent::*;
422 let parsing_mode = match allow_computationally_dependent {
423 No => ParsingMode::DISALLOW_COMPUTATIONALLY_DEPENDENT,
424 Yes => ParsingMode::DEFAULT,
425 };
426 let ref context = ParserContext::new(
427 Origin::Author,
428 url_data,
429 Some(CssRuleType::Style),
430 parsing_mode,
431 QuirksMode::NoQuirks,
432 Default::default(),
433 None,
434 None,
435 );
436 for component in self.syntax.components.iter() {
437 let result = input.try_parse(|input| {
438 input.parse_entirely(|input| {
439 Self::parse_value(context, input, &component.unpremultiplied())
440 })
441 });
442 let Ok(values) = result else { continue };
443 self.output.extend(values);
444 *self.output_multiplier = component.multiplier();
445 break;
446 }
447 if self.output.is_empty() {
448 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
449 }
450 Ok(())
451 }
452
453 fn parse_value<'i, 't>(
454 context: &ParserContext,
455 input: &mut CSSParser<'i, 't>,
456 component: &SyntaxComponent,
457 ) -> Result<SmallComponentVec, StyleParseError<'i>> {
458 let mut values = SmallComponentVec::new();
459 values.push(Self::parse_component_without_multiplier(
460 context, input, component,
461 )?);
462
463 if let Some(multiplier) = component.multiplier() {
464 loop {
465 let result = Self::expect_multiplier(input, &multiplier);
466 if Self::expect_multiplier_yielded_eof_error(&result) {
467 break;
468 }
469 result?;
470 values.push(Self::parse_component_without_multiplier(
471 context, input, component,
472 )?);
473 }
474 }
475 Ok(values)
476 }
477
478 fn parse_component_without_multiplier<'i, 't>(
479 context: &ParserContext,
480 input: &mut CSSParser<'i, 't>,
481 component: &SyntaxComponent,
482 ) -> Result<SpecifiedValueComponent, StyleParseError<'i>> {
483 let data_type = match component.name() {
484 ComponentName::DataType(ty) => ty,
485 ComponentName::Ident(ref name) => {
486 let ident = CustomIdent::parse(input, &[])?;
487 if ident != *name {
488 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
489 }
490 return Ok(SpecifiedValueComponent::CustomIdent(ident));
491 },
492 };
493
494 let value = match data_type {
495 DataType::Length => {
496 SpecifiedValueComponent::Length(specified::Length::parse(context, input)?)
497 },
498 DataType::Number => {
499 SpecifiedValueComponent::Number(specified::Number::parse(context, input)?)
500 },
501 DataType::Percentage => {
502 SpecifiedValueComponent::Percentage(specified::Percentage::parse(context, input)?)
503 },
504 DataType::LengthPercentage => SpecifiedValueComponent::LengthPercentage(
505 specified::LengthPercentage::parse(context, input)?,
506 ),
507 DataType::Color => {
508 SpecifiedValueComponent::Color(specified::Color::parse(context, input)?)
509 },
510 DataType::Image => {
511 SpecifiedValueComponent::Image(specified::Image::parse(context, input)?)
512 },
513 DataType::Url => {
514 SpecifiedValueComponent::Url(specified::url::SpecifiedUrl::parse(context, input)?)
515 },
516 DataType::Integer => {
517 SpecifiedValueComponent::Integer(specified::Integer::parse(context, input)?)
518 },
519 DataType::Angle => {
520 SpecifiedValueComponent::Angle(specified::Angle::parse(context, input)?)
521 },
522 DataType::Time => {
523 SpecifiedValueComponent::Time(specified::Time::parse(context, input)?)
524 },
525 DataType::Resolution => {
526 SpecifiedValueComponent::Resolution(specified::Resolution::parse(context, input)?)
527 },
528 DataType::TransformFunction => SpecifiedValueComponent::TransformFunction(
529 specified::Transform::parse(context, input)?,
530 ),
531 DataType::CustomIdent => {
532 let name = CustomIdent::parse(input, &[])?;
533 SpecifiedValueComponent::CustomIdent(name)
534 },
535 DataType::TransformList => {
536 let mut values = vec![];
537 let Some(multiplier) = component.unpremultiplied().multiplier() else {
538 debug_assert!(false, "Unpremultiplied <transform-list> had no multiplier?");
539 return Err(
540 input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(
541 PropertySyntaxParseError::UnexpectedEOF,
542 )),
543 );
544 };
545 debug_assert_eq!(multiplier, Multiplier::Space);
546 loop {
547 values.push(SpecifiedValueComponent::TransformFunction(
548 specified::Transform::parse(context, input)?,
549 ));
550 let result = Self::expect_multiplier(input, &multiplier);
551 if Self::expect_multiplier_yielded_eof_error(&result) {
552 break;
553 }
554 result?;
555 }
556 let list = ComponentList {
557 multiplier,
558 components: values.into(),
559 };
560 SpecifiedValueComponent::TransformList(list)
561 },
562 DataType::String => {
563 let string = input.expect_string()?;
564 SpecifiedValueComponent::String(string.as_ref().to_owned().into())
565 },
566 };
567 Ok(value)
568 }
569
570 fn expect_multiplier_yielded_eof_error<'i>(result: &Result<(), StyleParseError<'i>>) -> bool {
571 matches!(
572 result,
573 Err(StyleParseError {
574 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
575 ..
576 })
577 )
578 }
579
580 fn expect_multiplier<'i, 't>(
581 input: &mut CSSParser<'i, 't>,
582 multiplier: &Multiplier,
583 ) -> Result<(), StyleParseError<'i>> {
584 match multiplier {
585 Multiplier::Space => {
586 input.expect_whitespace()?;
587 if input.is_exhausted() {
588 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
590 }
591 Ok(())
592 },
593 Multiplier::Comma => Ok(input.expect_comma()?),
594 }
595 }
596}
597
598#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
600pub struct CustomAnimatedValue {
601 pub(crate) name: crate::custom_properties::Name,
603 pub(crate) value: Option<ComputedValue>,
606}
607
608impl Animate for CustomAnimatedValue {
609 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
610 if self.name != other.name {
611 return Err(());
612 }
613 let value = self.value.animate(&other.value, procedure)?;
614 Ok(Self {
615 name: self.name.clone(),
616 value,
617 })
618 }
619}
620
621impl CustomAnimatedValue {
622 pub(crate) fn from_computed(
623 name: &crate::custom_properties::Name,
624 value: Option<&ComputedValue>,
625 ) -> Self {
626 Self {
627 name: name.clone(),
628 value: value.cloned(),
629 }
630 }
631
632 pub(crate) fn from_declaration(
633 declaration: &properties::CustomDeclaration,
634 context: &mut computed::Context,
635 ) -> Option<Self> {
636 let computed_value = match declaration.value {
637 properties::CustomDeclarationValue::Unparsed(ref value) => Some({
638 debug_assert!(
639 context.builder.stylist.is_some(),
640 "Need a Stylist to get property registration!"
641 );
642 let registration = context
643 .builder
644 .stylist
645 .unwrap()
646 .get_custom_property_registration(&declaration.name);
647 if registration.syntax.is_universal() {
648 ComputedValue {
650 v: ValueInner::Universal(Arc::clone(value)),
651 url_data: value.url_data.clone(),
652 }
653 } else {
654 let mut input = cssparser::ParserInput::new(&value.css);
655 let mut input = CSSParser::new(&mut input);
656 SpecifiedValue::compute(
657 &mut input,
658 registration,
659 None,
660 &value.url_data,
661 context,
662 AllowComputationallyDependent::Yes,
663 )
664 .unwrap_or_else(|_| ComputedValue {
665 v: ValueInner::Universal(Arc::clone(value)),
666 url_data: value.url_data.clone(),
667 })
668 }
669 }),
670 properties::CustomDeclarationValue::Parsed(ref v) => Some(v.to_computed_value(context)),
671 properties::CustomDeclarationValue::CSSWideKeyword(keyword) => {
672 let stylist = context.builder.stylist.unwrap();
673 let registration = stylist.get_custom_property_registration(&declaration.name);
674 match keyword {
675 CSSWideKeyword::Initial => stylist
676 .get_custom_property_initial_values()
677 .get(registration, &declaration.name),
678 CSSWideKeyword::Inherit => context
679 .builder
680 .inherited_custom_properties()
681 .get(registration, &declaration.name),
682 CSSWideKeyword::Unset => match registration.inherits {
683 Inherits::False => stylist
684 .get_custom_property_initial_values()
685 .get(registration, &declaration.name),
686 Inherits::True => context
687 .builder
688 .inherited_custom_properties()
689 .get(registration, &declaration.name),
690 },
691 CSSWideKeyword::Revert | CSSWideKeyword::RevertLayer => return None,
701 }
702 .cloned()
703 },
704 };
705 Some(Self {
706 name: declaration.name.clone(),
707 value: computed_value,
708 })
709 }
710
711 pub(crate) fn to_declaration(&self) -> properties::PropertyDeclaration {
712 properties::PropertyDeclaration::Custom(properties::CustomDeclaration {
713 name: self.name.clone(),
714 value: match &self.value {
715 Some(value) => value.to_declared_value(),
716 None => CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Initial),
717 },
718 })
719 }
720}