1use crate::derives::*;
9use crate::parser::{Parse, ParserContext};
10use crate::values::generics::grid::{
11 Flex, FlexUnit, GridTemplateComponent, ImplicitGridTracks, RepeatCount,
12};
13use crate::values::generics::grid::{LineNameList, LineNameListValue, NameRepeat, TrackBreadth};
14use crate::values::generics::grid::{TrackList, TrackListValue, TrackRepeat, TrackSize};
15use crate::values::specified::{Integer, LengthPercentage};
16use crate::values::CustomIdent;
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
214 .extend_from_slice(&mut input.try_parse(parse_line_names).unwrap_or_default());
215 if let Ok(track_size) = input.try_parse(|i| TrackSize::parse(context, i)) {
216 if !track_size.is_fixed() {
217 at_least_one_not_fixed = true;
218 if auto_repeat_index.is_some() {
219 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
221 }
222 }
223
224 let vec = std::mem::take(&mut current_names);
225 names.push(vec.into());
226 values.push(TrackListValue::TrackSize(track_size));
227 continue;
228 }
229 if let Ok((repeat, type_)) =
230 input.try_parse(|i| TrackRepeat::parse_with_repeat_type(context, i))
231 {
232 match type_ {
233 RepeatType::Normal => {
234 at_least_one_not_fixed = true;
235 if auto_repeat_index.is_some() {
236 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
238 }
239 },
240 RepeatType::Auto => {
241 if auto_repeat_index.is_some() || at_least_one_not_fixed {
242 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
244 }
245 auto_repeat_index = Some(values.len());
246 },
247 RepeatType::Fixed => {},
248 }
249
250 let vec = std::mem::take(&mut current_names);
251 names.push(vec.into());
252 values.push(TrackListValue::TrackRepeat(repeat));
253 continue;
254 }
255 if values.is_empty() && auto_repeat_index.is_none() {
256 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
257 }
258 names.push(current_names.into());
259 break;
260 }
261
262 Ok(TrackList {
263 auto_repeat_index: auto_repeat_index.unwrap_or(usize::MAX),
264 values: values.into(),
265 line_names: names.into(),
266 })
267 }
268}
269
270#[inline]
271fn allow_grid_template_subgrids() -> bool {
272 crate::pref!("layout.css.grid-template-subgrid-value.enabled", gecko = true)
273}
274
275#[inline]
276fn allow_grid_template_masonry() -> bool {
277 crate::pref!("layout.css.grid-template-masonry-value.enabled")
278}
279
280impl Parse for GridTemplateComponent<LengthPercentage, Integer> {
281 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
282 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
283 return Ok(GridTemplateComponent::None);
284 }
285
286 Self::parse_without_none(context, input)
287 }
288}
289
290impl GridTemplateComponent<LengthPercentage, Integer> {
291 pub fn parse_without_none(
293 context: &ParserContext,
294 input: &mut Parser,
295 ) -> Result<Self, ParseError> {
296 if allow_grid_template_subgrids() {
297 if let Ok(t) = input.try_parse(|i| LineNameList::parse(context, i)) {
298 return Ok(GridTemplateComponent::Subgrid(Box::new(t)));
299 }
300 }
301 if allow_grid_template_masonry()
302 && input
303 .try_parse(|i| i.expect_ident_matching("masonry"))
304 .is_ok()
305 {
306 return Ok(GridTemplateComponent::Masonry);
307 }
308 let track_list = TrackList::parse(context, input)?;
309 Ok(GridTemplateComponent::TrackList(Box::new(track_list)))
310 }
311}
312
313impl Parse for NameRepeat<Integer> {
314 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
315 input.expect_function_matching("repeat")?;
316 input.parse_nested_block(|i| {
317 let count = RepeatCount::parse(context, i)?;
318
319 if matches!(count, RepeatCount::Number(ref n) if n.resolve().is_none()) {
322 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
323 }
324
325 if matches!(count, RepeatCount::AutoFit) {
328 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
329 }
330
331 i.expect_comma()?;
332 let mut names_list = vec![];
333 names_list.push(parse_line_names(i)?); while let Ok(names) = i.try_parse(parse_line_names) {
335 names_list.push(names);
336 }
337
338 Ok(NameRepeat {
339 count,
340 line_names: names_list.into(),
341 })
342 })
343 }
344}
345
346impl Parse for LineNameListValue<Integer> {
347 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
348 if let Ok(repeat) = input.try_parse(|i| NameRepeat::parse(context, i)) {
349 return Ok(LineNameListValue::Repeat(repeat));
350 }
351
352 parse_line_names(input).map(LineNameListValue::LineNames)
353 }
354}
355
356impl LineNameListValue<Integer> {
357 #[inline]
360 pub fn line_names_length(&self) -> usize {
361 match *self {
362 Self::LineNames(..) => 1,
363 Self::Repeat(ref r) => {
364 match r.count {
365 RepeatCount::Number(ref v) => {
368 r.line_names.len() * v.resolve().unwrap() as usize
369 },
370 _ => 0,
371 }
372 },
373 }
374 }
375}
376
377impl Parse for LineNameList<Integer> {
378 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
379 input.expect_ident_matching("subgrid")?;
380
381 let mut auto_repeat = false;
382 let mut expanded_line_names_length = 0;
383 let mut line_names = vec![];
384 while let Ok(value) = input.try_parse(|i| LineNameListValue::parse(context, i)) {
385 match value {
386 LineNameListValue::Repeat(ref r) if r.is_auto_fill() => {
387 if auto_repeat {
388 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
392 }
393 auto_repeat = true;
394 },
395 _ => (),
396 };
397
398 expanded_line_names_length += value.line_names_length();
399 line_names.push(value);
400 }
401
402 Ok(LineNameList {
403 expanded_line_names_length,
404 line_names: line_names.into(),
405 })
406 }
407}