diff --git a/Libraries/StyleSheet/processTransform.js b/Libraries/StyleSheet/processTransform.js index fc44b5f8c..bddd54f54 100644 --- a/Libraries/StyleSheet/processTransform.js +++ b/Libraries/StyleSheet/processTransform.js @@ -26,14 +26,22 @@ var stringifySafe = require('stringifySafe'); * interface to native code. */ function processTransform(transform: Object): Object { + if (__DEV__) { + _validateTransforms(transform); + } + + // Android implementation of transform property accepts the list of transform + // properties as opposed to a transform Matrix. This is necessary to control + // transform property updates completely on the native thread. + if (Platform.OS === 'android') { + return transform; + } + var result = MatrixMath.createIdentityMatrix(); transform.forEach(transformation => { var key = Object.keys(transformation)[0]; var value = transformation[key]; - if (__DEV__) { - _validateTransform(key, value, transformation); - } switch (key) { case 'matrix': @@ -107,6 +115,14 @@ function _convertToRadians(value: string): number { return value.indexOf('rad') > -1 ? floatValue : floatValue * Math.PI / 180; } +function _validateTransforms(transform: Object): void { + transform.forEach(transformation => { + var key = Object.keys(transformation)[0]; + var value = transformation[key]; + _validateTransform(key, value, transformation); + }); +} + function _validateTransform(key, value, transformation) { invariant( !value.getValue, diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 4586bf78b..815bad0fa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -8,7 +8,6 @@ import android.view.View; import android.view.ViewGroup; import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.annotations.ReactProp; /** @@ -53,9 +52,9 @@ public abstract class BaseViewManager sHelperMatrix = new ThreadLocal() { + @Override + protected double[] initialValue() { + return new double[16]; + } + }; + + private static double convertToRadians(ReadableMap transformMap, String key) { + double value; + boolean inRadians = false; + if (transformMap.getType(key) == ReadableType.String) { + String stringValue = transformMap.getString(key); + if (stringValue.endsWith("rad")) { + inRadians = true; + stringValue = stringValue.substring(0, stringValue.length() - 3); + } else if (stringValue.endsWith("deg")) { + stringValue = stringValue.substring(0, stringValue.length() - 3); + } + value = Float.parseFloat(stringValue); + } else { + value = transformMap.getDouble(key); + } + return inRadians ? value : MatrixMathHelper.degreesToRadians(value); + } + + public static void processTransform(ReadableArray transforms, double[] result) { + double[] helperMatrix = sHelperMatrix.get(); + MatrixMathHelper.resetIdentityMatrix(result); + + for (int transformIdx = 0, size = transforms.size(); transformIdx < size; transformIdx++) { + ReadableMap transform = transforms.getMap(transformIdx); + String transformType = transform.keySetIterator().nextKey(); + + MatrixMathHelper.resetIdentityMatrix(helperMatrix); + if ("matrix".equals(transformType)) { + ReadableArray matrix = transform.getArray(transformType); + for (int i = 0; i < 16; i++) { + helperMatrix[i] = matrix.getDouble(i); + } + } else if ("perspective".equals(transformType)) { + MatrixMathHelper.applyPerspective(helperMatrix, transform.getDouble(transformType)); + } else if ("rotateX".equals(transformType)) { + MatrixMathHelper.applyRotateX( + helperMatrix, + convertToRadians(transform, transformType)); + } else if ("rotateY".equals(transformType)) { + MatrixMathHelper.applyRotateY( + helperMatrix, + convertToRadians(transform, transformType)); + } else if ("rotate".equals(transformType) || "rotateZ".equals(transformType)) { + MatrixMathHelper.applyRotateZ( + helperMatrix, + convertToRadians(transform, transformType)); + } else if ("scale".equals(transformType)) { + MatrixMathHelper.applyScaleZ(helperMatrix, transform.getDouble(transformType)); + } else if ("scaleX".equals(transformType)) { + MatrixMathHelper.applyScaleX(helperMatrix, transform.getDouble(transformType)); + } else if ("scaleY".equals(transformType)) { + MatrixMathHelper.applyScaleY(helperMatrix, transform.getDouble(transformType)); + } else if ("translate".equals(transformType)) { + ReadableArray value = transform.getArray(transformType); + double x = value.getDouble(0); + double y = value.getDouble(1); + double z = value.size() > 2 ? value.getDouble(2) : 0d; + MatrixMathHelper.applyTranslate3D(helperMatrix, x, y, z); + } else if ("translateX".equals(transformType)) { + MatrixMathHelper.applyTranslate2D(helperMatrix, transform.getDouble(transformType), 0d); + } else if ("translateY".equals(transformType)) { + MatrixMathHelper.applyTranslate2D(helperMatrix, 0d, transform.getDouble(transformType)); + } else if ("skewX".equals(transformType)) { + MatrixMathHelper.applySkewX( + helperMatrix, + convertToRadians(transform, transformType)); + } else if ("skewY".equals(transformType)) { + MatrixMathHelper.applySkewY( + helperMatrix, + convertToRadians(transform, transformType)); + } else { + throw new JSApplicationIllegalArgumentException("Unsupported transform type: " + + transformType); + } + + MatrixMathHelper.multiplyInto(result, result, helperMatrix); + } + } +} diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/MatrixMathHelperTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/MatrixMathHelperTest.java index 66e9a2144..c7d332813 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/MatrixMathHelperTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/MatrixMathHelperTest.java @@ -114,21 +114,12 @@ public class MatrixMathHelperTest { verifyXRotatedMatrix(360, 0d, 0d, 0d); } - private static double[] createIdentityMatrix() { - return new double[] { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - } - private static double degreesToRadians(double degrees) { return degrees * Math.PI / 180; } private static double[] createRotateZ(double radians) { - double[] mat = createIdentityMatrix(); + double[] mat = MatrixMathHelper.createIdentityMatrix(); mat[0] = Math.cos(radians); mat[1] = Math.sin(radians); mat[4] = -Math.sin(radians); @@ -137,7 +128,7 @@ public class MatrixMathHelperTest { } private static double[] createRotateY(double radians) { - double[] mat = createIdentityMatrix(); + double[] mat = MatrixMathHelper.createIdentityMatrix(); mat[0] = Math.cos(radians); mat[2] = -Math.sin(radians); mat[8] = Math.sin(radians); @@ -146,7 +137,7 @@ public class MatrixMathHelperTest { } private static double[] createRotateX(double radians) { - double[] mat = createIdentityMatrix(); + double[] mat = MatrixMathHelper.createIdentityMatrix(); mat[5] = Math.cos(radians); mat[6] = Math.sin(radians); mat[9] = -Math.sin(radians);