From ce243df9725baff265fcd275b420ee78971e75cb Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Mon, 22 Sep 2025 03:28:31 -0700 Subject: [PATCH] Correctly implement transform: matrix with 2d matrices (#53860) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53860 Fixes https://github.com/facebook/react-native/issues/53639 I've realized that our docs and validation logic states that we do support 3x3 matrixes (for 2d transforms). However they're not properly processed as the values are just copied into a 4x4 matrix. This can be verified by applying the 3x3 identity matrix on any transform. I'm fixing it by correctly populating the 4x4 matrix getting the values from the 3x3 matrix in input. Changelog: [General] [Fixed] - 9-element (2d) transform matrix are not correctly working Reviewed By: christophpurrer Differential Revision: D82836192 fbshipit-source-id: 12029b37ffd8375fff48ea7f9386b849dfe96a62 --- .../renderer/components/view/conversions.h | 30 ++++++++++++++-- .../js/examples/Transform/TransformExample.js | 34 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h index 0927a1a83bb..d0a8fd98989 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h @@ -614,8 +614,34 @@ inline void fromRawValue( } size_t i = 0; - for (auto number : numbers) { - transformMatrix.matrix[i++] = number; + if (numbers.size() == 16) { + for (auto number : numbers) { + transformMatrix.matrix[i++] = number; + } + } else if (numbers.size() == 9) { + // We need to convert the 2d transform matrix into a 3d one as such: + // [ + // x01, x02, 0, x03 + // x10, x11, 0, x12 + // 0, 0, 1, 0 + // x20, x21, 0, x22 + // ] + transformMatrix.matrix[0] = numbers[0]; + transformMatrix.matrix[1] = numbers[1]; + transformMatrix.matrix[2] = 0; + transformMatrix.matrix[3] = numbers[2]; + transformMatrix.matrix[4] = numbers[3]; + transformMatrix.matrix[5] = numbers[4]; + transformMatrix.matrix[6] = 0; + transformMatrix.matrix[7] = numbers[5]; + transformMatrix.matrix[8] = 0; + transformMatrix.matrix[9] = 0; + transformMatrix.matrix[10] = 1; + transformMatrix.matrix[11] = 0; + transformMatrix.matrix[12] = numbers[6]; + transformMatrix.matrix[13] = numbers[7]; + transformMatrix.matrix[14] = 0; + transformMatrix.matrix[15] = numbers[8]; } transformMatrix.operations.push_back(TransformOperation{ TransformOperationType::Arbitrary, Zero, Zero, Zero}); diff --git a/packages/rn-tester/js/examples/Transform/TransformExample.js b/packages/rn-tester/js/examples/Transform/TransformExample.js index 963dd89b106..cd6c1b1d020 100644 --- a/packages/rn-tester/js/examples/Transform/TransformExample.js +++ b/packages/rn-tester/js/examples/Transform/TransformExample.js @@ -144,6 +144,13 @@ function TranslatePercentage() { return ; } +function TranslateMatrix2D() { + return ; +} +function TranslateMatrix3D() { + return ; +} + const styles = StyleSheet.create({ container: { height: 500, @@ -288,6 +295,18 @@ const styles = StyleSheet.create({ alignSelf: 'flex-start', backgroundColor: 'lightblue', }, + translateMatrix2D: { + transform: [{matrix: [1, 0, 0, 0, 1, 0, 0, 0, 1]}], + width: 50, + height: 50, + backgroundColor: 'red', + }, + translateMatrix3D: { + transform: [{matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]}], + height: 50, + width: 50, + backgroundColor: 'green', + }, }); exports.title = 'Transforms'; @@ -414,4 +433,19 @@ exports.examples = [ return ; }, }, + { + title: 'Transform Matrix 2D', + description: "transform: 'matrix(1, 0, 0, 0, 1, 0, 0, 0, 1)'", + render(): React.Node { + return ; + }, + }, + { + title: 'Transform Matrix 3D', + description: + "transform: 'matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)'", + render(): React.Node { + return ; + }, + }, ] as Array;