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 std::mem;
19use style_traits::{ParseError, StyleParseErrorKind};
20
21impl Flex {
22 fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
24 let location = input.current_source_location();
25 match *input.next()? {
26 Token::Dimension {
27 value, ref unit, ..
28 } if FlexUnit::matches(unit) && value.is_sign_positive() => Ok(Self(value)),
29 ref t => Err(location.new_unexpected_token_error(t.clone())),
30 }
31 }
32}
33
34impl<L> TrackBreadth<L> {
35 fn parse_keyword<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
36 #[derive(Parse)]
37 enum TrackKeyword {
38 Auto,
39 MaxContent,
40 MinContent,
41 }
42
43 Ok(match TrackKeyword::parse(input)? {
44 TrackKeyword::Auto => TrackBreadth::Auto,
45 TrackKeyword::MaxContent => TrackBreadth::MaxContent,
46 TrackKeyword::MinContent => TrackBreadth::MinContent,
47 })
48 }
49}
50
51impl Parse for TrackBreadth<LengthPercentage> {
52 fn parse<'i, 't>(
53 context: &ParserContext,
54 input: &mut Parser<'i, 't>,
55 ) -> Result<Self, ParseError<'i>> {
56 if let Ok(lp) = input.try_parse(|i| LengthPercentage::parse_non_negative(context, i)) {
61 return Ok(TrackBreadth::Breadth(lp));
62 }
63
64 if let Ok(f) = input.try_parse(Flex::parse) {
65 return Ok(TrackBreadth::Flex(f));
66 }
67
68 Self::parse_keyword(input)
69 }
70}
71
72impl Parse for TrackSize<LengthPercentage> {
73 fn parse<'i, 't>(
74 context: &ParserContext,
75 input: &mut Parser<'i, 't>,
76 ) -> Result<Self, ParseError<'i>> {
77 if let Ok(b) = input.try_parse(|i| TrackBreadth::parse(context, i)) {
78 return Ok(TrackSize::Breadth(b));
79 }
80
81 if input
82 .try_parse(|i| i.expect_function_matching("minmax"))
83 .is_ok()
84 {
85 return input.parse_nested_block(|input| {
86 let inflexible_breadth =
87 match input.try_parse(|i| LengthPercentage::parse_non_negative(context, i)) {
88 Ok(lp) => TrackBreadth::Breadth(lp),
89 Err(..) => TrackBreadth::parse_keyword(input)?,
90 };
91
92 input.expect_comma()?;
93 Ok(TrackSize::Minmax(
94 inflexible_breadth,
95 TrackBreadth::parse(context, input)?,
96 ))
97 });
98 }
99
100 input.expect_function_matching("fit-content")?;
101 let lp = input.parse_nested_block(|i| LengthPercentage::parse_non_negative(context, i))?;
102 Ok(TrackSize::FitContent(TrackBreadth::Breadth(lp)))
103 }
104}
105
106impl Parse for ImplicitGridTracks<TrackSize<LengthPercentage>> {
107 fn parse<'i, 't>(
108 context: &ParserContext,
109 input: &mut Parser<'i, 't>,
110 ) -> Result<Self, ParseError<'i>> {
111 use style_traits::{Separator, Space};
112 let track_sizes = Space::parse(input, |i| TrackSize::parse(context, i))?;
113 if track_sizes.len() == 1 && track_sizes[0].is_initial() {
114 return Ok(Default::default());
116 }
117 return Ok(ImplicitGridTracks(track_sizes.into()));
118 }
119}
120
121pub fn parse_line_names<'i, 't>(
125 input: &mut Parser<'i, 't>,
126) -> Result<crate::OwnedSlice<CustomIdent>, ParseError<'i>> {
127 input.expect_square_bracket_block()?;
128 input.parse_nested_block(|input| {
129 let mut values = vec![];
130 while let Ok(ident) = input.try_parse(|i| CustomIdent::parse(i, &["span", "auto"])) {
131 values.push(ident);
132 }
133
134 Ok(values.into())
135 })
136}
137
138#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
142enum RepeatType {
143 Auto,
145 Normal,
147 Fixed,
149}
150
151impl TrackRepeat<LengthPercentage, Integer> {
152 fn parse_with_repeat_type<'i, 't>(
153 context: &ParserContext,
154 input: &mut Parser<'i, 't>,
155 ) -> Result<(Self, RepeatType), ParseError<'i>> {
156 input
157 .try_parse(|i| i.expect_function_matching("repeat").map_err(|e| e.into()))
158 .and_then(|_| {
159 input.parse_nested_block(|input| {
160 let count = RepeatCount::parse(context, input)?;
161 input.expect_comma()?;
162
163 let is_auto = count == RepeatCount::AutoFit || count == RepeatCount::AutoFill;
164 let mut repeat_type = if is_auto {
165 RepeatType::Auto
166 } else {
167 RepeatType::Fixed
169 };
170
171 let mut names = vec![];
172 let mut values = vec![];
173 let mut current_names;
174
175 loop {
176 current_names = input.try_parse(parse_line_names).unwrap_or_default();
177 if let Ok(track_size) = input.try_parse(|i| TrackSize::parse(context, i)) {
178 if !track_size.is_fixed() {
179 if is_auto {
180 return Err(input
182 .new_custom_error(StyleParseErrorKind::UnspecifiedError));
183 }
184
185 if repeat_type == RepeatType::Fixed {
186 repeat_type = RepeatType::Normal }
188 }
189
190 values.push(track_size);
191 names.push(current_names);
192 } else {
193 if values.is_empty() {
194 return Err(
196 input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
197 );
198 }
199
200 names.push(current_names); break; }
203 }
204
205 let repeat = TrackRepeat {
206 count,
207 track_sizes: values.into(),
208 line_names: names.into(),
209 };
210
211 Ok((repeat, repeat_type))
212 })
213 })
214 }
215}
216
217impl Parse for TrackList<LengthPercentage, Integer> {
218 fn parse<'i, 't>(
219 context: &ParserContext,
220 input: &mut Parser<'i, 't>,
221 ) -> Result<Self, ParseError<'i>> {
222 let mut current_names = vec![];
223 let mut names = vec![];
224 let mut values = vec![];
225
226 let mut auto_repeat_index = None;
228 let mut at_least_one_not_fixed = false;
230 loop {
231 current_names
232 .extend_from_slice(&mut input.try_parse(parse_line_names).unwrap_or_default());
233 if let Ok(track_size) = input.try_parse(|i| TrackSize::parse(context, i)) {
234 if !track_size.is_fixed() {
235 at_least_one_not_fixed = true;
236 if auto_repeat_index.is_some() {
237 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
239 }
240 }
241
242 let vec = mem::replace(&mut current_names, vec![]);
243 names.push(vec.into());
244 values.push(TrackListValue::TrackSize(track_size));
245 } else if let Ok((repeat, type_)) =
246 input.try_parse(|i| TrackRepeat::parse_with_repeat_type(context, i))
247 {
248 match type_ {
249 RepeatType::Normal => {
250 at_least_one_not_fixed = true;
251 if auto_repeat_index.is_some() {
252 return Err(
254 input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
255 );
256 }
257 },
258 RepeatType::Auto => {
259 if auto_repeat_index.is_some() || at_least_one_not_fixed {
260 return Err(
262 input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
263 );
264 }
265 auto_repeat_index = Some(values.len());
266 },
267 RepeatType::Fixed => {},
268 }
269
270 let vec = mem::replace(&mut current_names, vec![]);
271 names.push(vec.into());
272 values.push(TrackListValue::TrackRepeat(repeat));
273 } else {
274 if values.is_empty() && auto_repeat_index.is_none() {
275 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
276 }
277
278 names.push(current_names.into());
279 break;
280 }
281 }
282
283 Ok(TrackList {
284 auto_repeat_index: auto_repeat_index.unwrap_or(std::usize::MAX),
285 values: values.into(),
286 line_names: names.into(),
287 })
288 }
289}
290
291#[cfg(feature = "gecko")]
292#[inline]
293fn allow_grid_template_subgrids() -> bool {
294 true
295}
296
297#[cfg(feature = "servo")]
298#[inline]
299fn allow_grid_template_subgrids() -> bool {
300 false
301}
302
303#[cfg(feature = "gecko")]
304#[inline]
305fn allow_grid_template_masonry() -> bool {
306 static_prefs::pref!("layout.css.grid-template-masonry-value.enabled")
307}
308
309#[cfg(feature = "servo")]
310#[inline]
311fn allow_grid_template_masonry() -> bool {
312 false
313}
314
315impl Parse for GridTemplateComponent<LengthPercentage, Integer> {
316 fn parse<'i, 't>(
317 context: &ParserContext,
318 input: &mut Parser<'i, 't>,
319 ) -> Result<Self, ParseError<'i>> {
320 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
321 return Ok(GridTemplateComponent::None);
322 }
323
324 Self::parse_without_none(context, input)
325 }
326}
327
328impl GridTemplateComponent<LengthPercentage, Integer> {
329 pub fn parse_without_none<'i, 't>(
331 context: &ParserContext,
332 input: &mut Parser<'i, 't>,
333 ) -> Result<Self, ParseError<'i>> {
334 if allow_grid_template_subgrids() {
335 if let Ok(t) = input.try_parse(|i| LineNameList::parse(context, i)) {
336 return Ok(GridTemplateComponent::Subgrid(Box::new(t)));
337 }
338 }
339 if allow_grid_template_masonry() {
340 if input
341 .try_parse(|i| i.expect_ident_matching("masonry"))
342 .is_ok()
343 {
344 return Ok(GridTemplateComponent::Masonry);
345 }
346 }
347 let track_list = TrackList::parse(context, input)?;
348 Ok(GridTemplateComponent::TrackList(Box::new(track_list)))
349 }
350}
351
352impl Parse for NameRepeat<Integer> {
353 fn parse<'i, 't>(
354 context: &ParserContext,
355 input: &mut Parser<'i, 't>,
356 ) -> Result<Self, ParseError<'i>> {
357 input.expect_function_matching("repeat")?;
358 input.parse_nested_block(|i| {
359 let count = RepeatCount::parse(context, i)?;
360
361 if matches!(count, RepeatCount::Number(ref n) if n.resolve().is_none()) {
364 return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError));
365 }
366
367 if matches!(count, RepeatCount::AutoFit) {
370 return Err(i.new_custom_error(StyleParseErrorKind::UnspecifiedError));
371 }
372
373 i.expect_comma()?;
374 let mut names_list = vec![];
375 names_list.push(parse_line_names(i)?); while let Ok(names) = i.try_parse(parse_line_names) {
377 names_list.push(names);
378 }
379
380 Ok(NameRepeat {
381 count,
382 line_names: names_list.into(),
383 })
384 })
385 }
386}
387
388impl Parse for LineNameListValue<Integer> {
389 fn parse<'i, 't>(
390 context: &ParserContext,
391 input: &mut Parser<'i, 't>,
392 ) -> Result<Self, ParseError<'i>> {
393 if let Ok(repeat) = input.try_parse(|i| NameRepeat::parse(context, i)) {
394 return Ok(LineNameListValue::Repeat(repeat));
395 }
396
397 parse_line_names(input).map(LineNameListValue::LineNames)
398 }
399}
400
401impl LineNameListValue<Integer> {
402 #[inline]
405 pub fn line_names_length(&self) -> usize {
406 match *self {
407 Self::LineNames(..) => 1,
408 Self::Repeat(ref r) => {
409 match r.count {
410 RepeatCount::Number(ref v) => {
413 r.line_names.len() * v.resolve().unwrap() as usize
414 },
415 _ => 0,
416 }
417 },
418 }
419 }
420}
421
422impl Parse for LineNameList<Integer> {
423 fn parse<'i, 't>(
424 context: &ParserContext,
425 input: &mut Parser<'i, 't>,
426 ) -> Result<Self, ParseError<'i>> {
427 input.expect_ident_matching("subgrid")?;
428
429 let mut auto_repeat = false;
430 let mut expanded_line_names_length = 0;
431 let mut line_names = vec![];
432 while let Ok(value) = input.try_parse(|i| LineNameListValue::parse(context, i)) {
433 match value {
434 LineNameListValue::Repeat(ref r) if r.is_auto_fill() => {
435 if auto_repeat {
436 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
440 }
441 auto_repeat = true;
442 },
443 _ => (),
444 };
445
446 expanded_line_names_length += value.line_names_length();
447 line_names.push(value);
448 }
449
450 Ok(LineNameList {
451 expanded_line_names_length,
452 line_names: line_names.into(),
453 })
454 }
455}