diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h b/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h index d7606b51f20..15e5037c684 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSKeywords.h @@ -25,9 +25,15 @@ enum class CSSKeyword : uint8_t { Absolute, Auto, Baseline, + Block, Center, + Clip, Column, ColumnReverse, + Content, + Contents, + End, + Fixed, Flex, FlexEnd, FlexStart, @@ -35,8 +41,16 @@ enum class CSSKeyword : uint8_t { Inherit, Initial, Inline, + InlineBlock, + InlineFlex, + InlineGrid, Ltr, + Grid, + MaxContent, + Medium, + MinContent, None, + Normal, NoWrap, Relative, Row, @@ -46,8 +60,12 @@ enum class CSSKeyword : uint8_t { SpaceAround, SpaceBetween, SpaceEvenly, + Start, Static, + Sticky, Stretch, + Thick, + Thin, Unset, Visible, Wrap, @@ -55,159 +73,21 @@ enum class CSSKeyword : uint8_t { }; /** - * Represents a set of CSS keywords, including CSS-wide keywords. + * Represents a contrained set of CSS keywords. */ template -concept CSSKeywordSet = std::is_enum_v && requires { - { T::Inherit } -> std::same_as; - { T::Initial } -> std::same_as; - { T::Unset } -> std::same_as; -}; - -/** - * Defines a new set of CSS keywords - */ -#define CSS_DEFINE_KEYWORD_SET(name, ...) \ - enum class name : uint8_t { \ - Inherit = to_underlying(CSSKeyword::Inherit), \ - Initial = to_underlying(CSSKeyword::Initial), \ - Unset = to_underlying(CSSKeyword::Unset), \ - __VA_ARGS__ \ - }; +concept CSSKeywordSet = std::is_enum_v && std:: + is_same_v, std::underlying_type_t>; /** * CSS-wide keywords. * https://www.w3.org/TR/css-values-4/#common-keywords */ -CSS_DEFINE_KEYWORD_SET(CSSWideKeyword) - -/** - * CSS-wide keywords along with a context-dependent "auto" keyword. - */ -CSS_DEFINE_KEYWORD_SET(CSSAutoKeyword, Auto = to_underlying(CSSKeyword::Auto)) - -/** - * Keywords for the CSS "align-content" property. - * https://www.w3.org/TR/css-flexbox-1/#align-content-property - * https://www.w3.org/TR/css-align-3/#align-justify-content - */ -CSS_DEFINE_KEYWORD_SET( - CSSAlignContent, - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - SpaceAround = to_underlying(CSSKeyword::SpaceAround), - SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), - SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly), - Stretch = to_underlying(CSSKeyword::Stretch)) - -/** - * Keywords for the CSS "align-items" property. - * https://www.w3.org/TR/css-flexbox-1/#align-items-property - * https://www.w3.org/TR/css-align-3/#align-items-property - */ -CSS_DEFINE_KEYWORD_SET( - CSSAlignItems, - Baseline = to_underlying(CSSKeyword::Baseline), - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - Stretch = to_underlying(CSSKeyword::Stretch)) - -/** - * Keywords for the CSS "align-items" property. - * https://www.w3.org/TR/css-flexbox-1/#align-self-property - * https://www.w3.org/TR/css-align-3/#align-self-property - */ -CSS_DEFINE_KEYWORD_SET( - CSSAlignSelf, - Auto = to_underlying(CSSKeyword::Auto), - Baseline = to_underlying(CSSKeyword::Baseline), - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - Stretch = to_underlying(CSSKeyword::Stretch)) - -/** - * Keywords for the CSS "direction" property. - * https://www.w3.org/TR/css-writing-modes-3/#direction - */ -CSS_DEFINE_KEYWORD_SET( - CSSDirection, - Ltr = to_underlying(CSSKeyword::Ltr), - Rtl = to_underlying(CSSKeyword::Rtl)) - -/** - * Keywords for the CSS "display" property. - * https://www.w3.org/TR/css-display-3/#display-type - */ -CSS_DEFINE_KEYWORD_SET( - CSSDisplay, - Flex = to_underlying(CSSKeyword::Flex), - Inline = to_underlying(CSSKeyword::Inline), - None = to_underlying(CSSKeyword::None)) - -/** - * Keywords for the CSS "flex-direction" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-direction-property - */ -CSS_DEFINE_KEYWORD_SET( - CSSFlexDirection, - Column = to_underlying(CSSKeyword::Column), - ColumnReverse = to_underlying(CSSKeyword::ColumnReverse), - Row = to_underlying(CSSKeyword::Row), - RowReverse = to_underlying(CSSKeyword::RowReverse)) - -/** - * Keywords for the CSS "flex-wrap" property. - * https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property - */ -CSS_DEFINE_KEYWORD_SET( - CSSFlexWrap, - NoWrap = to_underlying(CSSKeyword::NoWrap), - Wrap = to_underlying(CSSKeyword::Wrap), - WrapReverse = to_underlying(CSSKeyword::WrapReverse)) - -/** - * Keywords for the CSS "justify-content" property. - * https://www.w3.org/TR/css-flexbox-1/#justify-content-property - * https://www.w3.org/TR/css-align-3/#align-justify-content - */ -CSS_DEFINE_KEYWORD_SET( - CSSJustifyContent, - Center = to_underlying(CSSKeyword::Center), - FlexEnd = to_underlying(CSSKeyword::FlexEnd), - FlexStart = to_underlying(CSSKeyword::FlexStart), - SpaceAround = to_underlying(CSSKeyword::SpaceAround), - SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), - SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly)) - -/** - * Keywords for the CSS "overflow" property. - * https://www.w3.org/TR/css-overflow-3/#overflow-control - */ -CSS_DEFINE_KEYWORD_SET( - CSSOverflow, - Hidden = to_underlying(CSSKeyword::Hidden), - Scroll = to_underlying(CSSKeyword::Scroll), - Visible = to_underlying(CSSKeyword::Visible)) - -/** - * Keywords for the CSS "position" property. - * https://www.w3.org/TR/css-position-3/#position-property - */ -CSS_DEFINE_KEYWORD_SET( - CSSPosition, - Absolute = to_underlying(CSSKeyword::Absolute), - Relative = to_underlying(CSSKeyword::Relative), - Static = to_underlying(CSSKeyword::Static)) - -/** - * Compare two keywords of any representation - */ -constexpr bool operator==(CSSKeywordSet auto lhs, CSSKeywordSet auto rhs) { - return to_underlying(lhs) == to_underlying(rhs); -} +enum class CSSWideKeyword : std::underlying_type_t { + Inherit = to_underlying(CSSKeyword::Inherit), + Initial = to_underlying(CSSKeyword::Initial), + Unset = to_underlying(CSSKeyword::Unset), +}; /** * Defines a concept for whether an enum has a given member. @@ -221,18 +101,32 @@ constexpr bool operator==(CSSKeywordSet auto lhs, CSSKeywordSet auto rhs) { CSS_DEFINE_KEYWORD_CONEPTS(Absolute) CSS_DEFINE_KEYWORD_CONEPTS(Auto) CSS_DEFINE_KEYWORD_CONEPTS(Baseline) +CSS_DEFINE_KEYWORD_CONEPTS(Block) CSS_DEFINE_KEYWORD_CONEPTS(Center) +CSS_DEFINE_KEYWORD_CONEPTS(Clip) CSS_DEFINE_KEYWORD_CONEPTS(Column) CSS_DEFINE_KEYWORD_CONEPTS(ColumnReverse) +CSS_DEFINE_KEYWORD_CONEPTS(Content) +CSS_DEFINE_KEYWORD_CONEPTS(Contents) +CSS_DEFINE_KEYWORD_CONEPTS(End) +CSS_DEFINE_KEYWORD_CONEPTS(Fixed) CSS_DEFINE_KEYWORD_CONEPTS(Flex) CSS_DEFINE_KEYWORD_CONEPTS(FlexEnd) CSS_DEFINE_KEYWORD_CONEPTS(FlexStart) +CSS_DEFINE_KEYWORD_CONEPTS(Grid) CSS_DEFINE_KEYWORD_CONEPTS(Hidden) CSS_DEFINE_KEYWORD_CONEPTS(Inherit) CSS_DEFINE_KEYWORD_CONEPTS(Initial) CSS_DEFINE_KEYWORD_CONEPTS(Inline) +CSS_DEFINE_KEYWORD_CONEPTS(InlineBlock) +CSS_DEFINE_KEYWORD_CONEPTS(InlineFlex) +CSS_DEFINE_KEYWORD_CONEPTS(InlineGrid) CSS_DEFINE_KEYWORD_CONEPTS(Ltr) +CSS_DEFINE_KEYWORD_CONEPTS(MaxContent) +CSS_DEFINE_KEYWORD_CONEPTS(Medium) +CSS_DEFINE_KEYWORD_CONEPTS(MinContent) CSS_DEFINE_KEYWORD_CONEPTS(None) +CSS_DEFINE_KEYWORD_CONEPTS(Normal) CSS_DEFINE_KEYWORD_CONEPTS(NoWrap) CSS_DEFINE_KEYWORD_CONEPTS(Relative) CSS_DEFINE_KEYWORD_CONEPTS(Row) @@ -242,8 +136,12 @@ CSS_DEFINE_KEYWORD_CONEPTS(Scroll) CSS_DEFINE_KEYWORD_CONEPTS(SpaceAround) CSS_DEFINE_KEYWORD_CONEPTS(SpaceBetween) CSS_DEFINE_KEYWORD_CONEPTS(SpaceEvenly) +CSS_DEFINE_KEYWORD_CONEPTS(Start) CSS_DEFINE_KEYWORD_CONEPTS(Static) +CSS_DEFINE_KEYWORD_CONEPTS(Sticky) CSS_DEFINE_KEYWORD_CONEPTS(Stretch) +CSS_DEFINE_KEYWORD_CONEPTS(Thick) +CSS_DEFINE_KEYWORD_CONEPTS(Thin) CSS_DEFINE_KEYWORD_CONEPTS(Unset) CSS_DEFINE_KEYWORD_CONEPTS(Visible) CSS_DEFINE_KEYWORD_CONEPTS(Wrap) @@ -279,11 +177,21 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return KeywordT::Baseline; } break; + case fnv1a("block"): + if constexpr (detail::hasBlock) { + return KeywordT::Block; + } + break; case fnv1a("center"): if constexpr (detail::hasCenter) { return KeywordT::Center; } break; + case fnv1a("clip"): + if constexpr (detail::hasClip) { + return KeywordT::Clip; + } + break; case fnv1a("column"): if constexpr (detail::hasColumn) { return KeywordT::Column; @@ -294,6 +202,25 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return KeywordT::ColumnReverse; } break; + case fnv1a("content"): + if constexpr (detail::hasContent) { + return KeywordT::Content; + } + break; + case fnv1a("contents"): + if constexpr (detail::hasContents) { + return KeywordT::Contents; + } + break; + case fnv1a("end"): + if constexpr (detail::hasEnd) { + return KeywordT::End; + } + break; + case fnv1a("fixed"): + if constexpr (detail::hasFixed) { + return KeywordT::Fixed; + } case fnv1a("flex"): if constexpr (detail::hasFlex) { return KeywordT::Flex; @@ -309,6 +236,11 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return KeywordT::FlexStart; } break; + case fnv1a("grid"): + if constexpr (detail::hasGrid) { + return KeywordT::Grid; + } + break; case fnv1a("hidden"): if constexpr (detail::hasHidden) { return KeywordT::Hidden; @@ -324,17 +256,52 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return KeywordT::Inline; } break; + case fnv1a("inline-block"): + if constexpr (detail::hasInlineBlock) { + return KeywordT::InlineBlock; + } + break; + case fnv1a("inline-flex"): + if constexpr (detail::hasInlineFlex) { + return KeywordT::InlineFlex; + } + break; + case fnv1a("inline-grid"): + if constexpr (detail::hasInlineGrid) { + return KeywordT::InlineGrid; + } + break; case fnv1a("ltr"): if constexpr (detail::hasLtr) { return KeywordT::Ltr; } break; + case fnv1a("max-content"): + if constexpr (detail::hasMaxContent) { + return KeywordT::MaxContent; + } + break; + case fnv1a("medium"): + if constexpr (detail::hasMedium) { + return KeywordT::Medium; + } + break; + case fnv1a("min-content"): + if constexpr (detail::hasMinContent) { + return KeywordT::MinContent; + } + break; case fnv1a("none"): if constexpr (detail::hasNone) { return KeywordT::None; } break; - case fnv1a("no-wrap"): + case fnv1a("normal"): + if constexpr (detail::hasNormal) { + return KeywordT::Normal; + } + break; + case fnv1a("nowrap"): if constexpr (detail::hasNoWrap) { return KeywordT::NoWrap; } @@ -379,16 +346,35 @@ constexpr std::optional parseCSSKeyword(std::string_view ident) { return KeywordT::Scroll; } break; + case fnv1a("start"): + if constexpr (detail::hasStart) { + return KeywordT::Start; + } case fnv1a("static"): if constexpr (detail::hasStatic) { return KeywordT::Static; } break; + case fnv1a("sticky"): + if constexpr (detail::hasSticky) { + return KeywordT::Sticky; + } + break; case fnv1a("stretch"): if constexpr (detail::hasStretch) { return KeywordT::Stretch; } break; + case fnv1a("thick"): + if constexpr (detail::hasThick) { + return KeywordT::Thick; + } + break; + case fnv1a("thin"): + if constexpr (detail::hasThin) { + return KeywordT::Thin; + } + break; case fnv1a("unset"): if constexpr (detail::hasUnset) { return KeywordT::Unset; diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSParser.h b/packages/react-native/ReactCommon/react/renderer/css/CSSParser.h index 6c31b259ab1..f9ad61c4846 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSParser.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSParser.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -23,13 +24,13 @@ class CSSParser { explicit constexpr CSSParser(std::string_view css) : tokenizer_{css}, currentToken_(tokenizer_.next()) {} - template - constexpr CSSValueVariant - consumeComponentValue() { - using CSSValueT = CSSValueVariant; + template + constexpr CSSValueVariant consumeComponentValue() { + using CSSValueT = CSSValueVariant; switch (peek().type()) { case CSSTokenType::Ident: - if (auto keywordValue = consumeIdentToken()) { + if (auto keywordValue = + consumeIdentToken()) { return *keywordValue; } break; @@ -80,16 +81,26 @@ class CSSParser { return prevToken; } - template + template constexpr std::optional consumeIdentToken() { - if (auto keyword = - parseCSSKeyword(consumeToken().stringValue())) { - return CSSValueT::keyword(*keyword); + if constexpr (!std::is_same_v) { + if (auto keyword = parseCSSKeyword( + peek().stringValue())) { + consumeToken(); + return CSSValueT::keyword(*keyword); + } + } + if constexpr (traits::containsType()) { + if (auto keyword = + parseCSSKeyword(peek().stringValue())) { + consumeToken(); + return CSSValueT::cssWideKeyword(*keyword); + } } return {}; } - template + template constexpr std::optional consumeDimensionToken() { if constexpr (traits::containsType()) { if (auto unit = parseCSSLengthUnit(peek().unit())) { @@ -99,7 +110,7 @@ class CSSParser { return {}; } - template + template constexpr std::optional consumePercentageToken() { if constexpr (traits::containsType()) { return CSSValueT::percentage(consumeToken().numericValue()); @@ -107,7 +118,7 @@ class CSSParser { return {}; } - template + template constexpr std::optional consumeNumberToken() { // = [ / ]? // https://www.w3.org/TR/css-values-4/#ratio @@ -174,20 +185,36 @@ class CSSParser { * * https://www.w3.org/TR/css-syntax-3/#parse-component-value */ -template -constexpr CSSValueVariant parseCSSComponentValue( - std::string_view css) { +template +constexpr void parseCSSComponentValue( + std::string_view css, + CSSValueVariant& value) { detail::CSSParser parser(css); parser.consumeWhitespace(); - auto value = parser.consumeComponentValue(); + auto componentValue = parser.consumeComponentValue(); parser.consumeWhitespace(); if (parser.hasMoreTokens()) { - return {}; + value = {}; } else { - return value; + value = componentValue; } +}; + +template +CSSValueVariant parseCSSComponentValue(std::string_view css) { + CSSValueVariant value; + parseCSSComponentValue(css, value); + return value; +}; + +template +constexpr auto parseCSSProp(std::string_view css) { + // For now we only allow parsing props composed of a single component value. + CSSSpecifiedValue value; + parseCSSComponentValue(css, value); + return value; } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h b/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h new file mode 100644 index 00000000000..ad982552bcf --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSProperties.h @@ -0,0 +1,712 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react { + +/** + * All CSS properties,including CSS,and React-Native specific shorthands + * https://www.w3.org/TR/css-cascade-4/#css-property + */ +enum class CSSProp { + AlignContent, + AlignItems, + AlignSelf, + AspectRatio, + BorderBlockEndWidth, + BorderBlockStartWidth, + BorderBlockWidth, + BorderBottomWidth, + BorderEndWidth, + BorderHorizontalWidth, + BorderInlineEndWidth, + BorderInlineStartWidth, + BorderInlineWidth, + BorderLeftWidth, + BorderRightWidth, + BorderStartWidth, + BorderTopWidth, + BorderVerticalWidth, + BorderWidth, + Bottom, + ColumnGap, + Direction, + Display, + End, + Flex, + FlexBasis, + FlexDirection, + FlexGrow, + FlexShrink, + FlexWrap, + Gap, + Height, + Inset, + InsetBlock, + InsetBlockEnd, + InsetBlockStart, + InsetInline, + InsetInlineEnd, + InsetInlineStart, + JustifyContent, + Left, + Margin, + MarginBlock, + MarginBlockEnd, + MarginBlockStart, + MarginBottom, + MarginEnd, + MarginHorizontal, + MarginInline, + MarginInlineEnd, + MarginInlineStart, + MarginLeft, + MarginRight, + MarginStart, + MarginTop, + MarginVertical, + MaxHeight, + MaxWidth, + MinHeight, + MinWidth, + Overflow, + Padding, + PaddingBlock, + PaddingBlockEnd, + PaddingBlockStart, + PaddingBottom, + PaddingEnd, + PaddingHorizontal, + PaddingInline, + PaddingInlineEnd, + PaddingInlineStart, + PaddingLeft, + PaddingRight, + PaddingStart, + PaddingTop, + PaddingVertical, + Position, + Right, + RowGap, + Start, + Top, + Width, + // Please update "kCSSPropCount" if adding a new prop to the end +}; + +/** + * The total number of CSS properties. + */ +constexpr auto kCSSPropCount = to_underlying(CSSProp::Width) + 1; + +/** + * CSSPropDefinition associates a CSSProp to its + * supported data types, Keyword, and other behaviors. + */ +template +struct CSSPropDefinition {}; + +template +using CSSAllowedKeywords = typename CSSPropDefinition

::Keyword; + +template +using CSSSpecifiedValue = typename CSSPropDefinition

::SpecifiedValue; + +template +using CSSComputedValue = typename CSSPropDefinition

::ComputedValue; + +/** + * CSS "align-content" property. + * https://www.w3.org/TR/css-flexbox-1/#align-content-property + * https://www.w3.org/TR/css-align-3/#align-justify-content + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Center = to_underlying(CSSKeyword::Center), + FlexEnd = to_underlying(CSSKeyword::FlexEnd), + FlexStart = to_underlying(CSSKeyword::FlexStart), + SpaceAround = to_underlying(CSSKeyword::SpaceAround), + SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), + SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly), + Stretch = to_underlying(CSSKeyword::Stretch), + Start = to_underlying(CSSKeyword::Start), + End = to_underlying(CSSKeyword::End), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "align-items" property. + * https://www.w3.org/TR/css-flexbox-1/#align-items-property + * https://www.w3.org/TR/css-align-3/#align-items-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Baseline = to_underlying(CSSKeyword::Baseline), + Center = to_underlying(CSSKeyword::Center), + FlexEnd = to_underlying(CSSKeyword::FlexEnd), + FlexStart = to_underlying(CSSKeyword::FlexStart), + Stretch = to_underlying(CSSKeyword::Stretch), + Start = to_underlying(CSSKeyword::Start), + End = to_underlying(CSSKeyword::End), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "align-items" property. + * https://www.w3.org/TR/css-flexbox-1/#propdef-align-self + * https://www.w3.org/TR/css-align-3/#align-self-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + Baseline = to_underlying(CSSKeyword::Baseline), + Center = to_underlying(CSSKeyword::Center), + FlexEnd = to_underlying(CSSKeyword::FlexEnd), + FlexStart = to_underlying(CSSKeyword::FlexStart), + Stretch = to_underlying(CSSKeyword::Stretch), + Start = to_underlying(CSSKeyword::Start), + End = to_underlying(CSSKeyword::End), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "aspect-ratio" property. + * https://www.w3.org/TR/css-sizing-4/#aspect-ratio + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "border-width" properties + * https://www.w3.org/TR/css-backgrounds-3/#border-width + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Thin = to_underlying(CSSKeyword::Thin), + Medium = to_underlying(CSSKeyword::Medium), + Thick = to_underlying(CSSKeyword::Thick), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +/** + * CSS "direction" property. + * https://www.w3.org/TR/css-writing-modes-3/#direction + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Ltr = to_underlying(CSSKeyword::Ltr), + Rtl = to_underlying(CSSKeyword::Rtl), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "display" property. + * https://www.w3.org/TR/css-display-3/#display-type + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + None = to_underlying(CSSKeyword::None), + Contents = to_underlying(CSSKeyword::Contents), + Inline = to_underlying(CSSKeyword::Inline), + Block = to_underlying(CSSKeyword::Block), + InlineBlock = to_underlying(CSSKeyword::InlineBlock), + Flex = to_underlying(CSSKeyword::Flex), + InlineFlex = to_underlying(CSSKeyword::InlineFlex), + Grid = to_underlying(CSSKeyword::Grid), + InlineGrid = to_underlying(CSSKeyword::InlineGrid), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex" shorthand property. + * https://www.w3.org/TR/css-flexbox-1/#flex-property + * + * React Native's interpretation of this prop is currently different than in CSS + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + None = to_underlying(CSSKeyword::None), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex-basis" property. + * https://www.w3.org/TR/css-flexbox-1/#flex-basis-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + Content = to_underlying(CSSKeyword::Content), + }; + + using SpecifiedValue = + CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex-direction" property. + * https://www.w3.org/TR/css-flexbox-1/#flex-direction-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Row = to_underlying(CSSKeyword::Row), + RowReverse = to_underlying(CSSKeyword::RowReverse), + Column = to_underlying(CSSKeyword::Column), + ColumnReverse = to_underlying(CSSKeyword::ColumnReverse), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex-grow" property. + * https://www.w3.org/TR/css-flexbox-1/#flex-grow-property + */ +template <> +struct CSSPropDefinition { + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex-shrink" property. + * https://www.w3.org/TR/css-flexbox-1/#flex-shrink-property + */ +template <> +struct CSSPropDefinition { + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "flex-wrap" property. + * https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + NoWrap = to_underlying(CSSKeyword::NoWrap), + Wrap = to_underlying(CSSKeyword::Wrap), + WrapReverse = to_underlying(CSSKeyword::WrapReverse), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS gutter properties. + * https://www.w3.org/TR/css-align-3/#column-row-gap + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Normal = to_underlying(CSSKeyword::Normal), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition : CSSPropDefinition { +}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +/** + * CSS sizing properties + * https://www.w3.org/TR/css-sizing-3/#sizing-properties + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + MaxContent = to_underlying(CSSKeyword::MaxContent), + MinContent = to_underlying(CSSKeyword::MinContent), + }; + + using SpecifiedValue = + CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition : CSSPropDefinition { +}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +/** + * CSS box inset properties + * https://drafts.csswg.org/css-position-3/#insets + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + }; + + using SpecifiedValue = + CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition : CSSPropDefinition { +}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +/** + * CSS "justify-content" property. + * https://www.w3.org/TR/css-flexbox-1/#justify-content-property + * https://www.w3.org/TR/css-align-3/#align-justify-content + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Center = to_underlying(CSSKeyword::Center), + FlexEnd = to_underlying(CSSKeyword::FlexEnd), + FlexStart = to_underlying(CSSKeyword::FlexStart), + SpaceAround = to_underlying(CSSKeyword::SpaceAround), + SpaceBetween = to_underlying(CSSKeyword::SpaceBetween), + SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly), + Start = to_underlying(CSSKeyword::Start), + End = to_underlying(CSSKeyword::End), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS "margin" properties + * https://www.w3.org/TR/css-box-4/#margins + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + }; + + using SpecifiedValue = + CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +/** + * CSS "overflow" property. + * https://www.w3.org/TR/css-overflow-3/#overflow-control + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Auto = to_underlying(CSSKeyword::Auto), + Clip = to_underlying(CSSKeyword::Clip), + Hidden = to_underlying(CSSKeyword::Hidden), + Scroll = to_underlying(CSSKeyword::Scroll), + Visible = to_underlying(CSSKeyword::Visible), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +/** + * CSS padding properties + * https://www.w3.org/TR/css-box-4/#paddings + */ +template <> +struct CSSPropDefinition { + using SpecifiedValue = + CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +template <> +struct CSSPropDefinition + : CSSPropDefinition {}; + +/** + * CSS "position" property. + * https://www.w3.org/TR/css-position-3/#position-property + */ +template <> +struct CSSPropDefinition { + enum class Keyword : std::underlying_type_t { + Static = to_underlying(CSSKeyword::Static), + Relative = to_underlying(CSSKeyword::Relative), + Absolute = to_underlying(CSSKeyword::Absolute), + Fixed = to_underlying(CSSKeyword::Fixed), + Sticky = to_underlying(CSSKeyword::Sticky), + }; + + using SpecifiedValue = CSSValueVariant; + using ComputedValue = CSSValueVariant; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h b/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h index 255db87185a..4663dd9e818 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSValue.h @@ -23,6 +23,7 @@ namespace facebook::react { * https://www.w3.org/TR/css-values-4/#component-types */ enum class CSSValueType : uint8_t { + CSSWideKeyword, Keyword, Length, Number, @@ -31,11 +32,11 @@ enum class CSSValueType : uint8_t { }; /** - * Concrete representation for a CSS basic data type. + * Concrete representation for a CSS basic data type, or keywords * https://www.w3.org/TR/css-values-4/#component-types */ template -concept CSSBasicDataType = std::is_trivially_destructible_v && +concept CSSDataType = std::is_trivially_destructible_v && std::is_default_constructible_v && requires() { sizeof(T); }; @@ -88,9 +89,9 @@ struct CSSRatio { * set of values. */ #pragma pack(push, 1) -template +template class CSSValueVariant { - template + template constexpr ValueT getIf() const { if (type_ == Type) { return *std::launder(reinterpret_cast(data_.data())); @@ -99,16 +100,49 @@ class CSSValueVariant { } } - template + template static constexpr bool canRepresent() { - return traits::containsType(); + return traits::containsType(); } - public: - constexpr CSSValueVariant() - : CSSValueVariant(CSSValueType::Keyword, KeywordT::Unset) {} + template + static constexpr bool hasKeywordSet() { + if constexpr (CSSKeywordSet && !std::is_same_v) { + return true; + } else if constexpr (sizeof...(Rest) == 0) { + return false; + } else { + return hasKeywordSet(); + } + } - static constexpr CSSValueVariant keyword(KeywordT keyword) { + template + struct PackedKeywordSet { + using Type = void; + }; + + template + struct PackedKeywordSet { + using Type = std::conditional_t< + hasKeywordSet(), + T, + typename PackedKeywordSet::Type>; + }; + + public: + using Keyword = typename PackedKeywordSet::Type; + + constexpr CSSValueVariant() requires(canRepresent()) + : CSSValueVariant(CSSValueType::CSSWideKeyword, CSSWideKeyword::Unset) {} + + static constexpr CSSValueVariant cssWideKeyword(CSSWideKeyword keyword) { + return CSSValueVariant( + CSSValueType::CSSWideKeyword, CSSWideKeyword{keyword}); + } + + template + static constexpr CSSValueVariant keyword(KeywordT keyword) requires( + canRepresent()) { return CSSValueVariant(CSSValueType::Keyword, KeywordT{keyword}); } @@ -139,8 +173,14 @@ class CSSValueVariant { return type_; } - constexpr KeywordT getKeyword() const { - return getIf(); + constexpr CSSWideKeyword getCSSWideKeyword() const + requires(canRepresent()) { + return getIf(); + } + + constexpr Keyword getKeyword() const + requires(hasKeywordSet()) { + return getIf(); } constexpr CSSLength getLength() const requires(canRepresent()) { @@ -160,30 +200,29 @@ class CSSValueVariant { return getIf(); } - constexpr operator bool() const { + constexpr operator bool() const requires(canRepresent()) { return *this != CSSValueVariant{}; } constexpr bool operator==(const CSSValueVariant& rhs) const = default; private: - constexpr CSSValueVariant(CSSValueType type, CSSBasicDataType auto&& value) + constexpr CSSValueVariant(CSSValueType type, CSSDataType auto&& value) : type_(type) { new (data_.data()) std::remove_cvref_t{ std::forward(value)}; } CSSValueType type_; - std::array()> data_; + std::array()> data_; }; #pragma pack(pop) -static_assert(sizeof(CSSValueVariant) == 2); -static_assert(sizeof(CSSValueVariant) == 6); +static_assert(sizeof(CSSValueVariant) == 2); +static_assert(sizeof(CSSValueVariant) == 6); static_assert( - sizeof(CSSValueVariant) == 6); -static_assert(sizeof(CSSValueVariant) == 5); -static_assert( - sizeof(CSSValueVariant) == 9); + sizeof(CSSValueVariant) == 6); +static_assert(sizeof(CSSValueVariant) == 5); +static_assert(sizeof(CSSValueVariant) == 9); } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSParserTest.cpp b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSParserTest.cpp index a940fcc922c..280dc43e8be 100644 --- a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSParserTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSParserTest.cpp @@ -11,247 +11,288 @@ namespace facebook::react { TEST(CSSParser, keyword_values) { - auto emptyValue = parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); + auto emptyValue = parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto autoValue = parseCSSComponentValue("auto"); + auto autoValue = parseCSSComponentValue("auto"); EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); - auto autoCapsValue = parseCSSComponentValue("AuTO"); + auto autoCapsValue = + parseCSSComponentValue("AuTO"); EXPECT_EQ(autoCapsValue.type(), CSSValueType::Keyword); EXPECT_EQ(autoCapsValue.getKeyword(), CSSKeyword::Auto); - auto autoDisallowedValue = parseCSSComponentValue("auto"); - EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::Keyword); - EXPECT_EQ(autoDisallowedValue.getKeyword(), CSSKeyword::Unset); + auto autoDisallowedValue = parseCSSComponentValue("auto"); + EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(autoDisallowedValue.getCSSWideKeyword(), CSSWideKeyword::Unset); auto whitespaceValue = - parseCSSComponentValue(" flex-start "); + parseCSSComponentValue(" flex-start "); EXPECT_EQ(whitespaceValue.type(), CSSValueType::Keyword); - EXPECT_EQ(whitespaceValue.getKeyword(), CSSAlignItems::FlexStart); + EXPECT_EQ(whitespaceValue.getKeyword(), CSSKeyword::FlexStart); - auto badIdentValue = parseCSSComponentValue("bad"); - EXPECT_EQ(badIdentValue.type(), CSSValueType::Keyword); - EXPECT_EQ(badIdentValue.getKeyword(), CSSKeyword::Unset); + auto badIdentValue = + parseCSSComponentValue("bad"); + EXPECT_EQ(badIdentValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(badIdentValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto pxValue = parseCSSComponentValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::Keyword); - EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset); + auto pxValue = parseCSSComponentValue("20px"); + EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto multiValue = parseCSSComponentValue("auto flex-start"); - EXPECT_EQ(multiValue.type(), CSSValueType::Keyword); - EXPECT_EQ(multiValue.getKeyword(), CSSKeyword::Unset); + auto multiValue = parseCSSComponentValue("auto flex-start"); + EXPECT_EQ(multiValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(multiValue.getCSSWideKeyword(), CSSWideKeyword::Unset); } TEST(CSSParser, length_values) { - auto emptyValue = parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); + auto emptyValue = parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto autoValue = parseCSSComponentValue("auto"); + auto autoValue = + parseCSSComponentValue("auto"); EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); - auto pxValue = parseCSSComponentValue("20px"); + auto pxValue = parseCSSComponentValue("20px"); EXPECT_EQ(pxValue.type(), CSSValueType::Length); EXPECT_EQ(pxValue.getLength().value, 20.0f); EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px); - auto cmValue = parseCSSComponentValue("453cm"); + auto cmValue = parseCSSComponentValue("453cm"); EXPECT_EQ(cmValue.type(), CSSValueType::Length); EXPECT_EQ(cmValue.getLength().value, 453.0f); EXPECT_EQ(cmValue.getLength().unit, CSSLengthUnit::Cm); auto unitlessZeroValue = - parseCSSComponentValue("0"); + parseCSSComponentValue("0"); EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Length); EXPECT_EQ(unitlessZeroValue.getLength().value, 0.0f); EXPECT_EQ(unitlessZeroValue.getLength().unit, CSSLengthUnit::Px); auto unitlessNonzeroValue = - parseCSSComponentValue("123"); - EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::Keyword); - EXPECT_EQ(unitlessNonzeroValue.getKeyword(), CSSKeyword::Unset); + parseCSSComponentValue("123"); + EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(unitlessNonzeroValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto pctValue = parseCSSComponentValue("-40%"); - EXPECT_EQ(pctValue.type(), CSSValueType::Keyword); - EXPECT_EQ(pctValue.getKeyword(), CSSKeyword::Unset); + auto pctValue = parseCSSComponentValue("-40%"); + EXPECT_EQ(pctValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(pctValue.getCSSWideKeyword(), CSSWideKeyword::Unset); } TEST(CSSParser, length_percentage_values) { auto emptyValue = - parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); + parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto autoValue = - parseCSSComponentValue("auto"); + auto autoValue = parseCSSComponentValue< + CSSWideKeyword, + CSSKeyword, + CSSLength, + CSSPercentage>("auto"); EXPECT_EQ(autoValue.type(), CSSValueType::Keyword); EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto); auto pxValue = - parseCSSComponentValue("20px"); + parseCSSComponentValue("20px"); EXPECT_EQ(pxValue.type(), CSSValueType::Length); EXPECT_EQ(pxValue.getLength().value, 20.0f); EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px); auto pctValue = - parseCSSComponentValue("-40%"); + parseCSSComponentValue("-40%"); EXPECT_EQ(pctValue.type(), CSSValueType::Percentage); EXPECT_EQ(pctValue.getPercentage().value, -40.0f); } TEST(CSSParser, number_values) { - auto emptyValue = parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); + auto emptyValue = parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto inheritValue = parseCSSComponentValue("inherit"); - EXPECT_EQ(inheritValue.type(), CSSValueType::Keyword); - EXPECT_EQ(inheritValue.getKeyword(), CSSKeyword::Inherit); + auto inheritValue = + parseCSSComponentValue("inherit"); + EXPECT_EQ(inheritValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(inheritValue.getCSSWideKeyword(), CSSWideKeyword::Inherit); - auto pxValue = parseCSSComponentValue("20px"); - EXPECT_EQ(pxValue.type(), CSSValueType::Keyword); - EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset); + auto pxValue = + parseCSSComponentValue("20px"); + EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto numberValue = parseCSSComponentValue("123.456"); + auto numberValue = + parseCSSComponentValue("123.456"); EXPECT_EQ(numberValue.type(), CSSValueType::Number); EXPECT_EQ(numberValue.getNumber().value, 123.456f); auto unitlessZeroValue = - parseCSSComponentValue("0"); + parseCSSComponentValue("0"); EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Number); EXPECT_EQ(unitlessZeroValue.getNumber().value, 0.0f); } TEST(CSSParser, ratio_values) { - auto emptyValue = parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); + auto emptyValue = parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); - auto validRatio = parseCSSComponentValue("16/9"); + auto validRatio = parseCSSComponentValue("16/9"); EXPECT_EQ(validRatio.type(), CSSValueType::Ratio); EXPECT_EQ(validRatio.getRatio().numerator, 16.0f); EXPECT_EQ(validRatio.getRatio().denominator, 9.0f); auto validRatioWithWhitespace = - parseCSSComponentValue("16 / 9"); - EXPECT_EQ(validRatioWithWhitespace.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatioWithWhitespace.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatioWithWhitespace.getRatio().denominator, 9.0f); - - auto singleNumberRatio = parseCSSComponentValue("16"); - EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); - - auto fractionalNumber = parseCSSComponentValue("16.5"); - EXPECT_EQ(fractionalNumber.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumber.getRatio().numerator, 16.5f); - EXPECT_EQ(fractionalNumber.getRatio().denominator, 1.0f); - - auto negativeNumber = parseCSSComponentValue("-16"); - EXPECT_EQ(negativeNumber.type(), CSSValueType::Keyword); - EXPECT_EQ(negativeNumber.getKeyword(), CSSKeyword::Unset); - - auto missingDenominator = parseCSSComponentValue("16/"); - EXPECT_EQ(missingDenominator.type(), CSSValueType::Keyword); - EXPECT_EQ(missingDenominator.getKeyword(), CSSKeyword::Unset); - - auto negativeNumerator = - parseCSSComponentValue("-16/9"); - EXPECT_EQ(negativeNumerator.type(), CSSValueType::Keyword); - EXPECT_EQ(negativeNumerator.getKeyword(), CSSKeyword::Unset); - - auto negativeDenominator = - parseCSSComponentValue("16/-9"); - EXPECT_EQ(negativeDenominator.type(), CSSValueType::Keyword); - EXPECT_EQ(negativeDenominator.getKeyword(), CSSKeyword::Unset); - - auto fractionalNumerator = - parseCSSComponentValue("16.5/9"); - EXPECT_EQ(fractionalNumerator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalNumerator.getRatio().numerator, 16.5f); - EXPECT_EQ(fractionalNumerator.getRatio().denominator, 9.0f); - - auto fractionalDenominator = - parseCSSComponentValue("16/9.5"); - EXPECT_EQ(fractionalDenominator.type(), CSSValueType::Ratio); - EXPECT_EQ(fractionalDenominator.getRatio().numerator, 16.0f); - EXPECT_EQ(fractionalDenominator.getRatio().denominator, 9.5f); - - auto degenerateRatio = parseCSSComponentValue("0"); - EXPECT_EQ(degenerateRatio.type(), CSSValueType::Keyword); - EXPECT_EQ(degenerateRatio.getKeyword(), CSSKeyword::Unset); -} - -TEST(CSSParser, number_ratio_values) { - auto emptyValue = parseCSSComponentValue(""); - EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword); - EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset); - - auto validRatio = - parseCSSComponentValue("16/9"); - EXPECT_EQ(validRatio.type(), CSSValueType::Ratio); - EXPECT_EQ(validRatio.getRatio().numerator, 16.0f); - EXPECT_EQ(validRatio.getRatio().denominator, 9.0f); - - auto validRatioWithWhitespace = - parseCSSComponentValue("16 / 9"); + parseCSSComponentValue("16 / 9"); EXPECT_EQ(validRatioWithWhitespace.type(), CSSValueType::Ratio); EXPECT_EQ(validRatioWithWhitespace.getRatio().numerator, 16.0f); EXPECT_EQ(validRatioWithWhitespace.getRatio().denominator, 9.0f); auto singleNumberRatio = - parseCSSComponentValue("16"); + parseCSSComponentValue("16"); EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio); EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f); EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); auto fractionalNumber = - parseCSSComponentValue("16.5"); + parseCSSComponentValue("16.5"); EXPECT_EQ(fractionalNumber.type(), CSSValueType::Ratio); EXPECT_EQ(fractionalNumber.getRatio().numerator, 16.5f); - EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); + EXPECT_EQ(fractionalNumber.getRatio().denominator, 1.0f); - auto negativeNumber = - parseCSSComponentValue("-16"); - EXPECT_EQ(negativeNumber.type(), CSSValueType::Number); - EXPECT_EQ(negativeNumber.getNumber().value, -16.0f); + auto negativeNumber = parseCSSComponentValue("-16"); + EXPECT_EQ(negativeNumber.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(negativeNumber.getCSSWideKeyword(), CSSWideKeyword::Unset); auto missingDenominator = - parseCSSComponentValue("16/"); - EXPECT_EQ(missingDenominator.type(), CSSValueType::Keyword); - EXPECT_EQ(missingDenominator.getKeyword(), CSSKeyword::Unset); + parseCSSComponentValue("16/"); + EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); auto negativeNumerator = - parseCSSComponentValue("-16/9"); - EXPECT_EQ(negativeNumerator.type(), CSSValueType::Keyword); - EXPECT_EQ(negativeNumerator.getKeyword(), CSSKeyword::Unset); + parseCSSComponentValue("-16/9"); + EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset); auto negativeDenominator = - parseCSSComponentValue("16/-9"); - EXPECT_EQ(negativeDenominator.type(), CSSValueType::Keyword); - EXPECT_EQ(negativeDenominator.getKeyword(), CSSKeyword::Unset); + parseCSSComponentValue("16/-9"); + EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); auto fractionalNumerator = - parseCSSComponentValue("16.5/9"); + parseCSSComponentValue("16.5/9"); EXPECT_EQ(fractionalNumerator.type(), CSSValueType::Ratio); EXPECT_EQ(fractionalNumerator.getRatio().numerator, 16.5f); EXPECT_EQ(fractionalNumerator.getRatio().denominator, 9.0f); auto fractionalDenominator = - parseCSSComponentValue("16/9.5"); + parseCSSComponentValue("16/9.5"); + EXPECT_EQ(fractionalDenominator.type(), CSSValueType::Ratio); + EXPECT_EQ(fractionalDenominator.getRatio().numerator, 16.0f); + EXPECT_EQ(fractionalDenominator.getRatio().denominator, 9.5f); + + auto degenerateRatio = parseCSSComponentValue("0"); + EXPECT_EQ(degenerateRatio.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(degenerateRatio.getCSSWideKeyword(), CSSWideKeyword::Unset); +} + +TEST(CSSParser, number_ratio_values) { + auto emptyValue = + parseCSSComponentValue(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto validRatio = + parseCSSComponentValue("16/9"); + EXPECT_EQ(validRatio.type(), CSSValueType::Ratio); + EXPECT_EQ(validRatio.getRatio().numerator, 16.0f); + EXPECT_EQ(validRatio.getRatio().denominator, 9.0f); + + auto validRatioWithWhitespace = + parseCSSComponentValue("16 / 9"); + EXPECT_EQ(validRatioWithWhitespace.type(), CSSValueType::Ratio); + EXPECT_EQ(validRatioWithWhitespace.getRatio().numerator, 16.0f); + EXPECT_EQ(validRatioWithWhitespace.getRatio().denominator, 9.0f); + + auto singleNumberRatio = + parseCSSComponentValue("16"); + EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio); + EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f); + EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); + + auto fractionalNumber = + parseCSSComponentValue("16.5"); + EXPECT_EQ(fractionalNumber.type(), CSSValueType::Ratio); + EXPECT_EQ(fractionalNumber.getRatio().numerator, 16.5f); + EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f); + + auto negativeNumber = + parseCSSComponentValue("-16"); + EXPECT_EQ(negativeNumber.type(), CSSValueType::Number); + EXPECT_EQ(negativeNumber.getNumber().value, -16.0f); + + auto missingDenominator = + parseCSSComponentValue("16/"); + EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto negativeNumerator = + parseCSSComponentValue("-16/9"); + EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto negativeDenominator = + parseCSSComponentValue("16/-9"); + EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto fractionalNumerator = + parseCSSComponentValue("16.5/9"); + EXPECT_EQ(fractionalNumerator.type(), CSSValueType::Ratio); + EXPECT_EQ(fractionalNumerator.getRatio().numerator, 16.5f); + EXPECT_EQ(fractionalNumerator.getRatio().denominator, 9.0f); + + auto fractionalDenominator = + parseCSSComponentValue("16/9.5"); EXPECT_EQ(fractionalDenominator.type(), CSSValueType::Ratio); EXPECT_EQ(fractionalDenominator.getRatio().numerator, 16.0f); EXPECT_EQ(fractionalDenominator.getRatio().denominator, 9.5f); auto degenerateRatio = - parseCSSComponentValue("0"); + parseCSSComponentValue("0"); EXPECT_EQ(degenerateRatio.type(), CSSValueType::Number); EXPECT_EQ(degenerateRatio.getNumber().value, 0.0f); } +TEST(CSSParser, parse_prop) { + auto emptyValue = parseCSSProp(""); + EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto numberWidthValue = parseCSSProp("50px"); + EXPECT_EQ(numberWidthValue.type(), CSSValueType::Length); + EXPECT_EQ(numberWidthValue.getLength().value, 50.0f); + EXPECT_EQ(numberWidthValue.getLength().unit, CSSLengthUnit::Px); + + auto percentWidthValue = parseCSSProp("50%"); + EXPECT_EQ(percentWidthValue.type(), CSSValueType::Percentage); + EXPECT_EQ(percentWidthValue.getPercentage().value, 50.0f); + + auto autoWidthValue = parseCSSProp("auto"); + EXPECT_EQ(autoWidthValue.type(), CSSValueType::Keyword); + EXPECT_EQ( + autoWidthValue.getKeyword(), CSSAllowedKeywords::Auto); + + auto invalidWidthValue = parseCSSProp("50"); + EXPECT_EQ(invalidWidthValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(invalidWidthValue.getCSSWideKeyword(), CSSWideKeyword::Unset); + + auto invalidKeywordValue = parseCSSProp("flex-start"); + EXPECT_EQ(invalidKeywordValue.type(), CSSValueType::CSSWideKeyword); + EXPECT_EQ(invalidKeywordValue.getCSSWideKeyword(), CSSWideKeyword::Unset); +} + } // namespace facebook::react