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