Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Wide Gamut (DisplayP3) Colors to React Native #1

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
134b675
update normalizeColor and processColor to handle color()
ryanlntn Dec 19, 2023
396d05e
initial DisplayP3 support for iOS
ryanlntn Dec 21, 2023
f4539c6
fix testIDs
ryanlntn Dec 21, 2023
ee6d760
update js to use enum for color space
ryanlntn Jan 2, 2024
12e3c59
add global flag and reuse createColorFrom
ryanlntn Jan 2, 2024
88b16da
add static defaultColorSpace to ColorComponents
ryanlntn Jan 3, 2024
284653c
add colorSpaceFromString remove nested ternary
ryanlntn Jan 3, 2024
51414ea
fix RCTConversions and graphicsConversions
ryanlntn Jan 3, 2024
4c81a65
missed a cast
ryanlntn Jan 3, 2024
c5eab07
fix ColorComponents defaultColorSpace by providing getter
ryanlntn Jan 3, 2024
c9bddc8
update graphicsConversions to use getDefaultColorSpace
ryanlntn Jan 3, 2024
53090da
fix animated interpolation without native driver
ryanlntn Jan 4, 2024
a36c9fc
handle color space in AnimatedColor
ryanlntn Jan 4, 2024
7c5eeb9
mostly fix animation with native driver
ryanlntn Jan 5, 2024
4b6a0e8
temp include example animation
ryanlntn Jan 5, 2024
53aba9b
split out ColorComponents implementation to fix Android build
ryanlntn Jan 8, 2024
9f30b94
Revert "split out ColorComponents implementation to fix Android build"
ryanlntn Jan 8, 2024
f303df1
fix RCTGetDefaultColorSpace and RCTSetDefaultColorSpace
ryanlntn Jan 9, 2024
f975b6b
refactor away from RCTColorFromComponents in RCTColorAnimatedNode
ryanlntn Jan 9, 2024
1b41b02
refactor RCTInterpolateColorInRange
ryanlntn Jan 9, 2024
6a99355
Reapply "split out ColorComponents implementation to fix Android build"
ryanlntn Jan 9, 2024
2083fa0
initial Android handling of color function values (always sRGB for now)
ryanlntn Jan 9, 2024
f396fc3
fix crash in ColorAnimatedNode
ryanlntn Jan 10, 2024
e4b0949
fix color interpolation with native driver by reprocessing as srgb
ryanlntn Jan 11, 2024
506d1ab
set ReactActivity window color mode to COLOR_MODE_WIDE_COLOR_GAMUT
ryanlntn Jan 18, 2024
96ade88
get p3 backgrounds working
ryanlntn Jan 19, 2024
d3895f9
get display-p3 borders working in Android
ryanlntn Jan 20, 2024
a8d00a4
fix issues with bad defaults
ryanlntn Jan 20, 2024
e2884ad
update remaining color annotated props to long
ryanlntn Jan 23, 2024
f21a2a5
update MapBuffer to support long values
ryanlntn Jan 26, 2024
f0e1f69
change toAndroidRepr return type to int64_t
ryanlntn Jan 27, 2024
d65366e
update toAndroidRepr to support DisplayP3
ryanlntn Jan 30, 2024
5352b6d
update TextAttributesProps to support long colors
ryanlntn Jan 30, 2024
b5431ee
update ReactForegroundColorSpan so P3 text works
ryanlntn Jan 31, 2024
366001c
fix issues with basic FlatList example
ryanlntn Jan 31, 2024
6344460
update foreground and background color spans
ryanlntn Feb 1, 2024
e8cee4d
pass longs through scroll view managers to scroll views
ryanlntn Feb 1, 2024
d07c577
update endFillColor to support long colors
ryanlntn Feb 2, 2024
c6f8d99
update switch
ryanlntn Feb 2, 2024
b072f06
clean up ReactViewBackgroundDrawable
ryanlntn Feb 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions packages/normalize-color/__tests__/normalizeColor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,37 @@ it('handles number colors properly', () => {
expect(normalizeColor(0x01234567)).toBe(0x01234567);
});

it('handles color function properly', () => {
expect(normalizeColor('color(display-p3 1 0 0)')).toEqual({
space: 'display-p3',
r: 1,
g: 0,
b: 0,
a: 1,
});
expect(normalizeColor('color(display-p3 1 0 0 / 0.5)')).toEqual({
space: 'display-p3',
r: 1,
g: 0,
b: 0,
a: 0.5,
});
expect(normalizeColor('color(srgb 1 0 0)')).toEqual({
space: 'srgb',
r: 1,
g: 0,
b: 0,
a: 1,
});
expect(normalizeColor('color(srgb 1 0 0 / 0.5)')).toEqual({
space: 'srgb',
r: 1,
g: 0,
b: 0,
a: 0.5,
});
});

it('returns the same color when it is already normalized', () => {
const normalizedColor = normalizeColor('red') || 0;
expect(normalizeColor(normalizedColor)).toBe(normalizedColor);
Expand Down
26 changes: 26 additions & 0 deletions packages/normalize-color/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,24 @@ function normalizeColor(color) {
);
}

if ((match = matchers.color.exec(color))) {
return match[2]
? {
space: match[2],
r: parseFloat(match[3]),
g: parseFloat(match[4]),
b: parseFloat(match[5]),
a: 1,
}
: {
space: match[6],
r: parseFloat(match[7]),
g: parseFloat(match[8]),
b: parseFloat(match[9]),
a: parseFloat(match[10]),
};
}

return null;
}

Expand Down Expand Up @@ -209,6 +227,7 @@ function hwbToRgb(h, w, b) {
);
}

const COLOR_SPACE = 'display-p3|srgb';
const NUMBER = '[-+]?\\d*\\.?\\d+';
const PERCENTAGE = NUMBER + '%';

Expand All @@ -235,6 +254,13 @@ let cachedMatchers;
function getMatchers() {
if (cachedMatchers === undefined) {
cachedMatchers = {
color: new RegExp(
'color(' +
call(COLOR_SPACE, NUMBER, NUMBER, NUMBER) +
'|' +
callWithSlashSeparator(COLOR_SPACE, NUMBER, NUMBER, NUMBER, NUMBER) +
')',
),
rgb: new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER)),
rgba: new RegExp(
'rgba(' +
Expand Down
16 changes: 15 additions & 1 deletion packages/normalize-color/index.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@
* @flow strict
*/

declare module.exports: (color: ?(string | number)) => null | number;
enum ColorSpace {
SRGB = 'srgb',
DisplayP3 = 'display-p3',
}

export type RgbaValue = {
+space?: ColorSpace,
+r: number,
+g: number,
+b: number,
+a: number,
...
};

declare module.exports: (color: ?(string | number)) => null | number | RgbaValue;
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ function isRgbaAnimatedValue(value: any): boolean {
}

export default class AnimatedColor extends AnimatedWithChildren {
space: ?string;
r: AnimatedValue;
g: AnimatedValue;
b: AnimatedValue;
Expand Down Expand Up @@ -142,6 +143,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
this.nativeColor = (processedColor: NativeColorValue);
}

this.space = initColor.space;
this.r = new AnimatedValue(initColor.r);
this.g = new AnimatedValue(initColor.g);
this.b = new AnimatedValue(initColor.b);
Expand Down Expand Up @@ -266,6 +268,10 @@ export default class AnimatedColor extends AnimatedWithChildren {
__getValue(): ColorValue {
if (this.nativeColor != null) {
return this.nativeColor;
} else if (this.space) {
return `color(${
this.space
} ${this.r.__getValue()} ${this.g.__getValue()} ${this.b.__getValue()} / ${this.a.__getValue()})`;
} else {
return `rgba(${this.r.__getValue()}, ${this.g.__getValue()}, ${this.b.__getValue()}, ${this.a.__getValue()})`;
}
Expand Down Expand Up @@ -310,6 +316,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
__getNativeConfig(): {...} {
return {
type: 'color',
space: this.space,
r: this.r.__getNativeTag(),
g: this.g.__getNativeTag(),
b: this.b.__getNativeTag(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ function mapStringToNumericComponents(
| {isColor: false, components: $ReadOnlyArray<number | string>} {
let normalizedColor = normalizeColor(input);
invariant(
normalizedColor == null || typeof normalizedColor !== 'object',
normalizedColor == null ||
typeof normalizedColor !== 'object' ||
normalizedColor.hasOwnProperty('space'),
'PlatformColors are not supported',
);

Expand Down Expand Up @@ -395,6 +397,13 @@ export default class AnimatedInterpolation<
if (typeof processedColor === 'number') {
outputType = 'color';
return processedColor;
} else if (processedColor?.hasOwnProperty('space')) {
const {r, g, b, a} = processedColor;
const reprocessedColor = processColor(
`rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`,
);
outputType = 'color';
return reprocessedColor;
} else {
return NativeAnimatedHelper.transformDataType(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

@interface RCTColorAnimatedNode : RCTAnimatedNode

@property (nonatomic, assign) int32_t color;
// @property (nonatomic, strong) UIColor *color;
@property (nonatomic, strong) NSDictionary<NSString *, id> *color;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,30 @@
#import <React/RCTValueAnimatedNode.h>

#import <React/RCTAnimationUtils.h>
#import <React/RCTConvert.h>

@implementation RCTColorAnimatedNode

- (void)performUpdate
{
[super performUpdate];

CGFloat divisor = self.config[@"space"] ? 1.0 : 255.0;
RCTColorSpace space = [RCTConvert colorSpaceFromString:self.config[@"space"]];
RCTValueAnimatedNode *rNode = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:self.config[@"r"]];
RCTValueAnimatedNode *gNode = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:self.config[@"g"]];
RCTValueAnimatedNode *bNode = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:self.config[@"b"]];
RCTValueAnimatedNode *aNode = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:self.config[@"a"]];

_color = RCTColorFromComponents(rNode.value, gNode.value, bNode.value, aNode.value);

// TODO: why can't we just use UIColor here?
// _color = [RCTConvert createColorFrom:rNode.value green:gNode.value blue:bNode.value alpha:aNode.value andColorSpace:space];
_color = @{
@"space": space == RCTColorSpaceDisplayP3 ? @"display-p3" : @"srgb",
@"r": @(rNode.value / divisor),
@"g": @(gNode.value / divisor),
@"b": @(bNode.value / divisor),
@"a": @(aNode.value),
};

// TODO (T111179606): Support platform colors for color animations
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ - (void)performUpdate
CGFloat inputValue = _parentNode.value;
switch (_outputType) {
case RCTInterpolationOutputColor:
_outputvalue = @(RCTInterpolateColorInRange(inputValue, _inputRange, _outputRange));
_outputvalue = RCTInterpolateColorInRange(inputValue, _inputRange, _outputRange);
break;
case RCTInterpolationOutputString:
_outputvalue = RCTInterpolateString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ - (void)performUpdate
} else if ([parentNode isKindOfClass:[RCTColorAnimatedNode class]]) {
RCTColorAnimatedNode *colorAnimatedNode = (RCTColorAnimatedNode *)parentNode;
NSString *property = [self propertyNameForParentTag:parentTag];
_propsDictionary[property] = @(colorAnimatedNode.color);
_propsDictionary[property] = colorAnimatedNode.color;
} else if ([parentNode isKindOfClass:[RCTObjectAnimatedNode class]]) {
RCTObjectAnimatedNode *objectAnimatedNode = (RCTObjectAnimatedNode *)parentNode;
NSString *property = [self propertyNameForParentTag:parentTag];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ - (void)performUpdate
[_propsDictionary addEntriesFromDictionary:transformAnimatedNode.propsDictionary];
} else if ([node isKindOfClass:[RCTColorAnimatedNode class]]) {
RCTColorAnimatedNode *colorAnimatedNode = (RCTColorAnimatedNode *)node;
_propsDictionary[property] = @(colorAnimatedNode.color);
_propsDictionary[property] = colorAnimatedNode.color;
} else if ([node isKindOfClass:[RCTObjectAnimatedNode class]]) {
RCTObjectAnimatedNode *objectAnimatedNode = (RCTObjectAnimatedNode *)node;
_propsDictionary[property] = objectAnimatedNode.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ RCT_EXTERN CGFloat RCTInterpolateValueInRange(
NSString *extrapolateLeft,
NSString *extrapolateRight);

RCT_EXTERN uint32_t
// RCT_EXTERN UIColor*
RCT_EXTERN NSDictionary<NSString *, id>*
RCTInterpolateColorInRange(CGFloat value, NSArray<NSNumber *> *inputRange, NSArray<UIColor *> *outputRange);

// Represents a color as a int32_t. RGB components are assumed to be in [0-255] range and alpha in [0-1] range
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ CGFloat RCTInterpolateValueInRange(
return RCTInterpolateValue(value, inputMin, inputMax, outputMin, outputMax, extrapolateLeft, extrapolateRight);
}

uint32_t RCTInterpolateColorInRange(CGFloat value, NSArray<NSNumber *> *inputRange, NSArray<UIColor *> *outputRange)
//UIColor* RCTInterpolateColorInRange(CGFloat value, NSArray<NSNumber *> *inputRange, NSArray<UIColor *> *outputRange)
NSDictionary<NSString *, id>* RCTInterpolateColorInRange(CGFloat value, NSArray<NSNumber *> *inputRange, NSArray<UIColor *> *outputRange)
{
NSUInteger rangeIndex = RCTFindIndexOfNearestValue(value, inputRange);
CGFloat inputMin = inputRange[rangeIndex].doubleValue;
Expand All @@ -94,12 +95,20 @@ uint32_t RCTInterpolateColorInRange(CGFloat value, NSArray<NSNumber *> *inputRan
[outputRange[rangeIndex] getRed:&redMin green:&greenMin blue:&blueMin alpha:&alphaMin];
CGFloat redMax, greenMax, blueMax, alphaMax;
[outputRange[rangeIndex + 1] getRed:&redMax green:&greenMax blue:&blueMax alpha:&alphaMax];

return RCTColorFromComponents(
0xFF * (redMin + (value - inputMin) * (redMax - redMin) / (inputMax - inputMin)),
0xFF * (greenMin + (value - inputMin) * (greenMax - greenMin) / (inputMax - inputMin)),
0xFF * (blueMin + (value - inputMin) * (blueMax - blueMin) / (inputMax - inputMin)),
alphaMin + (value - inputMin) * (alphaMax - alphaMin) / (inputMax - inputMin));

CGFloat r = redMin + (value - inputMin) * (redMax - redMin) / (inputMax - inputMin);
CGFloat g = greenMin + (value - inputMin) * (greenMax - greenMin) / (inputMax - inputMin);
CGFloat b = blueMin + (value - inputMin) * (blueMax - blueMin) / (inputMax - inputMin);
CGFloat a = alphaMin + (value - inputMin) * (alphaMax - alphaMin) / (inputMax - inputMin);

// return [UIColor colorWithRed:r green:g blue:b alpha:a];
return @{
@"space": @"srgb",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cipolleschi I'm still struggling with how to handle the unclamped values here. If I understand Apple's docs correctly we'd need to pass those to colorWithRed:green:blue:alpha: so we'd want to stay in extended srgb color space. But this doesn't appear to work.

Also I'm not sure I understand why I can't just use UIColor. When I try to return the UIColor directly here or from RCTColorAnimatedNode I don't get the color to come through at all.

Copy link
Collaborator

@cipolleschi cipolleschi Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I completely understand your questions, but:

If I understand Apple's docs correctly we'd need to pass those to colorWithRed:green:blue:alpha: so we'd want to stay in extended srgb color space. But this doesn't appear to work.

This is true if the source space is sRGB.
If we are in displayP3, values that are < 0 and > 1 will not be properly represented. 🤔

I think we need to create the final UIColor by using colorWithDisplayP3Red:green:blue:alpha:.

Also I'm not sure I understand why I can't just use UIColor. When I try to return the UIColor directly here or from RCTColorAnimatedNode I don't get the color to come through at all

If we change the return type from int32_t to something else, we have to update the callsites to understand the new return type, no?

I'm not super familiar with this part of the codebase, I need to dig deeper here.


If this is the only blocker, I think we can move forward for the time being and consider this a known-issue: for the first implementation interpolateColor don't work with displayP3.

Even with this limitation, this would already be a massive improvement! I think that animating colors is not something every app actually require, so it is an edge case that it is ok to point out as "not working" for version 1 of the implementation.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using colorWithDisplayP3Red:green:blue:alpha: gives me the same behavior as before including the color space and I believe it's because per Apple:

The red component of the color object, specified as a value from 0.0 to 1.0.

and

Values below 0.0 are interpreted as 0.0, and values above 1.0 are interpreted as 1.0.

Meanwhile with colorWithRed:green:blue:alpha:

The red value of the color object. On applications linked for iOS 10 or later, the color is specified in an extended color space, and the input value is never clamped. On earlier versions of iOS, red values below 0.0 are interpreted as 0.0, and values above 1.0 are interpreted as 1.0.

So I believe if we have unclamped values we may actually need to use colorWithRed:green:blue:alpha: to have them interpreted correctly. But then again I couldn't get it to work completely either way.

As far as returning UIColor directly goes I updated the call sites for RCTInterpolateColorInRange and RCTColorAnimatedNode but I was having trouble following what happens to the values after performUpdate is called. Essentially I'd like to know how the animated values ultimately get applied back to the original views.


If this is the only blocker, I think we can move forward for the time being and consider this a known-issue: for the first implementation interpolateColor don't work with displayP3.

Even with this limitation, this would already be a massive improvement! I think that animating colors is not something every app actually require, so it is an edge case that it is ok to point out as "not working" for version 1 of the implementation.

Makes sense. I'll move on to Android today.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To explore how the colors change based on the rgb values, I created this small project: https://github.com/cipolleschi/P3Colors.

feel free to clone it and play with it.

The top-left view is sRGB
The to-right view is displayP3
The bottom-left view is sRGB when we passed in the rgb values obtained by getRed:green:blue:alpha method on the displayP3 color.
The bottom-right view is displayP3 when we passed in the rgb values obtained by getRed:green:blue:alpha method on the displayP3 color.

Use a retina display to look at it! 😄

Simulator.Screen.Recording.-.iPhone.15.Pro.-.2024-01-10.at.15.49.28.mp4

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMG_0905

Interesting. It looks like my interpretation of Apple's docs is correct then since passing the DisplayP3 colors to colorWithRed:green:blue:alpha: gives the same color as the original DisplayP3 color while passing to colorWithDisplayP3Red:green:blue:alpha: is too red up until you hit values greater than 1 at which point it's the same.

The behavior right now in RCTInterpolateColorInRange is even more bizarre then since it's currently cycling through yellow and blue as well. 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... it hink that the behavior of interpolate is wrong in the context of display P3 because the color space is non euclidean. So the usual interpolation formula (which are linear) would not work properly there... 😓
Unfortunately, I don't have a clear solution...
One idea we can try to:

  • preprocess: interpolate the starting color from displayP3 to sRGB representation (e.g. red in P3 to red in sRGB)
  • interpolation: interpolate the colors in sRGB, from the source to the destination (e.g from red to blue) reusing the sRGB formula
  • postprocess: interpolate the final color from sRGB to displayP3 (e.g. blue in P3 to blue in sRGB).

In that way we minimize the weirdness paying the tradeoff that interpolation is in sRGB... but if that happens mainly in animation, they should be "fast" enough so that the user won't notice that they are not in displayP3 space...

What do you think?

@"r":@(r),
@"g":@(g),
@"b":@(b),
@"a":@(a),
};
}

uint32_t RCTColorFromComponents(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ describe('processColor', () => {
});
});

describe('color() strings', () => {
it('should convert color(s r g b)', () => {
const colorFromString = processColor('color(srgb 1 0 0)');
expect(colorFromString).toEqual({space: 'srgb', r: 1, g: 0, b: 0, a: 1});
});

it('should convert color(s r g b / a)', () => {
const colorFromString = processColor('color(display-p3 1 0 0 / 0.5)');
expect(colorFromString).toEqual({
space: 'display-p3',
r: 1,
g: 0,
b: 0,
a: 0.5,
});
});
});

describe('RGB strings', () => {
it('should convert rgb(x, y, z)', () => {
const colorFromString = processColor('rgb(10, 20, 30)');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ describe('processColorArray', () => {
expect(colorFromStringArray).toEqual(expectedIntArray);
});

it('should convert array of color type color(display-p3 x y z)', () => {
const colorFromDisplayP3Array = processColorArray([
'color(display-p3 0.1 0.2 0.3)',
'color(display-p3 0.2 0.3 0.4)',
'color(display-p3 0.3 0.4 0.5)',
]);
expect(colorFromDisplayP3Array).toEqual([
{space: 'display-p3', r: 0.1, g: 0.2, b: 0.3, a: 1},
{space: 'display-p3', r: 0.2, g: 0.3, b: 0.4, a: 1},
{space: 'display-p3', r: 0.3, g: 0.4, b: 0.5, a: 1},
]);
});

it('should convert array of color type rgb(x, y, z)', () => {
const colorFromRGBArray = processColorArray([
'rgb(10, 20, 30)',
Expand Down
17 changes: 17 additions & 0 deletions packages/react-native/React/Base/RCTConvert.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
#import <React/RCTTextDecorationLineType.h>
#import <yoga/Yoga.h>

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
Expand Down Expand Up @@ -91,6 +101,13 @@ typedef NSURL RCTFileURL;

+ (CGAffineTransform)CGAffineTransform:(id)json;

+ (UIColor *)createColorFrom:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
+ (UIColor *)createColorFrom:(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;

Expand Down
Loading
Loading