Skip to main content

style/values/specified/
param.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Common handling for the specified value CSS param() values.
6
7use crate::custom_properties::VariableValue;
8use crate::parser::{Parse, ParserContext};
9use crate::values::fmt;
10use crate::values::CssWriter;
11use crate::{derives::*, values::DashedIdent};
12use cssparser::Parser;
13use std::fmt::Write;
14use style_traits::arc_slice::ArcSlice;
15use style_traits::owned_str::OwnedStr;
16use style_traits::{ParseError, ToCss};
17
18/// A struct to hold a specific '<declaration-value>?', since an empty value (param(--a, )) serializes differently than
19/// a non-provided value (param(--a))
20#[derive(
21    Clone,
22    Debug,
23    MallocSizeOf,
24    PartialEq,
25    SpecifiedValueInfo,
26    ToComputedValue,
27    ToResolvedValue,
28    ToShmem,
29)]
30#[repr(C, u8)]
31pub enum LinkParamValueOrNone {
32    /// Handles the case when no value is provided at all: param(--a)
33    None,
34    /// Handles the cases for provided, or provided but empty, e.g. param(--a, blue) and param(--a, )
35    Specified(OwnedStr),
36}
37
38/// A single param(--ident, value) entry: https://drafts.csswg.org/css-link-params-1/#funcdef-param
39#[derive(
40    Clone,
41    Debug,
42    MallocSizeOf,
43    PartialEq,
44    SpecifiedValueInfo,
45    ToComputedValue,
46    ToResolvedValue,
47    ToShmem,
48)]
49#[repr(C)]
50pub struct LinkParam {
51    /// link-parameters' param name, in the form of an <dashed-ident>: https://drafts.csswg.org/css-values-4/#typedef-dashed-ident
52    pub name: DashedIdent,
53    /// link-parameters' value, in the form of a <declaration-value>: https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
54    pub value: LinkParamValueOrNone,
55}
56
57/// A struct to hold all specified link-parameters: https://drafts.csswg.org/css-link-params-1/
58///
59/// We treat `none` as an empty slice and vis-versa
60#[derive(
61    Clone,
62    Debug,
63    Default,
64    MallocSizeOf,
65    PartialEq,
66    SpecifiedValueInfo,
67    ToComputedValue,
68    ToCss,
69    ToResolvedValue,
70    ToShmem,
71    ToTyped,
72)]
73#[repr(C)]
74#[css(comma)]
75#[typed(skip_derive_fields)]
76pub struct LinkParameters(
77    /// Slice of specified link-parameters properties: https://drafts.csswg.org/css-link-params-1/#link-param-prop
78    #[css(iterable, if_empty = "none")]
79    #[ignore_malloc_size_of = "Arc"]
80    pub ArcSlice<LinkParam>,
81);
82
83impl LinkParameters {
84    /// Returns the `none` value.
85    pub fn none() -> Self {
86        Self(ArcSlice::default())
87    }
88}
89
90impl Parse for LinkParameters {
91    fn parse<'i, 't>(
92        context: &ParserContext,
93        input: &mut Parser<'i, 't>,
94    ) -> Result<Self, ParseError<'i>> {
95        if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
96            return Ok(Self::none());
97        }
98
99        let params = input.parse_comma_separated(|input| {
100            input.expect_function_matching("param")?;
101            input.parse_nested_block(|input| {
102                let name = DashedIdent::parse(context, input)?;
103                // if a comma exists then parse it and set value as specified, even if no value provided
104                // need to handle url references properly https://bugzilla.mozilla.org/show_bug.cgi?id=2028998
105                let value = if input.try_parse(|i| i.expect_comma()).is_ok() {
106                    let parsed = VariableValue::parse(input, None, &context.url_data)?;
107                    LinkParamValueOrNone::Specified(OwnedStr::from(parsed.css))
108                } else {
109                    LinkParamValueOrNone::None
110                };
111                Ok(LinkParam { name, value })
112            })
113        })?;
114
115        Ok(Self(crate::ArcSlice::from_iter(params.into_iter())))
116    }
117}
118
119impl ToCss for LinkParam {
120    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
121    where
122        W: Write,
123    {
124        dest.write_str("param(")?;
125        self.name.to_css(dest)?;
126        if let LinkParamValueOrNone::Specified(param) = &self.value {
127            dest.write_str(", ")?;
128            if !param.is_empty() {
129                // Don't use to_css, instead write the raw CSS value without extra quoting, else serialization will include un-de-serializable quotes
130                dest.write_str(&param)?;
131            }
132        }
133        dest.write_char(')')
134    }
135}