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