1use crate::derives::*;
9use crate::parser::{Parse, ParserContext};
10use crate::values::CustomIdent;
11use crate::values::generics::grid::{
12 Flex, FlexUnit, GridTemplateComponent, ImplicitGridTracks, RepeatCount,
13};
14use crate::values::generics::grid::{LineNameList, LineNameListValue, NameRepeat, TrackBreadth};
15use crate::values::generics::grid::{TrackList, TrackListValue, TrackRepeat, TrackSize};
16use crate::values::specified::{Integer, LengthPercentage};
17use cssparser::{Parser, Token};
18use style_traits::{ParseError, StyleParseErrorKind};
19
20impl Flex {
21 fn parse(input: &mut Parser) -> Result<Self, ParseError> {
23 match *input.next()? {
24 Token::Dimension {
25 value, ref unit, ..
26 } if FlexUnit::matches(unit) && value.is_sign_positive() => Ok(Self(value)),
27 _ => Err(ParseError::unexpected_token()),
28 }
29 }
30}
31
32impl<L> TrackBreadth<L> {
33 fn parse_keyword(input: &mut Parser) -> Result<Self, ParseError> {
34 #[derive(Parse)]
35 enum TrackKeyword {
36 Auto,
37 MaxContent,
38 MinContent,
39 }
40
41 Ok(match TrackKeyword::parse(input)? {
42 TrackKeyword::Auto => TrackBreadth::Auto,
43 TrackKeyword::MaxContent => TrackBreadth::MaxContent,
44 TrackKeyword::MinContent => TrackBreadth::MinContent,
45 })
46 }
47}
48
49impl Parse for TrackBreadth<LengthPercentage> {
50 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
51 if let Ok(lp) = input.try_parse(|i| LengthPercentage::parse_non_negative(context, i)) {
56 return Ok(TrackBreadth::Breadth(lp));
57 }
58
59 if let Ok(f) = input.try_parse(Flex::parse) {
60 return Ok(TrackBreadth::Flex(f));
61 }
62
63 Self::parse_keyword(input)
64 }
65}
66
67impl Parse for TrackSize<LengthPercentage> {
68 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
69 if let Ok(b) = input.try_parse(|i| TrackBreadth::parse(context, i)) {
70 return Ok(TrackSize::Breadth(b));
71 }
72
73 if input
74 .try_parse(|i| i.expect_function_matching("minmax"))
75 .is_ok()
76 {
77 return input.parse_nested_block(|input| {
78 let inflexible_breadth =
79 match input.try_parse(|i| LengthPercentage::parse_non_negative(context, i)) {
80 Ok(lp) => TrackBreadth::Breadth(lp),
81 Err(..) => TrackBreadth::parse_keyword(input)?,
82 };
83
84 input.expect_comma()?;
85 Ok(TrackSize::Minmax(
86 inflexible_breadth,
87 TrackBreadth::parse(context, input)?,
88 ))
89 });
90 }
91
92 input.expect_function_matching("fit-content")?;
93 let lp = input.parse_nested_block(|i| LengthPercentage::parse_non_negative(context, i))?;
94 Ok(TrackSize::FitContent(TrackBreadth::Breadth(lp)))
95 }
96}
97
98impl Parse for ImplicitGridTracks<TrackSize<LengthPercentage>> {
99 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
100 use style_traits::{Separator, Space};
101 let track_sizes = Space::parse(input, |i| TrackSize::parse(context, i))?;
102 if track_sizes.len() == 1 && track_sizes[0].is_initial() {
103 return Ok(Default::default());
105 }
106 Ok(ImplicitGridTracks(track_sizes.into()))
107 }
108}
109
110pub fn parse_line_names(input: &mut Parser) -> Result<crate::OwnedSlice<CustomIdent>, ParseError> {
114 input.expect_square_bracket_block()?;
115 input.parse_nested_block(|input| {
116 let mut values = vec![];
117 while let Ok(ident) = input.try_parse(|i| CustomIdent::parse(i, &["span", "auto"])) {
118 values.push(ident);
119 }
120
121 Ok(values.into())
122 })
123}
124
125#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
129enum RepeatType {
130 Auto,
132 Normal,
134 Fixed,
136}
137
138impl TrackRepeat<LengthPercentage, Integer> {
139 fn parse_with_repeat_type(
140 context: &ParserContext,
141 input: &mut Parser,
142 ) -> Result<(Self, RepeatType), ParseError> {
143 input
144 .try_parse(|i| i.expect_function_matching("repeat").map_err(|e| e.into()))
145 .and_then(|_| {
146 input.parse_nested_block(|input| {
147 let count = RepeatCount::parse(context, input)?;
148 input.expect_comma()?;
149
150 let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
151 let mut repeat_type = if is_auto {
152 RepeatType::Auto
153 } else {
154 RepeatType::Fixed
156 };
157
158 let mut names = vec![];
159 let mut values = vec![];
160 let mut current_names;
161
162 loop {
163 current_names = input.try_parse(parse_line_names).unwrap_or_default();
164 if let Ok(track_size) = input.try_parse(|i| TrackSize::parse(context, i)) {
165 if !track_size.is_fixed() {
166 if is_auto {
167 return Err(ParseError::custom(
169 StyleParseErrorKind::UnspecifiedError,
170 ));
171 }
172
173 if repeat_type == RepeatType::Fixed {
174 repeat_type = RepeatType::Normal }
176 }
177
178 values.push(track_size);
179 names.push(current_names);
180 continue;
181 }
182 if values.is_empty() {
183 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
185 }
186 names.push(current_names); break; }
189
190 let repeat = TrackRepeat {
191 count,
192 track_sizes: values.into(),
193 line_names: names.into(),
194 };
195
196 Ok((repeat, repeat_type))
197 })
198 })
199 }
200}
201
202impl Parse for TrackList<LengthPercentage, Integer> {
203 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
204 let mut current_names = vec![];
205 let mut names = vec![];
206 let mut values = vec![];
207
208 let mut auto_repeat_index = None;
210 let mut at_least_one_not_fixed = false;
212 loop {
213 current_names.extend_from_slice(&input.try_parse(parse_line_names).unwrap_or_default());
214 if let Ok(track_size) = input.try_parse(|i| TrackSize::parse(context, i)) {
215 if !track_size.is_fixed() {
216 at_least_one_not_fixed = true;
217 if auto_repeat_index.is_some() {
218 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
220 }
221 }
222
223 let vec = std::mem::take(&mut current_names);
224 names.push(vec.into());
225 values.push(TrackListValue::TrackSize(track_size));
226 continue;
227 }
228 if let Ok((repeat, type_)) =
229 input.try_parse(|i| TrackRepeat::parse_with_repeat_type(context, i))
230 {
231 match type_ {
232 RepeatType::Normal => {
233 at_least_one_not_fixed = true;
234 if auto_repeat_index.is_some() {
235 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
237 }
238 },
239 RepeatType::Auto => {
240 if auto_repeat_index.is_some() || at_least_one_not_fixed {
241 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
243 }
244 auto_repeat_index = Some(values.len());
245 },
246 RepeatType::Fixed => {},
247 }
248
249 let vec = std::mem::take(&mut current_names);
250 names.push(vec.into());
251 values.push(TrackListValue::TrackRepeat(repeat));
252 continue;
253 }
254 if values.is_empty() && auto_repeat_index.is_none() {
255 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
256 }
257 names.push(current_names.into());
258 break;
259 }
260
261 Ok(TrackList {
262 auto_repeat_index: auto_repeat_index.unwrap_or(usize::MAX),
263 values: values.into(),
264 line_names: names.into(),
265 })
266 }
267}
268
269#[inline]
270fn allow_grid_template_subgrids() -> bool {
271 crate::pref!(
272 "layout.css.grid-template-subgrid-value.enabled",
273 gecko = true
274 )
275}
276
277impl Parse for GridTemplateComponent<LengthPercentage, Integer> {
278 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
279 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
280 return Ok(GridTemplateComponent::None);
281 }
282
283 Self::parse_without_none(context, input)
284 }
285}
286
287impl GridTemplateComponent<LengthPercentage, Integer> {
288 pub fn parse_without_none(
290 context: &ParserContext,
291 input: &mut Parser,
292 ) -> Result<Self, ParseError> {
293 if allow_grid_template_subgrids()
294 && let Ok(t) = input.try_parse(|i| LineNameList::parse(context, i))
295 {
296 return Ok(GridTemplateComponent::Subgrid(Box::new(t)));
297 }
298 let track_list = TrackList::parse(context, input)?;
299 Ok(GridTemplateComponent::TrackList(Box::new(track_list)))
300 }
301}
302
303impl Parse for NameRepeat<Integer> {
304 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
305 input.expect_function_matching("repeat")?;
306 input.parse_nested_block(|i| {
307 let count = RepeatCount::parse(context, i)?;
308
309 if matches!(count, RepeatCount::Number(ref n) if n.resolve().is_none()) {
312 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
313 }
314
315 if matches!(count, RepeatCount::AutoFit) {
318 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
319 }
320
321 i.expect_comma()?;
322 let mut names_list = vec![];
323 names_list.push(parse_line_names(i)?); while let Ok(names) = i.try_parse(parse_line_names) {
325 names_list.push(names);
326 }
327
328 Ok(NameRepeat {
329 count,
330 line_names: names_list.into(),
331 })
332 })
333 }
334}
335
336impl Parse for LineNameListValue<Integer> {
337 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
338 if let Ok(repeat) = input.try_parse(|i| NameRepeat::parse(context, i)) {
339 return Ok(LineNameListValue::Repeat(repeat));
340 }
341
342 parse_line_names(input).map(LineNameListValue::LineNames)
343 }
344}
345
346impl LineNameListValue<Integer> {
347 #[inline]
350 pub fn line_names_length(&self) -> usize {
351 match *self {
352 Self::LineNames(..) => 1,
353 Self::Repeat(ref r) => {
354 match r.count {
355 RepeatCount::Number(ref v) => {
358 r.line_names.len() * v.resolve().unwrap() as usize
359 },
360 _ => 0,
361 }
362 },
363 }
364 }
365}
366
367impl Parse for LineNameList<Integer> {
368 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
369 input.expect_ident_matching("subgrid")?;
370
371 let mut auto_repeat = false;
372 let mut expanded_line_names_length = 0;
373 let mut line_names = vec![];
374 while let Ok(value) = input.try_parse(|i| LineNameListValue::parse(context, i)) {
375 match value {
376 LineNameListValue::Repeat(ref r) if r.is_auto_fill() => {
377 if auto_repeat {
378 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
382 }
383 auto_repeat = true;
384 },
385 _ => (),
386 };
387
388 expanded_line_names_length += value.line_names_length();
389 line_names.push(value);
390 }
391
392 Ok(LineNameList {
393 expanded_line_names_length,
394 line_names: line_names.into(),
395 })
396 }
397}