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