/* * 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 #include #include #include #include #include #include namespace facebook::react { namespace detail { template < typename DataT, TemplateStringLiteral Name, CSSDataType... AllowedComponentsT> requires(std::is_same_v< decltype(DataT::value), std::variant>) struct CSSVariantComponentTransformParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, Name)) { return {}; } auto val = parseNextCSSValue(parser); return std::visit( [&](auto&& v) -> std::optional { if constexpr (std::is_same_v< std::remove_cvref_t, std::monostate>) { return {}; } else { return DataT{.value = std::forward(v)}; } }, val); } }; template requires(std::is_same_v) struct CSSNumberPercentTransformParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, Name)) { return {}; } auto val = parseNextCSSValue(parser); if (std::holds_alternative(val)) { return {}; } return DataT{ .value = std::holds_alternative(val) ? std::get(val).value : std::get(val).value / 100.0f}; } }; template requires(std::is_same_v) struct CSSAngleTransformParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, Name)) { return {}; } auto value = parseNextCSSValue(parser); if (std::holds_alternative(value)) { return {}; } return DataT{ .degrees = std::holds_alternative(value) ? std::get(value).degrees : 0.0f, }; } }; } // namespace detail /** * Representation of matrix() transform function. */ struct CSSMatrix { std::array values{}; constexpr bool operator==(const CSSMatrix& rhs) const = default; }; template <> struct CSSDataTypeParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, "matrix")) { return {}; } CSSMatrix matrix{}; for (int i = 0; i < 6; i++) { auto value = parseNextCSSValue( parser, i == 0 ? CSSDelimiter::None : CSSDelimiter::Comma); if (std::holds_alternative(value)) { return {}; } matrix.values[i] = std::get(value).value; } return matrix; } }; static_assert(CSSDataType); /** * Representation of translate() transform function. */ struct CSSTranslate { std::variant x{}; std::variant y{}; constexpr bool operator==(const CSSTranslate& rhs) const = default; }; template <> struct CSSDataTypeParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, "translate")) { return {}; } auto x = parseNextCSSValue(parser); if (std::holds_alternative(x)) { return {}; } auto y = parseNextCSSValue(parser, CSSDelimiter::Comma); CSSTranslate translate{}; translate.x = std::holds_alternative(x) ? std::variant{std::get(x)} : std::variant{std::get(x)}; if (!std::holds_alternative(y)) { translate.y = std::holds_alternative(y) ? std::variant{std::get(y)} : std::variant{std::get(y)}; } return translate; } }; static_assert(CSSDataType); /** * Representation of translate() transform function. */ struct CSSTranslate3D { std::variant x{}; std::variant y{}; CSSLength z{}; constexpr bool operator==(const CSSTranslate3D& rhs) const = default; }; template <> struct CSSDataTypeParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, "translate3d")) { return {}; } auto x = parseNextCSSValue(parser); if (std::holds_alternative(x)) { return {}; } auto y = parseNextCSSValue(parser, CSSDelimiter::Comma); if (std::holds_alternative(y)) { return {}; } auto z = parseNextCSSValue(parser, CSSDelimiter::Comma); if (std::holds_alternative(z)) { return {}; } return CSSTranslate3D{ .x = std::holds_alternative(x) ? std::variant{std::get(x)} : std::variant{std::get( x)}, .y = std::holds_alternative(y) ? std::variant{std::get(y)} : std::variant{std::get( y)}, .z = std::get(z), }; } }; static_assert(CSSDataType); /** * Representation of translateX() transform function. */ struct CSSTranslateX { std::variant value{}; constexpr bool operator==(const CSSTranslateX& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSVariantComponentTransformParser< CSSTranslateX, "translateX", CSSLength, CSSPercentage> {}; static_assert(CSSDataType); /** * Representation of translateY() transform function. */ struct CSSTranslateY { std::variant value{}; constexpr bool operator==(const CSSTranslateY& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSVariantComponentTransformParser< CSSTranslateY, "translateY", CSSLength, CSSPercentage> {}; static_assert(CSSDataType); /** * Representation of scale() transform function. */ struct CSSScale { float x{}; float y{}; constexpr bool operator==(const CSSScale& rhs) const = default; }; template <> struct CSSDataTypeParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, "scale")) { return {}; } // Transforms module level 2 allows percentage syntax // https://drafts.csswg.org/css-transforms-2/#transform-functions auto x = parseNextCSSValue(parser); if (std::holds_alternative(x)) { return {}; } auto y = parseNextCSSValue( parser, CSSDelimiter::Comma); auto normX = std::holds_alternative(x) ? std::get(x).value : std::get(x).value / 100.0f; auto normY = std::holds_alternative(y) ? normX : std::holds_alternative(y) ? std::get(y).value : std::get(y).value / 100.0f; return CSSScale{normX, normY}; } }; static_assert(CSSDataType); /** * Representation of scaleX() transform function. */ struct CSSScaleX { float value{}; constexpr bool operator==(const CSSScaleX& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSNumberPercentTransformParser {}; static_assert(CSSDataType); /** * Representation of scaleY() transform function. */ struct CSSScaleY { float value{}; constexpr bool operator==(const CSSScaleY& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSNumberPercentTransformParser {}; static_assert(CSSDataType); /** * Representation of rotate() transform function. */ struct CSSRotate { float degrees{}; constexpr bool operator==(const CSSRotate& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of rotateX() transform function. */ struct CSSRotateX { float degrees{}; constexpr bool operator==(const CSSRotateX& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of rotateY() transform function. */ struct CSSRotateY { float degrees{}; constexpr bool operator==(const CSSRotateY& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of rotateZ() transform function. */ struct CSSRotateZ { float degrees{}; constexpr bool operator==(const CSSRotateZ& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of skewX() transform function. */ struct CSSSkewX { float degrees{}; constexpr bool operator==(const CSSSkewX& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of skewY() transform function. */ struct CSSSkewY { float degrees{}; constexpr bool operator==(const CSSSkewY& rhs) const = default; }; template <> struct CSSDataTypeParser : public detail::CSSAngleTransformParser {}; static_assert(CSSDataType); /** * Representation of perspective() transform function. */ struct CSSPerspective { CSSLength length{}; constexpr bool operator==(const CSSPerspective& rhs) const = default; }; template <> struct CSSDataTypeParser { static constexpr auto consumeFunctionBlock( const CSSFunctionBlock& func, CSSSyntaxParser& parser) -> std::optional { if (!iequals(func.name, "perspective")) { return {}; } auto value = parseNextCSSValue(parser); if (std::holds_alternative(value) || std::get(value).value < 0) { return {}; } return CSSPerspective{ .length = std::get(value), }; } }; static_assert(CSSDataType); /** * Represents one of the types supported by react-native. * https://drafts.csswg.org/css-transforms-2/#transform-functions */ using CSSTransformFunction = CSSCompoundDataType< CSSMatrix, CSSTranslate, CSSTranslateX, CSSTranslateY, CSSTranslate3D, CSSScale, CSSScaleX, CSSScaleY, CSSRotate, CSSRotateX, CSSRotateY, CSSRotateZ, CSSSkewX, CSSSkewY, CSSPerspective>; /** * Represents the type. * https://drafts.csswg.org/css-transforms-1/#typedef-transform-list */ using CSSTransformList = CSSWhitespaceSeparatedList; } // namespace facebook::react