Merge branch 'ios-touch-CGPathContainsPoint-bug'

This commit is contained in:
Mikael Sand
2019-02-09 04:01:50 +02:00
7 changed files with 82 additions and 21 deletions
@@ -28,6 +28,8 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.text.ReactFontManager;
import java.util.ArrayList;
import javax.annotation.Nullable;
import static android.graphics.Matrix.MTRANS_X;
@@ -47,6 +49,8 @@ class TSpanView extends TextView {
@Nullable String mContent;
private TextPathView textPath;
ArrayList<String> emoji = new ArrayList<>();
ArrayList<Matrix> emojiTransforms = new ArrayList<>();
public TSpanView(ReactContext reactContext) {
super(reactContext);
@@ -61,6 +65,20 @@ class TSpanView extends TextView {
@Override
void draw(Canvas canvas, Paint paint, float opacity) {
if (mContent != null) {
int numEmoji = emoji.size();
if (numEmoji > 0) {
GlyphContext gc = getTextRootGlyphContext();
FontData font = gc.getFont();
applyTextPropertiesToPaint(paint, font);
for (int i = 0; i < numEmoji; i++) {
String current = emoji.get(i);
Matrix mid = emojiTransforms.get(i);
canvas.save();
canvas.concat(mid);
canvas.drawText(current, 0, 0, paint);
canvas.restore();
}
}
drawPath(canvas, paint, opacity);
} else {
clip(canvas, paint);
@@ -676,6 +694,9 @@ class TSpanView extends TextView {
final float[] midPointMatrixData = new float[9];
final float[] endPointMatrixData = new float[9];
emoji.clear();
emojiTransforms.clear();
for (int index = 0; index < length; index++) {
char currentChar = chars[index];
String current = String.valueOf(currentChar);
@@ -855,12 +876,12 @@ class TSpanView extends TextView {
glyph.computeBounds(bounds, true);
float width = bounds.width();
if (width == 0) { // Render unicode emoji
mid.getValues(midPointMatrixData);
double midX = midPointMatrixData[MTRANS_X];
double midY = midPointMatrixData[MTRANS_Y];
canvas.rotate((float) r, (float)midX, (float)midY);
canvas.drawText(current, (float)midX, (float)midY, paint);
canvas.rotate((float) -r, (float)midX, (float)midY);
canvas.save();
canvas.concat(mid);
emoji.add(current);
emojiTransforms.add(new Matrix(mid));
canvas.drawText(current, 0, 0, paint);
canvas.restore();
} else {
glyph.transform(mid);
path.addPath(glyph);
+9 -1
View File
@@ -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]) {
+1
View File
@@ -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);
+2
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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;
}
+26
View File
@@ -23,6 +23,8 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
NSArray *lines;
NSUInteger lineCount;
BOOL isClosed;
NSMutableArray *emoji;
NSMutableArray *emojiTransform;
}
- (id)init
@@ -33,6 +35,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
RNSVGTSpan_separators = [NSCharacterSet whitespaceCharacterSet];
}
emoji = [NSMutableArray arrayWithCapacity:0];
emojiTransform = [NSMutableArray arrayWithCapacity:0];
return self;
}
@@ -48,6 +53,21 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
{
if (self.content) {
if (self.path) {
NSUInteger count = [emoji count];
RNSVGGlyphContext* gc = [self.textRoot getGlyphContext];
CGFloat fontSize = [gc getFontSize];
for (NSUInteger i = 0; i < count; i++) {
UILabel *label = [emoji objectAtIndex:i];
NSValue *transformValue = [emojiTransform objectAtIndex:i];
CGAffineTransform transform = [transformValue CGAffineTransformValue];
CGContextConcatCTM(context, transform);
CGContextTranslateCTM(context, 0, -fontSize);
[label.layer renderInContext:context];
CGContextTranslateCTM(context, 0, fontSize);
CGContextConcatCTM(context, CGAffineTransformInvert(transform));
}
}
[self renderPathTo:context rect:rect];
} else {
[self clip:context];
@@ -658,6 +678,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
}
}
[emoji removeAllObjects];
[emojiTransform removeAllObjects];
CFArrayRef runs = CTLineGetGlyphRuns(line);
CFIndex runEnd = CFArrayGetCount(runs);
for (CFIndex r = 0; r < runEnd; r++) {
@@ -829,6 +852,9 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI;
[label.layer renderInContext:context];
CGContextTranslateCTM(context, 0, fontSize);
CGContextConcatCTM(context, CGAffineTransformInvert(transform));
[emoji addObject:label];
[emojiTransform addObject:[NSValue valueWithCGAffineTransform:transform]];
} else {
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGPathAddPath(path, &transform, glyphPath);