1use crate::derives::*;
8use crate::parser::{Parse, ParserContext};
9use crate::values::generics::background::BackgroundSize as GenericBackgroundSize;
10use crate::values::specified::length::{
11 NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto,
12};
13use cssparser::{match_ignore_ascii_case, Parser};
14use selectors::parser::SelectorParseErrorKind;
15use std::fmt::{self, Write};
16use style_traits::{CssString, CssWriter, KeywordValue, ParseError, ToCss, ToTyped, TypedValue};
17use thin_vec::ThinVec;
18
19pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthPercentage>;
21
22impl Parse for BackgroundSize {
23 fn parse<'i, 't>(
24 context: &ParserContext,
25 input: &mut Parser<'i, 't>,
26 ) -> Result<Self, ParseError<'i>> {
27 if let Ok(width) = input.try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i))
28 {
29 let height = input
30 .try_parse(|i| NonNegativeLengthPercentageOrAuto::parse(context, i))
31 .unwrap_or(NonNegativeLengthPercentageOrAuto::auto());
32 return Ok(GenericBackgroundSize::ExplicitSize { width, height });
33 }
34 Ok(try_match_ident_ignore_ascii_case! { input,
35 "cover" => GenericBackgroundSize::Cover,
36 "contain" => GenericBackgroundSize::Contain,
37 })
38 }
39}
40
41#[derive(
43 Clone,
44 Copy,
45 Debug,
46 Eq,
47 MallocSizeOf,
48 Parse,
49 PartialEq,
50 SpecifiedValueInfo,
51 ToComputedValue,
52 ToCss,
53 ToResolvedValue,
54 ToShmem,
55 ToTyped,
56)]
57#[allow(missing_docs)]
58#[value_info(other_values = "repeat-x,repeat-y")]
59pub enum BackgroundRepeatKeyword {
60 Repeat,
61 Space,
62 Round,
63 NoRepeat,
64}
65
66#[derive(
72 Clone,
73 Debug,
74 MallocSizeOf,
75 PartialEq,
76 SpecifiedValueInfo,
77 ToComputedValue,
78 ToResolvedValue,
79 ToShmem,
80)]
81pub struct BackgroundRepeat(pub BackgroundRepeatKeyword, pub BackgroundRepeatKeyword);
82
83impl BackgroundRepeat {
84 pub fn repeat() -> Self {
86 BackgroundRepeat(
87 BackgroundRepeatKeyword::Repeat,
88 BackgroundRepeatKeyword::Repeat,
89 )
90 }
91}
92
93impl ToCss for BackgroundRepeat {
94 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
95 where
96 W: Write,
97 {
98 match (self.0, self.1) {
99 (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) => {
100 dest.write_str("repeat-x")
101 },
102 (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) => {
103 dest.write_str("repeat-y")
104 },
105 (horizontal, vertical) => {
106 horizontal.to_css(dest)?;
107 if horizontal != vertical {
108 dest.write_char(' ')?;
109 vertical.to_css(dest)?;
110 }
111 Ok(())
112 },
113 }
114 }
115}
116
117impl ToTyped for BackgroundRepeat {
118 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
119 match (self.0, self.1) {
120 (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) => {
121 dest.push(TypedValue::Keyword(KeywordValue(CssString::from(
122 "repeat-x",
123 ))));
124 Ok(())
125 },
126 (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) => {
127 dest.push(TypedValue::Keyword(KeywordValue(CssString::from(
128 "repeat-y",
129 ))));
130 Ok(())
131 },
132 (horizontal, vertical) if horizontal == vertical => {
133 ToTyped::to_typed(&horizontal, dest)
134 },
135 _ => Err(()),
136 }
137 }
138}
139
140impl Parse for BackgroundRepeat {
141 fn parse<'i, 't>(
142 _context: &ParserContext,
143 input: &mut Parser<'i, 't>,
144 ) -> Result<Self, ParseError<'i>> {
145 let ident = input.expect_ident_cloned()?;
146
147 match_ignore_ascii_case! { &ident,
148 "repeat-x" => {
149 return Ok(BackgroundRepeat(BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat));
150 },
151 "repeat-y" => {
152 return Ok(BackgroundRepeat(BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat));
153 },
154 _ => {},
155 }
156
157 let horizontal = match BackgroundRepeatKeyword::from_ident(&ident) {
158 Ok(h) => h,
159 Err(()) => {
160 return Err(
161 input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
162 );
163 },
164 };
165
166 let vertical = input.try_parse(BackgroundRepeatKeyword::parse).ok();
167 Ok(BackgroundRepeat(horizontal, vertical.unwrap_or(horizontal)))
168 }
169}