Fix hit testing when using react-native transform arrays.

This commit is contained in:
Mikael Sand
2018-10-24 02:21:46 +03:00
parent f6995e856d
commit 38310677e3
13 changed files with 47 additions and 35 deletions
@@ -191,12 +191,13 @@ class GroupView extends RenderableView {
@Override @Override
int hitTest(final float[] src) { int hitTest(final float[] src) {
if (!mInvertible) { if (!mInvertible || !mTransformInvertible) {
return -1; return -1;
} }
float[] dst = new float[2]; float[] dst = new float[2];
mInvMatrix.mapPoints(dst, src); mInvMatrix.mapPoints(dst, src);
mInvTransform.mapPoints(dst, src);
int x = Math.round(dst[0]); int x = Math.round(dst[0]);
int y = Math.round(dst[1]); int y = Math.round(dst[1]);
@@ -428,12 +428,13 @@ abstract public class RenderableView extends VirtualView {
@Override @Override
int hitTest(final float[] src) { int hitTest(final float[] src) {
if (mPath == null || !mInvertible) { if (mPath == null || !mInvertible || !mTransformInvertible) {
return -1; return -1;
} }
float[] dst = new float[2]; float[] dst = new float[2];
mInvMatrix.mapPoints(dst, src); mInvMatrix.mapPoints(dst, src);
mInvTransform.mapPoints(dst, src);
int x = Math.round(dst[0]); int x = Math.round(dst[0]);
int y = Math.round(dst[1]); int y = Math.round(dst[1]);
@@ -9,6 +9,7 @@
package com.horcrux.svg; package com.horcrux.svg;
import android.graphics.Matrix;
import android.view.View; import android.view.View;
import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Assertions;
@@ -990,8 +991,10 @@ class RenderableViewManager extends ViewGroupManager<VirtualView> {
resetTransformProperty(node); resetTransformProperty(node);
} else { } else {
setTransformProperty(node, matrix); setTransformProperty(node, matrix);
node.mTransform = node.getMatrix();
} }
Matrix m = node.getMatrix();
node.mTransform = m;
node.mTransformInvertible = m.invert(node.mInvTransform);
} }
@ReactProp(name = "propList") @ReactProp(name = "propList")
@@ -971,12 +971,13 @@ class TSpanView extends TextView {
if (mContent == null) { if (mContent == null) {
return super.hitTest(src); return super.hitTest(src);
} }
if (mPath == null || !mInvertible) { if (mPath == null || !mInvertible || !mTransformInvertible) {
return -1; return -1;
} }
float[] dst = new float[2]; float[] dst = new float[2];
mInvMatrix.mapPoints(dst, src); mInvMatrix.mapPoints(dst, src);
mInvTransform.mapPoints(dst, src);
int x = Math.round(dst[0]); int x = Math.round(dst[0]);
int y = Math.round(dst[1]); int y = Math.round(dst[1]);
@@ -81,12 +81,13 @@ class UseView extends RenderableView {
@Override @Override
int hitTest(float[] src) { int hitTest(float[] src) {
if (!mInvertible) { if (!mInvertible || !mTransformInvertible) {
return -1; return -1;
} }
float[] dst = new float[2]; float[] dst = new float[2];
mInvMatrix.mapPoints(dst, src); mInvMatrix.mapPoints(dst, src);
mInvTransform.mapPoints(dst, src);
VirtualView template = getSvgView().getDefinedTemplate(mHref); VirtualView template = getSvgView().getDefinedTemplate(mHref);
int hitChild = template.hitTest(dst); int hitChild = template.hitTest(dst);
@@ -62,7 +62,9 @@ abstract public class VirtualView extends ViewGroup {
Matrix mMatrix = new Matrix(); Matrix mMatrix = new Matrix();
Matrix mTransform = new Matrix(); Matrix mTransform = new Matrix();
Matrix mInvMatrix = new Matrix(); Matrix mInvMatrix = new Matrix();
Matrix mInvTransform = new Matrix();
boolean mInvertible = true; boolean mInvertible = true;
boolean mTransformInvertible = true;
private RectF mClientRect; private RectF mClientRect;
private int mClipRule; private int mClipRule;
+2 -2
View File
@@ -81,8 +81,7 @@
{ {
CGRect clipBounds = CGContextGetClipBoundingBox(context); CGRect clipBounds = CGContextGetClipBoundingBox(context);
clipBounds = CGRectApplyAffineTransform(clipBounds, self.matrix); clipBounds = CGRectApplyAffineTransform(clipBounds, self.matrix);
CGAffineTransform transform = CATransform3DGetAffineTransform(self.layer.transform); clipBounds = CGRectApplyAffineTransform(clipBounds, self.transform);
clipBounds = CGRectApplyAffineTransform(clipBounds, transform);
CGFloat width = CGRectGetWidth(clipBounds); CGFloat width = CGRectGetWidth(clipBounds);
CGFloat height = CGRectGetHeight(clipBounds); CGFloat height = CGRectGetHeight(clipBounds);
@@ -128,6 +127,7 @@
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{ {
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
if (self.clipPath) { if (self.clipPath) {
RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath]; RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath];
+21 -22
View File
@@ -211,30 +211,29 @@
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{ {
CGPoint transformed = point;
if (self.align) { if (self.align) {
CGPoint transformed = CGPointApplyAffineTransform(point, _invviewBoxTransform); transformed = CGPointApplyAffineTransform(transformed, _invviewBoxTransform);
for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) {
if (![node isKindOfClass:[RNSVGNode class]]) {
continue;
}
if (event) {
node.active = NO;
} else if (node.active) {
return node;
}
UIView *hitChild = [node hitTest:transformed withEvent:event];
if (hitChild) {
node.active = YES;
return (node.responsible || (node != hitChild)) ? hitChild : self;
}
}
return nil;
} else {
return [super hitTest:point withEvent:event];
} }
for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) {
if (![node isKindOfClass:[RNSVGNode class]]) {
continue;
}
if (event) {
node.active = NO;
} else if (node.active) {
return node;
}
UIView *hitChild = [node hitTest:transformed withEvent:event];
if (hitChild) {
node.active = YES;
return (node.responsible || (node != hitChild)) ? hitChild : self;
}
}
return nil;
} }
+2 -1
View File
@@ -73,7 +73,8 @@
} }
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
const CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
RNSVGNode const* template = [self.svgView getDefinedTemplate:self.href]; RNSVGNode const* template = [self.svgView getDefinedTemplate:self.href];
if (event) { if (event) {
self.active = NO; self.active = NO;
+1
View File
@@ -34,6 +34,7 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
@property (nonatomic, assign) BOOL responsible; @property (nonatomic, assign) BOOL responsible;
@property (nonatomic, assign) CGAffineTransform matrix; @property (nonatomic, assign) CGAffineTransform matrix;
@property (nonatomic, assign) CGAffineTransform invmatrix; @property (nonatomic, assign) CGAffineTransform invmatrix;
@property (nonatomic, assign) CGAffineTransform invTransform;
@property (nonatomic, assign) BOOL active; @property (nonatomic, assign) BOOL active;
@property (nonatomic, assign) CGPathRef path; @property (nonatomic, assign) CGPathRef path;
@property (nonatomic, assign) CGRect clientRect; @property (nonatomic, assign) CGRect clientRect;
+1
View File
@@ -35,6 +35,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
{ {
if (self = [super init]) { if (self = [super init]) {
self.opacity = 1; self.opacity = 1;
self.invTransform = CGAffineTransformIdentity;
} }
return self; return self;
} }
+2 -2
View File
@@ -169,8 +169,7 @@ UInt32 saturate(CGFloat value) {
// This needs to be painted on a layer before being composited. // This needs to be painted on a layer before being composited.
CGContextSaveGState(context); CGContextSaveGState(context);
CGContextConcatCTM(context, self.matrix); CGContextConcatCTM(context, self.matrix);
CGAffineTransform transform = CATransform3DGetAffineTransform(self.layer.transform); CGContextConcatCTM(context, self.transform);
CGContextConcatCTM(context, transform);
CGContextSetAlpha(context, self.opacity); CGContextSetAlpha(context, self.opacity);
[self beginTransparencyLayer:context]; [self beginTransparencyLayer:context];
@@ -421,6 +420,7 @@ UInt32 saturate(CGFloat value) {
} }
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd; BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd;
if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) && if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) &&
+4 -3
View File
@@ -156,9 +156,10 @@ RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(matrix, CGAffineTransform) RCT_EXPORT_VIEW_PROPERTY(matrix, CGAffineTransform)
RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RNSVGNode) RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RNSVGNode)
{ {
view.layer.transform = json ? [RNSVGNodeManager CATransform3D:json] : defaultView.layer.transform; CATransform3D transform3d = json ? [RNSVGNodeManager CATransform3D:json] : defaultView.layer.transform;
// TODO: Improve this by enabling edge antialiasing only for transforms with rotation or skewing CGAffineTransform transform = CATransform3DGetAffineTransform(transform3d);
view.layer.allowsEdgeAntialiasing = !CATransform3DIsIdentity(view.layer.transform); view.invTransform = CGAffineTransformInvert(transform);
view.transform = transform;
[view invalidate]; [view invalidate];
} }
RCT_EXPORT_VIEW_PROPERTY(mask, NSString) RCT_EXPORT_VIEW_PROPERTY(mask, NSString)