fix: PlatformColor crashes on iOS and Android (#1703)

Follow-up PR to https://github.com/react-native-svg/react-native-svg/pull/1561 fixing the problems mentioned there. Also fixing the wrong releasing introduced in https://github.com/react-native-svg/react-native-svg/commit/027b8c16aa99267467b5aef0fcfd1aa8c2c8582a
This commit is contained in:
Wojciech Lewicki
2022-02-24 12:53:04 +01:00
committed by GitHub
parent d35878bacc
commit b007efe23a
10 changed files with 525 additions and 706 deletions
+38 -19
View File
@@ -1,30 +1,49 @@
import React from 'react';
import { PlatformColor, Platform, Button } from 'react-native';
import {
Svg,
Circle,
Rect,
Text,
TSpan
} from 'react-native-svg';
const color = PlatformColor(Platform.select({
ios: 'label',
android: '@android:color/primary_text_light',
default: 'black',
}))
export default () => {
const [test, setTest] = React.useState(50);
return (
<Svg height="100" width="100">
<Circle
cx="50"
cy="50"
r="45"
stroke="blue"
strokeWidth="2.5"
fill="green"
/>
<Rect
x="15"
y="15"
width="70"
height="70"
stroke="red"
strokeWidth="2"
fill="yellow"
/>
</Svg>
<>
<Svg height="100" width="100" color={color}>
<Circle
cx="50"
cy="50"
r={test}
strokeWidth="2.5"
fill={color}
/>
<Rect
x="15"
y="15"
width="70"
height="70"
stroke="currentColor"
strokeWidth="5"
/>
</Svg>
<Svg height="300" width="300" fill="red">
<Text x={0} y={0} fontSize={20}>
<TSpan dx={test} inlineSize={"100%"} fill="currentColor">
Testing word-wrap... Testing word-wrap... Testing word-wrap... Testing word-wrap...
</TSpan>
</Text>
</Svg>
<Button title="Click me" onPress={()=> setTest(test + 1)}/>
</>
);
}
@@ -23,6 +23,7 @@ import android.view.ViewParent;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ColorPropConverter;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.uimanager.DisplayMetricsHolder;
@@ -173,12 +174,17 @@ public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactC
}
@ReactProp(name = "tintColor")
public void setTintColor(@Nullable Integer tintColor) {
if (tintColor == null) {
mTintColor = 0;
} else {
mTintColor = tintColor;
}
public void setTintColor(@Nullable Dynamic tintColor) {
switch (tintColor.getType()) {
case Map:
mTintColor = ColorPropConverter.getColor(tintColor.asMap(), getContext());
break;
case Number:
mTintColor = tintColor.asInt();
break;
default:
mTintColor = 0;
}
invalidate();
clearChildCache();
}
@@ -78,12 +78,12 @@ class SvgViewManager extends ReactViewManager {
}
@ReactProp(name = "tintColor")
public void setTintColor(SvgView node, @Nullable Integer tintColor) {
public void setTintColor(SvgView node, @Nullable Dynamic tintColor) {
node.setTintColor(tintColor);
}
@ReactProp(name = "color")
public void setColor(SvgView node, @Nullable Integer color) {
public void setColor(SvgView node, @Nullable Dynamic color) {
node.setTintColor(color);
}
+6 -4
View File
@@ -7,19 +7,20 @@
*/
#import "RNSVGSolidColorBrush.h"
#import "RNSVGUIKit.h"
#import "RCTConvert+RNSVG.h"
#import <React/RCTLog.h>
@implementation RNSVGSolidColorBrush
{
UIColor *_color;
RNSVGColor *_color;
}
- (instancetype)initWithArray:(NSArray<RNSVGLength *> *)array
{
if ((self = [super initWithArray:array])) {
_color = [RCTConvert RNSVGUIColor:array offset:1];
_color = [RCTConvert RNSVGColor:array offset:1];
}
return self;
}
@@ -27,7 +28,7 @@
- (instancetype)initWithNumber:(NSNumber *)number
{
if ((self = [super init])) {
_color = [RCTConvert UIColor:number];
_color = [RCTConvert RNSVGColor:number];
}
return self;
}
@@ -41,7 +42,6 @@
{
CGColorRef baseColor = _color.CGColor;
CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor));
CGColorRelease(baseColor);
return color;
}
@@ -49,6 +49,7 @@
{
CGColorRef color = [self getColorWithOpacity:opacity];
CGContextSetFillColorWithColor(context, color);
CGColorRelease(color);
return YES;
}
@@ -56,6 +57,7 @@
{
CGColorRef color = [self getColorWithOpacity:opacity];
CGContextSetStrokeColorWithColor(context, color);
CGColorRelease(color);
return YES;
}
+4 -11
View File
@@ -65,31 +65,24 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
if (self.content) {
RNSVGGlyphContext* gc = [self.textRoot getGlyphContext];
if (self.inlineSize != nil && self.inlineSize.value != 0) {
CGColorRef color;
if (self.fill) {
if (self.fill.class == RNSVGBrush.class) {
color = [self.tintColor CGColor];
CGColorRef color = [self.tintColor CGColor];
[self drawWrappedText:context gc:gc rect:rect color:color];
} else {
color = [self.fill getColorWithOpacity:self.fillOpacity];
CGColorRef color = [self.fill getColorWithOpacity:self.fillOpacity];
[self drawWrappedText:context gc:gc rect:rect color:color];
}
if (color) {
CGColorRelease(color);
color = nil;
}
}
if (self.stroke) {
if (self.stroke.class == RNSVGBrush.class) {
color = [self.tintColor CGColor];
CGColorRef color = [self.tintColor CGColor];
[self drawWrappedText:context gc:gc rect:rect color:color];
} else {
color = [self.stroke getColorWithOpacity:self.strokeOpacity];
CGColorRef color = [self.stroke getColorWithOpacity:self.strokeOpacity];
[self drawWrappedText:context gc:gc rect:rect color:color];
}
if (color) {
CGColorRelease(color);
color = nil;
}
}
} else {
+1 -1
View File
@@ -28,7 +28,7 @@
+ (RNSVGBrush *)RNSVGBrush:(id)json;
+ (RNSVGPathParser *)RNSVGCGPath:(NSString *)d;
+ (CGRect)RNSVGCGRect:(id)json offset:(NSUInteger)offset;
+ (UIColor *)RNSVGUIColor:(id)json offset:(NSUInteger)offset;
+ (RNSVGColor *)RNSVGColor:(id)json offset:(NSUInteger)offset;
+ (CGGradientRef)RNSVGCGGradient:(id)json;
@end
+3 -3
View File
@@ -130,17 +130,17 @@ RCT_ENUM_CONVERTER(RNSVGUnits, (@{
};
}
+ (UIColor *)RNSVGUIColor:(id)json offset:(NSUInteger)offset
+ (RNSVGColor *)RNSVGColor:(id)json offset:(NSUInteger)offset
{
NSArray *arr = [self NSArray:json];
if (arr.count == offset + 1) {
return [self UIColor:[arr objectAtIndex:offset]];
return [self RNSVGColor:[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 UIColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
return [self RNSVGColor:[arr subarrayWithRange:(NSRange){offset, 4}]];
}
+ (CGGradientRef)RNSVGCGGradient:(id)json
+31 -27
View File
@@ -1,12 +1,16 @@
/**
* Flowtype definitions for index
* Generated by Flowgen from a Typescript Definition
* Flowgen v1.14.1
* Flowgen v1.17.0
*/
import * as React from "react";
import * as ReactNative from "react-native";
import { GestureResponderEvent, TransformsStyle } from "react-native";
import {
GestureResponderEvent,
TransformsStyle,
OpaqueColorValue,
} from "react-native";
export type NumberProp = string | number;
export type NumberArray = NumberProp[] | NumberProp;
export type FillRule = "evenodd" | "nonzero";
@@ -93,7 +97,7 @@ export type ResponderProps = {
} & ReactNative.GestureResponderHandlers;
export type rgbaArray = $ReadOnlyArray<number>;
export type int32ARGBColor = number;
export type Color = int32ARGBColor | rgbaArray | string;
export type Color = int32ARGBColor | rgbaArray | OpaqueColorValue | string;
export interface FillProps {
fill?: Color;
fillOpacity?: NumberProp;
@@ -205,14 +209,14 @@ export type CircleProps = {
...
} & CommonPathProps;
declare export var Circle: React.ComponentClass<CircleProps>;
export type Circle = React.ComponentClass<CircleProps>;
export type CircleType = React.ComponentClass<CircleProps>;
export interface ClipPathProps {
id?: string;
}
declare export var ClipPath: React.ComponentClass<ClipPathProps>;
export type ClipPath = React.ComponentClass<ClipPathProps>;
export type ClipPathType = React.ComponentClass<ClipPathProps>;
declare export var Defs: React.ComponentClass<{ ... }>;
export type Defs = React.ComponentClass<{ ... }>;
export type DefsType = React.ComponentClass<{ ... }>;
export type EllipseProps = {
cx?: NumberProp,
cy?: NumberProp,
@@ -222,13 +226,13 @@ export type EllipseProps = {
...
} & CommonPathProps;
declare export var Ellipse: React.ComponentClass<EllipseProps>;
export type Ellipse = React.ComponentClass<EllipseProps>;
export type EllipseType = React.ComponentClass<EllipseProps>;
export type GProps = {
opacity?: NumberProp,
...
} & CommonPathProps;
declare export var G: React.ComponentClass<GProps>;
export type G = React.ComponentClass<GProps>;
export type GType = React.ComponentClass<GProps>;
export interface ForeignObjectProps {
x?: NumberProp;
y?: NumberProp;
@@ -236,7 +240,7 @@ export interface ForeignObjectProps {
height?: NumberProp;
}
declare export var ForeignObject: React.ComponentClass<ForeignObjectProps>;
export type ForeignObject = React.ComponentClass<ForeignObjectProps>;
export type ForeignObjectType = React.ComponentClass<ForeignObjectProps>;
export type ImageProps = {
x?: NumberProp,
y?: NumberProp,
@@ -254,7 +258,7 @@ export type ImageProps = {
ClipProps &
TouchableProps;
declare export var Image: React.ComponentClass<ImageProps>;
export type Image = React.ComponentClass<ImageProps>;
export type ImageType = React.ComponentClass<ImageProps>;
export type LineProps = {
opacity?: NumberProp,
x1?: NumberProp,
@@ -264,7 +268,7 @@ export type LineProps = {
...
} & CommonPathProps;
declare export var Line: React.ComponentClass<LineProps>;
export type Line = React.ComponentClass<LineProps>;
export type LineType = React.ComponentClass<LineProps>;
export interface LinearGradientProps {
x1?: NumberProp;
x2?: NumberProp;
@@ -275,14 +279,14 @@ export interface LinearGradientProps {
id?: string;
}
declare export var LinearGradient: React.ComponentClass<LinearGradientProps>;
export type LinearGradient = React.ComponentClass<LinearGradientProps>;
export type LinearGradientType = React.ComponentClass<LinearGradientProps>;
export type PathProps = {
d?: string,
opacity?: NumberProp,
...
} & CommonPathProps;
declare export var Path: React.ComponentClass<PathProps>;
export type Path = React.ComponentClass<PathProps>;
export type PathType = React.ComponentClass<PathProps>;
export interface PatternProps {
id?: string;
x?: NumberProp;
@@ -296,21 +300,21 @@ export interface PatternProps {
preserveAspectRatio?: string;
}
declare export var Pattern: React.ComponentClass<PatternProps>;
export type Pattern = React.ComponentClass<PatternProps>;
export type PatternType = React.ComponentClass<PatternProps>;
export type PolygonProps = {
opacity?: NumberProp,
points?: string | $ReadOnlyArray<NumberProp>,
...
} & CommonPathProps;
declare export var Polygon: React.ComponentClass<PolygonProps>;
export type Polygon = React.ComponentClass<PolygonProps>;
export type PolygonType = React.ComponentClass<PolygonProps>;
export type PolylineProps = {
opacity?: NumberProp,
points?: string | $ReadOnlyArray<NumberProp>,
...
} & CommonPathProps;
declare export var Polyline: React.ComponentClass<PolylineProps>;
export type Polyline = React.ComponentClass<PolylineProps>;
export type PolylineType = React.ComponentClass<PolylineProps>;
export interface RadialGradientProps {
fx?: NumberProp;
fy?: NumberProp;
@@ -324,7 +328,7 @@ export interface RadialGradientProps {
id?: string;
}
declare export var RadialGradient: React.ComponentClass<RadialGradientProps>;
export type RadialGradient = React.ComponentClass<RadialGradientProps>;
export type RadialGradientType = React.ComponentClass<RadialGradientProps>;
export type RectProps = {
x?: NumberProp,
y?: NumberProp,
@@ -336,14 +340,14 @@ export type RectProps = {
...
} & CommonPathProps;
declare export var Rect: React.ComponentClass<RectProps>;
export type Rect = React.ComponentClass<RectProps>;
export type RectType = React.ComponentClass<RectProps>;
export interface StopProps {
stopColor?: Color;
stopOpacity?: NumberProp;
offset?: NumberProp;
}
declare export var Stop: React.ComponentClass<StopProps>;
export type Stop = React.ComponentClass<StopProps>;
export type StopType = React.ComponentClass<StopProps>;
export type SvgProps = {
width?: NumberProp,
height?: NumberProp,
@@ -355,7 +359,7 @@ export type SvgProps = {
} & GProps &
ReactNative.ViewProperties;
declare export var Svg: React.ComponentClass<SvgProps>;
export type Svg = React.ComponentClass<SvgProps>;
export type SvgType = React.ComponentClass<SvgProps>;
declare export default typeof Svg;
export interface SymbolProps {
id?: string;
@@ -364,7 +368,7 @@ export interface SymbolProps {
opacity?: NumberProp;
}
declare export var Symbol: React.ComponentClass<SymbolProps>;
export type Symbol = React.ComponentClass<SymbolProps>;
export type SymbolType = React.ComponentClass<SymbolProps>;
export type TSpanProps = {
x?: NumberArray,
y?: NumberArray,
@@ -376,7 +380,7 @@ export type TSpanProps = {
} & CommonPathProps &
FontProps;
declare export var TSpan: React.ComponentClass<TSpanProps>;
export type TSpan = React.ComponentClass<TSpanProps>;
export type TSpanType = React.ComponentClass<TSpanProps>;
export type TextSpecificProps = {
alignmentBaseline?: AlignmentBaseline,
baselineShift?: BaselineShift,
@@ -402,7 +406,7 @@ export type TextProps = {
...
} & TextSpecificProps;
declare export var Text: React.ComponentClass<TextProps>;
export type Text = React.ComponentClass<TextProps>;
export type TextType = React.ComponentClass<TextProps>;
export type TextPathProps = {
xlinkHref?: string,
href?: string,
@@ -413,7 +417,7 @@ export type TextPathProps = {
...
} & TextSpecificProps;
declare export var TextPath: React.ComponentClass<TextPathProps>;
export type TextPath = React.ComponentClass<TextPathProps>;
export type TextPathType = React.ComponentClass<TextPathProps>;
export type UseProps = {
xlinkHref?: string,
href?: string,
@@ -425,7 +429,7 @@ export type UseProps = {
...
} & CommonPathProps;
declare export var Use: React.ComponentClass<UseProps>;
export type Use = React.ComponentClass<UseProps>;
export type UseType = React.ComponentClass<UseProps>;
declare export var EMaskUnits: {|
+USER_SPACE_ON_USE: "userSpaceOnUse", // "userSpaceOnUse"
+OBJECT_BOUNDING_BOX: "objectBoundingBox", // "objectBoundingBox"
@@ -445,7 +449,7 @@ export type MaskProps = {
...
} & CommonPathProps;
declare export var Mask: React.ComponentClass<MaskProps>;
export type Mask = React.ComponentClass<MaskProps>;
export type MaskType = React.ComponentClass<MaskProps>;
declare export var MarkerUnits: {|
+STROKE_WIDTH: "strokeWidth", // "strokeWidth"
+USER_SPACE_ON_USE: "userSpaceOnUse", // "userSpaceOnUse"
@@ -467,7 +471,7 @@ export interface MarkerProps {
orient?: $Values<typeof Orient> | NumberProp;
}
declare export var Marker: React.ComponentClass<MarkerProps>;
export type Marker = React.ComponentClass<MarkerProps>;
export type MarkerType = React.ComponentClass<MarkerProps>;
export type Styles = {
[property: string]: string,
...
+9 -7
View File
@@ -40,14 +40,16 @@ export default function extractBrush(color?: Color) {
return int32ARGBColor;
}
// iOS PlatformColor
if ('semantic' in color) {
return [0, color];
}
if (typeof color === 'object' && color !== null) {
// iOS PlatformColor
if ('semantic' in color) {
return [0, color];
}
// Android PlatformColor
if ('resource_paths' 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`);
+419 -626
View File
File diff suppressed because it is too large Load Diff