diff --git a/packages/react-native/React-Core.podspec b/packages/react-native/React-Core.podspec index b912979d47af30..97bfafcc149ddc 100644 --- a/packages/react-native/React-Core.podspec +++ b/packages/react-native/React-Core.podspec @@ -134,6 +134,8 @@ Pod::Spec.new do |s| add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern') add_dependency(s, "RCTDeprecation") + add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"]) + if use_hermes s.dependency 'React-hermes' diff --git a/packages/react-native/React/Base/RCTConvert.h b/packages/react-native/React/Base/RCTConvert.h index 2d55e7c99acf12..f0ef6ac3c489b3 100644 --- a/packages/react-native/React/Base/RCTConvert.h +++ b/packages/react-native/React/Base/RCTConvert.h @@ -17,6 +17,15 @@ #import #import +typedef NS_ENUM(NSInteger, RCTColorSpace) { + RCTColorSpaceSRGB, + RCTColorSpaceDisplayP3, +}; + +// Change the default color space +RCTColorSpace RCTGetDefaultColorSpace(void); +RCT_EXTERN void RCTSetDefaultColorSpace(RCTColorSpace colorSpace); + /** * This class provides a collection of conversion functions for mapping * JSON objects to native types and classes. These are useful when writing @@ -91,6 +100,13 @@ typedef NSURL RCTFileURL; + (CGAffineTransform)CGAffineTransform:(id)json; ++ (UIColor *)RCTCreateColorWith:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; ++ (UIColor *)RCTCreateColorWith:(CGFloat)red + green:(CGFloat)green + blue:(CGFloat)blue + alpha:(CGFloat)alpha + andColorSpace:(RCTColorSpace)colorSpace; ++ (RCTColorSpace)colorSpaceFromString:(NSString *)colorSpace; + (UIColor *)UIColor:(id)json; + (CGColorRef)CGColor:(id)json CF_RETURNS_NOT_RETAINED; diff --git a/packages/react-native/React/Base/RCTConvert.m b/packages/react-native/React/Base/RCTConvert.mm similarity index 94% rename from packages/react-native/React/Base/RCTConvert.m rename to packages/react-native/React/Base/RCTConvert.mm index ae10d7713ee328..bf4c4726657de8 100644 --- a/packages/react-native/React/Base/RCTConvert.m +++ b/packages/react-native/React/Base/RCTConvert.mm @@ -16,6 +16,8 @@ #import "RCTParserUtils.h" #import "RCTUtils.h" +#import + @implementation RCTConvert RCT_CONVERTER(id, id, self) @@ -439,7 +441,7 @@ + (UIKeyboardType)UIKeyboardType:(id)json RCT_DYNAMIC mapping = temporaryMapping; }); - UIKeyboardType type = RCTConvertEnumValue("UIKeyboardType", mapping, @(UIKeyboardTypeDefault), json).integerValue; + UIKeyboardType type = (UIKeyboardType)RCTConvertEnumValue("UIKeyboardType", mapping, @(UIKeyboardTypeDefault), json).integerValue; return type; } @@ -844,7 +846,7 @@ + (UIEdgeInsets)UIEdgeInsets:(id)json RCTAssert([UIColor respondsToSelector:selector], @"RCTUIColor does not respond to a semantic color selector."); Class klass = [UIColor class]; IMP imp = [klass methodForSelector:selector]; - id (*getSemanticColorObject)(id, SEL) = (void *)imp; + id (*getSemanticColorObject)(id, SEL) = (id (*)(id, SEL))imp; id colorObject = getSemanticColorObject(klass, selector); if ([colorObject isKindOfClass:[UIColor class]]) { color = colorObject; @@ -878,6 +880,37 @@ + (UIEdgeInsets)UIEdgeInsets:(id)json return names; } +RCTColorSpace RCTGetDefaultColorSpace(void) +{ + return (RCTColorSpace)facebook::react::getDefaultColorSpace(); +} +void RCTSetDefaultColorSpace(RCTColorSpace colorSpace) +{ + facebook::react::setDefaultColorSpace((facebook::react::ColorSpace)colorSpace); +} + ++ (UIColor *)RCTCreateColorWith:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha +{ + RCTColorSpace space = RCTGetDefaultColorSpace(); + return [self RCTCreateColorWith:red green:green blue:blue alpha:alpha andColorSpace:space]; +} ++ (UIColor *)RCTCreateColorWith:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha andColorSpace:(RCTColorSpace)colorSpace +{ + if (colorSpace == RCTColorSpaceDisplayP3) { + return [UIColor colorWithDisplayP3Red:red green:green blue:blue alpha:alpha]; + } + return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +} + ++ (RCTColorSpace)colorSpaceFromString:(NSString *)colorSpace { + if ([colorSpace isEqualToString:@"display-p3"]) { + return RCTColorSpaceDisplayP3; + } else if ([colorSpace isEqualToString:@"srgb"]) { + return RCTColorSpaceSRGB; + } + return RCTGetDefaultColorSpace(); +} + + (UIColor *)UIColor:(id)json { if (!json) { @@ -886,21 +919,29 @@ + (UIColor *)UIColor:(id)json if ([json isKindOfClass:[NSArray class]]) { NSArray *components = [self NSNumberArray:json]; CGFloat alpha = components.count > 3 ? [self CGFloat:components[3]] : 1.0; - return [UIColor colorWithRed:[self CGFloat:components[0]] - green:[self CGFloat:components[1]] - blue:[self CGFloat:components[2]] - alpha:alpha]; + return [self RCTCreateColorWith:[self CGFloat:components[0]] + green:[self CGFloat:components[1]] + blue:[self CGFloat:components[2]] + alpha:alpha]; } else if ([json isKindOfClass:[NSNumber class]]) { NSUInteger argb = [self NSUInteger:json]; CGFloat a = ((argb >> 24) & 0xFF) / 255.0; CGFloat r = ((argb >> 16) & 0xFF) / 255.0; CGFloat g = ((argb >> 8) & 0xFF) / 255.0; CGFloat b = (argb & 0xFF) / 255.0; - return [UIColor colorWithRed:r green:g blue:b alpha:a]; + return [self RCTCreateColorWith:r green:g blue:b alpha:a]; } else if ([json isKindOfClass:[NSDictionary class]]) { NSDictionary *dictionary = json; id value = nil; - if ((value = [dictionary objectForKey:@"semantic"])) { + NSString *rawColorSpace = [dictionary objectForKey: @"space"]; + if ([@[@"display-p3", @"srgb"] containsObject:rawColorSpace]) { + CGFloat r = [[dictionary objectForKey:@"r"] floatValue]; + CGFloat g = [[dictionary objectForKey:@"g"] floatValue]; + CGFloat b = [[dictionary objectForKey:@"b"] floatValue]; + CGFloat a = [[dictionary objectForKey:@"a"] floatValue]; + RCTColorSpace colorSpace = [self colorSpaceFromString: rawColorSpace]; + return [self RCTCreateColorWith:r green:g blue:b alpha:a andColorSpace:colorSpace]; + } else if ((value = [dictionary objectForKey:@"semantic"])) { if ([value isKindOfClass:[NSString class]]) { NSString *semanticName = value; UIColor *color = [UIColor colorNamed:semanticName]; diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.cpp new file mode 100644 index 00000000000000..04df5f39b2b188 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.cpp @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "ColorComponents.h" + +namespace facebook::react { + +static ColorSpace defaultColorSpace = ColorSpace::sRGB; + +ColorSpace getDefaultColorSpace() { + return defaultColorSpace; +} + +void setDefaultColorSpace(ColorSpace newColorSpace) { + defaultColorSpace = newColorSpace; +} + +} // namespace facebook::react \ No newline at end of file diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.h b/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.h index 0a3887a3caeb7e..ce60f7a4074f4a 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/ColorComponents.h @@ -9,11 +9,17 @@ namespace facebook::react { +enum class ColorSpace { sRGB, DisplayP3 }; + +ColorSpace getDefaultColorSpace(); +void setDefaultColorSpace(ColorSpace newColorSpace); + struct ColorComponents { float red{0}; float green{0}; float blue{0}; float alpha{0}; + ColorSpace colorSpace{getDefaultColorSpace()}; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec b/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec index b5faee3286fc0e..94743610da2fe2 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec +++ b/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec @@ -61,7 +61,8 @@ Pod::Spec.new do |s| s.dependency "glog" s.dependency "RCT-Folly/Fabric", folly_version - s.dependency "React-Core/Default", version + s.dependency "React-jsi" + s.dependency "React-jsiexecutor" s.dependency "React-utils" s.dependency "DoubleConversion" s.dependency "fmt", "9.1.0" diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h index fbc07288fa318b..800e0ab2e0d613 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h @@ -44,6 +44,24 @@ inline void fromRawValueShared( result = colorFromComponents(colorComponents); } else { + if (value.hasType>()) { + auto items = (std::unordered_map)value; + if (items.find("space") != items.end()) { + colorComponents.red = (float)items.at("r"); + colorComponents.green = (float)items.at("g"); + colorComponents.blue = (float)items.at("b"); + colorComponents.alpha = (float)items.at("a"); + colorComponents.colorSpace = getDefaultColorSpace(); + std::string space = (std::string)items.at("space"); + if (space == "display-p3") { + colorComponents.colorSpace = ColorSpace::DisplayP3; + } else if (space == "srgb") { + colorComponents.colorSpace = ColorSpace::sRGB; + } + result = colorFromComponents(colorComponents); + return; + } + } result = parsePlatformColor(contextContainer, surfaceId, value); } } diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm index 36cd4ac08f7b75..da7e933d98aebb 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm @@ -87,6 +87,9 @@ int32_t ColorFromUIColor(const std::shared_ptr &uiColor) UIColor *_Nullable UIColorFromComponentsColor(const facebook::react::ColorComponents &components) { + if (components.colorSpace == ColorSpace::DisplayP3) { + return [UIColor colorWithDisplayP3Red:components.red green:components.green blue:components.blue alpha:components.alpha]; + } return [UIColor colorWithRed:components.red green:components.green blue:components.blue alpha:components.alpha]; } } // anonymous namespace