feat: implement filter region lengths directly on RNSVGFilterRegion (#2485)

# Summary

[apple] Use filter region directly instead of creating new one on every
rerender.
[android] rename some variables and add temporary fix for null lengths
This commit is contained in:
Jakub Grzywacz
2024-10-14 14:47:44 +02:00
committed by GitHub
parent 2b905c4b41
commit 3aae632d1f
10 changed files with 85 additions and 77 deletions
+5 -4
View File
@@ -3,12 +3,9 @@
@interface RNSVGFilter : RNSVGNode
@property (nonatomic, strong) RNSVGLength *x;
@property (nonatomic, strong) RNSVGLength *y;
@property (nonatomic, strong) RNSVGLength *width;
@property (nonatomic, strong) RNSVGLength *height;
@property (nonatomic, assign) RNSVGUnits filterUnits;
@property (nonatomic, assign) RNSVGUnits primitiveUnits;
@property (nonatomic, strong) RNSVGFilterRegion *filterRegion;
- (CIImage *)applyFilter:(CIImage *)img
backgroundImg:(CIImage *)backgroundImg
@@ -18,5 +15,9 @@
- (CGContext *)openContext:(CGSize)size;
- (void)endContext:(CGContext *)context;
- (CIImage *)getMaskFromRect:(CGContext *)context rect:(CGRect)rect ctm:(CGAffineTransform)ctm;
- (void)setX:(RNSVGLength *)x;
- (void)setY:(RNSVGLength *)y;
- (void)setWidth:(RNSVGLength *)width;
- (void)setHeight:(RNSVGLength *)height;
@end
+14 -22
View File
@@ -70,12 +70,9 @@ using namespace facebook::react;
- (void)prepareForRecycle
{
[super prepareForRecycle];
_x = nil;
_y = nil;
_width = nil;
_height = nil;
_filterUnits = kRNSVGUnitsObjectBoundingBox;
_primitiveUnits = kRNSVGUnitsUserSpaceOnUse;
_filterRegion = nil;
}
#endif // RCT_NEW_ARCH_ENABLED
@@ -83,6 +80,7 @@ using namespace facebook::react;
{
if (self = [super init]) {
resultsMap = [NSMutableDictionary dictionary];
_filterRegion = [[RNSVGFilterRegion alloc] init];
}
return self;
}
@@ -112,12 +110,9 @@ using namespace facebook::react;
for (RNSVGNode *node in self.subviews) {
if ([node isKindOfClass:[RNSVGFilterPrimitive class]]) {
currentFilter = (RNSVGFilterPrimitive *)node;
cropRect = [[RNSVGFilterRegion regionWithX:currentFilter.x
y:currentFilter.y
width:currentFilter.width
height:currentFilter.height] getCropRect:currentFilter
units:self.primitiveUnits
renderableBounds:renderableBounds];
cropRect = [currentFilter.filterSubregion getCropRect:currentFilter
units:self.primitiveUnits
bounds:renderableBounds];
mask = [self getMaskFromRect:cropContext rect:cropRect ctm:ctm];
[cropFilter setValue:[currentFilter applyFilter:resultsMap previousFilterResult:result ctm:ctm]
forKey:@"inputImage"];
@@ -136,10 +131,7 @@ using namespace facebook::react;
}
}
cropRect = [[RNSVGFilterRegion regionWithX:self.x y:self.y width:self.width
height:self.height] getCropRect:self
units:self.filterUnits
renderableBounds:renderableBounds];
cropRect = [currentFilter.filterSubregion getCropRect:self units:self.filterUnits bounds:renderableBounds];
mask = [self getMaskFromRect:cropContext rect:cropRect ctm:ctm];
[cropFilter setValue:result forKey:@"inputImage"];
[cropFilter setValue:mask forKey:@"inputMaskImage"];
@@ -212,41 +204,41 @@ static CIImage *applySourceAlphaFilter(CIImage *inputImage)
- (void)setX:(RNSVGLength *)x
{
if ([x isEqualTo:_x]) {
if ([x isEqualTo:_filterRegion.x]) {
return;
}
_x = x;
[_filterRegion setX:x];
[self invalidate];
}
- (void)setY:(RNSVGLength *)y
{
if ([y isEqualTo:_y]) {
if ([y isEqualTo:_filterRegion.y]) {
return;
}
_y = y;
[_filterRegion setY:y];
[self invalidate];
}
- (void)setWidth:(RNSVGLength *)width
{
if ([width isEqualTo:_width]) {
if ([width isEqualTo:_filterRegion.width]) {
return;
}
_width = width;
[_filterRegion setWidth:width];
[self invalidate];
}
- (void)setHeight:(RNSVGLength *)height
{
if ([height isEqualTo:_height]) {
if ([height isEqualTo:_filterRegion.height]) {
return;
}
_height = height;
[_filterRegion setHeight:height];
[self invalidate];
}
+5 -4
View File
@@ -3,15 +3,16 @@
@interface RNSVGFilterPrimitive : RNSVGNode
@property (nonatomic, strong) RNSVGLength *x;
@property (nonatomic, strong) RNSVGLength *y;
@property (nonatomic, strong) RNSVGLength *width;
@property (nonatomic, strong) RNSVGLength *height;
@property (nonatomic, strong) NSString *result;
@property (nonatomic, strong) RNSVGFilterRegion *filterSubregion;
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results previousFilterResult:(CIImage *)previous;
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
previousFilterResult:(CIImage *)previous
ctm:(CGAffineTransform)ctm;
- (void)setX:(RNSVGLength *)x;
- (void)setY:(RNSVGLength *)y;
- (void)setWidth:(RNSVGLength *)width;
- (void)setHeight:(RNSVGLength *)height;
@end
+19 -12
View File
@@ -1,5 +1,6 @@
#import <RNSVGFilterPrimitive.h>
#import <RNSVGNode.h>
#import "RNSVGFilter.h"
#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTConversions.h>
@@ -15,14 +16,20 @@
- (void)prepareForRecycle
{
[super prepareForRecycle];
_x = nil;
_y = nil;
_width = nil;
_height = nil;
_filterSubregion = nil;
_result = nil;
}
#endif // RCT_NEW_ARCH_ENABLED
- (instancetype)init
{
self = [super init];
if (self) {
_filterSubregion = [[RNSVGFilterRegion alloc] init];
}
return self;
}
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return nil;
@@ -40,41 +47,41 @@
- (void)setX:(RNSVGLength *)x
{
if ([x isEqualTo:_x]) {
if ([x isEqualTo:_filterSubregion.x]) {
return;
}
_x = x;
[_filterSubregion setX:x];
[self invalidate];
}
- (void)setY:(RNSVGLength *)y
{
if ([y isEqualTo:_y]) {
if ([y isEqualTo:_filterSubregion.y]) {
return;
}
_y = y;
[_filterSubregion setY:y];
[self invalidate];
}
- (void)setWidth:(RNSVGLength *)width
{
if ([width isEqualTo:_width]) {
if ([width isEqualTo:_filterSubregion.width]) {
return;
}
_width = width;
[_filterSubregion setWidth:width];
[self invalidate];
}
- (void)setHeight:(RNSVGLength *)height
{
if ([height isEqualTo:_height]) {
if ([height isEqualTo:_filterSubregion.height]) {
return;
}
_height = height;
[_filterSubregion setHeight:height];
[self invalidate];
}
+1 -1
View File
@@ -12,7 +12,7 @@
@property (nonatomic, strong) RNSVGLength *height;
+ (instancetype)regionWithX:(RNSVGLength *)x y:(RNSVGLength *)y width:(RNSVGLength *)width height:(RNSVGLength *)height;
- (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units renderableBounds:(CGRect)renderableBounds;
- (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units bounds:(CGRect)bounds;
@end
+6 -12
View File
@@ -5,12 +5,6 @@
- (instancetype)init
{
self = [super init];
if (self) {
_x = [RNSVGLength lengthWithNumber:0];
_y = [RNSVGLength lengthWithNumber:0];
_width = [RNSVGLength lengthWithNumber:0];
_height = [RNSVGLength lengthWithNumber:0];
}
return self;
}
@@ -44,15 +38,15 @@
_height = height;
}
- (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units renderableBounds:(CGRect)renderableBounds
- (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units bounds:(CGRect)bounds
{
CGFloat x, y, width, height;
if (units == kRNSVGUnitsObjectBoundingBox) {
x = [node relativeOnFraction:self.x relative:renderableBounds.size.width];
y = [node relativeOnFraction:self.y relative:renderableBounds.size.height];
width = [node relativeOnFraction:self.width relative:renderableBounds.size.width];
height = [node relativeOnFraction:self.height relative:renderableBounds.size.height];
return CGRectMake(renderableBounds.origin.x + x, renderableBounds.origin.y + y, width, height);
x = [node relativeOnFraction:self.x relative:bounds.size.width];
y = [node relativeOnFraction:self.y relative:bounds.size.height];
width = [node relativeOnFraction:self.width relative:bounds.size.width];
height = [node relativeOnFraction:self.height relative:bounds.size.height];
return CGRectMake(bounds.origin.x + x, bounds.origin.y + y, width, height);
} else { // kRNSVGUnitsUserSpaceOnUse
x = [node relativeOnWidth:self.x];
y = [node relativeOnHeight:self.y];
+7
View File
@@ -141,4 +141,11 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
- (void)clearPath;
/**
* get canvas dimensions
*/
- (CGFloat)getCanvasWidth;
- (CGFloat)getCanvasHeight;
@end