style/values/specified/
background.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//! Specified types for CSS values related to backgrounds.
6
7use crate::parser::{Parse, ParserContext};
8use crate::values::generics::background::BackgroundSize as GenericBackgroundSize;
9use crate::values::specified::length::{
10    NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto,
11};
12use cssparser::Parser;
13use selectors::parser::SelectorParseErrorKind;
14use std::fmt::{self, Write};
15use style_traits::{CssWriter, ParseError, ToCss};
16
17/// A specified value for the `background-size` property.
18pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthPercentage>;
19
20impl Parse for BackgroundSize {
21    fn parse<'i, 't>(
22        context: &ParserContext,
23        input: &mut Parser<'i, 't>,
24    ) -> Result<Self, ParseError<'i>> {
25        if let Ok(width) = input.try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i))
26        {
27            let height = input
28                .try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i))
29                .unwrap_or(NonNegativeLengthPercentageOrAuto::auto());
30            return Ok(GenericBackgroundSize::ExplicitSize { width, height });
31        }
32        Ok(try_match_ident_ignore_ascii_case! { input,
33            "cover" => GenericBackgroundSize::Cover,
34            "contain" => GenericBackgroundSize::Contain,
35        })
36    }
37}
38
39/// One of the keywords for `background-repeat`.
40#[derive(
41    Clone,
42    Copy,
43    Debug,
44    Eq,
45    MallocSizeOf,
46    Parse,
47    PartialEq,
48    SpecifiedValueInfo,
49    ToComputedValue,
50    ToCss,
51    ToResolvedValue,
52    ToShmem,
53)]
54#[allow(missing_docs)]
55#[value_info(other_values = "repeat-x,repeat-y")]
56pub enum BackgroundRepeatKeyword {
57    Repeat,
58    Space,
59    Round,
60    NoRepeat,
61}
62
63/// The value of the `background-repeat` property, with `repeat-x` / `repeat-y`
64/// represented as the combination of `no-repeat` and `repeat` in the opposite
65/// axes.
66///
67/// https://drafts.csswg.org/css-backgrounds/#the-background-repeat
68#[derive(
69    Clone,
70    Debug,
71    MallocSizeOf,
72    PartialEq,
73    SpecifiedValueInfo,
74    ToComputedValue,
75    ToResolvedValue,
76    ToShmem,
77)]
78pub struct BackgroundRepeat(pub BackgroundRepeatKeyword, pub BackgroundRepeatKeyword);
79
80impl BackgroundRepeat {
81    /// Returns the `repeat repeat` value.
82    pub fn repeat() -> Self {
83        BackgroundRepeat(
84            BackgroundRepeatKeyword::Repeat,
85            BackgroundRepeatKeyword::Repeat,
86        )
87    }
88}
89
90impl ToCss for BackgroundRepeat {
91    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
92    where
93        W: Write,
94    {
95        match (self.0, self.1) {
96            (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) => {
97                dest.write_str("repeat-x")
98            },
99            (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) => {
100                dest.write_str("repeat-y")
101            },
102            (horizontal, vertical) => {
103                horizontal.to_css(dest)?;
104                if horizontal != vertical {
105                    dest.write_char(' ')?;
106                    vertical.to_css(dest)?;
107                }
108                Ok(())
109            },
110        }
111    }
112}
113
114impl Parse for BackgroundRepeat {
115    fn parse<'i, 't>(
116        _context: &ParserContext,
117        input: &mut Parser<'i, 't>,
118    ) -> Result<Self, ParseError<'i>> {
119        let ident = input.expect_ident_cloned()?;
120
121        match_ignore_ascii_case! { &ident,
122            "repeat-x" => {
123                return Ok(BackgroundRepeat(BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat));
124            },
125            "repeat-y" => {
126                return Ok(BackgroundRepeat(BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat));
127            },
128            _ => {},
129        }
130
131        let horizontal = match BackgroundRepeatKeyword::from_ident(&ident) {
132            Ok(h) => h,
133            Err(()) => {
134                return Err(
135                    input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
136                );
137            },
138        };
139
140        let vertical = input.try_parse(BackgroundRepeatKeyword::parse).ok();
141        Ok(BackgroundRepeat(horizontal, vertical.unwrap_or(horizontal)))
142    }
143}