mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-22 19:01:36 +00:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user