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