Files
react-native/React/Views/RCTConvert+Transform.m
T
Moti Zilberman cb28a2c46e Reduce use of RCTLogError (redbox) in prop parsing (#36161)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36161

Changelog:
[iOS][Fixed] - Invalid prop values no longer trigger redbox in the legacy renderer

## Context

We are changing React Native to behave more like a browser in the sense that **bad style values are not runtime errors**. (See e.g. D43159284 (https://github.com/facebook/react-native/commit/d6e9891577c81503407adaa85db8f5bf97557db0), D43184380.) The recommended way for developers to ensure they are passing correct style values is to use a typechecker (TypeScript or Flow) in conjunction with E2E tests and manual spot checks.

## This diff

This change is similar to D43184380, but here we target the legacy renderer on iOS by removing the redboxes from most of `RCTConvert`'s methods.

I'm intentionally going with the simplest possible improvement which is to downgrade the redboxes to `RCTLogInfo` ( = log to stdout but not the JS console). Leaving the call sites in place (as opposed to deleting them) will be helpful if we decide that we want to repurpose these checks for a new, more visible diagnostic (though we would likely only build such a diagnostic in Fabric at this point).

Reviewed By: javache

Differential Revision: D43184379

fbshipit-source-id: 5a3d12f5d884372c7dc8743227d58d403caf24e3
2023-02-15 09:34:23 -08:00

148 lines
5.3 KiB
Objective-C

/*
* 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.
*/
#import "RCTConvert+Transform.h"
static const NSUInteger kMatrixArrayLength = 4 * 4;
@implementation RCTConvert (Transform)
+ (CGFloat)convertToRadians:(id)json
{
if ([json isKindOfClass:[NSString class]]) {
NSString *stringValue = (NSString *)json;
if ([stringValue hasSuffix:@"deg"]) {
CGFloat degrees = [[stringValue substringToIndex:stringValue.length - 3] floatValue];
return degrees * M_PI / 180;
}
if ([stringValue hasSuffix:@"rad"]) {
return [[stringValue substringToIndex:stringValue.length - 3] floatValue];
}
}
return [json floatValue];
}
+ (CATransform3D)CATransform3DFromMatrix:(id)json
{
CATransform3D transform = CATransform3DIdentity;
if (!json) {
return transform;
}
if (![json isKindOfClass:[NSArray class]]) {
RCTLogConvertError(json, @"a CATransform3D. Expected array for transform matrix.");
return transform;
}
if ([json count] != kMatrixArrayLength) {
RCTLogConvertError(json, @"a CATransform3D. Expected 4x4 matrix array.");
return transform;
}
for (NSUInteger i = 0; i < kMatrixArrayLength; i++) {
((CGFloat *)&transform)[i] = [RCTConvert CGFloat:json[i]];
}
return transform;
}
+ (CATransform3D)CATransform3D:(id)json
{
CATransform3D transform = CATransform3DIdentity;
if (!json) {
return transform;
}
if (![json isKindOfClass:[NSArray class]]) {
RCTLogConvertError(json, @"a CATransform3D. Did you pass something other than an array?");
return transform;
}
// legacy matrix support
if ([(NSArray *)json count] == kMatrixArrayLength && [json[0] isKindOfClass:[NSNumber class]]) {
RCTLogWarn(
@"[RCTConvert CATransform3D:] has deprecated a matrix as input. Pass an array of configs (which can contain a matrix key) instead.");
return [self CATransform3DFromMatrix:json];
}
CGFloat zeroScaleThreshold = FLT_EPSILON;
CATransform3D next;
for (NSDictionary *transformConfig in (NSArray<NSDictionary *> *)json) {
if (transformConfig.count != 1) {
RCTLogConvertError(json, @"a CATransform3D. You must specify exactly one property per transform object.");
return transform;
}
NSString *property = transformConfig.allKeys[0];
id value = transformConfig[property];
if ([property isEqualToString:@"matrix"]) {
next = [self CATransform3DFromMatrix:value];
transform = CATransform3DConcat(next, transform);
} else if ([property isEqualToString:@"perspective"]) {
next = CATransform3DIdentity;
next.m34 = -1 / [value floatValue];
transform = CATransform3DConcat(next, transform);
} else if ([property isEqualToString:@"rotateX"]) {
CGFloat rotate = [self convertToRadians:value];
transform = CATransform3DRotate(transform, rotate, 1, 0, 0);
} else if ([property isEqualToString:@"rotateY"]) {
CGFloat rotate = [self convertToRadians:value];
transform = CATransform3DRotate(transform, rotate, 0, 1, 0);
} else if ([property isEqualToString:@"rotate"] || [property isEqualToString:@"rotateZ"]) {
CGFloat rotate = [self convertToRadians:value];
transform = CATransform3DRotate(transform, rotate, 0, 0, 1);
} else if ([property isEqualToString:@"scale"]) {
CGFloat scale = [value floatValue];
scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
transform = CATransform3DScale(transform, scale, scale, 1);
} else if ([property isEqualToString:@"scaleX"]) {
CGFloat scale = [value floatValue];
scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
transform = CATransform3DScale(transform, scale, 1, 1);
} else if ([property isEqualToString:@"scaleY"]) {
CGFloat scale = [value floatValue];
scale = ABS(scale) < zeroScaleThreshold ? zeroScaleThreshold : scale;
transform = CATransform3DScale(transform, 1, scale, 1);
} else if ([property isEqualToString:@"translate"]) {
NSArray *array = (NSArray<NSNumber *> *)value;
CGFloat translateX = [array[0] floatValue];
CGFloat translateY = [array[1] floatValue];
CGFloat translateZ = array.count > 2 ? [array[2] floatValue] : 0;
transform = CATransform3DTranslate(transform, translateX, translateY, translateZ);
} else if ([property isEqualToString:@"translateX"]) {
CGFloat translate = [value floatValue];
transform = CATransform3DTranslate(transform, translate, 0, 0);
} else if ([property isEqualToString:@"translateY"]) {
CGFloat translate = [value floatValue];
transform = CATransform3DTranslate(transform, 0, translate, 0);
} else if ([property isEqualToString:@"skewX"]) {
CGFloat skew = [self convertToRadians:value];
next = CATransform3DIdentity;
next.m21 = tanf(skew);
transform = CATransform3DConcat(next, transform);
} else if ([property isEqualToString:@"skewY"]) {
CGFloat skew = [self convertToRadians:value];
next = CATransform3DIdentity;
next.m12 = tanf(skew);
transform = CATransform3DConcat(next, transform);
} else {
RCTLogInfo(@"Unsupported transform type for a CATransform3D: %@.", property);
}
}
return transform;
}
@end