mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-06 08:22:23 +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;
|
||||
}];
|
||||
[self setHitArea:[self getPath:context]];
|
||||
CGPathRef path = [self getPath:context];
|
||||
[self setHitArea:path];
|
||||
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
||||
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);
|
||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||
@@ -150,6 +154,10 @@
|
||||
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||
|
||||
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self.clipPath) {
|
||||
RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath];
|
||||
if ([clipNode isSimpleClipPath]) {
|
||||
@@ -169,7 +177,7 @@
|
||||
NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"active == TRUE"];
|
||||
NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive];
|
||||
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);
|
||||
[self setHitArea:hitAreaPath];
|
||||
CGPathRelease(hitAreaPath);
|
||||
self.pathBounds = hitArea;
|
||||
|
||||
// apply viewBox transform on Image render.
|
||||
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 merging;
|
||||
@property (nonatomic, assign) CGPathRef path;
|
||||
@property (nonatomic, assign) CGPathRef strokePath;
|
||||
@property (nonatomic, assign) CGRect clientRect;
|
||||
@property (nonatomic, assign) CGRect pathBounds;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
|
||||
|
||||
|
||||
|
||||
@@ -550,6 +550,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_cachedClipPath);
|
||||
CGPathRelease(_strokePath);
|
||||
CGImageRelease(_clipMask);
|
||||
CGPathRelease(_path);
|
||||
_clipMask = nil;
|
||||
|
||||
+16
-14
@@ -18,7 +18,6 @@
|
||||
NSArray<NSString *> *_attributeList;
|
||||
NSArray<RNSVGLength *> *_sourceStrokeDashArray;
|
||||
CGFloat *_strokeDashArrayData;
|
||||
CGPathRef _strokePath;
|
||||
CGPathRef _srcHitPath;
|
||||
CGPathRef _hitArea;
|
||||
}
|
||||
@@ -157,7 +156,6 @@
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_hitArea);
|
||||
CGPathRelease(_strokePath);
|
||||
_sourceStrokeDashArray = nil;
|
||||
if (_strokeDashArrayData) {
|
||||
free(_strokeDashArrayData);
|
||||
@@ -295,15 +293,15 @@ UInt32 saturate(CGFloat value) {
|
||||
self.path = CGPathRetain(path);
|
||||
}
|
||||
[self setHitArea:path];
|
||||
const CGRect fillBounds = CGPathGetBoundingBox(path);
|
||||
const CGRect strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
||||
self.pathBounds = CGRectUnion(fillBounds, strokeBounds);
|
||||
}
|
||||
|
||||
const CGRect fillBounds = CGPathGetBoundingBox(path);
|
||||
const CGRect strokeBounds = CGPathGetBoundingBox(_strokePath);
|
||||
const CGRect pathBounding = CGRectUnion(fillBounds, strokeBounds);
|
||||
const CGRect pathBounds = self.pathBounds;
|
||||
|
||||
CGAffineTransform current = CGContextGetCTM(context);
|
||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||
CGRect clientRect = CGRectApplyAffineTransform(pathBounding, svgToClientTransform);
|
||||
CGRect clientRect = CGRectApplyAffineTransform(pathBounds, svgToClientTransform);
|
||||
|
||||
self.clientRect = clientRect;
|
||||
|
||||
@@ -312,7 +310,7 @@ UInt32 saturate(CGFloat value) {
|
||||
CGAffineTransform matrix = CGAffineTransformConcat(transform, vbmatrix);
|
||||
|
||||
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);
|
||||
|
||||
self.bounds = bounds;
|
||||
@@ -352,7 +350,7 @@ UInt32 saturate(CGFloat value) {
|
||||
[self.fill paint:context
|
||||
opacity:self.fillOpacity
|
||||
painter:[self.svgView getDefinedPainter:self.fill.brushRef]
|
||||
bounds:pathBounding
|
||||
bounds:pathBounds
|
||||
];
|
||||
CGContextRestoreGState(context);
|
||||
|
||||
@@ -409,7 +407,7 @@ UInt32 saturate(CGFloat value) {
|
||||
[self.stroke paint:context
|
||||
opacity:self.strokeOpacity
|
||||
painter:[self.svgView getDefinedPainter:self.stroke.brushRef]
|
||||
bounds:pathBounding
|
||||
bounds:pathBounds
|
||||
];
|
||||
return;
|
||||
}
|
||||
@@ -426,13 +424,13 @@ UInt32 saturate(CGFloat value) {
|
||||
}
|
||||
_srcHitPath = path;
|
||||
CGPathRelease(_hitArea);
|
||||
CGPathRelease(_strokePath);
|
||||
CGPathRelease(self.strokePath);
|
||||
_hitArea = CGPathCreateCopy(path);
|
||||
_strokePath = nil;
|
||||
self.strokePath = nil;
|
||||
if (self.stroke && self.strokeWidth) {
|
||||
// Add stroke to hitArea
|
||||
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
|
||||
// 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);
|
||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||
|
||||
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd;
|
||||
if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) &&
|
||||
!CGPathContainsPoint(_strokePath, nil, transformed, NO)) {
|
||||
!CGPathContainsPoint(self.strokePath, nil, transformed, NO)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user