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(
204 Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem,
205)]
206pub struct Value<Component> {
207 pub(crate) v: ValueInner<Component>,
209 #[css(skip)]
212 url_data: UrlExtraData,
213}
214
215impl<Component: Animate> Animate for Value<Component> {
216 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
217 let v = self.v.animate(&other.v, procedure)?;
218 Ok(Value {
219 v,
220 url_data: self.url_data.clone(),
221 })
222 }
223}
224
225impl<Component> Value<Component> {
226 pub fn new(v: ValueInner<Component>, url_data: UrlExtraData) -> Self {
228 Self { v, url_data }
229 }
230
231 pub fn universal(var: Arc<ComputedPropertyValue>) -> Self {
233 let url_data = var.url_data.clone();
234 let v = ValueInner::Universal(var);
235 Self { v, url_data }
236 }
237}
238
239#[derive(
241 Animate, ToComputedValue, ToResolvedValue, ToCss, Clone, Debug, MallocSizeOf, PartialEq, ToShmem,
242)]
243pub enum ValueInner<Component> {
244 Component(Component),
247 #[animation(error)]
249 Universal(#[ignore_malloc_size_of = "Arc"] Arc<ComputedPropertyValue>),
250 List(#[animation(field_bound)] ComponentList<Component>),
252}
253
254pub type SpecifiedValue = Value<SpecifiedValueComponent>;
256
257pub type ComputedValue = Value<ComputedValueComponent>;
259
260impl SpecifiedValue {
261 pub fn compute<'i, 't>(
264 input: &mut CSSParser<'i, 't>,
265 registration: &PropertyRegistrationData,
266 url_data: &UrlExtraData,
267 context: &computed::Context,
268 allow_computationally_dependent: AllowComputationallyDependent,
269 ) -> Result<ComputedValue, ()> {
270 debug_assert!(!registration.syntax.is_universal(), "Shouldn't be needed");
271 let Ok(value) = Self::parse(
272 input,
273 ®istration.syntax,
274 url_data,
275 allow_computationally_dependent,
276 ) else {
277 return Err(());
278 };
279
280 Ok(value.to_computed_value(context))
281 }
282
283 pub fn parse<'i, 't>(
286 mut input: &mut CSSParser<'i, 't>,
287 syntax: &Descriptor,
288 url_data: &UrlExtraData,
289 allow_computationally_dependent: AllowComputationallyDependent,
290 ) -> Result<Self, StyleParseError<'i>> {
291 if syntax.is_universal() {
292 let parsed = ComputedPropertyValue::parse(&mut input, url_data)?;
293 return Ok(SpecifiedValue {
294 v: ValueInner::Universal(Arc::new(parsed)),
295 url_data: url_data.clone(),
296 });
297 }
298
299 let mut values = SmallComponentVec::new();
300 let mut multiplier = None;
301 {
302 let mut parser = Parser::new(syntax, &mut values, &mut multiplier);
303 parser.parse(&mut input, url_data, allow_computationally_dependent)?;
304 }
305 let v = if let Some(multiplier) = multiplier {
306 ValueInner::List(ComponentList {
307 multiplier,
308 components: values.to_vec().into(),
309 })
310 } else {
311 ValueInner::Component(values[0].clone())
312 };
313 Ok(Self {
314 v,
315 url_data: url_data.clone(),
316 })
317 }
318}
319
320impl ComputedValue {
321 fn serialization_types(&self) -> (TokenSerializationType, TokenSerializationType) {
322 match &self.v {
323 ValueInner::Component(component) => component.serialization_types(),
324 ValueInner::Universal(_) => unreachable!(),
325 ValueInner::List(list) => list
326 .components
327 .first()
328 .map_or(Default::default(), |f| f.serialization_types()),
329 }
330 }
331
332 fn to_declared_value(&self) -> properties::CustomDeclarationValue {
333 if let ValueInner::Universal(ref var) = self.v {
334 return properties::CustomDeclarationValue::Unparsed(Arc::clone(var));
335 }
336 properties::CustomDeclarationValue::Parsed(Arc::new(ToComputedValue::from_computed_value(
337 self,
338 )))
339 }
340
341 pub fn as_universal(&self) -> Option<&Arc<ComputedPropertyValue>> {
343 if let ValueInner::Universal(ref var) = self.v {
344 Some(var)
345 } else {
346 None
347 }
348 }
349
350 pub fn to_variable_value(&self) -> ComputedPropertyValue {
352 if let ValueInner::Universal(ref value) = self.v {
353 return (**value).clone();
354 }
355 let serialization_types = self.serialization_types();
356 ComputedPropertyValue::new(
357 self.to_css_string(),
358 &self.url_data,
359 serialization_types.0,
360 serialization_types.1,
361 )
362 }
363}
364
365pub enum AllowComputationallyDependent {
370 No,
372 Yes,
374}
375
376type SmallComponentVec = SmallVec<[SpecifiedValueComponent; 1]>;
377
378struct Parser<'a> {
379 syntax: &'a Descriptor,
380 output: &'a mut SmallComponentVec,
381 output_multiplier: &'a mut Option<Multiplier>,
382}
383
384impl<'a> Parser<'a> {
385 fn new(
386 syntax: &'a Descriptor,
387 output: &'a mut SmallComponentVec,
388 output_multiplier: &'a mut Option<Multiplier>,
389 ) -> Self {
390 Self {
391 syntax,
392 output,
393 output_multiplier,
394 }
395 }
396
397 fn parse<'i, 't>(
398 &mut self,
399 input: &mut CSSParser<'i, 't>,
400 url_data: &UrlExtraData,
401 allow_computationally_dependent: AllowComputationallyDependent,
402 ) -> Result<(), StyleParseError<'i>> {
403 use self::AllowComputationallyDependent::*;
404 let parsing_mode = match allow_computationally_dependent {
405 No => ParsingMode::DISALLOW_COMPUTATIONALLY_DEPENDENT,
406 Yes => ParsingMode::DEFAULT,
407 };
408 let ref context = ParserContext::new(
409 Origin::Author,
410 url_data,
411 Some(CssRuleType::Style),
412 parsing_mode,
413 QuirksMode::NoQuirks,
414 Default::default(),
415 None,
416 None,
417 );
418 for component in self.syntax.components.iter() {
419 let result = input.try_parse(|input| {
420 input.parse_entirely(|input| {
421 Self::parse_value(context, input, &component.unpremultiplied())
422 })
423 });
424 let Ok(values) = result else { continue };
425 self.output.extend(values);
426 *self.output_multiplier = component.multiplier();
427 break;
428 }
429 if self.output.is_empty() {
430 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
431 }
432 Ok(())
433 }
434
435 fn parse_value<'i, 't>(
436 context: &ParserContext,
437 input: &mut CSSParser<'i, 't>,
438 component: &SyntaxComponent,
439 ) -> Result<SmallComponentVec, StyleParseError<'i>> {
440 let mut values = SmallComponentVec::new();
441 values.push(Self::parse_component_without_multiplier(
442 context, input, component,
443 )?);
444
445 if let Some(multiplier) = component.multiplier() {
446 loop {
447 let result = Self::expect_multiplier(input, &multiplier);
448 if Self::expect_multiplier_yielded_eof_error(&result) {
449 break;
450 }
451 result?;
452 values.push(Self::parse_component_without_multiplier(
453 context, input, component,
454 )?);
455 }
456 }
457 Ok(values)
458 }
459
460 fn parse_component_without_multiplier<'i, 't>(
461 context: &ParserContext,
462 input: &mut CSSParser<'i, 't>,
463 component: &SyntaxComponent,
464 ) -> Result<SpecifiedValueComponent, StyleParseError<'i>> {
465 let data_type = match component.name() {
466 ComponentName::DataType(ty) => ty,
467 ComponentName::Ident(ref name) => {
468 let ident = CustomIdent::parse(input, &[])?;
469 if ident != *name {
470 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
471 }
472 return Ok(SpecifiedValueComponent::CustomIdent(ident));
473 },
474 };
475
476 let value = match data_type {
477 DataType::Length => {
478 SpecifiedValueComponent::Length(specified::Length::parse(context, input)?)
479 },
480 DataType::Number => {
481 SpecifiedValueComponent::Number(specified::Number::parse(context, input)?)
482 },
483 DataType::Percentage => {
484 SpecifiedValueComponent::Percentage(specified::Percentage::parse(context, input)?)
485 },
486 DataType::LengthPercentage => SpecifiedValueComponent::LengthPercentage(
487 specified::LengthPercentage::parse(context, input)?,
488 ),
489 DataType::Color => {
490 SpecifiedValueComponent::Color(specified::Color::parse(context, input)?)
491 },
492 DataType::Image => {
493 SpecifiedValueComponent::Image(specified::Image::parse(context, input)?)
494 },
495 DataType::Url => {
496 SpecifiedValueComponent::Url(specified::url::SpecifiedUrl::parse(context, input)?)
497 },
498 DataType::Integer => {
499 SpecifiedValueComponent::Integer(specified::Integer::parse(context, input)?)
500 },
501 DataType::Angle => {
502 SpecifiedValueComponent::Angle(specified::Angle::parse(context, input)?)
503 },
504 DataType::Time => {
505 SpecifiedValueComponent::Time(specified::Time::parse(context, input)?)
506 },
507 DataType::Resolution => {
508 SpecifiedValueComponent::Resolution(specified::Resolution::parse(context, input)?)
509 },
510 DataType::TransformFunction => SpecifiedValueComponent::TransformFunction(
511 specified::Transform::parse(context, input)?,
512 ),
513 DataType::CustomIdent => {
514 let name = CustomIdent::parse(input, &[])?;
515 SpecifiedValueComponent::CustomIdent(name)
516 },
517 DataType::TransformList => {
518 let mut values = vec![];
519 let Some(multiplier) = component.unpremultiplied().multiplier() else {
520 debug_assert!(false, "Unpremultiplied <transform-list> had no multiplier?");
521 return Err(
522 input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(
523 PropertySyntaxParseError::UnexpectedEOF,
524 )),
525 );
526 };
527 debug_assert_matches!(multiplier, Multiplier::Space);
528 loop {
529 values.push(SpecifiedValueComponent::TransformFunction(
530 specified::Transform::parse(context, input)?,
531 ));
532 let result = Self::expect_multiplier(input, &multiplier);
533 if Self::expect_multiplier_yielded_eof_error(&result) {
534 break;
535 }
536 result?;
537 }
538 let list = ComponentList {
539 multiplier,
540 components: values.into(),
541 };
542 SpecifiedValueComponent::TransformList(list)
543 },
544 DataType::String => {
545 let string = input.expect_string()?;
546 SpecifiedValueComponent::String(string.as_ref().to_owned().into())
547 },
548 };
549 Ok(value)
550 }
551
552 fn expect_multiplier_yielded_eof_error<'i>(result: &Result<(), StyleParseError<'i>>) -> bool {
553 matches!(
554 result,
555 Err(StyleParseError {
556 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
557 ..
558 })
559 )
560 }
561
562 fn expect_multiplier<'i, 't>(
563 input: &mut CSSParser<'i, 't>,
564 multiplier: &Multiplier,
565 ) -> Result<(), StyleParseError<'i>> {
566 match multiplier {
567 Multiplier::Space => {
568 input.expect_whitespace()?;
569 if input.is_exhausted() {
570 return Err(input.new_error(BasicParseErrorKind::EndOfInput));
572 }
573 Ok(())
574 },
575 Multiplier::Comma => Ok(input.expect_comma()?),
576 }
577 }
578}
579
580#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
582pub struct CustomAnimatedValue {
583 pub(crate) name: crate::custom_properties::Name,
585 value: ComputedValue,
587}
588
589impl Animate for CustomAnimatedValue {
590 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
591 if self.name != other.name {
592 return Err(());
593 }
594 let value = self.value.animate(&other.value, procedure)?;
595 Ok(Self {
596 name: self.name.clone(),
597 value,
598 })
599 }
600}
601
602impl CustomAnimatedValue {
603 pub(crate) fn from_computed(
604 name: &crate::custom_properties::Name,
605 value: &ComputedValue,
606 ) -> Self {
607 Self {
608 name: name.clone(),
609 value: value.clone(),
610 }
611 }
612
613 pub(crate) fn from_declaration(
614 declaration: &properties::CustomDeclaration,
615 context: &mut computed::Context,
616 _initial: &properties::ComputedValues,
617 ) -> Option<Self> {
618 let computed_value = match declaration.value {
619 properties::CustomDeclarationValue::Unparsed(ref value) => {
620 debug_assert!(
621 context.builder.stylist.is_some(),
622 "Need a Stylist to get property registration!"
623 );
624 let registration = context
625 .builder
626 .stylist
627 .unwrap()
628 .get_custom_property_registration(&declaration.name);
629 if registration.syntax.is_universal() {
630 ComputedValue {
632 v: ValueInner::Universal(Arc::clone(value)),
633 url_data: value.url_data.clone(),
634 }
635 } else {
636 let mut input = cssparser::ParserInput::new(&value.css);
637 let mut input = CSSParser::new(&mut input);
638 SpecifiedValue::compute(
639 &mut input,
640 registration,
641 &value.url_data,
642 context,
643 AllowComputationallyDependent::Yes,
644 )
645 .unwrap_or_else(|_| ComputedValue {
646 v: ValueInner::Universal(Arc::clone(value)),
647 url_data: value.url_data.clone(),
648 })
649 }
650 },
651 properties::CustomDeclarationValue::Parsed(ref v) => v.to_computed_value(context),
652 properties::CustomDeclarationValue::CSSWideKeyword(..) => return None,
655 };
656 Some(Self {
657 name: declaration.name.clone(),
658 value: computed_value,
659 })
660 }
661
662 pub(crate) fn to_declaration(&self) -> properties::PropertyDeclaration {
663 properties::PropertyDeclaration::Custom(properties::CustomDeclaration {
664 name: self.name.clone(),
665 value: self.value.to_declared_value(),
666 })
667 }
668}