1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5 //! Values for CSS Box Alignment properties
6 //!
7 //! https://drafts.csswg.org/css-align/
8
9 use crate::parser::{Parse, ParserContext};
10 use cssparser::Parser;
11 use std::fmt::{self, Write};
12 use style_traits::{CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, ToCss};
13
14 bitflags! {
15 /// Constants shared by multiple CSS Box Alignment properties
16 #[derive(MallocSizeOf, ToComputedValue, ToResolvedValue, ToShmem)]
17 #[repr(C)]
18 pub struct AlignFlags: u8 {
19 // Enumeration stored in the lower 5 bits:
20 /// {align,justify}-{content,items,self}: 'auto'
21 const AUTO = 0;
22 /// 'normal'
23 const NORMAL = 1;
24 /// 'start'
25 const START = 2;
26 /// 'end'
27 const END = 3;
28 /// 'flex-start'
29 const FLEX_START = 4;
30 /// 'flex-end'
31 const FLEX_END = 5;
32 /// 'center'
33 const CENTER = 6;
34 /// 'left'
35 const LEFT = 7;
36 /// 'right'
37 const RIGHT = 8;
38 /// 'baseline'
39 const BASELINE = 9;
40 /// 'last-baseline'
41 const LAST_BASELINE = 10;
42 /// 'stretch'
43 const STRETCH = 11;
44 /// 'self-start'
45 const SELF_START = 12;
46 /// 'self-end'
47 const SELF_END = 13;
48 /// 'space-between'
49 const SPACE_BETWEEN = 14;
50 /// 'space-around'
51 const SPACE_AROUND = 15;
52 /// 'space-evenly'
53 const SPACE_EVENLY = 16;
54
55 // Additional flags stored in the upper bits:
56 /// 'legacy' (mutually exclusive w. SAFE & UNSAFE)
57 const LEGACY = 1 << 5;
58 /// 'safe'
59 const SAFE = 1 << 6;
60 /// 'unsafe' (mutually exclusive w. SAFE)
61 const UNSAFE = 1 << 7;
62
63 /// Mask for the additional flags above.
64 const FLAG_BITS = 0b11100000;
65 }
66 }
67
68 impl AlignFlags {
69 /// Returns the enumeration value stored in the lower 5 bits.
70 #[inline]
value(&self) -> Self71 fn value(&self) -> Self {
72 *self & !AlignFlags::FLAG_BITS
73 }
74 }
75
76 impl ToCss for AlignFlags {
to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,77 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
78 where
79 W: Write,
80 {
81 let extra_flags = *self & AlignFlags::FLAG_BITS;
82 let value = self.value();
83
84 match extra_flags {
85 AlignFlags::LEGACY => {
86 dest.write_str("legacy")?;
87 if value.is_empty() {
88 return Ok(());
89 }
90 dest.write_char(' ')?;
91 },
92 AlignFlags::SAFE => dest.write_str("safe ")?,
93 AlignFlags::UNSAFE => dest.write_str("unsafe ")?,
94 _ => {
95 debug_assert_eq!(extra_flags, AlignFlags::empty());
96 },
97 }
98
99 dest.write_str(match value {
100 AlignFlags::AUTO => "auto",
101 AlignFlags::NORMAL => "normal",
102 AlignFlags::START => "start",
103 AlignFlags::END => "end",
104 AlignFlags::FLEX_START => "flex-start",
105 AlignFlags::FLEX_END => "flex-end",
106 AlignFlags::CENTER => "center",
107 AlignFlags::LEFT => "left",
108 AlignFlags::RIGHT => "right",
109 AlignFlags::BASELINE => "baseline",
110 AlignFlags::LAST_BASELINE => "last baseline",
111 AlignFlags::STRETCH => "stretch",
112 AlignFlags::SELF_START => "self-start",
113 AlignFlags::SELF_END => "self-end",
114 AlignFlags::SPACE_BETWEEN => "space-between",
115 AlignFlags::SPACE_AROUND => "space-around",
116 AlignFlags::SPACE_EVENLY => "space-evenly",
117 _ => unreachable!(),
118 })
119 }
120 }
121
122 /// An axis direction, either inline (for the `justify` properties) or block,
123 /// (for the `align` properties).
124 #[derive(Clone, Copy, PartialEq)]
125 pub enum AxisDirection {
126 /// Block direction.
127 Block,
128 /// Inline direction.
129 Inline,
130 }
131
132 /// Shared value for the `align-content` and `justify-content` properties.
133 ///
134 /// <https://drafts.csswg.org/css-align/#content-distribution>
135 #[derive(
136 Clone,
137 Copy,
138 Debug,
139 Eq,
140 MallocSizeOf,
141 PartialEq,
142 ToComputedValue,
143 ToCss,
144 ToResolvedValue,
145 ToShmem,
146 )]
147 #[repr(C)]
148 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
149 pub struct ContentDistribution {
150 primary: AlignFlags,
151 // FIXME(https://github.com/w3c/csswg-drafts/issues/1002): This will need to
152 // accept fallback alignment, eventually.
153 }
154
155 impl ContentDistribution {
156 /// The initial value 'normal'
157 #[inline]
normal() -> Self158 pub fn normal() -> Self {
159 Self::new(AlignFlags::NORMAL)
160 }
161
162 /// `start`
163 #[inline]
start() -> Self164 pub fn start() -> Self {
165 Self::new(AlignFlags::START)
166 }
167
168 /// The initial value 'normal'
169 #[inline]
new(primary: AlignFlags) -> Self170 pub fn new(primary: AlignFlags) -> Self {
171 Self { primary }
172 }
173
174 /// Returns whether this value is a <baseline-position>.
is_baseline_position(&self) -> bool175 pub fn is_baseline_position(&self) -> bool {
176 matches!(
177 self.primary.value(),
178 AlignFlags::BASELINE | AlignFlags::LAST_BASELINE
179 )
180 }
181
182 /// The primary alignment
183 #[inline]
primary(self) -> AlignFlags184 pub fn primary(self) -> AlignFlags {
185 self.primary
186 }
187
188 /// Parse a value for align-content / justify-content.
parse<'i, 't>( input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result<Self, ParseError<'i>>189 pub fn parse<'i, 't>(
190 input: &mut Parser<'i, 't>,
191 axis: AxisDirection,
192 ) -> Result<Self, ParseError<'i>> {
193 // NOTE Please also update the `list_keywords` function below
194 // when this function is updated.
195
196 // Try to parse normal first
197 if input
198 .try_parse(|i| i.expect_ident_matching("normal"))
199 .is_ok()
200 {
201 return Ok(ContentDistribution::normal());
202 }
203
204 // Parse <baseline-position>, but only on the block axis.
205 if axis == AxisDirection::Block {
206 if let Ok(value) = input.try_parse(parse_baseline) {
207 return Ok(ContentDistribution::new(value));
208 }
209 }
210
211 // <content-distribution>
212 if let Ok(value) = input.try_parse(parse_content_distribution) {
213 return Ok(ContentDistribution::new(value));
214 }
215
216 // <overflow-position>? <content-position>
217 let overflow_position = input
218 .try_parse(parse_overflow_position)
219 .unwrap_or(AlignFlags::empty());
220
221 let content_position = try_match_ident_ignore_ascii_case! { input,
222 "start" => AlignFlags::START,
223 "end" => AlignFlags::END,
224 "flex-start" => AlignFlags::FLEX_START,
225 "flex-end" => AlignFlags::FLEX_END,
226 "center" => AlignFlags::CENTER,
227 "left" if axis == AxisDirection::Inline => AlignFlags::LEFT,
228 "right" if axis == AxisDirection::Inline => AlignFlags::RIGHT,
229 };
230
231 Ok(ContentDistribution::new(
232 content_position | overflow_position,
233 ))
234 }
235
list_keywords(f: KeywordsCollectFn, axis: AxisDirection)236 fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
237 f(&["normal"]);
238 if axis == AxisDirection::Block {
239 list_baseline_keywords(f);
240 }
241 list_content_distribution_keywords(f);
242 list_overflow_position_keywords(f);
243 f(&["start", "end", "flex-start", "flex-end", "center"]);
244 if axis == AxisDirection::Inline {
245 f(&["left", "right"]);
246 }
247 }
248 }
249
250 /// Value for the `align-content` property.
251 ///
252 /// <https://drafts.csswg.org/css-align/#propdef-align-content>
253 #[derive(
254 Clone,
255 Copy,
256 Debug,
257 Eq,
258 MallocSizeOf,
259 PartialEq,
260 ToComputedValue,
261 ToCss,
262 ToResolvedValue,
263 ToShmem,
264 )]
265 #[repr(transparent)]
266 pub struct AlignContent(pub ContentDistribution);
267
268 impl Parse for AlignContent {
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>269 fn parse<'i, 't>(
270 _: &ParserContext,
271 input: &mut Parser<'i, 't>,
272 ) -> Result<Self, ParseError<'i>> {
273 // NOTE Please also update `impl SpecifiedValueInfo` below when
274 // this function is updated.
275 Ok(AlignContent(ContentDistribution::parse(
276 input,
277 AxisDirection::Block,
278 )?))
279 }
280 }
281
282 impl SpecifiedValueInfo for AlignContent {
collect_completion_keywords(f: KeywordsCollectFn)283 fn collect_completion_keywords(f: KeywordsCollectFn) {
284 ContentDistribution::list_keywords(f, AxisDirection::Block);
285 }
286 }
287
288 /// Value for the `align-tracks` property.
289 ///
290 /// <https://github.com/w3c/csswg-drafts/issues/4650>
291 #[derive(
292 Clone,
293 Debug,
294 Default,
295 Eq,
296 MallocSizeOf,
297 PartialEq,
298 SpecifiedValueInfo,
299 ToComputedValue,
300 ToCss,
301 ToResolvedValue,
302 ToShmem,
303 )]
304 #[repr(transparent)]
305 #[css(comma)]
306 pub struct AlignTracks(#[css(iterable, if_empty = "normal")] pub crate::OwnedSlice<AlignContent>);
307
308 impl Parse for AlignTracks {
parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>309 fn parse<'i, 't>(
310 context: &ParserContext,
311 input: &mut Parser<'i, 't>,
312 ) -> Result<Self, ParseError<'i>> {
313 let values = input.parse_comma_separated(|input| AlignContent::parse(context, input))?;
314 Ok(AlignTracks(values.into()))
315 }
316 }
317
318 /// Value for the `justify-content` property.
319 ///
320 /// <https://drafts.csswg.org/css-align/#propdef-justify-content>
321 #[derive(
322 Clone,
323 Copy,
324 Debug,
325 Eq,
326 MallocSizeOf,
327 PartialEq,
328 ToComputedValue,
329 ToCss,
330 ToResolvedValue,
331 ToShmem,
332 )]
333 #[repr(transparent)]
334 pub struct JustifyContent(pub ContentDistribution);
335
336 impl Parse for JustifyContent {
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>337 fn parse<'i, 't>(
338 _: &ParserContext,
339 input: &mut Parser<'i, 't>,
340 ) -> Result<Self, ParseError<'i>> {
341 // NOTE Please also update `impl SpecifiedValueInfo` below when
342 // this function is updated.
343 Ok(JustifyContent(ContentDistribution::parse(
344 input,
345 AxisDirection::Inline,
346 )?))
347 }
348 }
349
350 impl SpecifiedValueInfo for JustifyContent {
collect_completion_keywords(f: KeywordsCollectFn)351 fn collect_completion_keywords(f: KeywordsCollectFn) {
352 ContentDistribution::list_keywords(f, AxisDirection::Inline);
353 }
354 }
355 /// Value for the `justify-tracks` property.
356 ///
357 /// <https://github.com/w3c/csswg-drafts/issues/4650>
358 #[derive(
359 Clone,
360 Debug,
361 Default,
362 Eq,
363 MallocSizeOf,
364 PartialEq,
365 SpecifiedValueInfo,
366 ToComputedValue,
367 ToCss,
368 ToResolvedValue,
369 ToShmem,
370 )]
371 #[repr(transparent)]
372 #[css(comma)]
373 pub struct JustifyTracks(
374 #[css(iterable, if_empty = "normal")] pub crate::OwnedSlice<JustifyContent>,
375 );
376
377 impl Parse for JustifyTracks {
parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>378 fn parse<'i, 't>(
379 context: &ParserContext,
380 input: &mut Parser<'i, 't>,
381 ) -> Result<Self, ParseError<'i>> {
382 let values = input.parse_comma_separated(|input| JustifyContent::parse(context, input))?;
383 Ok(JustifyTracks(values.into()))
384 }
385 }
386
387 /// <https://drafts.csswg.org/css-align/#self-alignment>
388 #[derive(
389 Clone,
390 Copy,
391 Debug,
392 Eq,
393 MallocSizeOf,
394 PartialEq,
395 ToComputedValue,
396 ToCss,
397 ToResolvedValue,
398 ToShmem,
399 )]
400 #[repr(transparent)]
401 pub struct SelfAlignment(pub AlignFlags);
402
403 impl SelfAlignment {
404 /// The initial value 'auto'
405 #[inline]
auto() -> Self406 pub fn auto() -> Self {
407 SelfAlignment(AlignFlags::AUTO)
408 }
409
410 /// Returns whether this value is valid for both axis directions.
is_valid_on_both_axes(&self) -> bool411 pub fn is_valid_on_both_axes(&self) -> bool {
412 match self.0.value() {
413 // left | right are only allowed on the inline axis.
414 AlignFlags::LEFT | AlignFlags::RIGHT => false,
415
416 _ => true,
417 }
418 }
419
420 /// Parse a self-alignment value on one of the axis.
parse<'i, 't>( input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result<Self, ParseError<'i>>421 pub fn parse<'i, 't>(
422 input: &mut Parser<'i, 't>,
423 axis: AxisDirection,
424 ) -> Result<Self, ParseError<'i>> {
425 // NOTE Please also update the `list_keywords` function below
426 // when this function is updated.
427
428 // <baseline-position>
429 //
430 // It's weird that this accepts <baseline-position>, but not
431 // justify-content...
432 if let Ok(value) = input.try_parse(parse_baseline) {
433 return Ok(SelfAlignment(value));
434 }
435
436 // auto | normal | stretch
437 if let Ok(value) = input.try_parse(parse_auto_normal_stretch) {
438 return Ok(SelfAlignment(value));
439 }
440
441 // <overflow-position>? <self-position>
442 let overflow_position = input
443 .try_parse(parse_overflow_position)
444 .unwrap_or(AlignFlags::empty());
445 let self_position = parse_self_position(input, axis)?;
446 Ok(SelfAlignment(overflow_position | self_position))
447 }
448
list_keywords(f: KeywordsCollectFn, axis: AxisDirection)449 fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
450 list_baseline_keywords(f);
451 list_auto_normal_stretch(f);
452 list_overflow_position_keywords(f);
453 list_self_position_keywords(f, axis);
454 }
455 }
456
457 /// The specified value of the align-self property.
458 ///
459 /// <https://drafts.csswg.org/css-align/#propdef-align-self>
460 #[derive(
461 Clone,
462 Copy,
463 Debug,
464 Eq,
465 MallocSizeOf,
466 PartialEq,
467 ToComputedValue,
468 ToCss,
469 ToResolvedValue,
470 ToShmem,
471 )]
472 #[repr(C)]
473 pub struct AlignSelf(pub SelfAlignment);
474
475 impl Parse for AlignSelf {
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>476 fn parse<'i, 't>(
477 _: &ParserContext,
478 input: &mut Parser<'i, 't>,
479 ) -> Result<Self, ParseError<'i>> {
480 // NOTE Please also update `impl SpecifiedValueInfo` below when
481 // this function is updated.
482 Ok(AlignSelf(SelfAlignment::parse(
483 input,
484 AxisDirection::Block,
485 )?))
486 }
487 }
488
489 impl SpecifiedValueInfo for AlignSelf {
collect_completion_keywords(f: KeywordsCollectFn)490 fn collect_completion_keywords(f: KeywordsCollectFn) {
491 SelfAlignment::list_keywords(f, AxisDirection::Block);
492 }
493 }
494
495 /// The specified value of the justify-self property.
496 ///
497 /// <https://drafts.csswg.org/css-align/#propdef-justify-self>
498 #[derive(
499 Clone,
500 Copy,
501 Debug,
502 Eq,
503 MallocSizeOf,
504 PartialEq,
505 ToComputedValue,
506 ToCss,
507 ToResolvedValue,
508 ToShmem,
509 )]
510 #[repr(C)]
511 pub struct JustifySelf(pub SelfAlignment);
512
513 impl Parse for JustifySelf {
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>514 fn parse<'i, 't>(
515 _: &ParserContext,
516 input: &mut Parser<'i, 't>,
517 ) -> Result<Self, ParseError<'i>> {
518 // NOTE Please also update `impl SpecifiedValueInfo` below when
519 // this function is updated.
520 Ok(JustifySelf(SelfAlignment::parse(
521 input,
522 AxisDirection::Inline,
523 )?))
524 }
525 }
526
527 impl SpecifiedValueInfo for JustifySelf {
collect_completion_keywords(f: KeywordsCollectFn)528 fn collect_completion_keywords(f: KeywordsCollectFn) {
529 SelfAlignment::list_keywords(f, AxisDirection::Inline);
530 }
531 }
532
533 /// Value of the `align-items` property
534 ///
535 /// <https://drafts.csswg.org/css-align/#propdef-align-items>
536 #[derive(
537 Clone,
538 Copy,
539 Debug,
540 Eq,
541 MallocSizeOf,
542 PartialEq,
543 ToComputedValue,
544 ToCss,
545 ToResolvedValue,
546 ToShmem,
547 )]
548 #[repr(C)]
549 pub struct AlignItems(pub AlignFlags);
550
551 impl AlignItems {
552 /// The initial value 'normal'
553 #[inline]
normal() -> Self554 pub fn normal() -> Self {
555 AlignItems(AlignFlags::NORMAL)
556 }
557 }
558
559 impl Parse for AlignItems {
560 // normal | stretch | <baseline-position> |
561 // <overflow-position>? <self-position>
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>562 fn parse<'i, 't>(
563 _: &ParserContext,
564 input: &mut Parser<'i, 't>,
565 ) -> Result<Self, ParseError<'i>> {
566 // NOTE Please also update `impl SpecifiedValueInfo` below when
567 // this function is updated.
568
569 // <baseline-position>
570 if let Ok(baseline) = input.try_parse(parse_baseline) {
571 return Ok(AlignItems(baseline));
572 }
573
574 // normal | stretch
575 if let Ok(value) = input.try_parse(parse_normal_stretch) {
576 return Ok(AlignItems(value));
577 }
578 // <overflow-position>? <self-position>
579 let overflow = input
580 .try_parse(parse_overflow_position)
581 .unwrap_or(AlignFlags::empty());
582 let self_position = parse_self_position(input, AxisDirection::Block)?;
583 Ok(AlignItems(self_position | overflow))
584 }
585 }
586
587 impl SpecifiedValueInfo for AlignItems {
collect_completion_keywords(f: KeywordsCollectFn)588 fn collect_completion_keywords(f: KeywordsCollectFn) {
589 list_baseline_keywords(f);
590 list_normal_stretch(f);
591 list_overflow_position_keywords(f);
592 list_self_position_keywords(f, AxisDirection::Block);
593 }
594 }
595
596 /// Value of the `justify-items` property
597 ///
598 /// <https://drafts.csswg.org/css-align/#justify-items-property>
599 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)]
600 #[repr(C)]
601 pub struct JustifyItems(pub AlignFlags);
602
603 impl JustifyItems {
604 /// The initial value 'legacy'
605 #[inline]
legacy() -> Self606 pub fn legacy() -> Self {
607 JustifyItems(AlignFlags::LEGACY)
608 }
609
610 /// The value 'normal'
611 #[inline]
normal() -> Self612 pub fn normal() -> Self {
613 JustifyItems(AlignFlags::NORMAL)
614 }
615 }
616
617 impl Parse for JustifyItems {
parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>>618 fn parse<'i, 't>(
619 _: &ParserContext,
620 input: &mut Parser<'i, 't>,
621 ) -> Result<Self, ParseError<'i>> {
622 // NOTE Please also update `impl SpecifiedValueInfo` below when
623 // this function is updated.
624
625 // <baseline-position>
626 //
627 // It's weird that this accepts <baseline-position>, but not
628 // justify-content...
629 if let Ok(baseline) = input.try_parse(parse_baseline) {
630 return Ok(JustifyItems(baseline));
631 }
632
633 // normal | stretch
634 if let Ok(value) = input.try_parse(parse_normal_stretch) {
635 return Ok(JustifyItems(value));
636 }
637
638 // legacy | [ legacy && [ left | right | center ] ]
639 if let Ok(value) = input.try_parse(parse_legacy) {
640 return Ok(JustifyItems(value));
641 }
642
643 // <overflow-position>? <self-position>
644 let overflow = input
645 .try_parse(parse_overflow_position)
646 .unwrap_or(AlignFlags::empty());
647 let self_position = parse_self_position(input, AxisDirection::Inline)?;
648 Ok(JustifyItems(overflow | self_position))
649 }
650 }
651
652 impl SpecifiedValueInfo for JustifyItems {
collect_completion_keywords(f: KeywordsCollectFn)653 fn collect_completion_keywords(f: KeywordsCollectFn) {
654 list_baseline_keywords(f);
655 list_normal_stretch(f);
656 list_legacy_keywords(f);
657 list_overflow_position_keywords(f);
658 list_self_position_keywords(f, AxisDirection::Inline);
659 }
660 }
661
662 // auto | normal | stretch
parse_auto_normal_stretch<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result<AlignFlags, ParseError<'i>>663 fn parse_auto_normal_stretch<'i, 't>(
664 input: &mut Parser<'i, 't>,
665 ) -> Result<AlignFlags, ParseError<'i>> {
666 // NOTE Please also update the `list_auto_normal_stretch` function
667 // below when this function is updated.
668 try_match_ident_ignore_ascii_case! { input,
669 "auto" => Ok(AlignFlags::AUTO),
670 "normal" => Ok(AlignFlags::NORMAL),
671 "stretch" => Ok(AlignFlags::STRETCH),
672 }
673 }
674
list_auto_normal_stretch(f: KeywordsCollectFn)675 fn list_auto_normal_stretch(f: KeywordsCollectFn) {
676 f(&["auto", "normal", "stretch"]);
677 }
678
679 // normal | stretch
parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>>680 fn parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
681 // NOTE Please also update the `list_normal_stretch` function below
682 // when this function is updated.
683 try_match_ident_ignore_ascii_case! { input,
684 "normal" => Ok(AlignFlags::NORMAL),
685 "stretch" => Ok(AlignFlags::STRETCH),
686 }
687 }
688
list_normal_stretch(f: KeywordsCollectFn)689 fn list_normal_stretch(f: KeywordsCollectFn) {
690 f(&["normal", "stretch"]);
691 }
692
693 // <baseline-position>
parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>>694 fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
695 // NOTE Please also update the `list_baseline_keywords` function
696 // below when this function is updated.
697 try_match_ident_ignore_ascii_case! { input,
698 "baseline" => Ok(AlignFlags::BASELINE),
699 "first" => {
700 input.expect_ident_matching("baseline")?;
701 Ok(AlignFlags::BASELINE)
702 },
703 "last" => {
704 input.expect_ident_matching("baseline")?;
705 Ok(AlignFlags::LAST_BASELINE)
706 },
707 }
708 }
709
list_baseline_keywords(f: KeywordsCollectFn)710 fn list_baseline_keywords(f: KeywordsCollectFn) {
711 f(&["baseline", "first baseline", "last baseline"]);
712 }
713
714 // <content-distribution>
parse_content_distribution<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result<AlignFlags, ParseError<'i>>715 fn parse_content_distribution<'i, 't>(
716 input: &mut Parser<'i, 't>,
717 ) -> Result<AlignFlags, ParseError<'i>> {
718 // NOTE Please also update the `list_content_distribution_keywords`
719 // function below when this function is updated.
720 try_match_ident_ignore_ascii_case! { input,
721 "stretch" => Ok(AlignFlags::STRETCH),
722 "space-between" => Ok(AlignFlags::SPACE_BETWEEN),
723 "space-around" => Ok(AlignFlags::SPACE_AROUND),
724 "space-evenly" => Ok(AlignFlags::SPACE_EVENLY),
725 }
726 }
727
list_content_distribution_keywords(f: KeywordsCollectFn)728 fn list_content_distribution_keywords(f: KeywordsCollectFn) {
729 f(&["stretch", "space-between", "space-around", "space-evenly"]);
730 }
731
732 // <overflow-position>
parse_overflow_position<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result<AlignFlags, ParseError<'i>>733 fn parse_overflow_position<'i, 't>(
734 input: &mut Parser<'i, 't>,
735 ) -> Result<AlignFlags, ParseError<'i>> {
736 // NOTE Please also update the `list_overflow_position_keywords`
737 // function below when this function is updated.
738 try_match_ident_ignore_ascii_case! { input,
739 "safe" => Ok(AlignFlags::SAFE),
740 "unsafe" => Ok(AlignFlags::UNSAFE),
741 }
742 }
743
list_overflow_position_keywords(f: KeywordsCollectFn)744 fn list_overflow_position_keywords(f: KeywordsCollectFn) {
745 f(&["safe", "unsafe"]);
746 }
747
748 // <self-position> | left | right in the inline axis.
parse_self_position<'i, 't>( input: &mut Parser<'i, 't>, axis: AxisDirection, ) -> Result<AlignFlags, ParseError<'i>>749 fn parse_self_position<'i, 't>(
750 input: &mut Parser<'i, 't>,
751 axis: AxisDirection,
752 ) -> Result<AlignFlags, ParseError<'i>> {
753 // NOTE Please also update the `list_self_position_keywords`
754 // function below when this function is updated.
755 Ok(try_match_ident_ignore_ascii_case! { input,
756 "start" => AlignFlags::START,
757 "end" => AlignFlags::END,
758 "flex-start" => AlignFlags::FLEX_START,
759 "flex-end" => AlignFlags::FLEX_END,
760 "center" => AlignFlags::CENTER,
761 "self-start" => AlignFlags::SELF_START,
762 "self-end" => AlignFlags::SELF_END,
763 "left" if axis == AxisDirection::Inline => AlignFlags::LEFT,
764 "right" if axis == AxisDirection::Inline => AlignFlags::RIGHT,
765 })
766 }
767
list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection)768 fn list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
769 f(&[
770 "start",
771 "end",
772 "flex-start",
773 "flex-end",
774 "center",
775 "self-start",
776 "self-end",
777 ]);
778 if axis == AxisDirection::Inline {
779 f(&["left", "right"]);
780 }
781 }
782
parse_left_right_center<'i, 't>( input: &mut Parser<'i, 't>, ) -> Result<AlignFlags, ParseError<'i>>783 fn parse_left_right_center<'i, 't>(
784 input: &mut Parser<'i, 't>,
785 ) -> Result<AlignFlags, ParseError<'i>> {
786 // NOTE Please also update the `list_legacy_keywords` function below
787 // when this function is updated.
788 Ok(try_match_ident_ignore_ascii_case! { input,
789 "left" => AlignFlags::LEFT,
790 "right" => AlignFlags::RIGHT,
791 "center" => AlignFlags::CENTER,
792 })
793 }
794
795 // legacy | [ legacy && [ left | right | center ] ]
parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>>796 fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
797 // NOTE Please also update the `list_legacy_keywords` function below
798 // when this function is updated.
799 let flags = try_match_ident_ignore_ascii_case! { input,
800 "legacy" => {
801 let flags = input.try_parse(parse_left_right_center)
802 .unwrap_or(AlignFlags::empty());
803
804 return Ok(AlignFlags::LEGACY | flags)
805 },
806 "left" => AlignFlags::LEFT,
807 "right" => AlignFlags::RIGHT,
808 "center" => AlignFlags::CENTER,
809 };
810
811 input.expect_ident_matching("legacy")?;
812 Ok(AlignFlags::LEGACY | flags)
813 }
814
list_legacy_keywords(f: KeywordsCollectFn)815 fn list_legacy_keywords(f: KeywordsCollectFn) {
816 f(&["legacy", "left", "right", "center"]);
817 }
818