fix: radialGradient r={0} (#2271)

# Summary

* Fixed crash on Android when `<RadialGradient r={0}>`.
* Fixed render issue on Android and iOS when radius is zero. According
to [MDN
Docs](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r#radialgradient)
> A value of lower or equal to zero will cause the area to be painted as
a single color using the color and opacity of the last gradient
`<stop>`.

## Test Plan

Test is available in `TestsExample` as `Test2170`

## Compatibility

| OS      | Implemented |
| ------- | :---------: |
| iOS     |        |
| Android |        |


Fixes #2170
This commit is contained in:
Jakub Grzywacz
2024-05-15 12:00:52 +02:00
committed by GitHub
parent 19b2e42e1b
commit 38a8dbca39
3 changed files with 82 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
import * as React from 'react';
import {View} from 'react-native';
import {
Circle,
RadialGradient,
Rect,
Stop,
Svg,
SvgXml,
} from 'react-native-svg';
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r#example
const svgXml = `
<svg viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
<radialGradient r="0" id="myGradient000">
<stop offset="0" stop-color="white" />
<stop offset="100%" stop-color="black" />
</radialGradient>
<radialGradient r="50%" id="myGradient050">
<stop offset="0" stop-color="white" />
<stop offset="100%" stop-color="black" />
</radialGradient>
<radialGradient r="100%" id="myGradient100">
<stop offset="0" stop-color="white" />
<stop offset="100%" stop-color="black" />
</radialGradient>
<circle cx="50" cy="50" r="0" />
<circle cx="150" cy="50" r="25" />
<circle cx="250" cy="50" r="50" />
<rect x="20" y="120" width="60" height="60" fill="url(#myGradient000)" />
<rect x="120" y="120" width="60" height="60" fill="url(#myGradient050)" />
<rect x="220" y="120" width="60" height="60" fill="url(#myGradient100)" />
</svg>
`;
export default function App() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<SvgXml width={400} height={300} xml={svgXml} />
<Svg width={400} height={300}>
<RadialGradient id="a" r={0}>
<Stop offset={0} stopColor="#f00" />
<Stop offset="50%" stopColor="#0f0" />
<Stop offset="100%" stopColor="#00f" />
</RadialGradient>
<RadialGradient id="b" r="50%">
<Stop offset={0} stopColor="#f00" />
<Stop offset="100%" stopColor="#00f" />
</RadialGradient>
<RadialGradient id="c" r="100%">
<Stop offset={0} stopColor="#f00" />
<Stop offset="100%" stopColor="#00f" />
</RadialGradient>
<Rect x={0} y={100} width={100} height={100} fill="url(#a)" />
<Rect x={150} y={100} width={100} height={100} fill="url(#b)" />
<Rect x={300} y={100} width={100} height={100} fill="url(#c)" />
<Circle cx={50} cy={250} r={50} fill="url(#a)" />
<Circle cx={200} cy={250} r={50} fill="url(#b)" />
<Circle cx={350} cy={250} r={50} fill="url(#c)" />
</Svg>
</View>
);
}
@@ -204,6 +204,14 @@ class Brush {
double rx = getVal(mPoints[2], width, scale, textSize); double rx = getVal(mPoints[2], width, scale, textSize);
double ry = getVal(mPoints[3], height, scale, textSize); double ry = getVal(mPoints[3], height, scale, textSize);
if (rx <= 0 || ry <= 0) {
// Gradient with radius = 0 should be rendered as solid color of the last stop
rx = width;
ry = height;
stops = new float[] {stops[0], stops[stops.length - 1]};
stopsColors =
new int[] {stopsColors[stopsColors.length - 1], stopsColors[stopsColors.length - 1]};
}
double ratio = ry / rx; double ratio = ry / rx;
double cx = getVal(mPoints[4], width, scale, textSize) + offsetX; double cx = getVal(mPoints[4], width, scale, textSize) + offsetX;
+9
View File
@@ -232,6 +232,15 @@ void PatternFunction(void *info, CGContextRef context)
CGFloat rx = [self getVal:[_points objectAtIndex:2] relative:width]; CGFloat rx = [self getVal:[_points objectAtIndex:2] relative:width];
CGFloat ry = [self getVal:[_points objectAtIndex:3] relative:height]; CGFloat ry = [self getVal:[_points objectAtIndex:3] relative:height];
if (rx <= 0 || ry <= 0) {
// Gradient with radius = 0 should be rendered as solid color of the last stop
rx = width;
ry = height;
CGGradientRelease(gradient);
NSArray<NSNumber *> *gradientArray = @[_colors.firstObject, _colors.lastObject, _colors[_colors.count-2], _colors.lastObject];
gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:gradientArray]);
}
double ratio = ry / rx; double ratio = ry / rx;
CGFloat fx = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX; CGFloat fx = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX;