Add CSSProp and CSSPropDefinition (#42913)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/42913

This structures properties into a `CSSProp` enum (so that we can have a runtime-key per style prop), associated with a `CSSPropDefinition` structure which groups the supported types and keywords. This has some niceness of removing the macro bits, but more importantly, means we can query parse related information without a field of the value yet existing (need for sparse storage of CSS values). In the future, it will serve as where we define "initial" values, and likely, the processes for interpolation and inheritance.

We restructure `CSSValueVariant` to not always support keywords, as it may not be a valid possibility for computed values (which do not have CSS wide keywords). Computed values themselves may also reduce more keywords than the global ones (e.g. border width computed value absolutizes keywords).

We also flesh out more of the prop definitions, and parsing. All the properties here relay back to YogaStylableProps of today, but I intentionally filled out the prop definitions a bit more than we do anything with right now (will design higher level to ignore unknown props).

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D53518450

fbshipit-source-id: 1b48ae2513a258d15c5e7fd16ef06f1b6be8dab2
This commit is contained in:
Nick Gerleman
2024-02-13 20:13:22 -08:00
committed by Facebook GitHub Bot
parent a8f239d957
commit c37fc74212
5 changed files with 1127 additions and 322 deletions
@@ -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 <typename T>
concept CSSKeywordSet = std::is_enum_v<T> && requires {
{ T::Inherit } -> std::same_as<T>;
{ T::Initial } -> std::same_as<T>;
{ T::Unset } -> std::same_as<T>;
};
/**
* 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<T> && std::
is_same_v<std::underlying_type_t<T>, std::underlying_type_t<CSSKeyword>>;
/**
* 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<CSSKeyword> {
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<KeywordT> parseCSSKeyword(std::string_view ident) {
return KeywordT::Baseline;
}
break;
case fnv1a("block"):
if constexpr (detail::hasBlock<KeywordT>) {
return KeywordT::Block;
}
break;
case fnv1a("center"):
if constexpr (detail::hasCenter<KeywordT>) {
return KeywordT::Center;
}
break;
case fnv1a("clip"):
if constexpr (detail::hasClip<KeywordT>) {
return KeywordT::Clip;
}
break;
case fnv1a("column"):
if constexpr (detail::hasColumn<KeywordT>) {
return KeywordT::Column;
@@ -294,6 +202,25 @@ constexpr std::optional<KeywordT> parseCSSKeyword(std::string_view ident) {
return KeywordT::ColumnReverse;
}
break;
case fnv1a("content"):
if constexpr (detail::hasContent<KeywordT>) {
return KeywordT::Content;
}
break;
case fnv1a("contents"):
if constexpr (detail::hasContents<KeywordT>) {
return KeywordT::Contents;
}
break;
case fnv1a("end"):
if constexpr (detail::hasEnd<KeywordT>) {
return KeywordT::End;
}
break;
case fnv1a("fixed"):
if constexpr (detail::hasFixed<KeywordT>) {
return KeywordT::Fixed;
}
case fnv1a("flex"):
if constexpr (detail::hasFlex<KeywordT>) {
return KeywordT::Flex;
@@ -309,6 +236,11 @@ constexpr std::optional<KeywordT> parseCSSKeyword(std::string_view ident) {
return KeywordT::FlexStart;
}
break;
case fnv1a("grid"):
if constexpr (detail::hasGrid<KeywordT>) {
return KeywordT::Grid;
}
break;
case fnv1a("hidden"):
if constexpr (detail::hasHidden<KeywordT>) {
return KeywordT::Hidden;
@@ -324,17 +256,52 @@ constexpr std::optional<KeywordT> parseCSSKeyword(std::string_view ident) {
return KeywordT::Inline;
}
break;
case fnv1a("inline-block"):
if constexpr (detail::hasInlineBlock<KeywordT>) {
return KeywordT::InlineBlock;
}
break;
case fnv1a("inline-flex"):
if constexpr (detail::hasInlineFlex<KeywordT>) {
return KeywordT::InlineFlex;
}
break;
case fnv1a("inline-grid"):
if constexpr (detail::hasInlineGrid<KeywordT>) {
return KeywordT::InlineGrid;
}
break;
case fnv1a("ltr"):
if constexpr (detail::hasLtr<KeywordT>) {
return KeywordT::Ltr;
}
break;
case fnv1a("max-content"):
if constexpr (detail::hasMaxContent<KeywordT>) {
return KeywordT::MaxContent;
}
break;
case fnv1a("medium"):
if constexpr (detail::hasMedium<KeywordT>) {
return KeywordT::Medium;
}
break;
case fnv1a("min-content"):
if constexpr (detail::hasMinContent<KeywordT>) {
return KeywordT::MinContent;
}
break;
case fnv1a("none"):
if constexpr (detail::hasNone<KeywordT>) {
return KeywordT::None;
}
break;
case fnv1a("no-wrap"):
case fnv1a("normal"):
if constexpr (detail::hasNormal<KeywordT>) {
return KeywordT::Normal;
}
break;
case fnv1a("nowrap"):
if constexpr (detail::hasNoWrap<KeywordT>) {
return KeywordT::NoWrap;
}
@@ -379,16 +346,35 @@ constexpr std::optional<KeywordT> parseCSSKeyword(std::string_view ident) {
return KeywordT::Scroll;
}
break;
case fnv1a("start"):
if constexpr (detail::hasStart<KeywordT>) {
return KeywordT::Start;
}
case fnv1a("static"):
if constexpr (detail::hasStatic<KeywordT>) {
return KeywordT::Static;
}
break;
case fnv1a("sticky"):
if constexpr (detail::hasSticky<KeywordT>) {
return KeywordT::Sticky;
}
break;
case fnv1a("stretch"):
if constexpr (detail::hasStretch<KeywordT>) {
return KeywordT::Stretch;
}
break;
case fnv1a("thick"):
if constexpr (detail::hasThick<KeywordT>) {
return KeywordT::Thick;
}
break;
case fnv1a("thin"):
if constexpr (detail::hasThin<KeywordT>) {
return KeywordT::Thin;
}
break;
case fnv1a("unset"):
if constexpr (detail::hasUnset<KeywordT>) {
return KeywordT::Unset;
@@ -11,6 +11,7 @@
#include <react/renderer/css/CSSKeywords.h>
#include <react/renderer/css/CSSLengthUnit.h>
#include <react/renderer/css/CSSProperties.h>
#include <react/renderer/css/CSSTokenizer.h>
#include <react/renderer/css/CSSValue.h>
#include <react/utils/PackTraits.h>
@@ -23,13 +24,13 @@ class CSSParser {
explicit constexpr CSSParser(std::string_view css)
: tokenizer_{css}, currentToken_(tokenizer_.next()) {}
template <CSSKeywordSet KeywordT, CSSBasicDataType... AllowedTypesT>
constexpr CSSValueVariant<KeywordT, AllowedTypesT...>
consumeComponentValue() {
using CSSValueT = CSSValueVariant<KeywordT, AllowedTypesT...>;
template <CSSDataType... AllowedTypesT>
constexpr CSSValueVariant<AllowedTypesT...> consumeComponentValue() {
using CSSValueT = CSSValueVariant<AllowedTypesT...>;
switch (peek().type()) {
case CSSTokenType::Ident:
if (auto keywordValue = consumeIdentToken<CSSValueT, KeywordT>()) {
if (auto keywordValue =
consumeIdentToken<CSSValueT, AllowedTypesT...>()) {
return *keywordValue;
}
break;
@@ -80,16 +81,26 @@ class CSSParser {
return prevToken;
}
template <typename CSSValueT, CSSKeywordSet KeywordT>
template <typename CSSValueT, CSSDataType... AllowedTypesT>
constexpr std::optional<CSSValueT> consumeIdentToken() {
if (auto keyword =
parseCSSKeyword<KeywordT>(consumeToken().stringValue())) {
return CSSValueT::keyword(*keyword);
if constexpr (!std::is_same_v<typename CSSValueT::Keyword, void>) {
if (auto keyword = parseCSSKeyword<typename CSSValueT::Keyword>(
peek().stringValue())) {
consumeToken();
return CSSValueT::keyword(*keyword);
}
}
if constexpr (traits::containsType<CSSWideKeyword, AllowedTypesT...>()) {
if (auto keyword =
parseCSSKeyword<CSSWideKeyword>(peek().stringValue())) {
consumeToken();
return CSSValueT::cssWideKeyword(*keyword);
}
}
return {};
}
template <typename CSSValueT, CSSBasicDataType... AllowedTypesT>
template <typename CSSValueT, CSSDataType... AllowedTypesT>
constexpr std::optional<CSSValueT> consumeDimensionToken() {
if constexpr (traits::containsType<CSSLength, AllowedTypesT...>()) {
if (auto unit = parseCSSLengthUnit(peek().unit())) {
@@ -99,7 +110,7 @@ class CSSParser {
return {};
}
template <typename CSSValueT, CSSBasicDataType... AllowedTypesT>
template <typename CSSValueT, CSSDataType... AllowedTypesT>
constexpr std::optional<CSSValueT> consumePercentageToken() {
if constexpr (traits::containsType<CSSPercentage, AllowedTypesT...>()) {
return CSSValueT::percentage(consumeToken().numericValue());
@@ -107,7 +118,7 @@ class CSSParser {
return {};
}
template <typename CSSValueT, CSSBasicDataType... AllowedTypesT>
template <typename CSSValueT, CSSDataType... AllowedTypesT>
constexpr std::optional<CSSValueT> consumeNumberToken() {
// <ratio> = <number [0,∞]> [ / <number [0,∞]> ]?
// 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 <CSSKeywordSet KeywordT, CSSBasicDataType... AllowedTypesT>
constexpr CSSValueVariant<KeywordT, AllowedTypesT...> parseCSSComponentValue(
std::string_view css) {
template <CSSDataType... AllowedTypesT>
constexpr void parseCSSComponentValue(
std::string_view css,
CSSValueVariant<AllowedTypesT...>& value) {
detail::CSSParser parser(css);
parser.consumeWhitespace();
auto value = parser.consumeComponentValue<KeywordT, AllowedTypesT...>();
auto componentValue = parser.consumeComponentValue<AllowedTypesT...>();
parser.consumeWhitespace();
if (parser.hasMoreTokens()) {
return {};
value = {};
} else {
return value;
value = componentValue;
}
};
template <CSSDataType... AllowedTypesT>
CSSValueVariant<AllowedTypesT...> parseCSSComponentValue(std::string_view css) {
CSSValueVariant<AllowedTypesT...> value;
parseCSSComponentValue<AllowedTypesT...>(css, value);
return value;
};
template <CSSProp Prop>
constexpr auto parseCSSProp(std::string_view css) {
// For now we only allow parsing props composed of a single component value.
CSSSpecifiedValue<Prop> value;
parseCSSComponentValue(css, value);
return value;
}
} // namespace facebook::react
@@ -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 <react/renderer/css/CSSValue.h>
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 <CSSProp P>
struct CSSPropDefinition {};
template <CSSProp P>
using CSSAllowedKeywords = typename CSSPropDefinition<P>::Keyword;
template <CSSProp P>
using CSSSpecifiedValue = typename CSSPropDefinition<P>::SpecifiedValue;
template <CSSProp P>
using CSSComputedValue = typename CSSPropDefinition<P>::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<CSSProp::AlignContent> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* 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<CSSProp::AlignItems> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* 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<CSSProp::AlignSelf> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS "aspect-ratio" property.
* https://www.w3.org/TR/css-sizing-4/#aspect-ratio
*/
template <>
struct CSSPropDefinition<CSSProp::AspectRatio> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSRatio>;
using ComputedValue = CSSValueVariant<Keyword, CSSRatio>;
};
/**
* CSS "border-width" properties
* https://www.w3.org/TR/css-backgrounds-3/#border-width
*/
template <>
struct CSSPropDefinition<CSSProp::BorderWidth> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Thin = to_underlying(CSSKeyword::Thin),
Medium = to_underlying(CSSKeyword::Medium),
Thick = to_underlying(CSSKeyword::Thick),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using ComputedValue = CSSValueVariant<CSSLength>;
};
template <>
struct CSSPropDefinition<CSSProp::BorderBlockEndWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderBlockStartWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderBlockWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderBottomWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderEndWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderHorizontalWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderInlineEndWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderInlineStartWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderInlineWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderLeftWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderRightWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderStartWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderTopWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
template <>
struct CSSPropDefinition<CSSProp::BorderVerticalWidth>
: CSSPropDefinition<CSSProp::BorderWidth> {};
/**
* CSS "direction" property.
* https://www.w3.org/TR/css-writing-modes-3/#direction
*/
template <>
struct CSSPropDefinition<CSSProp::Direction> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Ltr = to_underlying(CSSKeyword::Ltr),
Rtl = to_underlying(CSSKeyword::Rtl),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS "display" property.
* https://www.w3.org/TR/css-display-3/#display-type
*/
template <>
struct CSSPropDefinition<CSSProp::Display> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* 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<CSSProp::Flex> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
None = to_underlying(CSSKeyword::None),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSNumber>;
using ComputedValue = CSSValueVariant<Keyword, CSSNumber>;
};
/**
* CSS "flex-basis" property.
* https://www.w3.org/TR/css-flexbox-1/#flex-basis-property
*/
template <>
struct CSSPropDefinition<CSSProp::FlexBasis> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
Content = to_underlying(CSSKeyword::Content),
};
using SpecifiedValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
};
/**
* CSS "flex-direction" property.
* https://www.w3.org/TR/css-flexbox-1/#flex-direction-property
*/
template <>
struct CSSPropDefinition<CSSProp::FlexDirection> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Row = to_underlying(CSSKeyword::Row),
RowReverse = to_underlying(CSSKeyword::RowReverse),
Column = to_underlying(CSSKeyword::Column),
ColumnReverse = to_underlying(CSSKeyword::ColumnReverse),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS "flex-grow" property.
* https://www.w3.org/TR/css-flexbox-1/#flex-grow-property
*/
template <>
struct CSSPropDefinition<CSSProp::FlexGrow> {
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using ComputedValue = CSSValueVariant<CSSNumber>;
};
/**
* CSS "flex-shrink" property.
* https://www.w3.org/TR/css-flexbox-1/#flex-shrink-property
*/
template <>
struct CSSPropDefinition<CSSProp::FlexShrink> {
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using ComputedValue = CSSValueVariant<CSSNumber>;
};
/**
* CSS "flex-wrap" property.
* https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property
*/
template <>
struct CSSPropDefinition<CSSProp::FlexWrap> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
NoWrap = to_underlying(CSSKeyword::NoWrap),
Wrap = to_underlying(CSSKeyword::Wrap),
WrapReverse = to_underlying(CSSKeyword::WrapReverse),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS gutter properties.
* https://www.w3.org/TR/css-align-3/#column-row-gap
*/
template <>
struct CSSPropDefinition<CSSProp::Gap> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Normal = to_underlying(CSSKeyword::Normal),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength>;
};
template <>
struct CSSPropDefinition<CSSProp::ColumnGap> : CSSPropDefinition<CSSProp::Gap> {
};
template <>
struct CSSPropDefinition<CSSProp::RowGap> : CSSPropDefinition<CSSProp::Gap> {};
/**
* CSS sizing properties
* https://www.w3.org/TR/css-sizing-3/#sizing-properties
*/
template <>
struct CSSPropDefinition<CSSProp::Height> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
MaxContent = to_underlying(CSSKeyword::MaxContent),
MinContent = to_underlying(CSSKeyword::MinContent),
};
using SpecifiedValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
};
template <>
struct CSSPropDefinition<CSSProp::Width> : CSSPropDefinition<CSSProp::Height> {
};
template <>
struct CSSPropDefinition<CSSProp::MinWidth>
: CSSPropDefinition<CSSProp::Height> {};
template <>
struct CSSPropDefinition<CSSProp::MinHeight>
: CSSPropDefinition<CSSProp::Height> {};
template <>
struct CSSPropDefinition<CSSProp::MaxWidth>
: CSSPropDefinition<CSSProp::Height> {};
template <>
struct CSSPropDefinition<CSSProp::MaxHeight>
: CSSPropDefinition<CSSProp::Height> {};
/**
* CSS box inset properties
* https://drafts.csswg.org/css-position-3/#insets
*/
template <>
struct CSSPropDefinition<CSSProp::Inset> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
};
template <>
struct CSSPropDefinition<CSSProp::Top> : CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::Right> : CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::Bottom> : CSSPropDefinition<CSSProp::Inset> {
};
template <>
struct CSSPropDefinition<CSSProp::Left> : CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::Start> : CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::End> : CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetBlock>
: CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetBlockEnd>
: CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetBlockStart>
: CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetInline>
: CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetInlineEnd>
: CSSPropDefinition<CSSProp::Inset> {};
template <>
struct CSSPropDefinition<CSSProp::InsetInlineStart>
: CSSPropDefinition<CSSProp::Inset> {};
/**
* 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<CSSProp::JustifyContent> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS "margin" properties
* https://www.w3.org/TR/css-box-4/#margins
*/
template <>
struct CSSPropDefinition<CSSProp::Margin> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
};
template <>
struct CSSPropDefinition<CSSProp::MarginBlock>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginBlockEnd>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginBlockStart>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginBottom>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginEnd>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginHorizontal>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginInline>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginInlineEnd>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginInlineStart>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginLeft>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginRight>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginStart>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginTop>
: CSSPropDefinition<CSSProp::Margin> {};
template <>
struct CSSPropDefinition<CSSProp::MarginVertical>
: CSSPropDefinition<CSSProp::Margin> {};
/**
* CSS "overflow" property.
* https://www.w3.org/TR/css-overflow-3/#overflow-control
*/
template <>
struct CSSPropDefinition<CSSProp::Overflow> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
/**
* CSS padding properties
* https://www.w3.org/TR/css-box-4/#paddings
*/
template <>
struct CSSPropDefinition<CSSProp::Padding> {
using SpecifiedValue =
CSSValueVariant<CSSWideKeyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<CSSLength, CSSPercentage>;
};
template <>
struct CSSPropDefinition<CSSProp::PaddingBlock>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingBlockEnd>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingBlockStart>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingBottom>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingEnd>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingHorizontal>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingInline>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingInlineEnd>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingInlineStart>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingLeft>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingRight>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingStart>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingTop>
: CSSPropDefinition<CSSProp::Padding> {};
template <>
struct CSSPropDefinition<CSSProp::PaddingVertical>
: CSSPropDefinition<CSSProp::Padding> {};
/**
* CSS "position" property.
* https://www.w3.org/TR/css-position-3/#position-property
*/
template <>
struct CSSPropDefinition<CSSProp::Position> {
enum class Keyword : std::underlying_type_t<CSSKeyword> {
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<CSSWideKeyword, Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
};
} // namespace facebook::react
@@ -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 <typename T>
concept CSSBasicDataType = std::is_trivially_destructible_v<T> &&
concept CSSDataType = std::is_trivially_destructible_v<T> &&
std::is_default_constructible_v<T> && requires() {
sizeof(T);
};
@@ -88,9 +89,9 @@ struct CSSRatio {
* set of values.
*/
#pragma pack(push, 1)
template <typename KeywordT, CSSBasicDataType... Rest>
template <CSSDataType... AllowedTypesT>
class CSSValueVariant {
template <CSSValueType Type, CSSBasicDataType ValueT>
template <CSSValueType Type, CSSDataType ValueT>
constexpr ValueT getIf() const {
if (type_ == Type) {
return *std::launder(reinterpret_cast<const ValueT*>(data_.data()));
@@ -99,16 +100,49 @@ class CSSValueVariant {
}
}
template <CSSBasicDataType ValueT>
template <CSSDataType ValueT>
static constexpr bool canRepresent() {
return traits::containsType<ValueT, KeywordT, Rest...>();
return traits::containsType<ValueT, AllowedTypesT...>();
}
public:
constexpr CSSValueVariant()
: CSSValueVariant(CSSValueType::Keyword, KeywordT::Unset) {}
template <CSSDataType T, CSSDataType... Rest>
static constexpr bool hasKeywordSet() {
if constexpr (CSSKeywordSet<T> && !std::is_same_v<T, CSSWideKeyword>) {
return true;
} else if constexpr (sizeof...(Rest) == 0) {
return false;
} else {
return hasKeywordSet<Rest...>();
}
}
static constexpr CSSValueVariant keyword(KeywordT keyword) {
template <typename... T>
struct PackedKeywordSet {
using Type = void;
};
template <typename T, typename... RestT>
struct PackedKeywordSet<T, RestT...> {
using Type = std::conditional_t<
hasKeywordSet<T>(),
T,
typename PackedKeywordSet<RestT...>::Type>;
};
public:
using Keyword = typename PackedKeywordSet<AllowedTypesT...>::Type;
constexpr CSSValueVariant() requires(canRepresent<CSSWideKeyword>())
: CSSValueVariant(CSSValueType::CSSWideKeyword, CSSWideKeyword::Unset) {}
static constexpr CSSValueVariant cssWideKeyword(CSSWideKeyword keyword) {
return CSSValueVariant(
CSSValueType::CSSWideKeyword, CSSWideKeyword{keyword});
}
template <CSSKeywordSet KeywordT>
static constexpr CSSValueVariant keyword(KeywordT keyword) requires(
canRepresent<KeywordT>()) {
return CSSValueVariant(CSSValueType::Keyword, KeywordT{keyword});
}
@@ -139,8 +173,14 @@ class CSSValueVariant {
return type_;
}
constexpr KeywordT getKeyword() const {
return getIf<CSSValueType::Keyword, KeywordT>();
constexpr CSSWideKeyword getCSSWideKeyword() const
requires(canRepresent<CSSWideKeyword>()) {
return getIf<CSSValueType::CSSWideKeyword, CSSWideKeyword>();
}
constexpr Keyword getKeyword() const
requires(hasKeywordSet<AllowedTypesT...>()) {
return getIf<CSSValueType::Keyword, Keyword>();
}
constexpr CSSLength getLength() const requires(canRepresent<CSSLength>()) {
@@ -160,30 +200,29 @@ class CSSValueVariant {
return getIf<CSSValueType::Ratio, CSSRatio>();
}
constexpr operator bool() const {
constexpr operator bool() const requires(canRepresent<CSSWideKeyword>()) {
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<decltype(value)>{
std::forward<decltype(value)>(value)};
}
CSSValueType type_;
std::array<std::byte, traits::maxSizeof<KeywordT, Rest...>()> data_;
std::array<std::byte, traits::maxSizeof<AllowedTypesT...>()> data_;
};
#pragma pack(pop)
static_assert(sizeof(CSSValueVariant<CSSFlexDirection>) == 2);
static_assert(sizeof(CSSValueVariant<CSSAutoKeyword, CSSLength>) == 6);
static_assert(sizeof(CSSValueVariant<CSSKeyword>) == 2);
static_assert(sizeof(CSSValueVariant<CSSKeyword, CSSLength>) == 6);
static_assert(
sizeof(CSSValueVariant<CSSAutoKeyword, CSSLength, CSSPercentage>) == 6);
static_assert(sizeof(CSSValueVariant<CSSWideKeyword, CSSNumber>) == 5);
static_assert(
sizeof(CSSValueVariant<CSSWideKeyword, CSSNumber, CSSRatio>) == 9);
sizeof(CSSValueVariant<CSSKeyword, CSSLength, CSSPercentage>) == 6);
static_assert(sizeof(CSSValueVariant<CSSKeyword, CSSNumber>) == 5);
static_assert(sizeof(CSSValueVariant<CSSKeyword, CSSNumber, CSSRatio>) == 9);
} // namespace facebook::react
@@ -11,247 +11,288 @@
namespace facebook::react {
TEST(CSSParser, keyword_values) {
auto emptyValue = parseCSSComponentValue<CSSKeyword>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
auto emptyValue = parseCSSComponentValue<CSSWideKeyword, CSSKeyword>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto autoValue = parseCSSComponentValue<CSSKeyword>("auto");
auto autoValue = parseCSSComponentValue<CSSWideKeyword, CSSKeyword>("auto");
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
auto autoCapsValue = parseCSSComponentValue<CSSKeyword>("AuTO");
auto autoCapsValue =
parseCSSComponentValue<CSSWideKeyword, CSSKeyword>("AuTO");
EXPECT_EQ(autoCapsValue.type(), CSSValueType::Keyword);
EXPECT_EQ(autoCapsValue.getKeyword(), CSSKeyword::Auto);
auto autoDisallowedValue = parseCSSComponentValue<CSSFlexDirection>("auto");
EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::Keyword);
EXPECT_EQ(autoDisallowedValue.getKeyword(), CSSKeyword::Unset);
auto autoDisallowedValue = parseCSSComponentValue<CSSWideKeyword>("auto");
EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(autoDisallowedValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto whitespaceValue =
parseCSSComponentValue<CSSAlignItems>(" flex-start ");
parseCSSComponentValue<CSSWideKeyword, CSSKeyword>(" flex-start ");
EXPECT_EQ(whitespaceValue.type(), CSSValueType::Keyword);
EXPECT_EQ(whitespaceValue.getKeyword(), CSSAlignItems::FlexStart);
EXPECT_EQ(whitespaceValue.getKeyword(), CSSKeyword::FlexStart);
auto badIdentValue = parseCSSComponentValue<CSSWideKeyword>("bad");
EXPECT_EQ(badIdentValue.type(), CSSValueType::Keyword);
EXPECT_EQ(badIdentValue.getKeyword(), CSSKeyword::Unset);
auto badIdentValue =
parseCSSComponentValue<CSSWideKeyword, CSSKeyword>("bad");
EXPECT_EQ(badIdentValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(badIdentValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto pxValue = parseCSSComponentValue<CSSKeyword>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::Keyword);
EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset);
auto pxValue = parseCSSComponentValue<CSSWideKeyword>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto multiValue = parseCSSComponentValue<CSSKeyword>("auto flex-start");
EXPECT_EQ(multiValue.type(), CSSValueType::Keyword);
EXPECT_EQ(multiValue.getKeyword(), CSSKeyword::Unset);
auto multiValue = parseCSSComponentValue<CSSWideKeyword>("auto flex-start");
EXPECT_EQ(multiValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(multiValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
TEST(CSSParser, length_values) {
auto emptyValue = parseCSSComponentValue<CSSAutoKeyword, CSSLength>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
auto emptyValue = parseCSSComponentValue<CSSWideKeyword, CSSLength>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto autoValue = parseCSSComponentValue<CSSAutoKeyword, CSSLength>("auto");
auto autoValue =
parseCSSComponentValue<CSSWideKeyword, CSSKeyword, CSSLength>("auto");
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
auto pxValue = parseCSSComponentValue<CSSAutoKeyword, CSSLength>("20px");
auto pxValue = parseCSSComponentValue<CSSWideKeyword, CSSLength>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::Length);
EXPECT_EQ(pxValue.getLength().value, 20.0f);
EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px);
auto cmValue = parseCSSComponentValue<CSSAutoKeyword, CSSLength>("453cm");
auto cmValue = parseCSSComponentValue<CSSWideKeyword, CSSLength>("453cm");
EXPECT_EQ(cmValue.type(), CSSValueType::Length);
EXPECT_EQ(cmValue.getLength().value, 453.0f);
EXPECT_EQ(cmValue.getLength().unit, CSSLengthUnit::Cm);
auto unitlessZeroValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength>("0");
parseCSSComponentValue<CSSWideKeyword, CSSLength>("0");
EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Length);
EXPECT_EQ(unitlessZeroValue.getLength().value, 0.0f);
EXPECT_EQ(unitlessZeroValue.getLength().unit, CSSLengthUnit::Px);
auto unitlessNonzeroValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength>("123");
EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::Keyword);
EXPECT_EQ(unitlessNonzeroValue.getKeyword(), CSSKeyword::Unset);
parseCSSComponentValue<CSSWideKeyword, CSSLength>("123");
EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(unitlessNonzeroValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto pctValue = parseCSSComponentValue<CSSAutoKeyword, CSSLength>("-40%");
EXPECT_EQ(pctValue.type(), CSSValueType::Keyword);
EXPECT_EQ(pctValue.getKeyword(), CSSKeyword::Unset);
auto pctValue = parseCSSComponentValue<CSSWideKeyword, CSSLength>("-40%");
EXPECT_EQ(pctValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(pctValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
TEST(CSSParser, length_percentage_values) {
auto emptyValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength, CSSPercentage>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
parseCSSComponentValue<CSSWideKeyword, CSSLength, CSSPercentage>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto autoValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength, CSSPercentage>("auto");
auto autoValue = parseCSSComponentValue<
CSSWideKeyword,
CSSKeyword,
CSSLength,
CSSPercentage>("auto");
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
auto pxValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength, CSSPercentage>("20px");
parseCSSComponentValue<CSSWideKeyword, CSSLength, CSSPercentage>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::Length);
EXPECT_EQ(pxValue.getLength().value, 20.0f);
EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px);
auto pctValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength, CSSPercentage>("-40%");
parseCSSComponentValue<CSSWideKeyword, CSSLength, CSSPercentage>("-40%");
EXPECT_EQ(pctValue.type(), CSSValueType::Percentage);
EXPECT_EQ(pctValue.getPercentage().value, -40.0f);
}
TEST(CSSParser, number_values) {
auto emptyValue = parseCSSComponentValue<CSSKeyword, CSSNumber>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
auto emptyValue = parseCSSComponentValue<CSSWideKeyword, CSSNumber>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto inheritValue = parseCSSComponentValue<CSSKeyword, CSSNumber>("inherit");
EXPECT_EQ(inheritValue.type(), CSSValueType::Keyword);
EXPECT_EQ(inheritValue.getKeyword(), CSSKeyword::Inherit);
auto inheritValue =
parseCSSComponentValue<CSSWideKeyword, CSSNumber>("inherit");
EXPECT_EQ(inheritValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(inheritValue.getCSSWideKeyword(), CSSWideKeyword::Inherit);
auto pxValue = parseCSSComponentValue<CSSKeyword, CSSNumber>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::Keyword);
EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset);
auto pxValue =
parseCSSComponentValue<CSSWideKeyword, CSSKeyword, CSSNumber>("20px");
EXPECT_EQ(pxValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(pxValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto numberValue = parseCSSComponentValue<CSSKeyword, CSSNumber>("123.456");
auto numberValue =
parseCSSComponentValue<CSSWideKeyword, CSSKeyword, CSSNumber>("123.456");
EXPECT_EQ(numberValue.type(), CSSValueType::Number);
EXPECT_EQ(numberValue.getNumber().value, 123.456f);
auto unitlessZeroValue =
parseCSSComponentValue<CSSAutoKeyword, CSSLength, CSSNumber>("0");
parseCSSComponentValue<CSSWideKeyword, CSSLength, CSSNumber>("0");
EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Number);
EXPECT_EQ(unitlessZeroValue.getNumber().value, 0.0f);
}
TEST(CSSParser, ratio_values) {
auto emptyValue = parseCSSComponentValue<CSSKeyword, CSSRatio>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
auto emptyValue = parseCSSComponentValue<CSSWideKeyword, CSSRatio>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto validRatio = parseCSSComponentValue<CSSKeyword, CSSRatio>("16/9");
auto validRatio = parseCSSComponentValue<CSSWideKeyword, CSSRatio>("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<CSSKeyword, CSSRatio>("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<CSSKeyword, CSSRatio>("16");
EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f);
auto fractionalNumber = parseCSSComponentValue<CSSKeyword, CSSRatio>("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<CSSKeyword, CSSRatio>("-16");
EXPECT_EQ(negativeNumber.type(), CSSValueType::Keyword);
EXPECT_EQ(negativeNumber.getKeyword(), CSSKeyword::Unset);
auto missingDenominator = parseCSSComponentValue<CSSKeyword, CSSRatio>("16/");
EXPECT_EQ(missingDenominator.type(), CSSValueType::Keyword);
EXPECT_EQ(missingDenominator.getKeyword(), CSSKeyword::Unset);
auto negativeNumerator =
parseCSSComponentValue<CSSKeyword, CSSRatio>("-16/9");
EXPECT_EQ(negativeNumerator.type(), CSSValueType::Keyword);
EXPECT_EQ(negativeNumerator.getKeyword(), CSSKeyword::Unset);
auto negativeDenominator =
parseCSSComponentValue<CSSKeyword, CSSRatio>("16/-9");
EXPECT_EQ(negativeDenominator.type(), CSSValueType::Keyword);
EXPECT_EQ(negativeDenominator.getKeyword(), CSSKeyword::Unset);
auto fractionalNumerator =
parseCSSComponentValue<CSSKeyword, CSSRatio>("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<CSSKeyword, CSSRatio>("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<CSSKeyword, CSSRatio>("0");
EXPECT_EQ(degenerateRatio.type(), CSSValueType::Keyword);
EXPECT_EQ(degenerateRatio.getKeyword(), CSSKeyword::Unset);
}
TEST(CSSParser, number_ratio_values) {
auto emptyValue = parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
auto validRatio =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("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<CSSKeyword, CSSNumber, CSSRatio>("16 / 9");
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("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<CSSKeyword, CSSNumber, CSSRatio>("16");
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("16");
EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f);
auto fractionalNumber =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("16.5");
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("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<CSSKeyword, CSSNumber, CSSRatio>("-16");
EXPECT_EQ(negativeNumber.type(), CSSValueType::Number);
EXPECT_EQ(negativeNumber.getNumber().value, -16.0f);
auto negativeNumber = parseCSSComponentValue<CSSWideKeyword, CSSRatio>("-16");
EXPECT_EQ(negativeNumber.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(negativeNumber.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto missingDenominator =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("16/");
EXPECT_EQ(missingDenominator.type(), CSSValueType::Keyword);
EXPECT_EQ(missingDenominator.getKeyword(), CSSKeyword::Unset);
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("16/");
EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto negativeNumerator =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("-16/9");
EXPECT_EQ(negativeNumerator.type(), CSSValueType::Keyword);
EXPECT_EQ(negativeNumerator.getKeyword(), CSSKeyword::Unset);
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("-16/9");
EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto negativeDenominator =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("16/-9");
EXPECT_EQ(negativeDenominator.type(), CSSValueType::Keyword);
EXPECT_EQ(negativeDenominator.getKeyword(), CSSKeyword::Unset);
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("16/-9");
EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto fractionalNumerator =
parseCSSComponentValue<CSSKeyword, CSSNumber, CSSRatio>("16.5/9");
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("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<CSSKeyword, CSSNumber, CSSRatio>("16/9.5");
parseCSSComponentValue<CSSWideKeyword, CSSRatio>("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<CSSWideKeyword, CSSRatio>("0");
EXPECT_EQ(degenerateRatio.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(degenerateRatio.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
TEST(CSSParser, number_ratio_values) {
auto emptyValue =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto validRatio =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("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<CSSWideKeyword, CSSNumber, CSSRatio>("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<CSSWideKeyword, CSSNumber, CSSRatio>("16");
EXPECT_EQ(singleNumberRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(singleNumberRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(singleNumberRatio.getRatio().denominator, 1.0f);
auto fractionalNumber =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("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<CSSWideKeyword, CSSNumber, CSSRatio>("-16");
EXPECT_EQ(negativeNumber.type(), CSSValueType::Number);
EXPECT_EQ(negativeNumber.getNumber().value, -16.0f);
auto missingDenominator =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("16/");
EXPECT_EQ(missingDenominator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(missingDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto negativeNumerator =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("-16/9");
EXPECT_EQ(negativeNumerator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(negativeNumerator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto negativeDenominator =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("16/-9");
EXPECT_EQ(negativeDenominator.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(negativeDenominator.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto fractionalNumerator =
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("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<CSSWideKeyword, CSSNumber, CSSRatio>("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<CSSKeyword, CSSNumber, CSSRatio>("0");
parseCSSComponentValue<CSSWideKeyword, CSSNumber, CSSRatio>("0");
EXPECT_EQ(degenerateRatio.type(), CSSValueType::Number);
EXPECT_EQ(degenerateRatio.getNumber().value, 0.0f);
}
TEST(CSSParser, parse_prop) {
auto emptyValue = parseCSSProp<CSSProp::Width>("");
EXPECT_EQ(emptyValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(emptyValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto numberWidthValue = parseCSSProp<CSSProp::Width>("50px");
EXPECT_EQ(numberWidthValue.type(), CSSValueType::Length);
EXPECT_EQ(numberWidthValue.getLength().value, 50.0f);
EXPECT_EQ(numberWidthValue.getLength().unit, CSSLengthUnit::Px);
auto percentWidthValue = parseCSSProp<CSSProp::Width>("50%");
EXPECT_EQ(percentWidthValue.type(), CSSValueType::Percentage);
EXPECT_EQ(percentWidthValue.getPercentage().value, 50.0f);
auto autoWidthValue = parseCSSProp<CSSProp::Width>("auto");
EXPECT_EQ(autoWidthValue.type(), CSSValueType::Keyword);
EXPECT_EQ(
autoWidthValue.getKeyword(), CSSAllowedKeywords<CSSProp::Width>::Auto);
auto invalidWidthValue = parseCSSProp<CSSProp::Width>("50");
EXPECT_EQ(invalidWidthValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(invalidWidthValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto invalidKeywordValue = parseCSSProp<CSSProp::Width>("flex-start");
EXPECT_EQ(invalidKeywordValue.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(invalidKeywordValue.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
} // namespace facebook::react