tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

align.rs (21879B)


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