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