Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  align.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */


//! Values for CSS Box Alignment properties
//!
//! https://drafts.csswg.org/css-align/

use crate::derives::*;
use crate::parser::{Parse, ParserContext};
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, ToCss};

/// Constants shared by multiple CSS Box Alignment properties
#[derive(
    Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
pub struct AlignFlags(u8);
bitflags! {
    impl AlignFlags: u8 {
        // Enumeration stored in the lower 5 bits:
        /// {align,justify}-{content,items,self}: 'auto'
        const AUTO = 0;
        /// 'normal'
        const NORMAL = 1;
        /// 'start'
        const START = 2;
        /// 'end'
        const END = 3;
        /// 'flex-start'
        const FLEX_START = 4;
        /// 'flex-end'
        const FLEX_END = 5;
        /// 'center'
        const CENTER = 6;
        /// 'left'
        const LEFT = 7;
        /// 'right'
        const RIGHT = 8;
        /// 'baseline'
        const BASELINE = 9;
        /// 'last-baseline'
        const LAST_BASELINE = 10;
        /// 'stretch'
        const STRETCH = 11;
        /// 'self-start'
        const SELF_START = 12;
        /// 'self-end'
        const SELF_END = 13;
        /// 'space-between'
        const SPACE_BETWEEN = 14;
        /// 'space-around'
        const SPACE_AROUND = 15;
        /// 'space-evenly'
        const SPACE_EVENLY = 16;
        /// `anchor-center`
        const ANCHOR_CENTER = 17;

        // Additional flags stored in the upper bits:
        /// 'legacy' (mutually exclusive w. SAFE & UNSAFE)
        const LEGACY = 1 << 5;
        /// 'safe'
        const SAFE = 1 << 6;
        /// 'unsafe' (mutually exclusive w. SAFE)
        const UNSAFE = 1 << 7;

        /// Mask for the additional flags above.
        const FLAG_BITS = 0b11100000;
    }
}

impl AlignFlags {
    /// Returns the enumeration value stored in the lower 5 bits.
    #[inline]
    pub fn value(&self) -> Self {
        *self & !AlignFlags::FLAG_BITS
    }

    /// Returns an updated value with the same flags.
    #[inline]
    pub fn with_value(&self, value: AlignFlags) -> Self {
        debug_assert!(!value.intersects(Self::FLAG_BITS));
        value | self.flags()
    }

    /// Returns the flags stored in the upper 3 bits.
    #[inline]
    pub fn flags(&self) -> Self {
        *self & AlignFlags::FLAG_BITS
    }
}

impl ToCss for AlignFlags {
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: Write,
    {
        let flags = self.flags();
        let value = self.value();
        match flags {
            AlignFlags::LEGACY => {
                dest.write_str("legacy")?;
                if value.is_empty() {
                    return Ok(());
                }
                dest.write_char(' ')?;
            },
            AlignFlags::SAFE => dest.write_str("safe ")?,
            AlignFlags::UNSAFE => dest.write_str("unsafe ")?,
            _ => {
                debug_assert_eq!(flags, AlignFlags::empty());
            },
        }

        dest.write_str(match value {
            AlignFlags::AUTO => "auto",
            AlignFlags::NORMAL => "normal",
            AlignFlags::START => "start",
            AlignFlags::END => "end",
            AlignFlags::FLEX_START => "flex-start",
            AlignFlags::FLEX_END => "flex-end",
            AlignFlags::CENTER => "center",
            AlignFlags::LEFT => "left",
            AlignFlags::RIGHT => "right",
            AlignFlags::BASELINE => "baseline",
            AlignFlags::LAST_BASELINE => "last baseline",
            AlignFlags::STRETCH => "stretch",
            AlignFlags::SELF_START => "self-start",
            AlignFlags::SELF_END => "self-end",
            AlignFlags::SPACE_BETWEEN => "space-between",
            AlignFlags::SPACE_AROUND => "space-around",
            AlignFlags::SPACE_EVENLY => "space-evenly",
            AlignFlags::ANCHOR_CENTER => "anchor-center",
            _ => unreachable!(),
        })
    }
}

/// An axis direction, either inline (for the `justify` properties) or block,
/// (for the `align` properties).
#[derive(Clone, Copy, PartialEq)]
pub enum AxisDirection {
    /// Block direction.
    Block,
    /// Inline direction.
    Inline,
}

/// Shared value for the `align-content` and `justify-content` properties.
///
/// <https://drafts.csswg.org/css-align/#content-distribution>
/// <https://drafts.csswg.org/css-align/#propdef-align-content>
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    MallocSizeOf,
    PartialEq,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
    ToTyped,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
#[typed(todo_derive_fields)]
pub struct ContentDistribution {
    primary: AlignFlags,
    // FIXME(https://github.com/w3c/csswg-drafts/issues/1002): This will need to
    // accept fallback alignment, eventually.
}

impl ContentDistribution {
    /// The initial value 'normal'
    #[inline]
    pub fn normal() -> Self {
        Self::new(AlignFlags::NORMAL)
    }

    /// `start`
    #[inline]
    pub fn start() -> Self {
        Self::new(AlignFlags::START)
    }

    /// The initial value 'normal'
    #[inline]
    pub fn new(primary: AlignFlags) -> Self {
        Self { primary }
    }

    /// Returns whether this value is a <baseline-position>.
    pub fn is_baseline_position(&self) -> bool {
        matches!(
            self.primary.value(),
            AlignFlags::BASELINE | AlignFlags::LAST_BASELINE
        )
    }

    /// The primary alignment
    #[inline]
    pub fn primary(self) -> AlignFlags {
        self.primary
    }

    /// Parse a value for align-content
    pub fn parse_block<'i>(
        _: &ParserContext,
        input: &mut Parser<'i, '_>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Block)
    }

    /// Parse a value for justify-content
    pub fn parse_inline<'i>(
        _: &ParserContext,
        input: &mut Parser<'i, '_>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Inline)
    }

    fn parse<'i, 't>(
        input: &mut Parser<'i, 't>,
        axis: AxisDirection,
    ) -> Result<Self, ParseError<'i>> {
        // NOTE Please also update the `list_keywords` function below
        //      when this function is updated.

        // Try to parse normal first
        if input
            .try_parse(|i| i.expect_ident_matching("normal"))
            .is_ok()
        {
            return Ok(ContentDistribution::normal());
        }

        // Parse <baseline-position>, but only on the block axis.
        if axis == AxisDirection::Block {
            if let Ok(value) = input.try_parse(parse_baseline) {
                return Ok(ContentDistribution::new(value));
            }
        }

        // <content-distribution>
        if let Ok(value) = input.try_parse(parse_content_distribution) {
            return Ok(ContentDistribution::new(value));
        }

        // <overflow-position>? <content-position>
        let overflow_position = input
            .try_parse(parse_overflow_position)
            .unwrap_or(AlignFlags::empty());

        let content_position = try_match_ident_ignore_ascii_case! { input,
            "start" => AlignFlags::START,
            "end" => AlignFlags::END,
            "flex-start" => AlignFlags::FLEX_START,
            "flex-end" => AlignFlags::FLEX_END,
            "center" => AlignFlags::CENTER,
            "left" if axis == AxisDirection::Inline => AlignFlags::LEFT,
            "right" if axis == AxisDirection::Inline => AlignFlags::RIGHT,
        };

        Ok(ContentDistribution::new(
            content_position | overflow_position,
        ))
    }
}

impl SpecifiedValueInfo for ContentDistribution {
    fn collect_completion_keywords(f: KeywordsCollectFn) {
        f(&["normal"]);
        list_baseline_keywords(f); // block-axis only
        list_content_distribution_keywords(f);
        list_overflow_position_keywords(f);
        f(&["start""end""flex-start""flex-end""center"]);
        f(&["left""right"]); // inline-axis only
    }
}

/// The specified value of the {align,justify}-self properties.
///
/// <https://drafts.csswg.org/css-align/#self-alignment>
/// <https://drafts.csswg.org/css-align/#propdef-align-self>
#[derive(
    Clone,
    Copy,
    Debug,
    Deref,
    Eq,
    MallocSizeOf,
    PartialEq,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
    ToTyped,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
#[typed(todo_derive_fields)]
pub struct SelfAlignment(pub AlignFlags);

impl SelfAlignment {
    /// The initial value 'auto'
    #[inline]
    pub fn auto() -> Self {
        SelfAlignment(AlignFlags::AUTO)
    }

    /// Returns whether this value is valid for both axis directions.
    pub fn is_valid_on_both_axes(&self) -> bool {
        match self.0.value() {
            // left | right are only allowed on the inline axis.
            AlignFlags::LEFT | AlignFlags::RIGHT => false,

            _ => true,
        }
    }

    /// Parse self-alignment on the block axis (for align-self)
    pub fn parse_block<'i, 't>(
        _: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Block)
    }

    /// Parse self-alignment on the block axis (for align-self)
    pub fn parse_inline<'i, 't>(
        _: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Inline)
    }

    /// Parse a self-alignment value on one of the axes.
    fn parse<'i, 't>(
        input: &mut Parser<'i, 't>,
        axis: AxisDirection,
    ) -> Result<Self, ParseError<'i>> {
        // NOTE Please also update the `list_keywords` function below
        //      when this function is updated.

        // <baseline-position>
        //
        // It's weird that this accepts <baseline-position>, but not
        // justify-content...
        if let Ok(value) = input.try_parse(parse_baseline) {
            return Ok(SelfAlignment(value));
        }

        // auto | normal | stretch
        if let Ok(value) = input.try_parse(parse_auto_normal_stretch) {
            return Ok(SelfAlignment(value));
        }

        // <overflow-position>? <self-position>
        let overflow_position = input
            .try_parse(parse_overflow_position)
            .unwrap_or(AlignFlags::empty());
        let self_position = parse_self_position(input, axis)?;
        Ok(SelfAlignment(overflow_position | self_position))
    }

    fn list_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
        list_baseline_keywords(f);
        list_auto_normal_stretch(f);
        list_overflow_position_keywords(f);
        list_self_position_keywords(f, axis);
    }

    /// Performs a flip of the position, that is, for self-start we return self-end, for left
    /// we return right, etc.
    pub fn flip_position(self) -> Self {
        let flipped_value = match self.0.value() {
            AlignFlags::START => AlignFlags::END,
            AlignFlags::END => AlignFlags::START,
            AlignFlags::FLEX_START => AlignFlags::FLEX_END,
            AlignFlags::FLEX_END => AlignFlags::FLEX_START,
            AlignFlags::LEFT => AlignFlags::RIGHT,
            AlignFlags::RIGHT => AlignFlags::LEFT,
            AlignFlags::SELF_START => AlignFlags::SELF_END,
            AlignFlags::SELF_END => AlignFlags::SELF_START,

            AlignFlags::AUTO
            | AlignFlags::NORMAL
            | AlignFlags::BASELINE
            | AlignFlags::LAST_BASELINE
            | AlignFlags::STRETCH
            | AlignFlags::CENTER
            | AlignFlags::SPACE_BETWEEN
            | AlignFlags::SPACE_AROUND
            | AlignFlags::SPACE_EVENLY
            | AlignFlags::ANCHOR_CENTER => return self,
            _ => {
                debug_assert!(false"Unexpected alignment enumeration value");
                return self;
            },
        };
        self.with_value(flipped_value)
    }

    /// Returns a fixed-up alignment value.
    #[inline]
    pub fn with_value(self, value: AlignFlags) -> Self {
        Self(self.0.with_value(value))
    }
}

impl SpecifiedValueInfo for SelfAlignment {
    fn collect_completion_keywords(f: KeywordsCollectFn) {
        // TODO: This technically lists left/right for align-self. Not amazing but also not sure
        // worth fixing here, could be special-cased on the caller.
        Self::list_keywords(f, AxisDirection::Block);
    }
}

/// Value of the `align-items` and `justify-items` properties
///
/// <https://drafts.csswg.org/css-align/#propdef-align-items>
/// <https://drafts.csswg.org/css-align/#propdef-justify-items>
#[derive(
    Clone,
    Copy,
    Debug,
    Deref,
    Eq,
    MallocSizeOf,
    PartialEq,
    ToComputedValue,
    ToCss,
    ToResolvedValue,
    ToShmem,
    ToTyped,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
#[typed(todo_derive_fields)]
pub struct ItemPlacement(pub AlignFlags);

impl ItemPlacement {
    /// The value 'normal'
    #[inline]
    pub fn normal() -> Self {
        Self(AlignFlags::NORMAL)
    }
}

impl ItemPlacement {
    /// Parse a value for align-items
    pub fn parse_block<'i>(
        _: &ParserContext,
        input: &mut Parser<'i, '_>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Block)
    }

    /// Parse a value for justify-items
    pub fn parse_inline<'i>(
        _: &ParserContext,
        input: &mut Parser<'i, '_>,
    ) -> Result<Self, ParseError<'i>> {
        Self::parse(input, AxisDirection::Inline)
    }

    fn parse<'i, 't>(
        input: &mut Parser<'i, 't>,
        axis: AxisDirection,
    ) -> Result<Self, ParseError<'i>> {
        // NOTE Please also update `impl SpecifiedValueInfo` below when
        //      this function is updated.

        // <baseline-position>
        if let Ok(baseline) = input.try_parse(parse_baseline) {
            return Ok(Self(baseline));
        }

        // normal | stretch
        if let Ok(value) = input.try_parse(parse_normal_stretch) {
            return Ok(Self(value));
        }

        if axis == AxisDirection::Inline {
            // legacy | [ legacy && [ left | right | center ] ]
            if let Ok(value) = input.try_parse(parse_legacy) {
                return Ok(Self(value));
            }
        }

        // <overflow-position>? <self-position>
        let overflow = input
            .try_parse(parse_overflow_position)
            .unwrap_or(AlignFlags::empty());
        let self_position = parse_self_position(input, axis)?;
        Ok(ItemPlacement(self_position | overflow))
    }
}

impl SpecifiedValueInfo for ItemPlacement {
    fn collect_completion_keywords(f: KeywordsCollectFn) {
        list_baseline_keywords(f);
        list_normal_stretch(f);
        list_overflow_position_keywords(f);
        list_self_position_keywords(f, AxisDirection::Block);
    }
}

/// Value of the `justify-items` property
///
/// <https://drafts.csswg.org/css-align/#justify-items-property>
#[derive(
    Clone, Copy, Debug, Deref, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem, ToTyped,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
pub struct JustifyItems(pub ItemPlacement);

impl JustifyItems {
    /// The initial value 'legacy'
    #[inline]
    pub fn legacy() -> Self {
        Self(ItemPlacement(AlignFlags::LEGACY))
    }

    /// The value 'normal'
    #[inline]
    pub fn normal() -> Self {
        Self(ItemPlacement::normal())
    }
}

impl Parse for JustifyItems {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        ItemPlacement::parse_inline(context, input).map(Self)
    }
}

impl SpecifiedValueInfo for JustifyItems {
    fn collect_completion_keywords(f: KeywordsCollectFn) {
        ItemPlacement::collect_completion_keywords(f);
        list_legacy_keywords(f); // Inline axis only
    }
}

// auto | normal | stretch
fn parse_auto_normal_stretch<'i, 't>(
    input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_auto_normal_stretch` function
    //      below when this function is updated.
    try_match_ident_ignore_ascii_case! { input,
        "auto" => Ok(AlignFlags::AUTO),
        "normal" => Ok(AlignFlags::NORMAL),
        "stretch" => Ok(AlignFlags::STRETCH),
    }
}

fn list_auto_normal_stretch(f: KeywordsCollectFn) {
    f(&["auto""normal""stretch"]);
}

// normal | stretch
fn parse_normal_stretch<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_normal_stretch` function below
    //      when this function is updated.
    try_match_ident_ignore_ascii_case! { input,
        "normal" => Ok(AlignFlags::NORMAL),
        "stretch" => Ok(AlignFlags::STRETCH),
    }
}

fn list_normal_stretch(f: KeywordsCollectFn) {
    f(&["normal""stretch"]);
}

// <baseline-position>
fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_baseline_keywords` function
    //      below when this function is updated.
    try_match_ident_ignore_ascii_case! { input,
        "baseline" => Ok(AlignFlags::BASELINE),
        "first" => {
            input.expect_ident_matching("baseline")?;
            Ok(AlignFlags::BASELINE)
        },
        "last" => {
            input.expect_ident_matching("baseline")?;
            Ok(AlignFlags::LAST_BASELINE)
        },
    }
}

fn list_baseline_keywords(f: KeywordsCollectFn) {
    f(&["baseline""first baseline""last baseline"]);
}

// <content-distribution>
fn parse_content_distribution<'i, 't>(
    input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_content_distribution_keywords`
    //      function below when this function is updated.
    try_match_ident_ignore_ascii_case! { input,
        "stretch" => Ok(AlignFlags::STRETCH),
        "space-between" => Ok(AlignFlags::SPACE_BETWEEN),
        "space-around" => Ok(AlignFlags::SPACE_AROUND),
        "space-evenly" => Ok(AlignFlags::SPACE_EVENLY),
    }
}

fn list_content_distribution_keywords(f: KeywordsCollectFn) {
    f(&["stretch""space-between""space-around""space-evenly"]);
}

// <overflow-position>
fn parse_overflow_position<'i, 't>(
    input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_overflow_position_keywords`
    //      function below when this function is updated.
    try_match_ident_ignore_ascii_case! { input,
        "safe" => Ok(AlignFlags::SAFE),
        "unsafe" => Ok(AlignFlags::UNSAFE),
    }
}

fn list_overflow_position_keywords(f: KeywordsCollectFn) {
    f(&["safe""unsafe"]);
}

// <self-position> | left | right in the inline axis.
fn parse_self_position<'i, 't>(
    input: &mut Parser<'i, 't>,
    axis: AxisDirection,
) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_self_position_keywords`
    //      function below when this function is updated.
    Ok(try_match_ident_ignore_ascii_case! { input,
        "start" => AlignFlags::START,
        "end" => AlignFlags::END,
        "flex-start" => AlignFlags::FLEX_START,
        "flex-end" => AlignFlags::FLEX_END,
        "center" => AlignFlags::CENTER,
        "self-start" => AlignFlags::SELF_START,
        "self-end" => AlignFlags::SELF_END,
        "left" if axis == AxisDirection::Inline => AlignFlags::LEFT,
        "right" if axis == AxisDirection::Inline => AlignFlags::RIGHT,
        "anchor-center" if static_prefs::pref!("layout.css.anchor-positioning.enabled") => AlignFlags::ANCHOR_CENTER,
    })
}

fn list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection) {
    f(&[
        "start",
        "end",
        "flex-start",
        "flex-end",
        "center",
        "self-start",
        "self-end",
    ]);

    if static_prefs::pref!("layout.css.anchor-positioning.enabled") {
        f(&["anchor-center"]);
    }

    if axis == AxisDirection::Inline {
        f(&["left""right"]);
    }
}

fn parse_left_right_center<'i, 't>(
    input: &mut Parser<'i, 't>,
) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_legacy_keywords` function below
    //      when this function is updated.
    Ok(try_match_ident_ignore_ascii_case! { input,
        "left" => AlignFlags::LEFT,
        "right" => AlignFlags::RIGHT,
        "center" => AlignFlags::CENTER,
    })
}

// legacy | [ legacy && [ left | right | center ] ]
fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
    // NOTE Please also update the `list_legacy_keywords` function below
    //      when this function is updated.
    let flags = try_match_ident_ignore_ascii_case! { input,
        "legacy" => {
            let flags = input.try_parse(parse_left_right_center)
                .unwrap_or(AlignFlags::empty());

            return Ok(AlignFlags::LEGACY | flags)
        },
        "left" => AlignFlags::LEFT,
        "right" => AlignFlags::RIGHT,
        "center" => AlignFlags::CENTER,
    };

    input.expect_ident_matching("legacy")?;
    Ok(AlignFlags::LEGACY | flags)
}

fn list_legacy_keywords(f: KeywordsCollectFn) {
    f(&["legacy""left""right""center"]);
}

Messung V0.5 in Prozent
C=92 H=96 G=93

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002