CSSDeclaredStyle

Summary:
Adds a sparse `CSSDeclaredStyle` structure to represent the collection of declarations from the user, before being further processed/computed. This will later be procssed into computed style.

Also fixes up some bad naming wrt specified value and declared value.

Changelog: [Internal]

Reviewed By: joevilches

Differential Revision: D53696422

fbshipit-source-id: 4258c86a29a0b2251c969b299b5b4703c06696db
This commit is contained in:
Nick Gerleman
2024-02-13 20:13:22 -08:00
committed by Facebook GitHub Bot
parent 516c4ccb71
commit f2d09651e0
5 changed files with 376 additions and 87 deletions
@@ -0,0 +1,108 @@
/*
* 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 <algorithm>
#include <bitset>
#include <memory>
#include <type_traits>
#include <vector>
#include <react/debug/react_native_assert.h>
#include <react/renderer/css/CSSParser.h>
#include <react/renderer/css/CSSProperties.h>
namespace facebook::react {
/**
* CSSDeclaredStyle represents the set of style declarations on an element set
* by the user. Users should generally not read from CSSDeclaredStyle directly,
* and should instead use the computed style calculated on ShadowTree commit.
*/
class CSSDeclaredStyle {
public:
template <CSSProp Prop>
void set(const CSSDeclaredValue<Prop>& value) {
using DeclaredValueT = std::remove_cvref_t<CSSDeclaredValue<Prop>>;
static_assert(sizeof(value) <= sizeof(PropMapping::value));
static_assert(std::is_trivially_destructible_v<DeclaredValueT>);
if (specifiedProperties_.test(to_underlying(Prop))) {
auto it = std::lower_bound(
properties_.begin(), properties_.end(), PropMapping{Prop, {}});
react_native_assert(it->prop == Prop);
std::construct_at(
reinterpret_cast<DeclaredValueT*>(it->value.data()), value);
} else {
auto it = std::upper_bound(
properties_.begin(), properties_.end(), PropMapping{Prop, {}});
it = properties_.insert(it, {Prop, {}});
std::construct_at(
reinterpret_cast<DeclaredValueT*>(it->value.data()), value);
specifiedProperties_.set(to_underlying(Prop));
}
}
template <CSSProp Prop>
void set(std::string_view value) {
set<Prop>(parseCSSProp<Prop>(value));
}
/**
* Returns the declared value, represented as the "unset" keyword if never
* specified. Additional shorthands can be provided in order
* of precedence if Prop is unset.
*/
template <CSSProp Prop, CSSProp... ShorthandsT>
CSSDeclaredValue<Prop> get() const {
if (specifiedProperties_.test(to_underlying(Prop))) {
auto it = std::lower_bound(
properties_.begin(), properties_.end(), PropMapping{Prop, {}});
react_native_assert(it->prop == Prop);
CSSDeclaredValue<Prop> value{*std::launder(
reinterpret_cast<const CSSDeclaredValue<Prop>*>(it->value.data()))};
if (value) {
return value;
}
}
if constexpr (sizeof...(ShorthandsT) == 0) {
return {};
} else {
return get<ShorthandsT...>();
}
}
bool operator==(const CSSDeclaredStyle& rhs) const = default;
private:
struct PropMapping {
CSSProp prop;
std::array<
std::byte,
sizeof(CSSValueVariant<
CSSWideKeyword,
CSSKeyword,
CSSLength,
CSSNumber,
CSSPercentage,
CSSRatio>)>
value;
constexpr bool operator<(const PropMapping& rhs) const {
return to_underlying(prop) < to_underlying(rhs.prop);
}
};
std::vector<PropMapping> properties_;
std::bitset<kCSSPropCount> specifiedProperties_;
};
} // namespace facebook::react
@@ -212,7 +212,7 @@ CSSValueVariant<AllowedTypesT...> parseCSSComponentValue(std::string_view css) {
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;
CSSDeclaredValue<Prop> value;
parseCSSComponentValue(css, value);
return value;
}
@@ -137,16 +137,22 @@ struct CSSPropDefinition {};
template <CSSProp P>
using CSSAllowedKeywords = typename CSSPropDefinition<P>::Keyword;
template <CSSProp P>
using CSSDeclaredValue = typename CSSPropDefinition<P>::DeclaredValue;
template <CSSProp P>
using CSSSpecifiedValue = typename CSSPropDefinition<P>::SpecifiedValue;
template <CSSProp P>
using CSSComputedValue = typename CSSPropDefinition<P>::ComputedValue;
struct CSSComputeContext {
bool isRTL{false};
bool useWebDefaults{false};
bool swapLeftAndRight{false};
/**
* Whether to behave in accordance with W3C specs, or to incorporate React
* Native specific tweaks to defaults and computation.
*/
enum class CSSFlavor {
W3C,
ReactNative,
};
/**
@@ -168,16 +174,18 @@ struct CSSPropDefinition<CSSProp::AlignContent> {
End = to_underlying(CSSKeyword::End),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::Stretch)
: SpecifiedValue::keyword(Keyword::FlexStart);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C
? DeclaredValue::keyword(Keyword::Stretch)
: DeclaredValue::keyword(Keyword::FlexStart);
}
};
@@ -198,15 +206,16 @@ struct CSSPropDefinition<CSSProp::AlignItems> {
End = to_underlying(CSSKeyword::End),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Stretch);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Stretch);
}
};
@@ -228,15 +237,16 @@ struct CSSPropDefinition<CSSProp::AlignSelf> {
End = to_underlying(CSSKeyword::End),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Auto);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Auto);
}
};
@@ -250,15 +260,16 @@ struct CSSPropDefinition<CSSProp::AspectRatio> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSRatio>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSRatio>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSRatio>;
using ComputedValue = CSSValueVariant<Keyword, CSSRatio>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Auto);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Auto);
}
};
@@ -268,16 +279,17 @@ struct CSSPropDefinition<CSSProp::AspectRatio> {
*/
template <>
struct CSSPropDefinition<CSSProp::BorderRadius> {
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::length(0.0f, CSSLengthUnit::Px);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::length(0.0f, CSSLengthUnit::Px);
}
};
@@ -332,16 +344,17 @@ struct CSSPropDefinition<CSSProp::BorderStyle> {
Outset = to_underlying(CSSKeyword::Outset),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::None)
: SpecifiedValue::keyword(Keyword::Solid);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::None)
: DeclaredValue::keyword(Keyword::Solid);
}
};
@@ -397,16 +410,18 @@ struct CSSPropDefinition<CSSProp::BorderWidth> {
Thick = to_underlying(CSSKeyword::Thick),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using SpecifiedValue = CSSValueVariant<CSSLength, CSSKeyword>;
using ComputedValue = CSSValueVariant<CSSLength>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::Medium)
: SpecifiedValue::length(0.0f, CSSLengthUnit::Px);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C
? DeclaredValue::keyword(Keyword::Medium)
: DeclaredValue::length(0.0f, CSSLengthUnit::Px);
}
};
@@ -477,15 +492,16 @@ struct CSSPropDefinition<CSSProp::Direction> {
Rtl = to_underlying(CSSKeyword::Rtl),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return true;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Ltr);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Ltr);
}
};
@@ -507,16 +523,17 @@ struct CSSPropDefinition<CSSProp::Display> {
InlineGrid = to_underlying(CSSKeyword::InlineGrid),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::Inline)
: SpecifiedValue::keyword(Keyword::Flex);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Inline)
: DeclaredValue::keyword(Keyword::Flex);
}
};
@@ -534,15 +551,16 @@ struct CSSPropDefinition<CSSProp::Flex> {
None = to_underlying(CSSKeyword::None),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSNumber>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSNumber>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSNumber>;
using ComputedValue = CSSValueVariant<Keyword, CSSNumber>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::number(0.0f);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::number(0.0f);
}
};
@@ -557,16 +575,17 @@ struct CSSPropDefinition<CSSProp::FlexBasis> {
Content = to_underlying(CSSKeyword::Content),
};
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Auto);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Auto);
}
};
@@ -583,16 +602,17 @@ struct CSSPropDefinition<CSSProp::FlexDirection> {
ColumnReverse = to_underlying(CSSKeyword::ColumnReverse),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::Row)
: SpecifiedValue::keyword(Keyword::Column);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Row)
: DeclaredValue::keyword(Keyword::Column);
}
};
@@ -602,15 +622,16 @@ struct CSSPropDefinition<CSSProp::FlexDirection> {
*/
template <>
struct CSSPropDefinition<CSSProp::FlexGrow> {
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using SpecifiedValue = CSSValueVariant<CSSNumber>;
using ComputedValue = CSSValueVariant<CSSNumber>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::number(0.0f);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::number(0.0f);
}
};
@@ -620,16 +641,17 @@ struct CSSPropDefinition<CSSProp::FlexGrow> {
*/
template <>
struct CSSPropDefinition<CSSProp::FlexShrink> {
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using SpecifiedValue = CSSValueVariant<CSSNumber>;
using ComputedValue = CSSValueVariant<CSSNumber>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::number(1.0f)
: SpecifiedValue::number(0.0f);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C ? DeclaredValue::number(1.0f)
: DeclaredValue::number(0.0f);
}
};
@@ -645,15 +667,16 @@ struct CSSPropDefinition<CSSProp::FlexWrap> {
WrapReverse = to_underlying(CSSKeyword::WrapReverse),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::NoWrap);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::NoWrap);
}
};
@@ -667,15 +690,16 @@ struct CSSPropDefinition<CSSProp::Gap> {
Normal = to_underlying(CSSKeyword::Normal),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword, CSSLength>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSLength>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Normal);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Normal);
}
};
@@ -698,16 +722,17 @@ struct CSSPropDefinition<CSSProp::Height> {
MinContent = to_underlying(CSSKeyword::MinContent),
};
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Auto);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Auto);
}
};
@@ -741,16 +766,17 @@ struct CSSPropDefinition<CSSProp::Inset> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Auto);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Auto);
}
};
@@ -815,15 +841,16 @@ struct CSSPropDefinition<CSSProp::JustifyContent> {
End = to_underlying(CSSKeyword::End),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::FlexStart);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::FlexStart);
}
};
@@ -837,16 +864,17 @@ struct CSSPropDefinition<CSSProp::Margin> {
Auto = to_underlying(CSSKeyword::Auto),
};
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, Keyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<Keyword, CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::length(0.0f, CSSLengthUnit::Px);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::length(0.0f, CSSLengthUnit::Px);
}
};
@@ -912,15 +940,16 @@ struct CSSPropDefinition<CSSProp::MarginVertical>
*/
template <>
struct CSSPropDefinition<CSSProp::Opacity> {
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, CSSNumber>;
using SpecifiedValue = CSSValueVariant<CSSNumber>;
using ComputedValue = CSSValueVariant<CSSNumber>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::number(1.0f);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::number(1.0f);
}
};
@@ -938,15 +967,16 @@ struct CSSPropDefinition<CSSProp::Overflow> {
Visible = to_underlying(CSSKeyword::Visible),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::keyword(Keyword::Visible);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::keyword(Keyword::Visible);
}
};
@@ -956,16 +986,17 @@ struct CSSPropDefinition<CSSProp::Overflow> {
*/
template <>
struct CSSPropDefinition<CSSProp::Padding> {
using SpecifiedValue =
using DeclaredValue =
CSSValueVariant<CSSWideKeyword, CSSLength, CSSPercentage>;
using SpecifiedValue = CSSValueVariant<CSSLength, CSSPercentage>;
using ComputedValue = CSSValueVariant<CSSLength, CSSPercentage>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext&) {
return SpecifiedValue::length(0.0f, CSSLengthUnit::Px);
constexpr static DeclaredValue initialValue(CSSFlavor /*flavor*/) {
return DeclaredValue::length(0.0f, CSSLengthUnit::Px);
}
};
@@ -1039,16 +1070,17 @@ struct CSSPropDefinition<CSSProp::Position> {
Sticky = to_underlying(CSSKeyword::Sticky),
};
using SpecifiedValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using DeclaredValue = CSSValueVariant<CSSWideKeyword, Keyword>;
using SpecifiedValue = CSSValueVariant<Keyword>;
using ComputedValue = CSSValueVariant<Keyword>;
constexpr static bool isInherited() {
return false;
}
constexpr static SpecifiedValue initialValue(const CSSComputeContext& ctx) {
return ctx.useWebDefaults ? SpecifiedValue::keyword(Keyword::Static)
: SpecifiedValue::keyword(Keyword::Relative);
constexpr static DeclaredValue initialValue(CSSFlavor flavor) {
return flavor == CSSFlavor::W3C ? DeclaredValue::keyword(Keyword::Static)
: DeclaredValue::keyword(Keyword::Relative);
}
};
@@ -36,9 +36,7 @@ enum class CSSValueType : uint8_t {
*/
template <typename T>
concept CSSDataType = std::is_trivially_destructible_v<T> &&
std::is_default_constructible_v<T> && requires() {
sizeof(T);
};
std::is_copy_constructible_v<T> && std::is_default_constructible_v<T>;
#pragma pack(push, 1)
/**
@@ -0,0 +1,151 @@
/*
* 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.
*/
#include <gtest/gtest.h>
#include <react/renderer/css/CSSDeclaredStyle.h>
#include <react/renderer/css/CSSParser.h>
namespace facebook::react {
TEST(CSSDeclaredStyle, unset_keyword) {
CSSDeclaredStyle style;
auto value = style.get<CSSProp::FlexDirection>();
EXPECT_EQ(value.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(value.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
TEST(CSSDeclaredStyle, unset_ratio) {
CSSDeclaredStyle style;
auto value = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(value.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(value.getCSSWideKeyword(), CSSWideKeyword::Unset);
}
TEST(CSSDeclaredStyle, set_keyword) {
CSSDeclaredStyle style;
style.set<CSSProp::FlexDirection>("row");
auto value = style.get<CSSProp::FlexDirection>();
EXPECT_EQ(value.type(), CSSValueType::Keyword);
EXPECT_EQ(
value.getKeyword(), CSSAllowedKeywords<CSSProp::FlexDirection>::Row);
}
TEST(CSSDeclaredStyle, set_ratio) {
CSSDeclaredStyle style;
style.set<CSSProp::AspectRatio>("16 / 9");
auto value = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(value.type(), CSSValueType::Ratio);
EXPECT_EQ(value.getRatio().numerator, 16.0f);
EXPECT_EQ(value.getRatio().denominator, 9.0f);
}
TEST(CSSDeclaredStyle, overwrite_ratio) {
CSSDeclaredStyle style;
style.set<CSSProp::AspectRatio>("16 / 9");
auto value1 = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(value1.type(), CSSValueType::Ratio);
EXPECT_EQ(value1.getRatio().numerator, 16.0f);
EXPECT_EQ(value1.getRatio().denominator, 9.0f);
style.set<CSSProp::AspectRatio>("4/3");
auto value2 = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(value2.type(), CSSValueType::Ratio);
EXPECT_EQ(value2.getRatio().numerator, 4.0f);
EXPECT_EQ(value2.getRatio().denominator, 3.0f);
}
TEST(CSSDeclaredStyle, set_multiple) {
CSSDeclaredStyle style;
style.set<CSSProp::FlexDirection>("row");
style.set<CSSProp::AspectRatio>("16 / 9");
auto flexDirection = style.get<CSSProp::FlexDirection>();
EXPECT_EQ(flexDirection.type(), CSSValueType::Keyword);
EXPECT_EQ(
flexDirection.getKeyword(),
CSSAllowedKeywords<CSSProp::FlexDirection>::Row);
auto aspectRatio = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f);
}
TEST(CSSDeclaredStyle, set_multiple_overwrite) {
CSSDeclaredStyle style;
style.set<CSSProp::FlexDirection>("row");
style.set<CSSProp::AspectRatio>("16 / 9");
style.set<CSSProp::FlexDirection>("column");
auto flexDirection = style.get<CSSProp::FlexDirection>();
EXPECT_EQ(flexDirection.type(), CSSValueType::Keyword);
EXPECT_EQ(
flexDirection.getKeyword(),
CSSAllowedKeywords<CSSProp::FlexDirection>::Column);
auto aspectRatio = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f);
}
TEST(CSSDeclaredStyle, set_multiple_reset) {
CSSDeclaredStyle style;
style.set<CSSProp::FlexDirection>("row");
style.set<CSSProp::AspectRatio>("16 / 9");
style.set<CSSProp::FlexDirection>("");
auto flexDirection = style.get<CSSProp::FlexDirection>();
EXPECT_EQ(flexDirection.type(), CSSValueType::CSSWideKeyword);
EXPECT_EQ(flexDirection.getCSSWideKeyword(), CSSWideKeyword::Unset);
auto aspectRatio = style.get<CSSProp::AspectRatio>();
EXPECT_EQ(aspectRatio.type(), CSSValueType::Ratio);
EXPECT_EQ(aspectRatio.getRatio().numerator, 16.0f);
EXPECT_EQ(aspectRatio.getRatio().denominator, 9.0f);
}
TEST(CSSDeclaredStyle, get_with_precedence) {
CSSDeclaredStyle style;
style.set<CSSProp::Margin>("1px");
auto margin1 = style.get<
CSSProp::MarginStart,
CSSProp::MarginLeft,
CSSProp::MarginInline,
CSSProp::MarginHorizontal,
CSSProp::Margin>();
EXPECT_EQ(margin1.type(), CSSValueType::Length);
EXPECT_EQ(margin1.getLength().value, 1.0f);
EXPECT_EQ(margin1.getLength().unit, CSSLengthUnit::Px);
style.set<CSSProp::MarginLeft>("3px");
auto margin2 = style.get<
CSSProp::MarginStart,
CSSProp::MarginLeft,
CSSProp::MarginInline,
CSSProp::MarginHorizontal,
CSSProp::Margin>();
EXPECT_EQ(margin2.type(), CSSValueType::Length);
EXPECT_EQ(margin2.getLength().value, 3.0f);
EXPECT_EQ(margin2.getLength().unit, CSSLengthUnit::Px);
}
} // namespace facebook::react