fix: Make native methods synchronous

This commit is contained in:
Mikael Sand
2019-10-05 18:43:00 +03:00
parent 409af915ea
commit 8ce76113e1
3 changed files with 280 additions and 383 deletions
@@ -16,12 +16,10 @@ import android.graphics.RectF;
import android.graphics.Region;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import javax.annotation.Nonnull;
@@ -37,106 +35,97 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
return "RNSVGRenderableManager";
}
private static void isPointInFill(final int tag, final float[] src, final Callback successCallback, final int attempt) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) {
if (attempt < 1) {
RenderableViewManager.runWhenViewIsAvailable(tag, new Runnable() {
@Override
public void run() {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) { // Should never happen
successCallback.invoke(false);
return;
}
isPointInFill(tag, src, successCallback, attempt + 1);
}
});
} else {
successCallback.invoke(false);
}
} else {
float scale = svg.mScale;
src[0] *= scale;
src[1] *= scale;
int i = svg.hitTest(src);
successCallback.invoke(i != -1);
}
}
}
);
}
@SuppressWarnings("unused")
@ReactMethod
public void isPointInFill(int tag, ReadableMap options, Callback successCallback) {
float x = (float) options.getDouble("x");
float y = (float) options.getDouble("y");
float[] src = new float[]{x, y};
isPointInFill(tag, src, successCallback, 0);
}
@SuppressWarnings("unused")
@ReactMethod
public void isPointInStroke(int tag, ReadableMap options, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean isPointInFill(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) {
successCallback.invoke(false);
return;
return false;
}
float scale = svg.mScale;
float x = (float) options.getDouble("x") * scale;
float y = (float) options.getDouble("y") * scale;
int i = svg.hitTest(new float[]{x, y});
return i != -1;
}
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean isPointInStroke(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) {
return false;
}
svg.getPath(null, null);
svg.initBounds();
Region strokeRegion = svg.mStrokeRegion;
float scale = svg.mScale;
int x = (int) (options.getDouble("x") * scale);
int y = (int) (options.getDouble("y") * scale);
boolean hit = strokeRegion != null && strokeRegion.contains(x, y);
successCallback.invoke(hit);
Region strokeRegion = svg.mStrokeRegion;
return strokeRegion != null && strokeRegion.contains(x, y);
}
@SuppressWarnings("unused")
@ReactMethod
public void getTotalLength(int tag, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public float getTotalLength(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
PathMeasure pm = new PathMeasure(svg.getPath(null, null), false);
float scale = svg.mScale;
successCallback.invoke(pm.getLength() / scale);
if (svg == null) {
return 0;
}
Path path = svg.getPath(null, null);
PathMeasure pm = new PathMeasure(path, false);
return pm.getLength() / svg.mScale;
}
@SuppressWarnings("unused")
@ReactMethod
public void getPointAtLength(int tag, ReadableMap options, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getPointAtLength(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) {
return null;
}
Path path = svg.getPath(null, null);
PathMeasure pm = new PathMeasure(path, false);
float length = (float) options.getDouble("length");
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
PathMeasure pm = new PathMeasure(svg.getPath(null, null), false);
float pathLength = pm.getLength();
float scale = svg.mScale;
float[] pos = new float[2];
float[] tan = new float[2];
pm.getPosTan(Math.max(0, Math.min(length, pathLength)), pos, tan);
float distance = Math.max(0, Math.min(length, pm.getLength()));
pm.getPosTan(distance, pos, tan);
double angle = Math.atan2(tan[1], tan[0]);
WritableMap result = Arguments.createMap();
float scale = svg.mScale;
result.putDouble("x", pos[0] / scale);
result.putDouble("y", pos[1] / scale);
result.putDouble("angle", angle);
successCallback.invoke(result);
return result;
}
@SuppressWarnings("unused")
@ReactMethod
public void getBBox(int tag, ReadableMap options, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getBBox(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
if (svg == null) {
return null;
}
boolean fill = options.getBoolean("fill");
boolean stroke = options.getBoolean("stroke");
boolean markers = options.getBoolean("markers");
boolean clipped = options.getBoolean("clipped");
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Path path = svg.getPath(null, null);
float scale = svg.mScale;
svg.initBounds();
RectF bounds = new RectF();
if (fill) {
bounds.union(svg.mFillBounds);
@@ -153,26 +142,30 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
bounds.intersect(svg.mClipBounds);
}
}
WritableMap result = Arguments.createMap();
float scale = svg.mScale;
result.putDouble("x", bounds.left / scale);
result.putDouble("y", bounds.top / scale);
result.putDouble("width", bounds.width() / scale);
result.putDouble("height", bounds.height() / scale);
successCallback.invoke(result);
return result;
}
@SuppressWarnings("unused")
@ReactMethod
public void getCTM(int tag, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getCTM(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Matrix screenCTM = svg.mCTM;
Matrix invViewBox = svg.getSvgView().mInvViewBoxMatrix;
Matrix ctm = new Matrix(screenCTM);
ctm.preConcat(invViewBox);
if (svg == null) {
return null;
}
Matrix ctm = new Matrix(svg.mCTM);
Matrix invViewBoxMatrix = svg.getSvgView().mInvViewBoxMatrix;
ctm.preConcat(invViewBoxMatrix);
float[] values = new float[9];
ctm.getValues(values);
WritableMap result = Arguments.createMap();
result.putDouble("a", values[Matrix.MSCALE_X]);
result.putDouble("b", values[Matrix.MSKEW_Y]);
@@ -180,18 +173,23 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
result.putDouble("d", values[Matrix.MSCALE_Y]);
result.putDouble("e", values[Matrix.MTRANS_X]);
result.putDouble("f", values[Matrix.MTRANS_Y]);
successCallback.invoke(result);
return result;
}
@SuppressWarnings("unused")
@ReactMethod
public void getScreenCTM(int tag, Callback successCallback) {
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getScreenCTM(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
Matrix screenCTM = svg.mCTM;
if (svg == null) {
return null;
}
float[] values = new float[9];
svg.mCTM.getValues(values);
SvgView root = svg.getSvgView();
float scale = svg.mScale;
float[] values = new float[9];
screenCTM.getValues(values);
WritableMap result = Arguments.createMap();
result.putDouble("a", values[Matrix.MSCALE_X]);
result.putDouble("b", values[Matrix.MSKEW_Y]);
@@ -199,6 +197,6 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
result.putDouble("d", values[Matrix.MSCALE_Y]);
result.putDouble("e", values[Matrix.MTRANS_X] + root.getLeft() / scale);
result.putDouble("f", values[Matrix.MTRANS_Y] + root.getTop() / scale);
successCallback.invoke(result);
return result;
}
}
+166 -192
View File
@@ -38,237 +38,211 @@ RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(vectorEffect, int)
RCT_EXPORT_VIEW_PROPERTY(propList, NSArray<NSString *>)
typedef void (^RNSVGSuccessBlock)(RNSVGRenderable *view);
typedef void (^RNSVGFailBlock)(void);
- (void)withTag:(nonnull NSNumber *)reactTag success:(RNSVGSuccessBlock)successBlock fail:(RNSVGFailBlock)failBlock attempt:(int)attempt {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
__kindof UIView *view = viewRegistry[reactTag];
if (!view) {
if (attempt < 1) {
void (^retryBlock)(void) = ^{
[self withTag:reactTag success:successBlock fail:failBlock attempt:(attempt + 1)];
};
RCTExecuteOnUIManagerQueue(retryBlock);
} else {
failBlock();
}
} else if ([view isKindOfClass:[RNSVGRenderable class]]) {
RNSVGRenderable *svg = view;
successBlock(svg);
} else {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
failBlock();
}
}];
}
RCT_EXPORT_METHOD(isPointInFill:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInFill:(nonnull NSNumber *)reactTag options:(NSDictionary *)options)
{
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return [NSNumber numberWithBool:false];
}
if (options == nil) {
RCTLogError(@"Invalid options given to isPointInFill, got: %@", options);
callback(@[[NSNumber numberWithBool:false]]);
return;
return [NSNumber numberWithBool:false];
}
id xo = [options objectForKey:@"x"];
id yo = [options objectForKey:@"y"];
if (![xo isKindOfClass:NSNumber.class] ||
![yo isKindOfClass:NSNumber.class]) {
RCTLogError(@"Invalid x or y given to isPointInFill");
callback(@[[NSNumber numberWithBool:false]]);
return;
return [NSNumber numberWithBool:false];
}
CGFloat x = (CGFloat)[xo floatValue];
CGFloat y = (CGFloat)[yo floatValue];
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGFloat x = (CGFloat)[xo doubleValue];
CGFloat y = (CGFloat)[yo doubleValue];
CGPoint point = CGPointMake(x, y);
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
UIView *target = [svg hitTest:point withEvent:nil];
BOOL hit = target != nil;
callback(@[[NSNumber numberWithBool:hit]]);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
UIView *target = [svg hitTest:point withEvent:nil];
BOOL hit = target != nil;
return [NSNumber numberWithBool:hit];
}
RCT_EXPORT_METHOD(isPointInStroke:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInStroke:(nonnull NSNumber *)reactTag options:(NSDictionary *)options)
{
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return [NSNumber numberWithBool:false];
}
if (options == nil) {
RCTLogError(@"Invalid options given to isPointInFill, got: %@", options);
callback(@[[NSNumber numberWithBool:false]]);
return;
return [NSNumber numberWithBool:false];
}
id xo = [options objectForKey:@"x"];
id yo = [options objectForKey:@"y"];
if (![xo isKindOfClass:NSNumber.class] ||
![yo isKindOfClass:NSNumber.class]) {
RCTLogError(@"Invalid x or y given to isPointInFill");
callback(@[[NSNumber numberWithBool:false]]);
return;
return [NSNumber numberWithBool:false];
}
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
CGFloat x = (CGFloat)[xo floatValue];
CGFloat y = (CGFloat)[yo floatValue];
CGPoint point = CGPointMake(x, y);
BOOL hit = CGPathContainsPoint(svg.strokePath, nil, point, NO);
callback(@[[NSNumber numberWithBool:hit]]);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGFloat x = (CGFloat)[xo doubleValue];
CGFloat y = (CGFloat)[yo doubleValue];
CGPoint point = CGPointMake(x, y);
BOOL hit = CGPathContainsPoint(svg.strokePath, nil, point, NO);
return [NSNumber numberWithBool:hit];
}
RCT_EXPORT_METHOD(getTotalLength:(nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getTotalLength:(nonnull NSNumber *)reactTag)
{
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
CGPathRef target = [svg getPath:nil];
RNSVGPathMeasure *measure = [[RNSVGPathMeasure alloc]init];
[measure extractPathData:target];
CGFloat pathLegth = measure.pathLength;
callback(@[[NSNumber numberWithDouble:pathLegth]]);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return [NSNumber numberWithDouble:0];
}
RNSVGPathMeasure *measure = [[RNSVGPathMeasure alloc]init];
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGPathRef target = [svg getPath:nil];
[measure extractPathData:target];
return [NSNumber numberWithDouble:measure.pathLength];
}
RCT_EXPORT_METHOD(getPointAtLength:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getPointAtLength:(nonnull NSNumber *)reactTag options:(NSDictionary *)options)
{
id length = [options objectForKey:@"length"];
CGFloat position = (CGFloat)[length floatValue];
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
CGPathRef target = [svg getPath:nil];
RNSVGPathMeasure *measure = [[RNSVGPathMeasure alloc]init];
[measure extractPathData:target];
CGFloat angle;
CGFloat x;
CGFloat y;
[measure getPosAndTan:&angle midPoint:fmax(0, fmin(position, measure.pathLength)) x:&x y:&y];
callback(
@[
@{
@"x":@(x),
@"y":@(y),
@"angle":@(angle)
}
]
);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return nil;
}
CGFloat position = (CGFloat)[[options objectForKey:@"length"] doubleValue];
RNSVGPathMeasure *measure = [[RNSVGPathMeasure alloc]init];
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGPathRef target = [svg getPath:nil];
[measure extractPathData:target];
CGFloat x;
CGFloat y;
CGFloat angle;
double midPoint = fmax(0, fmin(position, measure.pathLength));
[measure getPosAndTan:&angle midPoint:midPoint x:&x y:&y];
return @{
@"x":@(x),
@"y":@(y),
@"angle":@(angle)
};
}
RCT_EXPORT_METHOD(getBBox:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getBBox:(nonnull NSNumber *)reactTag options:(NSDictionary *)options)
{
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
BOOL fill = [[options objectForKey:@"fill"] boolValue];
BOOL stroke = [[options objectForKey:@"stroke"] boolValue];
BOOL markers = [[options objectForKey:@"markers"] boolValue];
BOOL clipped = [[options objectForKey:@"clipped"] boolValue];
[svg getPath:nil];
CGRect bounds = CGRectZero;
if (fill) {
bounds = CGRectUnion(bounds, svg.fillBounds);
}
if (stroke) {
bounds = CGRectUnion(bounds, svg.strokeBounds);
}
if (markers) {
bounds = CGRectUnion(bounds, svg.markerBounds);
}
if (clipped) {
CGPathRef clipPath = [svg getClipPath];
CGRect clipBounds = CGPathGetBoundingBox(clipPath);
if (clipPath && !CGRectIsEmpty(clipBounds)) {
bounds = CGRectIntersection(bounds, clipBounds);
}
}
CGPoint origin = bounds.origin;
CGSize size = bounds.size;
callback(
@[
@{
@"x":@(origin.x),
@"y":@(origin.y),
@"width":@(size.width),
@"height":@(size.height)
}
]
);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return nil;
}
RNSVGRenderable *svg = (RNSVGRenderable *)view;
BOOL fill = [[options objectForKey:@"fill"] boolValue];
BOOL stroke = [[options objectForKey:@"stroke"] boolValue];
BOOL markers = [[options objectForKey:@"markers"] boolValue];
BOOL clipped = [[options objectForKey:@"clipped"] boolValue];
[svg getPath:nil];
CGRect bounds = CGRectZero;
if (fill) {
bounds = CGRectUnion(bounds, svg.fillBounds);
}
if (stroke) {
bounds = CGRectUnion(bounds, svg.strokeBounds);
}
if (markers) {
bounds = CGRectUnion(bounds, svg.markerBounds);
}
if (clipped) {
CGPathRef clipPath = [svg getClipPath];
CGRect clipBounds = CGPathGetBoundingBox(clipPath);
if (clipPath && !CGRectIsEmpty(clipBounds)) {
bounds = CGRectIntersection(bounds, clipBounds);
}
}
CGPoint origin = bounds.origin;
CGSize size = bounds.size;
return @{
@"x":@(origin.x),
@"y":@(origin.y),
@"width":@(size.width),
@"height":@(size.height)
};
}
RCT_EXPORT_METHOD(getCTM:(nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getCTM:(nonnull NSNumber *)reactTag)
{
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
CGAffineTransform ctm = svg.ctm;
callback(
@[
@{
@"a":@(ctm.a),
@"b":@(ctm.b),
@"c":@(ctm.c),
@"d":@(ctm.d),
@"e":@(ctm.tx),
@"f":@(ctm.ty)
}
]
);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return nil;
}
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGAffineTransform ctm = svg.ctm;
return @{
@"a":@(ctm.a),
@"b":@(ctm.b),
@"c":@(ctm.c),
@"d":@(ctm.d),
@"e":@(ctm.tx),
@"f":@(ctm.ty)
};
}
RCT_EXPORT_METHOD(getScreenCTM:(nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getScreenCTM:(nonnull NSNumber *)reactTag)
{
[self
withTag:reactTag
success:^(RNSVGRenderable *svg){
RNSVGSvgView* root = svg.svgView;
CGAffineTransform viewbox = [root getViewBoxTransform];
CGAffineTransform ctm = CGAffineTransformConcat(svg.ctm, viewbox);
CGPoint offset = [root convertPoint:CGPointZero toView:svg.window];
callback(
@[
@{
@"a":@(ctm.a),
@"b":@(ctm.b),
@"c":@(ctm.c),
@"d":@(ctm.d),
@"e":@(ctm.tx + offset.x),
@"f":@(ctm.ty + offset.y)
}
]
);
}
fail:^{
callback(@[[NSNumber numberWithBool:false]]);
}
attempt:0];
__block UIView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
if (![view isKindOfClass:[RNSVGRenderable class]]) {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGRenderable, got: %@", view);
return nil;
}
RNSVGRenderable *svg = (RNSVGRenderable *)view;
RNSVGSvgView* root = svg.svgView;
CGAffineTransform viewbox = [root getViewBoxTransform];
CGAffineTransform ctm = CGAffineTransformConcat(svg.ctm, viewbox);
CGPoint offset = [root convertPoint:CGPointZero toView:svg.window];
return @{
@"a":@(ctm.a),
@"b":@(ctm.b),
@"c":@(ctm.c),
@"d":@(ctm.d),
@"e":@(ctm.tx + offset.x),
@"f":@(ctm.ty + offset.y)
};
}
@end
+32 -107
View File
@@ -264,117 +264,42 @@ export default class Shape<P> extends Component<P> {
) => {
this.root && this.root.setNativeProps(props);
};
getBBox = (
options?: SVGBoundingBoxOptions,
callback?: (box: SVGRect) => void,
) => {
getBBox = (options?: SVGBoundingBoxOptions): SVGRect => {
const { fill = true, stroke = true, markers = true, clipped = true } =
options || {};
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.getBBox(
handle,
{
fill,
stroke,
markers,
clipped,
},
resolve,
);
});
}
RNSVGRenderableManager.getBBox(
handle,
{
fill,
stroke,
markers,
clipped,
},
callback,
return RNSVGRenderableManager.getBBox(handle, {
fill,
stroke,
markers,
clipped,
});
};
getCTM = (): SVGMatrix => {
const handle = findNodeHandle(this.root as Component);
return new SVGMatrix(RNSVGRenderableManager.getCTM(handle));
};
getScreenCTM = (): SVGMatrix => {
const handle = findNodeHandle(this.root as Component);
return new SVGMatrix(RNSVGRenderableManager.getScreenCTM(handle));
};
isPointInFill = (options: DOMPointInit): boolean => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.isPointInFill(handle, options);
};
isPointInStroke = (options: DOMPointInit): boolean => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.isPointInStroke(handle, options);
};
getTotalLength = (): number => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.getTotalLength(handle);
};
getPointAtLength = (length: number): SVGPoint => {
const handle = findNodeHandle(this.root as Component);
return new SVGPoint(
RNSVGRenderableManager.getPointAtLength(handle, { length }),
);
return undefined;
};
getCTM = (callback: (screenCTM: SVGMatrix) => void) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.getCTM(handle, (matrix: Matrix) =>
resolve(new SVGMatrix(matrix)),
);
});
}
RNSVGRenderableManager.getCTM(handle, (matrix: Matrix) =>
callback(new SVGMatrix(matrix)),
);
return undefined;
};
getScreenCTM = (callback: (screenCTM: SVGMatrix) => void) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.getScreenCTM(handle, (matrix: Matrix) =>
resolve(new SVGMatrix(matrix)),
);
});
}
RNSVGRenderableManager.getScreenCTM(handle, (matrix: Matrix) =>
callback(new SVGMatrix(matrix)),
);
return undefined;
};
isPointInFill = (options: DOMPointInit, callback: (res: boolean) => void) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.isPointInFill(handle, options, resolve);
});
}
RNSVGRenderableManager.isPointInFill(handle, options, callback);
return undefined;
};
isPointInStroke = (
options: DOMPointInit,
callback?: (res: boolean) => void,
) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.isPointInStroke(handle, options, resolve);
});
}
RNSVGRenderableManager.isPointInStroke(handle, options, callback);
return undefined;
};
getTotalLength = (callback?: (length: number) => void) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.getTotalLength(handle, resolve);
});
}
RNSVGRenderableManager.getTotalLength(handle, callback);
return undefined;
};
getPointAtLength = (length: number, callback: (point: SVGPoint) => void) => {
const handle = findNodeHandle(this.root as Component);
if (!callback) {
return new Promise(resolve => {
RNSVGRenderableManager.getPointAtLength(
handle,
{ length },
(point: Point) => resolve(new SVGPoint(point)),
);
});
}
RNSVGRenderableManager.getPointAtLength(
handle,
{ length },
(point: Point) => callback(new SVGPoint(point)),
);
return undefined;
};
}
Shape.prototype.ownerSVGElement = ownerSVGElement;