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