|
9 | 9 |
|
10 | 10 | #include <glog/logging.h> |
11 | 11 | #include <react/debug/react_native_expect.h> |
| 12 | +#include <react/featureflags/ReactNativeFeatureFlags.h> |
12 | 13 | #include <react/renderer/components/view/primitives.h> |
13 | 14 | #include <react/renderer/core/LayoutMetrics.h> |
14 | 15 | #include <react/renderer/core/PropsParserContext.h> |
|
17 | 18 | #include <react/renderer/css/CSSAngle.h> |
18 | 19 | #include <react/renderer/css/CSSNumber.h> |
19 | 20 | #include <react/renderer/css/CSSPercentage.h> |
| 21 | +#include <react/renderer/css/CSSRatio.h> |
| 22 | +#include <react/renderer/css/CSSTransform.h> |
| 23 | +#include <react/renderer/css/CSSTransformOrigin.h> |
20 | 24 | #include <react/renderer/css/CSSValueParser.h> |
21 | 25 | #include <react/renderer/debug/flags.h> |
22 | 26 | #include <react/renderer/graphics/BackgroundPosition.h> |
@@ -533,7 +537,136 @@ inline void fromRawValue(const PropsParserContext & /*context*/, const RawValue |
533 | 537 | result = toValueUnit(value); |
534 | 538 | } |
535 | 539 |
|
536 | | -inline void fromRawValue(const PropsParserContext & /*context*/, const RawValue &value, Transform &result) |
| 540 | +inline ValueUnit cssLengthPercentageToValueUnit(const std::variant<CSSLength, CSSPercentage> &value) |
| 541 | +{ |
| 542 | + if (std::holds_alternative<CSSLength>(value)) { |
| 543 | + auto len = std::get<CSSLength>(value); |
| 544 | + if (len.unit != CSSLengthUnit::Px) { |
| 545 | + return {}; |
| 546 | + } |
| 547 | + return {len.value, UnitType::Point}; |
| 548 | + } else { |
| 549 | + return {std::get<CSSPercentage>(value).value, UnitType::Percent}; |
| 550 | + } |
| 551 | +} |
| 552 | + |
| 553 | +inline std::optional<TransformOperation> fromCSSTransformFunction(const CSSTransformFunctionVariant &cssTransform) |
| 554 | +{ |
| 555 | + constexpr auto Zero = ValueUnit(0, UnitType::Point); |
| 556 | + constexpr auto One = ValueUnit(1, UnitType::Point); |
| 557 | + |
| 558 | + return std::visit( |
| 559 | + [&](auto &&func) -> std::optional<TransformOperation> { |
| 560 | + using T = std::decay_t<decltype(func)>; |
| 561 | + |
| 562 | + if constexpr (std::is_same_v<T, CSSRotate>) { |
| 563 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 564 | + return TransformOperation{ |
| 565 | + .type = TransformOperationType::Rotate, .x = Zero, .y = Zero, .z = ValueUnit(radians, UnitType::Point)}; |
| 566 | + } |
| 567 | + |
| 568 | + if constexpr (std::is_same_v<T, CSSRotateX>) { |
| 569 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 570 | + return TransformOperation{ |
| 571 | + .type = TransformOperationType::Rotate, .x = ValueUnit(radians, UnitType::Point), .y = Zero, .z = Zero}; |
| 572 | + } |
| 573 | + |
| 574 | + if constexpr (std::is_same_v<T, CSSRotateY>) { |
| 575 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 576 | + return TransformOperation{ |
| 577 | + .type = TransformOperationType::Rotate, .x = Zero, .y = ValueUnit(radians, UnitType::Point), .z = Zero}; |
| 578 | + } |
| 579 | + |
| 580 | + if constexpr (std::is_same_v<T, CSSRotateZ>) { |
| 581 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 582 | + return TransformOperation{ |
| 583 | + .type = TransformOperationType::Rotate, .x = Zero, .y = Zero, .z = ValueUnit(radians, UnitType::Point)}; |
| 584 | + } |
| 585 | + |
| 586 | + if constexpr (std::is_same_v<T, CSSTranslate>) { |
| 587 | + auto x = cssLengthPercentageToValueUnit(func.x); |
| 588 | + auto y = cssLengthPercentageToValueUnit(func.y); |
| 589 | + if (!x || !y) { |
| 590 | + return std::nullopt; |
| 591 | + } |
| 592 | + return TransformOperation{.type = TransformOperationType::Translate, .x = x, .y = y, .z = Zero}; |
| 593 | + } |
| 594 | + |
| 595 | + if constexpr (std::is_same_v<T, CSSTranslateX>) { |
| 596 | + auto x = cssLengthPercentageToValueUnit(func.value); |
| 597 | + if (!x) { |
| 598 | + return std::nullopt; |
| 599 | + } |
| 600 | + return TransformOperation{.type = TransformOperationType::Translate, .x = x, .y = Zero, .z = Zero}; |
| 601 | + } |
| 602 | + |
| 603 | + if constexpr (std::is_same_v<T, CSSTranslateY>) { |
| 604 | + auto y = cssLengthPercentageToValueUnit(func.value); |
| 605 | + if (!y) { |
| 606 | + return std::nullopt; |
| 607 | + } |
| 608 | + return TransformOperation{.type = TransformOperationType::Translate, .x = Zero, .y = y, .z = Zero}; |
| 609 | + } |
| 610 | + |
| 611 | + if constexpr (std::is_same_v<T, CSSTranslate3D>) { |
| 612 | + auto x = cssLengthPercentageToValueUnit(func.x); |
| 613 | + auto y = cssLengthPercentageToValueUnit(func.y); |
| 614 | + if (!x || !y || func.z.unit != CSSLengthUnit::Px) { |
| 615 | + return std::nullopt; |
| 616 | + } |
| 617 | + return TransformOperation{ |
| 618 | + .type = TransformOperationType::Translate, .x = x, .y = y, .z = ValueUnit(func.z.value, UnitType::Point)}; |
| 619 | + } |
| 620 | + |
| 621 | + if constexpr (std::is_same_v<T, CSSScale>) { |
| 622 | + return TransformOperation{ |
| 623 | + .type = TransformOperationType::Scale, |
| 624 | + .x = ValueUnit(func.x, UnitType::Point), |
| 625 | + .y = ValueUnit(func.y, UnitType::Point), |
| 626 | + .z = One}; |
| 627 | + } |
| 628 | + |
| 629 | + if constexpr (std::is_same_v<T, CSSScaleX>) { |
| 630 | + return TransformOperation{ |
| 631 | + .type = TransformOperationType::Scale, .x = ValueUnit(func.value, UnitType::Point), .y = One, .z = One}; |
| 632 | + } |
| 633 | + |
| 634 | + if constexpr (std::is_same_v<T, CSSScaleY>) { |
| 635 | + return TransformOperation{ |
| 636 | + .type = TransformOperationType::Scale, .x = One, .y = ValueUnit(func.value, UnitType::Point), .z = One}; |
| 637 | + } |
| 638 | + |
| 639 | + if constexpr (std::is_same_v<T, CSSSkewX>) { |
| 640 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 641 | + return TransformOperation{ |
| 642 | + .type = TransformOperationType::Skew, .x = ValueUnit(radians, UnitType::Point), .y = Zero, .z = Zero}; |
| 643 | + } |
| 644 | + |
| 645 | + if constexpr (std::is_same_v<T, CSSSkewY>) { |
| 646 | + auto radians = static_cast<float>(func.degrees * M_PI / 180.0f); |
| 647 | + return TransformOperation{ |
| 648 | + .type = TransformOperationType::Skew, .x = Zero, .y = ValueUnit(radians, UnitType::Point), .z = Zero}; |
| 649 | + } |
| 650 | + |
| 651 | + if constexpr (std::is_same_v<T, CSSPerspective>) { |
| 652 | + if (func.length.unit != CSSLengthUnit::Px) { |
| 653 | + return std::nullopt; |
| 654 | + } |
| 655 | + return TransformOperation{ |
| 656 | + .type = TransformOperationType::Perspective, |
| 657 | + .x = ValueUnit(func.length.value, UnitType::Point), |
| 658 | + .y = Zero, |
| 659 | + .z = Zero}; |
| 660 | + } |
| 661 | + |
| 662 | + if constexpr (std::is_same_v<T, CSSMatrix>) { |
| 663 | + return TransformOperation{.type = TransformOperationType::Arbitrary, .x = Zero, .y = Zero, .z = Zero}; |
| 664 | + } |
| 665 | + }, |
| 666 | + cssTransform); |
| 667 | +} |
| 668 | + |
| 669 | +inline void parseProcessedTransform(const PropsParserContext & /*context*/, const RawValue &value, Transform &result) |
537 | 670 | { |
538 | 671 | auto transformMatrix = Transform{}; |
539 | 672 | react_native_expect(value.hasType<std::vector<RawValue>>()); |
@@ -770,6 +903,71 @@ inline void fromRawValue(const PropsParserContext & /*context*/, const RawValue |
770 | 903 | result = transformMatrix; |
771 | 904 | } |
772 | 905 |
|
| 906 | +inline void parseUnprocessedTransformString(const std::string &value, Transform &result) |
| 907 | +{ |
| 908 | + auto transformList = parseCSSProperty<CSSTransformList>(value); |
| 909 | + if (!std::holds_alternative<CSSTransformList>(transformList)) { |
| 910 | + result = {}; |
| 911 | + return; |
| 912 | + } |
| 913 | + |
| 914 | + auto transformMatrix = Transform{}; |
| 915 | + const auto &cssFuncs = std::get<CSSTransformList>(transformList); |
| 916 | + transformMatrix.operations.reserve(cssFuncs.size()); |
| 917 | + for (const auto &cssFunc : cssFuncs) { |
| 918 | + auto op = fromCSSTransformFunction(cssFunc); |
| 919 | + if (!op.has_value()) { |
| 920 | + result = {}; |
| 921 | + return; |
| 922 | + } |
| 923 | + |
| 924 | + if (op->type == TransformOperationType::Arbitrary) { |
| 925 | + // CSSMatrix: expand 6-value 2D matrix to 4x4 matrix |
| 926 | + if (std::holds_alternative<CSSMatrix>(cssFunc)) { |
| 927 | + const auto &m = std::get<CSSMatrix>(cssFunc); |
| 928 | + transformMatrix.matrix[0] = m.values[0]; |
| 929 | + transformMatrix.matrix[1] = m.values[1]; |
| 930 | + transformMatrix.matrix[2] = 0; |
| 931 | + transformMatrix.matrix[3] = 0; |
| 932 | + transformMatrix.matrix[4] = m.values[2]; |
| 933 | + transformMatrix.matrix[5] = m.values[3]; |
| 934 | + transformMatrix.matrix[6] = 0; |
| 935 | + transformMatrix.matrix[7] = 0; |
| 936 | + transformMatrix.matrix[8] = 0; |
| 937 | + transformMatrix.matrix[9] = 0; |
| 938 | + transformMatrix.matrix[10] = 1; |
| 939 | + transformMatrix.matrix[11] = 0; |
| 940 | + transformMatrix.matrix[12] = m.values[4]; |
| 941 | + transformMatrix.matrix[13] = m.values[5]; |
| 942 | + transformMatrix.matrix[14] = 0; |
| 943 | + transformMatrix.matrix[15] = 1; |
| 944 | + } |
| 945 | + } |
| 946 | + |
| 947 | + transformMatrix.operations.push_back(*op); |
| 948 | + } |
| 949 | + |
| 950 | + result = transformMatrix; |
| 951 | +} |
| 952 | + |
| 953 | +inline void parseUnprocessedTransform(const PropsParserContext &context, const RawValue &value, Transform &result) |
| 954 | +{ |
| 955 | + if (value.hasType<std::string>()) { |
| 956 | + parseUnprocessedTransformString((std::string)value, result); |
| 957 | + } else { |
| 958 | + parseProcessedTransform(context, value, result); |
| 959 | + } |
| 960 | +} |
| 961 | + |
| 962 | +inline void fromRawValue(const PropsParserContext &context, const RawValue &value, Transform &result) |
| 963 | +{ |
| 964 | + if (ReactNativeFeatureFlags::enableNativeCSSParsing()) { |
| 965 | + parseUnprocessedTransform(context, value, result); |
| 966 | + } else { |
| 967 | + parseProcessedTransform(context, value, result); |
| 968 | + } |
| 969 | +} |
| 970 | + |
773 | 971 | inline void fromRawValue(const PropsParserContext &context, const RawValue &value, TransformOrigin &result) |
774 | 972 | { |
775 | 973 | if (!value.hasType<std::vector<RawValue>>()) { |
|
0 commit comments