Support PlatformColor (#1561)

Since version 0.63 React Native has supported PlatformColor structs that among other features has dark mode support built in. Using those values with RNSVG today throws a warning "[Object object]" is not a valid color or brush and makes the path have a clear color.

This PR adds support for PlatformColor by utilizing the color parsing code shipped with React Native itself. In order to support the dynamic properties I had to retain the reference as a UIColor and convert it to CGColorRef as it's read. This might have a performance penalty.

The Android implementation doesn't yet have support for dynamic values (EDIT: react-native itself doesn't support it, so we're good there I think). Since it relies on the ColorPropConverter class, I think it means minimum supported version of RN will be raised to 0.63.
This commit is contained in:
Joel Arvidsson
2022-02-23 16:28:31 +01:00
committed by GitHub
parent 86813032c9
commit d35878bacc
6 changed files with 33 additions and 16 deletions
@@ -27,6 +27,7 @@ import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.ColorPropConverter;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.annotations.ReactProp;
@@ -474,7 +475,12 @@ abstract public class RenderableView extends VirtualView {
switch (colorType) {
case 0:
if (colors.size() == 2) {
int color = colors.getInt(1);
int color;
if (colors.getType(1) == ReadableType.Map) {
color = ColorPropConverter.getColor(colors.getMap(1), getContext());
} else {
color = colors.getInt(1);
}
int alpha = color >>> 24;
int combined = Math.round((float)alpha * opacity);
paint.setColor(combined << 24 | (color & 0x00ffffff));
+10 -9
View File
@@ -13,13 +13,13 @@
@implementation RNSVGSolidColorBrush
{
CGColorRef _color;
UIColor *_color;
}
- (instancetype)initWithArray:(NSArray<RNSVGLength *> *)array
{
if ((self = [super initWithArray:array])) {
_color = CGColorRetain([RCTConvert RNSVGCGColor:array offset:1]);
_color = [RCTConvert RNSVGUIColor:array offset:1];
}
return self;
}
@@ -27,34 +27,35 @@
- (instancetype)initWithNumber:(NSNumber *)number
{
if ((self = [super init])) {
_color = CGColorRetain([RCTConvert CGColor:number]);
_color = [RCTConvert UIColor:number];
}
return self;
}
- (void)dealloc
{
CGColorRelease(_color);
_color = nil;
}
- (CGColorRef)getColorWithOpacity:(CGFloat)opacity
{
return CGColorCreateCopyWithAlpha(_color, opacity * CGColorGetAlpha(_color));
CGColorRef baseColor = _color.CGColor;
CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor));
CGColorRelease(baseColor);
return color;
}
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
{
CGColorRef color = CGColorCreateCopyWithAlpha(_color, opacity * CGColorGetAlpha(_color));
CGColorRef color = [self getColorWithOpacity:opacity];
CGContextSetFillColorWithColor(context, color);
CGColorRelease(color);
return YES;
}
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
{
CGColorRef color = CGColorCreateCopyWithAlpha(_color, opacity * CGColorGetAlpha(_color));
CGColorRef color = [self getColorWithOpacity:opacity];
CGContextSetStrokeColorWithColor(context, color);
CGColorRelease(color);
return YES;
}
+1 -1
View File
@@ -28,7 +28,7 @@
+ (RNSVGBrush *)RNSVGBrush:(id)json;
+ (RNSVGPathParser *)RNSVGCGPath:(NSString *)d;
+ (CGRect)RNSVGCGRect:(id)json offset:(NSUInteger)offset;
+ (CGColorRef)RNSVGCGColor:(id)json offset:(NSUInteger)offset;
+ (UIColor *)RNSVGUIColor:(id)json offset:(NSUInteger)offset;
+ (CGGradientRef)RNSVGCGGradient:(id)json;
@end
+3 -3
View File
@@ -130,17 +130,17 @@ RCT_ENUM_CONVERTER(RNSVGUnits, (@{
};
}
+ (CGColorRef)RNSVGCGColor:(id)json offset:(NSUInteger)offset
+ (UIColor *)RNSVGUIColor:(id)json offset:(NSUInteger)offset
{
NSArray *arr = [self NSArray:json];
if (arr.count == offset + 1) {
return [self CGColor:[arr objectAtIndex:offset]];
return [self UIColor:[arr objectAtIndex:offset]];
}
if (arr.count < offset + 4) {
RCTLogError(@"Too few elements in array (expected at least %zd): %@", (ssize_t)(4 + offset), arr);
return nil;
}
return [self CGColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
return [self UIColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
}
+ (CGGradientRef)RNSVGCGGradient:(id)json
+2 -2
View File
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactNative from 'react-native';
import { GestureResponderEvent, TransformsStyle } from 'react-native';
import { GestureResponderEvent, TransformsStyle, OpaqueColorValue } from 'react-native';
// Common props
export type NumberProp = string | number;
@@ -101,7 +101,7 @@ export type rgbaArray = ReadonlyArray<number>;
// int32ARGBColor = 0xaarrggbb
export type int32ARGBColor = number;
export type Color = int32ARGBColor | rgbaArray | string;
export type Color = int32ARGBColor | rgbaArray | OpaqueColorValue | string;
export interface FillProps {
fill?: Color;
+10
View File
@@ -40,6 +40,16 @@ export default function extractBrush(color?: Color) {
return int32ARGBColor;
}
// iOS PlatformColor
if ('semantic' in color) {
return [0, color];
}
// Android PlatformColor
if ('resource_paths' in color) {
return [0, color];
}
console.warn(`"${color}" is not a valid color or brush`);
return null;
}