fix: ignore invalid filter id (#2360)

# Summary

Closes #2356
Currently, when `filter` prop is defined, but there is no equivalent
`<Filter>` component, on iOS nothing is rendered, with this fix this
prop would be ignored, and the component should render as expected.

## Test Plan

```tsx
<Svg width="400" height="400" viewBox="0 0 124 124" fill="none">
  <Rect width="124" height="124" rx="24" fill="red" filter="url(#nonExistingFilterId)"/>
</Svg>
```

## Affected platforms

| OS      | Implemented |
| ------- | :---------: |
| iOS     |         |
This commit is contained in:
Jakub Grzywacz
2024-07-22 16:18:12 +02:00
committed by GitHub
parent 567e90521a
commit 0d97399d06
3 changed files with 31 additions and 27 deletions
+9 -6
View File
@@ -17,6 +17,9 @@
#endif // RCT_NEW_ARCH_ENABLED
@class RNSVGNode;
@class RNSVGMarker;
@class RNSVGMask;
@class RNSVGFilter;
@interface RNSVGSvgView :
#ifdef RCT_NEW_ARCH_ENABLED
@@ -55,17 +58,17 @@
- (RNSVGPainter *)getDefinedPainter:(NSString *)painterName;
- (void)defineMarker:(RNSVGNode *)marker markerName:(NSString *)markerName;
- (void)defineMarker:(RNSVGMarker *)marker markerName:(NSString *)markerName;
- (RNSVGNode *)getDefinedMarker:(NSString *)markerName;
- (RNSVGMarker *)getDefinedMarker:(NSString *)markerName;
- (void)defineMask:(RNSVGNode *)mask maskName:(NSString *)maskName;
- (void)defineMask:(RNSVGMask *)mask maskName:(NSString *)maskName;
- (RNSVGNode *)getDefinedMask:(NSString *)maskName;
- (RNSVGMask *)getDefinedMask:(NSString *)maskName;
- (void)defineFilter:(RNSVGNode *)filter filterName:(NSString *)filterName;
- (void)defineFilter:(RNSVGFilter *)filter filterName:(NSString *)filterName;
- (RNSVGNode *)getDefinedFilter:(NSString *)filterName;
- (RNSVGFilter *)getDefinedFilter:(NSString *)filterName;
- (NSString *)getDataURLWithBounds:(CGRect)bounds;
+9 -9
View File
@@ -23,9 +23,9 @@
NSMutableDictionary<NSString *, RNSVGNode *> *_clipPaths;
NSMutableDictionary<NSString *, RNSVGNode *> *_templates;
NSMutableDictionary<NSString *, RNSVGPainter *> *_painters;
NSMutableDictionary<NSString *, RNSVGNode *> *_markers;
NSMutableDictionary<NSString *, RNSVGNode *> *_masks;
NSMutableDictionary<NSString *, RNSVGNode *> *_filters;
NSMutableDictionary<NSString *, RNSVGMarker *> *_markers;
NSMutableDictionary<NSString *, RNSVGMask *> *_masks;
NSMutableDictionary<NSString *, RNSVGFilter *> *_filters;
CGAffineTransform _invviewBoxTransform;
bool rendered;
}
@@ -412,7 +412,7 @@ using namespace facebook::react;
return _painters ? [_painters objectForKey:painterName] : nil;
}
- (void)defineMarker:(RNSVGNode *)marker markerName:(NSString *)markerName
- (void)defineMarker:(RNSVGMarker *)marker markerName:(NSString *)markerName
{
if (!_markers) {
_markers = [[NSMutableDictionary alloc] init];
@@ -420,12 +420,12 @@ using namespace facebook::react;
[_markers setObject:marker forKey:markerName];
}
- (RNSVGNode *)getDefinedMarker:(NSString *)markerName;
- (RNSVGMarker *)getDefinedMarker:(NSString *)markerName;
{
return _markers ? [_markers objectForKey:markerName] : nil;
}
- (void)defineMask:(RNSVGNode *)mask maskName:(NSString *)maskName
- (void)defineMask:(RNSVGMask *)mask maskName:(NSString *)maskName
{
if (!_masks) {
_masks = [[NSMutableDictionary alloc] init];
@@ -433,12 +433,12 @@ using namespace facebook::react;
[_masks setObject:mask forKey:maskName];
}
- (RNSVGNode *)getDefinedMask:(NSString *)maskName;
- (RNSVGMask *)getDefinedMask:(NSString *)maskName;
{
return _masks ? [_masks objectForKey:maskName] : nil;
}
- (void)defineFilter:(RNSVGNode *)filter filterName:(NSString *)filterName
- (void)defineFilter:(RNSVGFilter *)filter filterName:(NSString *)filterName
{
if (!_filters) {
_filters = [[NSMutableDictionary alloc] init];
@@ -446,7 +446,7 @@ using namespace facebook::react;
[_filters setObject:filter forKey:filterName];
}
- (RNSVGNode *)getDefinedFilter:(NSString *)filterName
- (RNSVGFilter *)getDefinedFilter:(NSString *)filterName
{
return _filters ? [_filters objectForKey:filterName] : nil;
}
+13 -12
View File
@@ -250,7 +250,10 @@ UInt32 saturate(CGFloat value)
[self beginTransparencyLayer:context];
if (self.mask || self.filter) {
RNSVGFilter *filterNode = self.filter ? [self.svgView getDefinedFilter:self.filter] : nil;
RNSVGMask *maskNode = self.mask ? [self.svgView getDefinedMask:self.mask] : nil;
if (maskNode || filterNode) {
CGRect bounds = CGContextGetClipBoundingBox(context);
// Get current context transformations for offscreenContext
CGAffineTransform currentCTM = CGContextGetCTM(context);
@@ -269,9 +272,8 @@ UInt32 saturate(CGFloat value)
CGImage *contentImage = [RNSVGRenderUtils renderToImage:self ctm:currentCTM rect:rect clip:nil];
if (self.filter) {
if (filterNode) {
// https://www.w3.org/TR/SVG11/filters.html#FilterElement
RNSVGFilter *filterNode = (RNSVGFilter *)[self.svgView getDefinedFilter:self.filter];
CIImage *content = [CIImage imageWithCGImage:contentImage];
@@ -288,7 +290,7 @@ UInt32 saturate(CGFloat value)
CGImageRelease(contentImage);
contentImage = [[RNSVGRenderUtils sharedCIContext] createCGImage:content fromRect:scaledRect];
if (!self.mask) {
if (!maskNode) {
CGContextConcatCTM(context, CGAffineTransformInvert(currentCTM));
// On macOS the currentCTM is inverted, so we need to transform it again
@@ -306,9 +308,8 @@ UInt32 saturate(CGFloat value)
CGImageRelease(backgroundImage);
}
if (self.mask) {
if (maskNode) {
// https://www.w3.org/TR/SVG11/masking.html#MaskElement
RNSVGMask *_maskNode = (RNSVGMask *)[self.svgView getDefinedMask:self.mask];
// Allocate pixel buffer and bitmap context for mask
NSUInteger bytesPerPixel = 4;
@@ -334,18 +335,18 @@ UInt32 saturate(CGFloat value)
CGContextConcatCTM(bcontext, currentCTM);
// Clip to mask bounds and render the mask
CGSize currentBoundsSize = self.pathBounds.size;
CGFloat x = [self relativeOnFraction:[_maskNode x] relative:currentBoundsSize.width];
CGFloat y = [self relativeOnFraction:[_maskNode y] relative:currentBoundsSize.height];
CGFloat w = [self relativeOnFraction:[_maskNode maskwidth] relative:currentBoundsSize.width];
CGFloat h = [self relativeOnFraction:[_maskNode maskheight] relative:currentBoundsSize.height];
CGFloat x = [self relativeOnFraction:[maskNode x] relative:currentBoundsSize.width];
CGFloat y = [self relativeOnFraction:[maskNode y] relative:currentBoundsSize.height];
CGFloat w = [self relativeOnFraction:[maskNode maskwidth] relative:currentBoundsSize.width];
CGFloat h = [self relativeOnFraction:[maskNode maskheight] relative:currentBoundsSize.height];
CGRect maskBounds = CGRectApplyAffineTransform(CGRectMake(x, y, w, h), screenScaleCTM);
CGContextClipToRect(bcontext, maskBounds);
[_maskNode renderLayerTo:bcontext rect:bounds];
[maskNode renderLayerTo:bcontext rect:bounds];
// Apply luminanceToAlpha filter primitive
// https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement
UInt32 *currentPixel = pixels;
if (_maskNode.maskType == kRNSVGMaskTypeLuminance) {
if (maskNode.maskType == kRNSVGMaskTypeLuminance) {
for (NSUInteger i = 0; i < npixels; i++) {
UInt32 color = *currentPixel;