mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-07 16:54:52 +00:00
[ios] Workaround CGPathContainsPoint bug in iOS 12
https://github.com/react-native-community/react-native-svg/issues/794#issuecomment-461524902 https://stackoverflow.com/questions/54026261/cgpathcontainspoint-broken-in-ios-12-is-a-workaround-possible
This commit is contained in:
@@ -74,9 +74,13 @@
|
|||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
[self setHitArea:[self getPath:context]];
|
CGPathRef path = [self getPath:context];
|
||||||
|
[self setHitArea:path];
|
||||||
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
||||||
self.clientRect = bounds;
|
self.clientRect = bounds;
|
||||||
|
const CGRect fillBounds = CGPathGetBoundingBox(path);
|
||||||
|
const CGRect strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
||||||
|
self.pathBounds = CGRectUnion(fillBounds, strokeBounds);
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||||
@@ -150,6 +154,10 @@
|
|||||||
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
||||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||||
|
|
||||||
|
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
if (self.clipPath) {
|
if (self.clipPath) {
|
||||||
RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath];
|
RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath];
|
||||||
if ([clipNode isSimpleClipPath]) {
|
if ([clipNode isSimpleClipPath]) {
|
||||||
@@ -169,7 +177,7 @@
|
|||||||
NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"active == TRUE"];
|
NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"active == TRUE"];
|
||||||
NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive];
|
NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive];
|
||||||
if ([filtered count] != 0) {
|
if ([filtered count] != 0) {
|
||||||
return [filtered.firstObject hitTest:transformed withEvent:event];
|
return [filtered.lastObject hitTest:transformed withEvent:event];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,7 @@
|
|||||||
CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil);
|
CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil);
|
||||||
[self setHitArea:hitAreaPath];
|
[self setHitArea:hitAreaPath];
|
||||||
CGPathRelease(hitAreaPath);
|
CGPathRelease(hitAreaPath);
|
||||||
|
self.pathBounds = hitArea;
|
||||||
|
|
||||||
// apply viewBox transform on Image render.
|
// apply viewBox transform on Image render.
|
||||||
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
|
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
|
|||||||
@property (nonatomic, assign) BOOL dirty;
|
@property (nonatomic, assign) BOOL dirty;
|
||||||
@property (nonatomic, assign) BOOL merging;
|
@property (nonatomic, assign) BOOL merging;
|
||||||
@property (nonatomic, assign) CGPathRef path;
|
@property (nonatomic, assign) CGPathRef path;
|
||||||
|
@property (nonatomic, assign) CGPathRef strokePath;
|
||||||
@property (nonatomic, assign) CGRect clientRect;
|
@property (nonatomic, assign) CGRect clientRect;
|
||||||
|
@property (nonatomic, assign) CGRect pathBounds;
|
||||||
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
|
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -550,6 +550,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
|
|||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGPathRelease(_cachedClipPath);
|
CGPathRelease(_cachedClipPath);
|
||||||
|
CGPathRelease(_strokePath);
|
||||||
CGImageRelease(_clipMask);
|
CGImageRelease(_clipMask);
|
||||||
CGPathRelease(_path);
|
CGPathRelease(_path);
|
||||||
_clipMask = nil;
|
_clipMask = nil;
|
||||||
|
|||||||
+16
-14
@@ -18,7 +18,6 @@
|
|||||||
NSArray<NSString *> *_attributeList;
|
NSArray<NSString *> *_attributeList;
|
||||||
NSArray<RNSVGLength *> *_sourceStrokeDashArray;
|
NSArray<RNSVGLength *> *_sourceStrokeDashArray;
|
||||||
CGFloat *_strokeDashArrayData;
|
CGFloat *_strokeDashArrayData;
|
||||||
CGPathRef _strokePath;
|
|
||||||
CGPathRef _srcHitPath;
|
CGPathRef _srcHitPath;
|
||||||
CGPathRef _hitArea;
|
CGPathRef _hitArea;
|
||||||
}
|
}
|
||||||
@@ -157,7 +156,6 @@
|
|||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGPathRelease(_hitArea);
|
CGPathRelease(_hitArea);
|
||||||
CGPathRelease(_strokePath);
|
|
||||||
_sourceStrokeDashArray = nil;
|
_sourceStrokeDashArray = nil;
|
||||||
if (_strokeDashArrayData) {
|
if (_strokeDashArrayData) {
|
||||||
free(_strokeDashArrayData);
|
free(_strokeDashArrayData);
|
||||||
@@ -295,15 +293,15 @@ UInt32 saturate(CGFloat value) {
|
|||||||
self.path = CGPathRetain(path);
|
self.path = CGPathRetain(path);
|
||||||
}
|
}
|
||||||
[self setHitArea:path];
|
[self setHitArea:path];
|
||||||
|
const CGRect fillBounds = CGPathGetBoundingBox(path);
|
||||||
|
const CGRect strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
||||||
|
self.pathBounds = CGRectUnion(fillBounds, strokeBounds);
|
||||||
}
|
}
|
||||||
|
const CGRect pathBounds = self.pathBounds;
|
||||||
const CGRect fillBounds = CGPathGetBoundingBox(path);
|
|
||||||
const CGRect strokeBounds = CGPathGetBoundingBox(_strokePath);
|
|
||||||
const CGRect pathBounding = CGRectUnion(fillBounds, strokeBounds);
|
|
||||||
|
|
||||||
CGAffineTransform current = CGContextGetCTM(context);
|
CGAffineTransform current = CGContextGetCTM(context);
|
||||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||||
CGRect clientRect = CGRectApplyAffineTransform(pathBounding, svgToClientTransform);
|
CGRect clientRect = CGRectApplyAffineTransform(pathBounds, svgToClientTransform);
|
||||||
|
|
||||||
self.clientRect = clientRect;
|
self.clientRect = clientRect;
|
||||||
|
|
||||||
@@ -312,7 +310,7 @@ UInt32 saturate(CGFloat value) {
|
|||||||
CGAffineTransform matrix = CGAffineTransformConcat(transform, vbmatrix);
|
CGAffineTransform matrix = CGAffineTransformConcat(transform, vbmatrix);
|
||||||
|
|
||||||
CGRect bounds = CGRectMake(0, 0, CGRectGetWidth(clientRect), CGRectGetHeight(clientRect));
|
CGRect bounds = CGRectMake(0, 0, CGRectGetWidth(clientRect), CGRectGetHeight(clientRect));
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(pathBounding), CGRectGetMidY(pathBounding));
|
CGPoint mid = CGPointMake(CGRectGetMidX(pathBounds), CGRectGetMidY(pathBounds));
|
||||||
CGPoint center = CGPointApplyAffineTransform(mid, matrix);
|
CGPoint center = CGPointApplyAffineTransform(mid, matrix);
|
||||||
|
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
@@ -352,7 +350,7 @@ UInt32 saturate(CGFloat value) {
|
|||||||
[self.fill paint:context
|
[self.fill paint:context
|
||||||
opacity:self.fillOpacity
|
opacity:self.fillOpacity
|
||||||
painter:[self.svgView getDefinedPainter:self.fill.brushRef]
|
painter:[self.svgView getDefinedPainter:self.fill.brushRef]
|
||||||
bounds:pathBounding
|
bounds:pathBounds
|
||||||
];
|
];
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
|
|
||||||
@@ -409,7 +407,7 @@ UInt32 saturate(CGFloat value) {
|
|||||||
[self.stroke paint:context
|
[self.stroke paint:context
|
||||||
opacity:self.strokeOpacity
|
opacity:self.strokeOpacity
|
||||||
painter:[self.svgView getDefinedPainter:self.stroke.brushRef]
|
painter:[self.svgView getDefinedPainter:self.stroke.brushRef]
|
||||||
bounds:pathBounding
|
bounds:pathBounds
|
||||||
];
|
];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -426,13 +424,13 @@ UInt32 saturate(CGFloat value) {
|
|||||||
}
|
}
|
||||||
_srcHitPath = path;
|
_srcHitPath = path;
|
||||||
CGPathRelease(_hitArea);
|
CGPathRelease(_hitArea);
|
||||||
CGPathRelease(_strokePath);
|
CGPathRelease(self.strokePath);
|
||||||
_hitArea = CGPathCreateCopy(path);
|
_hitArea = CGPathCreateCopy(path);
|
||||||
_strokePath = nil;
|
self.strokePath = nil;
|
||||||
if (self.stroke && self.strokeWidth) {
|
if (self.stroke && self.strokeWidth) {
|
||||||
// Add stroke to hitArea
|
// Add stroke to hitArea
|
||||||
CGFloat width = [self relativeOnOther:self.strokeWidth];
|
CGFloat width = [self relativeOnOther:self.strokeWidth];
|
||||||
_strokePath = CGPathRetain(CFAutorelease(CGPathCreateCopyByStrokingPath(path, nil, width, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit)));
|
self.strokePath = CGPathRetain(CFAutorelease(CGPathCreateCopyByStrokingPath(path, nil, width, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit)));
|
||||||
// TODO add dashing
|
// TODO add dashing
|
||||||
// CGPathCreateCopyByDashingPath(CGPathRef _Nullable path, const CGAffineTransform * _Nullable transform, CGFloat phase, const CGFloat * _Nullable lengths, size_t count)
|
// CGPathCreateCopyByDashingPath(CGPathRef _Nullable path, const CGAffineTransform * _Nullable transform, CGFloat phase, const CGFloat * _Nullable lengths, size_t count)
|
||||||
}
|
}
|
||||||
@@ -460,9 +458,13 @@ UInt32 saturate(CGFloat value) {
|
|||||||
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
||||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||||
|
|
||||||
|
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd;
|
BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd;
|
||||||
if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) &&
|
if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) &&
|
||||||
!CGPathContainsPoint(_strokePath, nil, transformed, NO)) {
|
!CGPathContainsPoint(self.strokePath, nil, transformed, NO)) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user