/* * 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 #include #include #include #include #include #include #include namespace facebook::react { namespace detail { constexpr CSSProp kFirstCSSProp = static_cast(0); template constexpr size_t maxSizeofDeclaredValue() { if constexpr (to_underlying(Prop) < kCSSPropCount - 1) { return std::max( sizeof(CSSDeclaredValue), maxSizeofDeclaredValue( to_underlying(Prop) + 1)>()); } else { return sizeof(CSSDeclaredValue); } } } // namespace detail /** * 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 void set(const CSSDeclaredValue& value) { using DeclaredValueT = std::remove_cvref_t>; static_assert(sizeof(value) <= sizeof(PropMapping::value)); static_assert(std::is_trivially_destructible_v); 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(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(it->value.data()), value); specifiedProperties_.set(to_underlying(Prop)); } } template bool set(std::string_view value) { auto cssProp = parseCSSProp(value); set(cssProp); return cssProp.hasValue(); } bool set(std::string_view prop, std::string_view value) { return setPropIfHashMatches(fnv1a(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 CSSDeclaredValue 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 value{*std::launder( reinterpret_cast*>(it->value.data()))}; if (value) { return value; } } if constexpr (sizeof...(ShorthandsT) == 0) { return {}; } else { return get(); } } bool operator==(const CSSDeclaredStyle& rhs) const = default; private: struct PropMapping { CSSProp prop; std::array value; constexpr bool operator<(const PropMapping& rhs) const { return to_underlying(prop) < to_underlying(rhs.prop); } }; template constexpr bool setPropIfHashMatches( size_t propNameHash, std::string_view value) { constexpr std::string_view currentPropName = CSSPropDefinition::kName; constexpr size_t currentHash = fnv1a(currentPropName); if (currentHash == propNameHash) { return set(value); } else if constexpr (to_underlying(CurrentProp) < kCSSPropCount - 1) { return setPropIfHashMatches( to_underlying(CurrentProp) + 1)>(propNameHash, value); } else { return false; } } std::vector properties_; std::bitset specifiedProperties_; }; } // namespace facebook::react