feat: use codegenNativeComponent to import native views (#1847)

Changed `requireNativeComponent` to `codegenNativeComponent` so that upcoming changes (Static View Configs, Bridgeless Mode and idk what more) in `react-native` are available in the library. Also, types and native components are now taken directly from `fabric` folder to make sure the values passed to the native components are the ones defined in props. It should work on all supported versions since `codegenNativeComponent` function exists from RN v. 0.61.0. Suggested by @RSNara and @cipolleschi

Reason for [`5394bbb` (#1847)](5394bbbced): 
- on `Paper`, `Animated` uses `setNativeProps` method when we set `useNativeDriver`  to `false`, and does not rerender the component. Therefore, new transform lands only in `SvgView` and is parsed in `RCTViewManager.m` .
- on `Fabric`, the same code makes the components rerender. Due to this, information about new transform is passed to the `SvgView` child: `G` , making it apply translations from the transform in its `updateProps` method.
- other than `Animated` use-case, on both archs, if we just passed `transform` prop to `Svg` component, it would end up in double transformations now as well. All of those changes are due to https://github.com/software-mansion/react-native-svg/pull/1895, which added proper parsing of RN style `transform` prop (array of transformations objects) therefore making `G` properly handle `transform` prop passed from `Svg`.

Reason for [`19bcb24` (#1847)](19bcb2464b): Same as https://github.com/software-mansion/react-native-screens/pull/1624
This commit is contained in:
Wojciech Lewicki
2022-11-03 15:47:29 +01:00
committed by GitHub
parent 079d069c16
commit 1126079425
82 changed files with 4270 additions and 3218 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
},
"dependencies": {
"react": "18.1.0",
"react-native": "0.70.0",
"react-native": "0.70.4",
"react-native-svg": "link:../"
},
"devDependencies": {
@@ -21,7 +21,7 @@
"babel-jest": "^26.6.3",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.72.1",
"metro-react-native-babel-preset": "0.72.3",
"react-test-renderer": "18.1.0"
},
"jest": {

View File

@@ -133,26 +133,22 @@ class SvgNativeMethods extends Component {
};
alert = () => {
console.log("PRESSED");
this.root.toDataURL(base64 => {
this.root?.toDataURL(base64 => {
this.setState({
base64,
});
});
console.log(this.circle.isPointInFill({x: 200, y: 100}));
console.log(this.circle.isPointInStroke({x: 200, y: 100}));
console.log(this.circle.getTotalLength());
console.log(this.circle.getPointAtLength(25));
console.log(this.circle.getBBox({fill: true}));
console.log(this.circle.getCTM());
console.log(this.circle.getScreenCTM());
console.log(this.circle?.isPointInFill({x: 200, y: 100}));
console.log(this.circle?.isPointInStroke({x: 200, y: 100}));
console.log(this.circle?.getTotalLength());
console.log(this.circle?.getPointAtLength(25));
console.log(this.circle?.getBBox({fill: true}));
console.log(this.circle?.getCTM());
console.log(this.circle?.getScreenCTM());
};
root: any;
circle: any;
componentDidMount() {
this.alert();
}
root: Svg | null;
circle: Circle | null;
render() {
return (

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,12 @@ Pod::Spec.new do |s|
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "ReactCommon/turbomodule/core"
s.subspec "common" do |ss|
ss.source_files = "common/cpp/**/*.{cpp,h}"
ss.header_dir = "rnsvg"
ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\"" }
end
else
s.source_files = 'apple/**/*.{h,m,mm}'
s.exclude_files = 'apple/Utils/RNSVGFabricConversions.h'

View File

@@ -61,11 +61,7 @@ android {
sourceSets.main {
java {
if (isNewArchitectureEnabled()) {
srcDirs += [
"src/fabric/java",
]
} else {
if (!isNewArchitectureEnabled()) {
srcDirs += [
"src/paper/java",
"build/generated/source/codegen/java"
@@ -92,13 +88,3 @@ dependencies {
implementation 'com.facebook.react:react-native:+'
}
}
if (isNewArchitectureEnabled()) {
react {
reactRoot = rootProject.file("../node_modules/react-native/")
jsRootDir = file("../src/fabric/")
codegenDir = rootProject.file("../node_modules/react-native-codegen/")
libraryName = "rnsvg"
codegenJavaPackageName = "com.horcrux.rnsvg"
}
}

View File

@@ -3,7 +3,7 @@ apply plugin: 'com.diffplug.spotless'
spotless {
java {
target 'src/fabric/**/*.java', 'src/main/java/**/*.java', 'src/paper/java/com/horcrux/svg/**/*.java'
target 'src/main/java/**/*.java', 'src/paper/java/com/horcrux/svg/**/*.java'
googleJavaFormat()
}
}

View File

@@ -1,28 +0,0 @@
package com.horcrux.svg;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
@DoNotStrip
public class RNSvgComponentsRegistry {
static {
SoLoader.loadLibrary("rnsvg_modules");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private RNSvgComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static RNSvgComponentsRegistry register(ComponentFactory componentFactory) {
return new RNSvgComponentsRegistry(componentFactory);
}
}

View File

@@ -19,30 +19,35 @@ import android.graphics.Region;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
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.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.horcrux.rnsvg.NativeSvgRenderableModuleSpec;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.annotation.Nonnull;
class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@ReactModule(name = RNSVGRenderableManager.NAME)
class RNSVGRenderableManager extends NativeSvgRenderableModuleSpec {
RNSVGRenderableManager(ReactApplicationContext reactContext) {
super(reactContext);
}
public static final String NAME = "RNSVGRenderableModule";
@Nonnull
@Override
public String getName() {
return "RNSVGRenderableManager";
return NAME;
}
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean isPointInFill(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public boolean isPointInFill(Double tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return false;
}
@@ -57,8 +62,9 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public boolean isPointInStroke(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public boolean isPointInStroke(Double tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return false;
}
@@ -82,8 +88,9 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public float getTotalLength(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public double getTotalLength(Double tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return 0;
}
@@ -103,8 +110,9 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getPointAtLength(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public WritableMap getPointAtLength(Double tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return Arguments.createMap();
}
@@ -137,8 +145,9 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getBBox(int tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public WritableMap getBBox(Double tag, ReadableMap options) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return Arguments.createMap();
}
@@ -187,15 +196,20 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getCTM(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public WritableMap getCTM(Double tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return Arguments.createMap();
}
float scale = svg.mScale;
Matrix ctm = new Matrix(svg.mCTM);
Matrix invViewBoxMatrix = svg.getSvgView().mInvViewBoxMatrix;
SvgView svgView = svg.getSvgView();
if (svgView == null) {
throw new RuntimeException("Did not find parent SvgView for view with tag: " + tag);
}
Matrix invViewBoxMatrix = svgView.mInvViewBoxMatrix;
ctm.preConcat(invViewBoxMatrix);
float[] values = new float[9];
@@ -213,8 +227,9 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod(isBlockingSynchronousMethod = true)
public WritableMap getScreenCTM(int tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
@Override
public WritableMap getScreenCTM(Double tag) {
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue());
if (svg == null) {
return Arguments.createMap();
}
@@ -234,6 +249,7 @@ class RNSVGRenderableManager extends ReactContextBaseJavaModule {
}
@ReactMethod
@Override
public void getRawResource(String name, Promise promise) {
try {
ReactApplicationContext context = getReactApplicationContext();

View File

@@ -134,7 +134,6 @@ import com.facebook.react.viewmanagers.RNSVGTextPathManagerDelegate;
import com.facebook.react.viewmanagers.RNSVGTextPathManagerInterface;
import com.facebook.react.viewmanagers.RNSVGUseManagerDelegate;
import com.facebook.react.viewmanagers.RNSVGUseManagerInterface;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -149,6 +148,12 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
mClassName = svgclass.toString();
}
protected ViewManagerDelegate<V> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
static class RenderableShadowNode extends LayoutShadowNode {
@SuppressWarnings({"unused", "EmptyMethod"})
@@ -455,14 +460,9 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
@ReactProp(name = ViewProps.POINTER_EVENTS)
public void setPointerEvents(V view, @Nullable String pointerEventsStr) {
if (pointerEventsStr == null) {
view.setPointerEvents(PointerEvents.AUTO);
} else {
PointerEvents pointerEvents =
PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_"));
PointerEvents pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr);
view.setPointerEvents(pointerEvents);
}
}
@ReactProp(name = "onLayout")
public void setOnLayout(V node, boolean onLayout) {
@@ -733,11 +733,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGGroupManagerDelegate(this);
}
private final ViewManagerDelegate<GroupView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGGroup";
}
static class PathViewManager extends RenderableViewManager<PathView>
@@ -747,11 +743,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGPathManagerDelegate(this);
}
private final ViewManagerDelegate<PathView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGPath";
@ReactProp(name = "d")
public void setD(PathView node, String d) {
@@ -828,10 +820,6 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
view.setMethod(value);
}
public void setTextAnchor(K view, @Nullable String value) {
// TODO: is it available on Android?
}
public void setDx(K view, @Nullable ReadableArray value) {
view.setDeltaX(value);
}
@@ -840,14 +828,6 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
view.setDeltaY(value);
}
public void setPositionX(K view, @Nullable ReadableArray value) {
view.setPositionX(value);
}
public void setPositionY(K view, @Nullable ReadableArray value) {
view.setPositionY(value);
}
public void setX(K view, @Nullable ReadableArray value) {
view.setPositionX(value);
}
@@ -892,11 +872,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGTextManagerDelegate(this);
}
private final ViewManagerDelegate<TextView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGText";
TextViewManager(SVGClass svgClass) {
super(svgClass);
@@ -911,17 +887,13 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGTSpanManagerDelegate(this);
}
public static final String REACT_CLASS = "RNSVGTSpan";
TSpanViewManager(SVGClass svgClass) {
super(svgClass);
mDelegate = new RNSVGTSpanManagerDelegate(this);
}
private final ViewManagerDelegate<TSpanView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
@ReactProp(name = "content")
public void setContent(TSpanView node, @Nullable String content) {
node.setContent(content);
@@ -935,17 +907,13 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGTextPathManagerDelegate(this);
}
public static final String REACT_CLASS = "RNSVGTextPath";
TextPathViewManager(SVGClass svgClass) {
super(svgClass);
mDelegate = new RNSVGTextPathManagerDelegate(this);
}
private final ViewManagerDelegate<TextPathView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
@ReactProp(name = "href")
public void setHref(TextPathView node, String href) {
node.setHref(href);
@@ -998,11 +966,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGImageManagerDelegate(this);
}
private final ViewManagerDelegate<ImageView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGImage";
@ReactProp(name = "x")
public void setX(ImageView node, Dynamic x) {
@@ -1083,11 +1047,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGCircleManagerDelegate(this);
}
private final ViewManagerDelegate<CircleView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGCircle";
@ReactProp(name = "cx")
public void setCx(CircleView node, Dynamic cx) {
@@ -1139,11 +1099,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGEllipseManagerDelegate(this);
}
private final ViewManagerDelegate<EllipseView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGEllipse";
@ReactProp(name = "cx")
public void setCx(EllipseView node, Dynamic cx) {
@@ -1210,11 +1166,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGLineManagerDelegate(this);
}
private final ViewManagerDelegate<LineView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGLine";
@ReactProp(name = "x1")
public void setX1(LineView node, Dynamic x1) {
@@ -1281,11 +1233,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGRectManagerDelegate(this);
}
private final ViewManagerDelegate<RectView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGRect";
@ReactProp(name = "x")
public void setX(RectView node, Dynamic x) {
@@ -1379,11 +1327,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGClipPathManagerDelegate(this);
}
private final ViewManagerDelegate<ClipPathView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGClipPath";
}
static class DefsViewManager extends VirtualViewManager<DefsView>
@@ -1394,11 +1338,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGDefsManagerDelegate(this);
}
private final ViewManagerDelegate<DefsView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGDefs";
}
static class UseViewManager extends RenderableViewManager<UseView>
@@ -1409,11 +1349,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGUseManagerDelegate(this);
}
private final ViewManagerDelegate<UseView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGUse";
@ReactProp(name = "href")
public void setHref(UseView node, String href) {
@@ -1484,11 +1420,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGSymbolManagerDelegate(this);
}
private final ViewManagerDelegate<SymbolView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGSymbol";
@ReactProp(name = "minX")
public void setMinX(SymbolView node, float minX) {
@@ -1528,11 +1460,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGPatternManagerDelegate(this);
}
private final ViewManagerDelegate<PatternView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGPattern";
@ReactProp(name = "x")
public void setX(PatternView node, Dynamic x) {
@@ -1643,11 +1571,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGMaskManagerDelegate(this);
}
private final ViewManagerDelegate<MaskView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGMask";
@ReactProp(name = "x")
public void setX(MaskView node, Dynamic x) {
@@ -1723,11 +1647,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGForeignObjectManagerDelegate(this);
}
private final ViewManagerDelegate<ForeignObjectView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGForeignObject";
@ReactProp(name = "x")
public void setX(ForeignObjectView node, Dynamic x) {
@@ -1793,11 +1713,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGMarkerManagerDelegate(this);
}
private final ViewManagerDelegate<MarkerView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGMarker";
@ReactProp(name = "refX")
public void setRefX(MarkerView node, Dynamic refX) {
@@ -1904,11 +1820,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGLinearGradientManagerDelegate(this);
}
private final ViewManagerDelegate<RectView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGLinearGradient";
@ReactProp(name = "x1")
public void setX1(LinearGradientView node, Dynamic x1) {
@@ -1990,11 +1902,7 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
mDelegate = new RNSVGRadialGradientManagerDelegate(this);
}
private final ViewManagerDelegate<RectView> mDelegate;
protected ViewManagerDelegate getDelegate() {
return mDelegate;
}
public static final String REACT_CLASS = "RNSVGRadialGradient";
@ReactProp(name = "fx")
public void setFx(RadialGradientView node, Dynamic fx) {

View File

@@ -10,50 +10,156 @@ package com.horcrux.svg;
import static com.horcrux.svg.RenderableViewManager.*;
import com.facebook.react.ReactPackage;
import androidx.annotation.Nullable;
import com.facebook.react.TurboReactPackage;
import com.facebook.react.ViewManagerOnDemandReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.module.annotations.ReactModuleList;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
public class SvgPackage implements ReactPackage {
@ReactModuleList(
nativeModules = {
SvgViewModule.class,
RNSVGRenderableManager.class,
})
public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemandReactPackage {
@Nonnull
@Override
public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new GroupViewManager(),
new PathViewManager(),
new CircleViewManager(),
new EllipseViewManager(),
new LineViewManager(),
new RectViewManager(),
new TextViewManager(),
new TSpanViewManager(),
new TextPathViewManager(),
new ImageViewManager(),
new ClipPathViewManager(),
new DefsViewManager(),
new UseViewManager(),
new SymbolManager(),
new LinearGradientManager(),
new RadialGradientManager(),
new PatternManager(),
new MaskManager(),
new ForeignObjectManager(),
new MarkerManager(),
new SvgViewManager());
private @Nullable Map<String, ModuleSpec> mViewManagers;
private Map<String, ModuleSpec> getViewManagersMap(final ReactApplicationContext reactContext) {
if (mViewManagers == null) {
Map<String, ModuleSpec> specs = MapBuilder.newHashMap();
specs.put(
GroupViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new GroupViewManager()));
specs.put(
PathViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new PathViewManager()));
specs.put(
CircleViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new CircleViewManager()));
specs.put(
EllipseViewManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new EllipseViewManager()));
specs.put(
LineViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new LineViewManager()));
specs.put(
RectViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new RectViewManager()));
specs.put(
TextViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new TextViewManager()));
specs.put(
TSpanViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new TSpanViewManager()));
specs.put(
TextPathViewManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new TextPathViewManager()));
specs.put(
ImageViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new ImageViewManager()));
specs.put(
ClipPathViewManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new ClipPathViewManager()));
specs.put(
DefsViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new DefsViewManager()));
specs.put(UseViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new UseViewManager()));
specs.put(SymbolManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new SymbolManager()));
specs.put(
LinearGradientManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new LinearGradientManager()));
specs.put(
RadialGradientManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new RadialGradientManager()));
specs.put(PatternManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new PatternManager()));
specs.put(MaskManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new MaskManager()));
specs.put(
ForeignObjectManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(() -> new ForeignObjectManager()));
specs.put(MarkerManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new MarkerManager()));
specs.put(SvgViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec(() -> new SvgViewManager()));
mViewManagers = specs;
}
return mViewManagers;
}
@Nonnull
/** {@inheritDoc} */
@Override
public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new SvgViewModule(reactContext), new RNSVGRenderableManager(reactContext));
public Collection<String> getViewManagerNames(ReactApplicationContext reactContext) {
return getViewManagersMap(reactContext).keySet();
}
@Override
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
return new ArrayList<>(getViewManagersMap(reactContext).values());
}
/** {@inheritDoc} */
@Override
public @Nullable ViewManager createViewManager(
ReactApplicationContext reactContext, String viewManagerName) {
ModuleSpec spec = getViewManagersMap(reactContext).get(viewManagerName);
return spec != null ? (ViewManager) spec.getProvider().get() : null;
}
@Override
public NativeModule getModule(String name, @Nonnull ReactApplicationContext reactContext) {
switch (name) {
case SvgViewModule.NAME:
return new SvgViewModule(reactContext);
case RNSVGRenderableManager.NAME:
return new RNSVGRenderableManager(reactContext);
default:
return null;
}
}
@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
try {
Class<?> reactModuleInfoProviderClass =
Class.forName("com.horcrux.svg.SvgPackage$$ReactModuleInfoProvider");
return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
} catch (ClassNotFoundException e) {
// ReactModuleSpecProcessor does not run at build-time. Create this ReactModuleInfoProvider by
// hand.
return () -> {
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
Class<? extends NativeModule>[] moduleList =
new Class[] {
SvgViewModule.class, RNSVGRenderableManager.class,
};
for (Class<? extends NativeModule> moduleClass : moduleList) {
ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
reactModuleInfoMap.put(
reactModule.name(),
new ReactModuleInfo(
reactModule.name(),
moduleClass.getName(),
reactModule.canOverrideExistingModule(),
reactModule.needsEagerInit(),
reactModule.hasConstants(),
reactModule.isCxxModule(),
TurboModule.class.isAssignableFrom(moduleClass)));
}
return reactModuleInfoMap;
};
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(
"No ReactModuleInfoProvider for MyPackage$$ReactModuleInfoProvider", e);
}
}
@SuppressWarnings("unused")

View File

@@ -10,13 +10,15 @@ package com.horcrux.svg;
import android.util.SparseArray;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.DynamicFromObject;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewManagerDelegate;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerDelegate;
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerInterface;
import com.facebook.react.viewmanagers.RNSVGSvgViewAndroidManagerDelegate;
import com.facebook.react.viewmanagers.RNSVGSvgViewAndroidManagerInterface;
import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.views.view.ReactViewManager;
import java.lang.reflect.InvocationTargetException;
@@ -29,9 +31,10 @@ import javax.annotation.Nullable;
* ViewManager for RNSVGSvgView React views. Renders as a {@link SvgView} and handles invalidating
* the native view on view updates happening in the underlying tree.
*/
class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInterface<SvgView> {
class SvgViewManager extends ReactViewManager
implements RNSVGSvgViewAndroidManagerInterface<SvgView> {
private static final String REACT_CLASS = "RNSVGSvgView";
public static final String REACT_CLASS = "RNSVGSvgViewAndroid";
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
@@ -43,7 +46,7 @@ class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInte
}
public SvgViewManager() {
mDelegate = new RNSVGSvgViewManagerDelegate(this);
mDelegate = new RNSVGSvgViewAndroidManagerDelegate(this);
}
static void setSvgView(int tag, SvgView svg) {
@@ -182,4 +185,159 @@ class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInte
e.printStackTrace();
}
}
@Override
public void setHasTVPreferredFocus(SvgView view, boolean value) {
super.setTVPreferredFocus(view, value);
}
@Override
public void setBorderTopEndRadius(SvgView view, float value) {
super.setBorderRadius(view, 6, value);
}
@Override
public void setBorderBottomStartRadius(SvgView view, float value) {
super.setBorderRadius(view, 7, value);
}
@Override
public void setBorderBottomColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 4, value);
}
@Override
public void setNextFocusDown(SvgView view, int value) {
super.nextFocusDown(view, value);
}
@Override
public void setBorderRightColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 2, value);
}
@Override
public void setNextFocusRight(SvgView view, int value) {
super.nextFocusRight(view, value);
}
@Override
public void setBorderLeftColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 1, value);
}
@Override
public void setBorderColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 0, value);
}
@Override
public void setRemoveClippedSubviews(SvgView view, boolean value) {
super.setRemoveClippedSubviews(view, value);
}
@Override
public void setNextFocusForward(SvgView view, int value) {
super.nextFocusForward(view, value);
}
@Override
public void setNextFocusUp(SvgView view, int value) {
super.nextFocusUp(view, value);
}
@Override
public void setAccessible(SvgView view, boolean value) {
super.setAccessible(view, value);
}
@Override
public void setBorderStartColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 5, value);
}
@Override
public void setBorderBottomEndRadius(SvgView view, float value) {
super.setBorderRadius(view, 8, value);
}
@Override
public void setBorderEndColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 6, value);
}
@Override
public void setFocusable(SvgView view, boolean value) {
super.setFocusable(view, value);
}
@Override
public void setNativeBackgroundAndroid(SvgView view, @Nullable ReadableMap value) {
super.setNativeBackground(view, value);
}
@Override
public void setBorderTopStartRadius(SvgView view, float value) {
super.setBorderRadius(view, 5, value);
}
@Override
public void setNativeForegroundAndroid(SvgView view, @Nullable ReadableMap value) {
super.setNativeForeground(view, value);
}
@Override
public void setBackfaceVisibility(SvgView view, @Nullable String value) {
super.setBackfaceVisibility(view, value);
}
@Override
public void setBorderStyle(SvgView view, @Nullable String value) {
super.setBorderStyle(view, value);
}
@Override
public void setNeedsOffscreenAlphaCompositing(SvgView view, boolean value) {
super.setNeedsOffscreenAlphaCompositing(view, value);
}
@Override
public void setHitSlop(SvgView view, @Nullable ReadableMap value) {
super.setHitSlop(view, new DynamicFromObject(value));
}
@Override
public void setBorderTopColor(SvgView view, @Nullable Integer value) {
super.setBorderColor(view, 3, value);
}
@Override
public void setNextFocusLeft(SvgView view, int value) {
super.nextFocusLeft(view, value);
}
@Override
public void setBorderRadius(SvgView view, double value) {
super.setBorderRadius(view, 0, (float) value);
}
@Override
public void setBorderTopLeftRadius(SvgView view, double value) {
super.setBorderRadius(view, 1, (float) value);
}
@Override
public void setBorderTopRightRadius(SvgView view, double value) {
super.setBorderRadius(view, 2, (float) value);
}
@Override
public void setBorderBottomRightRadius(SvgView view, double value) {
super.setBorderRadius(view, 3, (float) value);
}
@Override
public void setBorderBottomLeftRadius(SvgView view, double value) {
super.setBorderRadius(view, 4, (float) value);
}
}

View File

@@ -10,21 +10,25 @@ package com.horcrux.svg;
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.module.annotations.ReactModule;
import com.horcrux.rnsvg.NativeSvgViewModuleSpec;
import javax.annotation.Nonnull;
class SvgViewModule extends ReactContextBaseJavaModule {
@ReactModule(name = SvgViewModule.NAME)
class SvgViewModule extends NativeSvgViewModuleSpec {
SvgViewModule(ReactApplicationContext reactContext) {
super(reactContext);
}
public static final String NAME = "RNSVGSvgViewModule";
@Nonnull
@Override
public String getName() {
return "RNSVGSvgViewManager";
return NAME;
}
private static void toDataURL(
@@ -76,7 +80,8 @@ class SvgViewModule extends ReactContextBaseJavaModule {
@SuppressWarnings("unused")
@ReactMethod
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
toDataURL(tag, options, successCallback, 0);
@Override
public void toDataURL(Double tag, ReadableMap options, Callback successCallback) {
toDataURL(tag.intValue(), options, successCallback, 0);
}
}

View File

@@ -373,6 +373,7 @@ public abstract class VirtualView extends ReactViewGroup {
abstract Path getPath(Canvas canvas, Paint paint);
@Nullable
SvgView getSvgView() {
if (svgView != null) {
return svgView;

View File

@@ -1,40 +0,0 @@
SVG_MAIN_THIS_DIR := $(call my-dir)
include $(SVG_MAIN_THIS_DIR)/../../../build/generated/source/codegen/jni/Android.mk
include $(CLEAR_VARS)
LOCAL_PATH := $(SVG_MAIN_THIS_DIR)
LOCAL_MODULE := rnsvg_modules
LOCAL_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
# Please note as one of the library listed is libreact_codegen_samplelibrary
# This name will be generated as libreact_codegen_<library-name>
# where <library-name> is the one you specified in the Gradle configuration
LOCAL_SHARED_LIBRARIES := libjsi \
libfbjni \
libglog \
libfolly_runtime \
libyoga \
libreact_nativemodule_core \
libturbomodulejsijni \
librrc_view \
libreact_render_core \
libreact_render_graphics \
libfabricjni \
libreact_debug \
libreact_render_componentregistry \
libreact_render_debug \
libruntimeexecutor \
libreact_render_mapbuffer \
libreact_codegen_rncore \
libreact_codegen_rnsvg
LOCAL_CFLAGS := \
-DLOG_TAG=\"ReactNative\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++17 -Wall
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
set(RNS_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
set(RNS_COMMON_DIR ${RNS_ANDROID_DIR}/../common/cpp)
set(RNS_GENERATED_DIR ${RNS_ANDROID_DIR}/build/generated)
set(RNS_GENERATED_JNI_DIR ${RNS_GENERATED_DIR}/source/codegen/jni)
set(RNS_GENERATED_REACT_DIR ${RNS_GENERATED_JNI_DIR}/react/renderer/components/rnsvg)
add_compile_options(
-fexceptions
-frtti
-std=c++17
-Wall
-Wpedantic
-Wno-gnu-zero-variadic-macro-arguments
)
file(GLOB rnsvg_SRCS CONFIGURE_DEPENDS *.cpp ${RNS_COMMON_DIR}/react/renderer/components/rnsvg/*.cpp)
file(GLOB rnsvg_codegen_SRCS CONFIGURE_DEPENDS ${RNS_GENERATED_REACT_DIR}/*cpp)
add_library(
react_codegen_rnsvg
SHARED
${rnsvg_SRCS}
${rnsvg_codegen_SRCS}
)
target_include_directories(
react_codegen_rnsvg
PUBLIC
.
${RNS_COMMON_DIR}
${RNS_GENERATED_JNI_DIR}
${RNS_GENERATED_REACT_DIR}
)
target_link_libraries(
react_codegen_rnsvg
fbjni
folly_runtime
glog
jsi
react_codegen_rncore
react_debug
react_nativemodule_core
react_render_core
react_render_debug
react_render_graphics
react_render_mapbuffer
rrc_view
turbomodulejsijni
yoga
react_render_imagemanager
)
target_compile_options(
react_codegen_rnsvg
PRIVATE
-DLOG_TAG=\"ReactNative\"
-fexceptions
-frtti
-std=c++17
-Wall
)
message(WARNING "CMAKE_CURRENT_SORUCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}")
target_include_directories(
${CMAKE_PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@@ -1,9 +0,0 @@
#include <fbjni/fbjni.h>
#include "RNSvgComponentsRegistry.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::RNSvgComponentsRegistry::registerNatives();
});
}

View File

@@ -1,75 +0,0 @@
#include "RNSvgComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rnsvg/ComponentDescriptors.h>
#include <react/renderer/mapbuffer/MapBuffer.h>
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
namespace facebook {
namespace react {
RNSvgComponentsRegistry::RNSvgComponentsRegistry(
ComponentFactory *delegate)
: delegate_(delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
RNSvgComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Svg
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGCircleComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGClipPathComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGDefsComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGEllipseComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGForeignObjectComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGGroupComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGImageComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGLinearGradientComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGLineComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGMarkerComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGMaskComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGPathComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGPatternComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGRadialGradientComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGRectComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGSvgViewComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGSymbolComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGTextComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGTextPathComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGTSpanComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<RNSVGUseComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<RNSvgComponentsRegistry::jhybriddata>
RNSvgComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = RNSvgComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void RNSvgComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", RNSvgComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

View File

@@ -1,34 +0,0 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class RNSvgComponentsRegistry
: public facebook::jni::HybridClass<RNSvgComponentsRegistry> {
public:
constexpr static auto kJavaDescriptor =
"Lcom/horcrux/svg/RNSvgComponentsRegistry;";
static void registerNatives();
RNSvgComponentsRegistry(ComponentFactory *delegate);
private:
friend HybridBase;
static std::shared_ptr<ComponentDescriptorProviderRegistry const> sharedProviderRegistry();
const ComponentFactory *delegate_;
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,88 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateModuleJniCpp.js
*/
#include "rnsvg.h"
namespace facebook {
namespace react {
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_isPointInFill(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, BooleanKind, "isPointInFill", "(Ljava/lang/Double;Lcom/facebook/react/bridge/ReadableMap;)Z", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_isPointInStroke(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, BooleanKind, "isPointInStroke", "(Ljava/lang/Double;Lcom/facebook/react/bridge/ReadableMap;)Z", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getTotalLength(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, NumberKind, "getTotalLength", "(Ljava/lang/Double;)D", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getPointAtLength(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, ObjectKind, "getPointAtLength", "(Ljava/lang/Double;Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getBBox(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, ObjectKind, "getBBox", "(Ljava/lang/Double;Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getCTM(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, ObjectKind, "getCTM", "(Ljava/lang/Double;)Lcom/facebook/react/bridge/WritableMap;", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getScreenCTM(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, ObjectKind, "getScreenCTM", "(Ljava/lang/Double;)Lcom/facebook/react/bridge/WritableMap;", args, count, cachedMethodId);
}
static facebook::jsi::Value __hostFunction_NativeSvgRenderableModuleSpecJSI_getRawResource(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getRawResource", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
}
NativeSvgRenderableModuleSpecJSI::NativeSvgRenderableModuleSpecJSI(const JavaTurboModule::InitParams &params)
: JavaTurboModule(params) {
methodMap_["isPointInFill"] = MethodMetadata {2, __hostFunction_NativeSvgRenderableModuleSpecJSI_isPointInFill};
methodMap_["isPointInStroke"] = MethodMetadata {2, __hostFunction_NativeSvgRenderableModuleSpecJSI_isPointInStroke};
methodMap_["getTotalLength"] = MethodMetadata {1, __hostFunction_NativeSvgRenderableModuleSpecJSI_getTotalLength};
methodMap_["getPointAtLength"] = MethodMetadata {2, __hostFunction_NativeSvgRenderableModuleSpecJSI_getPointAtLength};
methodMap_["getBBox"] = MethodMetadata {2, __hostFunction_NativeSvgRenderableModuleSpecJSI_getBBox};
methodMap_["getCTM"] = MethodMetadata {1, __hostFunction_NativeSvgRenderableModuleSpecJSI_getCTM};
methodMap_["getScreenCTM"] = MethodMetadata {1, __hostFunction_NativeSvgRenderableModuleSpecJSI_getScreenCTM};
methodMap_["getRawResource"] = MethodMetadata {1, __hostFunction_NativeSvgRenderableModuleSpecJSI_getRawResource};
}
static facebook::jsi::Value __hostFunction_NativeSvgViewModuleSpecJSI_toDataURL(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
static jmethodID cachedMethodId = nullptr;
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "toDataURL", "(Ljava/lang/Double;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Callback;)V", args, count, cachedMethodId);
}
NativeSvgViewModuleSpecJSI::NativeSvgViewModuleSpecJSI(const JavaTurboModule::InitParams &params)
: JavaTurboModule(params) {
methodMap_["toDataURL"] = MethodMetadata {3, __hostFunction_NativeSvgViewModuleSpecJSI_toDataURL};
}
std::shared_ptr<TurboModule> rnsvg_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
if (moduleName == "RNSVGRenderableModule") {
return std::make_shared<NativeSvgRenderableModuleSpecJSI>(params);
}
if (moduleName == "RNSVGSvgViewModule") {
return std::make_shared<NativeSvgViewModuleSpecJSI>(params);
}
return nullptr;
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,32 @@
#pragma once
#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>
#include <react/renderer/components/rnsvg/RNSVGImageComponentDescriptor.h>
namespace facebook {
namespace react {
/**
* JNI C++ class for module 'NativeSvgRenderableModule'
*/
class JSI_EXPORT NativeSvgRenderableModuleSpecJSI : public JavaTurboModule {
public:
NativeSvgRenderableModuleSpecJSI(const JavaTurboModule::InitParams &params);
};
/**
* JNI C++ class for module 'NativeSvgViewModule'
*/
class JSI_EXPORT NativeSvgViewModuleSpecJSI : public JavaTurboModule {
public:
NativeSvgViewModuleSpecJSI(const JavaTurboModule::InitParams &params);
};
JSI_EXPORT
std::shared_ptr<TurboModule> rnsvg_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,168 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/
package com.facebook.react.viewmanagers;
import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ColorPropConverter;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;
public class RNSVGSvgViewAndroidManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGSvgViewAndroidManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public RNSVGSvgViewAndroidManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "bbWidth":
if (value instanceof String) {
mViewManager.setBbWidth(view, (String) value);
} else if (value instanceof Double) {
mViewManager.setBbWidth(view, (Double) value);
} else {
mViewManager.setBbWidth(view, (Double) null);
}
break;
case "bbHeight":
if (value instanceof String) {
mViewManager.setBbHeight(view, (String) value);
} else if (value instanceof Double) {
mViewManager.setBbHeight(view, (Double) value);
} else {
mViewManager.setBbHeight(view, (Double) null);
}
break;
case "minX":
mViewManager.setMinX(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "minY":
mViewManager.setMinY(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "vbWidth":
mViewManager.setVbWidth(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "vbHeight":
mViewManager.setVbHeight(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "align":
mViewManager.setAlign(view, value == null ? null : (String) value);
break;
case "meetOrSlice":
mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue());
break;
case "tintColor":
mViewManager.setTintColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "color":
mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "pointerEvents":
mViewManager.setPointerEvents(view, value == null ? null : (String) value);
break;
case "hasTVPreferredFocus":
mViewManager.setHasTVPreferredFocus(view, value == null ? false : (boolean) value);
break;
case "borderTopEndRadius":
mViewManager.setBorderTopEndRadius(view, value == null ? 0f : ((Double) value).floatValue());
break;
case "borderBottomStartRadius":
mViewManager.setBorderBottomStartRadius(view, value == null ? 0f : ((Double) value).floatValue());
break;
case "borderBottomColor":
mViewManager.setBorderBottomColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "nextFocusDown":
mViewManager.setNextFocusDown(view, value == null ? 0 : ((Double) value).intValue());
break;
case "borderRightColor":
mViewManager.setBorderRightColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "nextFocusRight":
mViewManager.setNextFocusRight(view, value == null ? 0 : ((Double) value).intValue());
break;
case "borderLeftColor":
mViewManager.setBorderLeftColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "borderColor":
mViewManager.setBorderColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "removeClippedSubviews":
mViewManager.setRemoveClippedSubviews(view, value == null ? false : (boolean) value);
break;
case "nextFocusForward":
mViewManager.setNextFocusForward(view, value == null ? 0 : ((Double) value).intValue());
break;
case "nextFocusUp":
mViewManager.setNextFocusUp(view, value == null ? 0 : ((Double) value).intValue());
break;
case "accessible":
mViewManager.setAccessible(view, value == null ? false : (boolean) value);
break;
case "borderStartColor":
mViewManager.setBorderStartColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "borderBottomEndRadius":
mViewManager.setBorderBottomEndRadius(view, value == null ? 0f : ((Double) value).floatValue());
break;
case "borderEndColor":
mViewManager.setBorderEndColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "focusable":
mViewManager.setFocusable(view, value == null ? false : (boolean) value);
break;
case "nativeBackgroundAndroid":
mViewManager.setNativeBackgroundAndroid(view, (ReadableMap) value);
break;
case "borderTopStartRadius":
mViewManager.setBorderTopStartRadius(view, value == null ? 0f : ((Double) value).floatValue());
break;
case "nativeForegroundAndroid":
mViewManager.setNativeForegroundAndroid(view, (ReadableMap) value);
break;
case "backfaceVisibility":
mViewManager.setBackfaceVisibility(view, value == null ? null : (String) value);
break;
case "borderStyle":
mViewManager.setBorderStyle(view, value == null ? null : (String) value);
break;
case "needsOffscreenAlphaCompositing":
mViewManager.setNeedsOffscreenAlphaCompositing(view, value == null ? false : (boolean) value);
break;
case "hitSlop":
mViewManager.setHitSlop(view, (ReadableMap) value);
break;
case "borderTopColor":
mViewManager.setBorderTopColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "nextFocusLeft":
mViewManager.setNextFocusLeft(view, value == null ? 0 : ((Double) value).intValue());
break;
case "borderTopRightRadius":
mViewManager.setBorderTopRightRadius(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "borderBottomRightRadius":
mViewManager.setBorderBottomRightRadius(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "borderRadius":
mViewManager.setBorderRadius(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "borderBottomLeftRadius":
mViewManager.setBorderBottomLeftRadius(view, value == null ? 0f : ((Double) value).doubleValue());
break;
case "borderTopLeftRadius":
mViewManager.setBorderTopLeftRadius(view, value == null ? 0f : ((Double) value).doubleValue());
break;
default:
super.setProperty(view, propName, value);
}
}
}

View File

@@ -0,0 +1,61 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/
package com.facebook.react.viewmanagers;
import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableMap;
public interface RNSVGSvgViewAndroidManagerInterface<T extends View> {
void setBbWidth(T view, @Nullable String value);
void setBbWidth(T view, @Nullable Double value);
void setBbHeight(T view, @Nullable String value);
void setBbHeight(T view, @Nullable Double value);
void setMinX(T view, float value);
void setMinY(T view, float value);
void setVbWidth(T view, float value);
void setVbHeight(T view, float value);
void setAlign(T view, @Nullable String value);
void setMeetOrSlice(T view, int value);
void setTintColor(T view, @Nullable Integer value);
void setColor(T view, @Nullable Integer value);
void setPointerEvents(T view, @Nullable String value);
void setHasTVPreferredFocus(T view, boolean value);
void setBorderTopEndRadius(T view, float value);
void setBorderBottomStartRadius(T view, float value);
void setBorderBottomColor(T view, @Nullable Integer value);
void setNextFocusDown(T view, int value);
void setBorderRightColor(T view, @Nullable Integer value);
void setNextFocusRight(T view, int value);
void setBorderLeftColor(T view, @Nullable Integer value);
void setBorderColor(T view, @Nullable Integer value);
void setRemoveClippedSubviews(T view, boolean value);
void setNextFocusForward(T view, int value);
void setNextFocusUp(T view, int value);
void setAccessible(T view, boolean value);
void setBorderStartColor(T view, @Nullable Integer value);
void setBorderBottomEndRadius(T view, float value);
void setBorderEndColor(T view, @Nullable Integer value);
void setFocusable(T view, boolean value);
void setNativeBackgroundAndroid(T view, @Nullable ReadableMap value);
void setBorderTopStartRadius(T view, float value);
void setNativeForegroundAndroid(T view, @Nullable ReadableMap value);
void setBackfaceVisibility(T view, @Nullable String value);
void setBorderStyle(T view, @Nullable String value);
void setNeedsOffscreenAlphaCompositing(T view, boolean value);
void setHitSlop(T view, @Nullable ReadableMap value);
void setBorderTopColor(T view, @Nullable Integer value);
void setNextFocusLeft(T view, int value);
void setBorderTopRightRadius(T view, double value);
void setBorderBottomRightRadius(T view, double value);
void setBorderRadius(T view, double value);
void setBorderBottomLeftRadius(T view, double value);
void setBorderTopLeftRadius(T view, double value);
}

View File

@@ -1,74 +0,0 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/
package com.facebook.react.viewmanagers;
import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ColorPropConverter;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;
public class RNSVGSvgViewManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGSvgViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public RNSVGSvgViewManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "bbWidth":
if (value instanceof String) {
mViewManager.setBbWidth(view, (String) value);
} else if (value instanceof Double) {
mViewManager.setBbWidth(view, (Double) value);
} else {
mViewManager.setBbWidth(view, (Double) null);
}
break;
case "bbHeight":
if (value instanceof String) {
mViewManager.setBbHeight(view, (String) value);
} else if (value instanceof Double) {
mViewManager.setBbHeight(view, (Double) value);
} else {
mViewManager.setBbHeight(view, (Double) null);
}
break;
case "minX":
mViewManager.setMinX(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "minY":
mViewManager.setMinY(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "vbWidth":
mViewManager.setVbWidth(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "vbHeight":
mViewManager.setVbHeight(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "align":
mViewManager.setAlign(view, value == null ? null : (String) value);
break;
case "meetOrSlice":
mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue());
break;
case "tintColor":
mViewManager.setTintColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "color":
mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext()));
break;
case "pointerEvents":
mViewManager.setPointerEvents(view, value == null ? null : (String) value);
break;
default:
super.setProperty(view, propName, value);
}
}
}

View File

@@ -1,29 +0,0 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/
package com.facebook.react.viewmanagers;
import android.view.View;
import androidx.annotation.Nullable;
public interface RNSVGSvgViewManagerInterface<T extends View> {
void setBbWidth(T view, @Nullable String value);
void setBbWidth(T view, @Nullable Double value);
void setBbHeight(T view, @Nullable String value);
void setBbHeight(T view, @Nullable Double value);
void setMinX(T view, float value);
void setMinY(T view, float value);
void setVbWidth(T view, float value);
void setVbHeight(T view, float value);
void setAlign(T view, @Nullable String value);
void setMeetOrSlice(T view, int value);
void setTintColor(T view, @Nullable Integer value);
void setColor(T view, @Nullable Integer value);
void setPointerEvents(T view, @Nullable String value);
}

View File

@@ -0,0 +1,57 @@
/**
* This code was generated by
* [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* <p>Do not edit this file as changes may cause incorrect behavior and will be lost once the code
* is regenerated.
*
* @generated by codegen project: GenerateModuleJavaSpec.js
* @nolint
*/
package com.horcrux.rnsvg;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.Promise;
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.WritableMap;
public abstract class NativeSvgRenderableModuleSpec extends ReactContextBaseJavaModule {
public NativeSvgRenderableModuleSpec(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract boolean isPointInFill(Double tag, ReadableMap options);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract boolean isPointInStroke(Double tag, ReadableMap options);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract double getTotalLength(Double tag);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract WritableMap getPointAtLength(Double tag, ReadableMap options);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract WritableMap getBBox(Double tag, ReadableMap options);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract WritableMap getCTM(Double tag);
@ReactMethod(isBlockingSynchronousMethod = true)
@DoNotStrip
public abstract WritableMap getScreenCTM(Double tag);
@ReactMethod
@DoNotStrip
public abstract void getRawResource(String name, Promise promise);
}

View File

@@ -0,0 +1,28 @@
/**
* This code was generated by
* [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* <p>Do not edit this file as changes may cause incorrect behavior and will be lost once the code
* is regenerated.
*
* @generated by codegen project: GenerateModuleJavaSpec.js
* @nolint
*/
package com.horcrux.rnsvg;
import com.facebook.proguard.annotations.DoNotStrip;
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;
public abstract class NativeSvgViewModuleSpec extends ReactContextBaseJavaModule {
public NativeSvgViewModuleSpec(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
@DoNotStrip
public abstract void toDataURL(Double tag, ReadableMap options, Callback callback);
}

View File

@@ -15,7 +15,14 @@
#import <React/RCTImageSource.h>
#ifdef RN_FABRIC_ENABLED
#import <React/RCTImageResponseDelegate.h>
#endif
@interface RNSVGImage : RNSVGRenderable
#ifdef RN_FABRIC_ENABLED
<RCTImageResponseDelegate>
#endif
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, assign) RCTImageSource *src;
@@ -26,6 +33,4 @@
@property (nonatomic, strong) NSString *align;
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;
- (void)setImageSrc:(RCTImageSource *)source request:(NSURLRequest *)request;
@end

View File

@@ -29,24 +29,25 @@
#ifdef RN_FABRIC_ENABLED
#import <React/RCTConversions.h>
#import <React/RCTFabricComponentsPlugins.h>
#import <React/RCTImageResponseObserverProxy.h>
#import <React/RCTImageSource.h>
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
#import <react/renderer/components/view/conversions.h>
#import <react/renderer/imagemanager/RCTImagePrimitivesConversions.h>
#import <rnsvg/RNSVGImageComponentDescriptor.h>
#import "RNSVGFabricConversions.h"
// Some RN private method hacking below similar to how it is done in RNScreens:
// https://github.com/software-mansion/react-native-screens/blob/90e548739f35b5ded2524a9d6410033fc233f586/ios/RNSScreenStackHeaderConfig.mm#L30
@interface RCTBridge (Private)
+ (RCTBridge *)currentBridge;
@end
#endif // RN_FABRIC_ENABLED
@implementation RNSVGImage {
CGImageRef _image;
CGSize _imageSize;
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
#ifdef RN_FABRIC_ENABLED
RNSVGImageShadowNode::ConcreteState::Shared _state;
RCTImageResponseObserverProxy _imageResponseObserverProxy;
#endif // RN_FABRIC_ENABLED
}
#ifdef RN_FABRIC_ENABLED
using namespace facebook::react;
@@ -56,6 +57,10 @@ using namespace facebook::react;
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const RNSVGImageProps>();
_props = defaultProps;
#ifdef RN_FABRIC_ENABLED
_imageResponseObserverProxy = RCTImageResponseObserverProxy(self);
#endif
}
return self;
}
@@ -70,7 +75,6 @@ using namespace facebook::react;
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
const auto &newProps = *std::static_pointer_cast<const RNSVGImageProps>(props);
const auto &oldImageProps = *std::static_pointer_cast<const RNSVGImageProps>(oldProps);
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
@@ -80,15 +84,6 @@ using namespace facebook::react;
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
self.imagewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
}
if (oldProps == nullptr || oldImageProps.src != newProps.src) {
// TODO: make it the same as in e.g. slider
NSURLRequest *request = NSURLRequestFromImageSource(newProps.src);
CGSize size = RCTCGSizeFromSize(newProps.src.size);
CGFloat scale = newProps.src.scale;
RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURLRequest:request size:size scale:scale];
[self setImageSrc:imageSource request:request];
}
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
@@ -96,9 +91,68 @@ using namespace facebook::react;
_props = std::static_pointer_cast<RNSVGImageProps const>(props);
}
- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState
{
RCTAssert(state, @"`state` must not be null.");
RCTAssert(
std::dynamic_pointer_cast<RNSVGImageShadowNode::ConcreteState const>(state),
@"`state` must be a pointer to `RNSVGImageShadowNode::ConcreteState`.");
auto oldImageState = std::static_pointer_cast<RNSVGImageShadowNode::ConcreteState const>(_state);
auto newImageState = std::static_pointer_cast<RNSVGImageShadowNode::ConcreteState const>(state);
[self _setStateAndResubscribeImageResponseObserver:newImageState];
}
- (void)_setStateAndResubscribeImageResponseObserver:(RNSVGImageShadowNode::ConcreteState::Shared const &)state
{
if (_state) {
auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator();
observerCoordinator.removeObserver(_imageResponseObserverProxy);
}
_state = state;
if (_state) {
auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator();
observerCoordinator.addObserver(_imageResponseObserverProxy);
}
}
#pragma mark - RCTImageResponseDelegate
- (void)didReceiveImage:(UIImage *)image metadata:(id)metadata fromObserver:(void const *)observer
{
if (!_eventEmitter || !_state) {
// Notifications are delivered asynchronously and might arrive after the view is already recycled.
// In the future, we should incorporate an `EventEmitter` into a separate object owned by `ImageRequest` or `State`.
// See for more info: T46311063.
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
self->_image = CGImageRetain(image.CGImage);
self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image));
[self invalidate];
});
}
- (void)didReceiveProgress:(float)progress fromObserver:(void const *)observer
{
}
- (void)didReceiveFailureFromObserver:(void const *)observer
{
if (_image) {
CGImageRelease(_image);
}
_image = nil;
}
- (void)prepareForRecycle
{
[super prepareForRecycle];
[self _setStateAndResubscribeImageResponseObserver:nullptr];
_x = nil;
_y = nil;
_imageheight = nil;
@@ -116,8 +170,10 @@ using namespace facebook::react;
}
#endif // RN_FABRIC_ENABLED
- (void)setImageSrc:(RCTImageSource *)src request:(NSURLRequest *)request
- (void)setSrc:(RCTImageSource *)src
{
#ifdef RN_FABRIC_ENABLED
#else
if (src == _src) {
return;
}
@@ -136,24 +192,16 @@ using namespace facebook::react;
_reloadImageCancellationBlock = nil;
}
_reloadImageCancellationBlock = [[
#ifdef RN_FABRIC_ENABLED
[RCTBridge currentBridge]
#else
self.bridge
#endif // RN_FABRIC_ENABLED
moduleForName:@"ImageLoader"] loadImageWithURLRequest:request callback:^(NSError *error, UIImage *image) {
_reloadImageCancellationBlock = [[self.bridge moduleForName:@"ImageLoader"]
loadImageWithURLRequest:src.request
callback:^(NSError *error, UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
self->_image = CGImageRetain(image.CGImage);
self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image));
[self invalidate];
});
}];
}
- (void)setSrc:(RCTImageSource *)src
{
[self setImageSrc:src request:src.request];
#endif // RN_FABRIC_ENABLED
}
- (void)setX:(RNSVGLength *)x

View File

@@ -78,7 +78,7 @@ using namespace facebook::react;
if (RCTUIColorFromSharedColor(newProps.color)) {
self.tintColor = RCTUIColorFromSharedColor(newProps.color);
}
_props = std::static_pointer_cast<RNSVGSvgViewProps const>(props);
[super updateProps:props oldProps:oldProps];
}
- (void)prepareForRecycle

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef RN_FABRIC_ENABLED
#import <rnsvg/rnsvg.h>
#else
#import <React/RCTBridge.h>
#endif
@interface RNSVGRenderableModule : NSObject
#ifdef RN_FABRIC_ENABLED
<NativeSvgRenderableModuleSpec>
#else
<RCTBridgeModule>
#endif
@end

View File

@@ -0,0 +1,210 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNSVGRenderableModule.h"
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import "RNSVGPathMeasure.h"
#import "RNSVGRenderable.h"
#import "RCTConvert+RNSVG.h"
#import "RNSVGCGFCRule.h"
@implementation RNSVGRenderableModule
RCT_EXPORT_MODULE()
@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED;
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInFill : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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);
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");
return [NSNumber numberWithBool:false];
}
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGFloat x = (CGFloat)[xo doubleValue];
CGFloat y = (CGFloat)[yo doubleValue];
CGPoint point = CGPointMake(x, y);
RNSVGPlatformView *target = [svg hitTest:point withEvent:nil];
BOOL hit = target != nil;
return [NSNumber numberWithBool:hit];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInStroke : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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);
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");
return [NSNumber numberWithBool:false];
}
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_BLOCKING_SYNCHRONOUS_METHOD(getTotalLength : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getPointAtLength
: (nonnull NSNumber *)reactTag options
: (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getBBox : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getCTM : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getScreenCTM : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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)};
}
- (void)getRawResource:(NSString *)name resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
{
}
- (RNSVGPlatformView *)getRenderableView:(NSNumber *)reactTag
{
__block RNSVGPlatformView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.viewRegistry_DEPRECATED viewForReactTag:reactTag];
});
return view;
}
#ifdef RN_FABRIC_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeSvgRenderableModuleSpecJSI>(params);
}
#endif
@end

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef RN_FABRIC_ENABLED
#import <rnsvg/rnsvg.h>
#else
#import <React/RCTBridge.h>
#endif
@interface RNSVGSvgViewModule : NSObject
#ifdef RN_FABRIC_ENABLED
<NativeSvgViewModuleSpec>
#else
<RCTBridgeModule>
#endif
@end

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNSVGSvgViewModule.h"
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import "RNSVGSvgView.h"
@implementation RNSVGSvgViewModule
RCT_EXPORT_MODULE()
@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED;
@synthesize bridge = _bridge;
- (void)toDataURL:(nonnull NSNumber *)reactTag
options:(NSDictionary *)options
callback:(RCTResponseSenderBlock)callback
attempt:(int)attempt
{
void (^block)(void) = ^{
[self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) {
__kindof RNSVGPlatformView *view = [viewRegistry viewForReactTag:reactTag];
NSString *b64;
if ([view isKindOfClass:[RNSVGSvgView class]]) {
RNSVGSvgView *svg = view;
if (options == nil) {
b64 = [svg getDataURL];
} else {
id width = [options objectForKey:@"width"];
id height = [options objectForKey:@"height"];
if (![width isKindOfClass:NSNumber.class] || ![height isKindOfClass:NSNumber.class]) {
RCTLogError(@"Invalid width or height given to toDataURL");
return;
}
NSNumber *w = width;
NSInteger wi = (NSInteger)[w intValue];
NSNumber *h = height;
NSInteger hi = (NSInteger)[h intValue];
CGRect bounds = CGRectMake(0, 0, wi, hi);
b64 = [svg getDataURLwithBounds:bounds];
}
} else {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGSvgView, got: %@", view);
return;
}
if (b64) {
callback(@[ b64 ]);
} else if (attempt < 1) {
[self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)];
} else {
callback(@[]);
}
}];
};
if (self.bridge) {
dispatch_async(RCTGetUIManagerQueue(), block);
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
RCT_EXPORT_METHOD(toDataURL
: (nonnull NSNumber *)reactTag options
: (NSDictionary *)options callback
: (RCTResponseSenderBlock)callback)
{
[self toDataURL:reactTag options:options callback:callback attempt:0];
}
#ifdef RN_FABRIC_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeSvgViewModuleSpecJSI>(params);
}
#endif
@end

View File

@@ -8,6 +8,7 @@
@property NSString *text;
@property NSTextAlignment textAlignment;
#else
#import <UIKit/UIKit.h>
@interface RNSVGTopAlignedLabel : UILabel
#endif
@end

View File

@@ -5,6 +5,7 @@
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
typedef CF_ENUM(int32_t, RNSVGCGFCRule) {
kRNSVGCGFCRuleEvenodd,

View File

@@ -38,177 +38,4 @@ RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(vectorEffect, int)
RCT_EXPORT_VIEW_PROPERTY(propList, NSArray<NSString *>)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInFill : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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);
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");
return [NSNumber numberWithBool:false];
}
RNSVGRenderable *svg = (RNSVGRenderable *)view;
CGFloat x = (CGFloat)[xo doubleValue];
CGFloat y = (CGFloat)[yo doubleValue];
CGPoint point = CGPointMake(x, y);
RNSVGPlatformView *target = [svg hitTest:point withEvent:nil];
BOOL hit = target != nil;
return [NSNumber numberWithBool:hit];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isPointInStroke : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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);
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");
return [NSNumber numberWithBool:false];
}
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_BLOCKING_SYNCHRONOUS_METHOD(getTotalLength : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getPointAtLength
: (nonnull NSNumber *)reactTag options
: (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getBBox : (nonnull NSNumber *)reactTag options : (NSDictionary *)options)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getCTM : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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_BLOCKING_SYNCHRONOUS_METHOD(getScreenCTM : (nonnull NSNumber *)reactTag)
{
RNSVGPlatformView *view = [self getRenderableView: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)};
}
- (RNSVGPlatformView *)getRenderableView:(NSNumber *)reactTag
{
__block RNSVGPlatformView *view;
dispatch_sync(dispatch_get_main_queue(), ^{
view = [self.bridge.uiManager viewForReactTag:reactTag];
});
return view;
}
@end

View File

@@ -7,9 +7,6 @@
*/
#import "RNSVGSvgViewManager.h"
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import "RNSVGSvgView.h"
@implementation RNSVGSvgViewManager
@@ -32,58 +29,4 @@ RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(color, tintColor, UIColor)
- (void)toDataURL:(nonnull NSNumber *)reactTag
options:(NSDictionary *)options
callback:(RCTResponseSenderBlock)callback
attempt:(int)attempt
{
[self.bridge.uiManager
addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RNSVGPlatformView *> *viewRegistry) {
__kindof RNSVGPlatformView *view = [uiManager viewForReactTag:reactTag];
NSString *b64;
if ([view isKindOfClass:[RNSVGSvgView class]]) {
RNSVGSvgView *svg = view;
if (options == nil) {
b64 = [svg getDataURL];
} else {
id width = [options objectForKey:@"width"];
id height = [options objectForKey:@"height"];
if (![width isKindOfClass:NSNumber.class] || ![height isKindOfClass:NSNumber.class]) {
RCTLogError(@"Invalid width or height given to toDataURL");
return;
}
NSNumber *w = width;
NSInteger wi = (NSInteger)[w intValue];
NSNumber *h = height;
NSInteger hi = (NSInteger)[h intValue];
CGRect bounds = CGRectMake(0, 0, wi, hi);
b64 = [svg getDataURLwithBounds:bounds];
}
} else {
RCTLogError(@"Invalid svg returned from registry, expecting RNSVGSvgView, got: %@", view);
return;
}
if (b64) {
callback(@[ b64 ]);
} else if (attempt < 1) {
void (^retryBlock)(void) = ^{
[self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)];
};
RCTExecuteOnUIManagerQueue(retryBlock);
} else {
callback(@[]);
}
}];
}
RCT_EXPORT_METHOD(toDataURL
: (nonnull NSNumber *)reactTag options
: (NSDictionary *)options callback
: (RCTResponseSenderBlock)callback)
{
[self toDataURL:reactTag options:options callback:callback attempt:0];
}
@end

View File

@@ -32,7 +32,6 @@ RCT_CUSTOM_VIEW_PROPERTY(x, id, RNSVGText)
{
view.positionX = [RCTConvert RNSVGLengthArray:json];
}
RCT_CUSTOM_VIEW_PROPERTY(y, id, RNSVGText)
{
view.positionY = [RCTConvert RNSVGLengthArray:json];

View File

@@ -1,3 +1,6 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'@react-native/babel-plugin-codegen',
]
};

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/core/ConcreteComponentDescriptor.h>
#include <react/renderer/imagemanager/ImageManager.h>
#include <react/utils/ContextContainer.h>
#include "RNSVGImageShadowNode.h"
namespace facebook {
namespace react {
/*
* Descriptor for <RNSVGImage> component.
*/
class RNSVGImageComponentDescriptor final
: public ConcreteComponentDescriptor<RNSVGImageShadowNode> {
public:
RNSVGImageComponentDescriptor(ComponentDescriptorParameters const &parameters)
: ConcreteComponentDescriptor(parameters),
imageManager_(std::make_shared<ImageManager>(contextContainer_)){};
void adopt(ShadowNode::Unshared const &shadowNode) const override {
ConcreteComponentDescriptor::adopt(shadowNode);
auto imageShadowNode =
std::static_pointer_cast<RNSVGImageShadowNode>(shadowNode);
// `RNSVGImageShadowNode` uses `ImageManager` to initiate image loading and
// communicate the loading state and results to mounting layer.
imageShadowNode->setImageManager(imageManager_);
}
private:
const SharedImageManager imageManager_;
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <cstdlib>
#include <limits>
#include <react/renderer/core/LayoutContext.h>
#include "RNSVGImageShadowNode.h"
namespace facebook {
namespace react {
const char RNSVGImageComponentName[] = "RNSVGImage";
void RNSVGImageShadowNode::setImageManager(
const SharedImageManager &imageManager) {
ensureUnsealed();
imageManager_ = imageManager;
}
ImageSource RNSVGImageShadowNode::getImageSource() const {
auto source = getConcreteProps().src;
auto layoutMetrics = getLayoutMetrics();
auto size = layoutMetrics.getContentFrame().size;
auto scale = layoutMetrics.pointScaleFactor;
source.size = size;
source.scale = scale;
return source;
}
void RNSVGImageShadowNode::updateStateIfNeeded() {
ensureUnsealed();
auto imageSource = getImageSource();
auto const &currentState = getStateData();
bool hasSameImageSource = currentState.getImageSource() == imageSource;
if (hasSameImageSource) {
return;
}
auto state = RNSVGImageState{
imageSource,
imageManager_->requestImage(imageSource, getSurfaceId()),
};
setStateData(std::move(state));
}
#pragma mark - LayoutableShadowNode
void RNSVGImageShadowNode::layout(LayoutContext layoutContext) {
updateStateIfNeeded();
ConcreteViewShadowNode::layout(layoutContext);
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <jsi/jsi.h>
#include <react/renderer/components/rnsvg/EventEmitters.h>
#include <react/renderer/components/rnsvg/Props.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/imagemanager/ImageManager.h>
#include <react/renderer/imagemanager/primitives.h>
#include "RNSVGImageState.h"
namespace facebook {
namespace react {
JSI_EXPORT extern const char RNSVGImageComponentName[];
/*
* `ShadowNode` for <RNSVGImage> component.
*/
class JSI_EXPORT RNSVGImageShadowNode final : public ConcreteViewShadowNode<
RNSVGImageComponentName,
RNSVGImageProps,
ViewEventEmitter,
RNSVGImageState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteViewShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
return traits;
}
/*
* Associates a shared `ImageManager` with the node.
*/
void setImageManager(const SharedImageManager &imageManager);
static RNSVGImageState initialStateData(
ShadowNodeFragment const &fragment,
ShadowNodeFamilyFragment const &familyFragment,
ComponentDescriptor const &componentDescriptor) {
auto imageSource = ImageSource{ImageSource::Type::Invalid};
return {imageSource, {imageSource, nullptr}};
}
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
private:
ImageSource getImageSource() const;
SharedImageManager imageManager_;
void updateStateIfNeeded();
};
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "RNSVGImageState.h"
namespace facebook {
namespace react {
ImageSource RNSVGImageState::getImageSource() const {
return imageSource_;
}
ImageRequest const &RNSVGImageState::getImageRequest() const {
return *imageRequest_;
}
} // namespace react
} // namespace facebook

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <jsi/jsi.h>
#include <react/renderer/imagemanager/ImageRequest.h>
#include <react/renderer/imagemanager/primitives.h>
#ifdef ANDROID
#include <react/renderer/mapbuffer/MapBuffer.h>
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
#endif
namespace facebook {
namespace react {
/*
* State for <Image> component.
*/
class JSI_EXPORT RNSVGImageState final {
public:
RNSVGImageState(ImageSource const &imageSource, ImageRequest imageRequest)
: imageSource_(imageSource),
imageRequest_(
std::make_shared<ImageRequest>(std::move(imageRequest))){};
/*
* Returns stored ImageSource object.
*/
ImageSource getImageSource() const;
/*
* Exposes for reading stored `ImageRequest` object.
* `ImageRequest` object cannot be copied or moved from `ImageLocalData`.
*/
ImageRequest const &getImageRequest() const;
#ifdef ANDROID
RNSVGImageState(RNSVGImageState const &previousState, folly::dynamic data){};
/*
* Empty implementation for Android because it doesn't use this class.
*/
folly::dynamic getDynamic() const {
return {};
};
MapBuffer getMapBuffer() const {
return MapBufferBuilder::EMPTY();
};
#endif
private:
ImageSource imageSource_;
std::shared_ptr<ImageRequest> imageRequest_;
};
} // namespace react
} // namespace facebook

View File

@@ -16,12 +16,14 @@
"__tests__",
"android",
"apple",
"common",
"elements",
"lib",
"src",
"RNSVG.podspec",
"!android/build",
"windows"
"windows",
"react-native-config.js"
],
"@react-native-community/bob": {
"source": "src",
@@ -48,7 +50,7 @@
"flow": "flow src",
"flowtyped": "flow-typed install",
"format": "yarn format-js && yarn format-ios && yarn format-java",
"format-ios": "find apple/ -iname *.h -o -iname *.m -o -iname *.cpp -o -iname *.mm | xargs clang-format -i",
"format-ios": "find apple/ common/ -iname *.h -o -iname *.m -o -iname *.cpp -o -iname *.mm | xargs clang-format -i",
"format-java": "node ./scripts/format-java.js",
"format-js": "prettier --write README.md CONTRIBUTING.md CODE_OF_CONDUCT.md USAGE.md './src/**/*.{ts,tsx}' './Example/**/*.{ts,tsx}'",
"jest": "jest",
@@ -56,7 +58,7 @@
"peg": "pegjs -o src/lib/extract/transform.js ./src/lib/extract/transform.peg",
"prepare": "npm run bob && husky install",
"release": "npm login && release-it",
"test": "npm run lint && npm run tsc && npm run jest",
"test": "npm run lint && npm run tsc",
"tsc": "tsc --noEmit"
},
"peerDependencies": {
@@ -72,8 +74,12 @@
"@babel/plugin-syntax-flow": "^7.17.12",
"@babel/plugin-transform-react-jsx": "^7.17.12",
"@react-native-community/bob": "^0.9.7",
"@react-native-community/cli": "^9.0.0",
"@react-native-community/cli-platform-android": "^9.0.0",
"@react-native-community/cli-platform-ios": "^9.0.0",
"@react-native-community/eslint-config": "^3.0.2",
"@react-native-community/eslint-plugin": "^1.2.0",
"@react-native/babel-plugin-codegen": "^0.71.0",
"@types/css-tree": "^1.0.3",
"@types/jest": "^27.5.2",
"@types/node": "*",
@@ -102,6 +108,11 @@
"ts-node": "^10.8.0",
"typescript": "^4.7.2"
},
"resolutions": {
"@react-native-community/cli-platform-android": "^9.0.0",
"@react-native-community/cli": "^9.0.0",
"@react-native-community/cli-platform-ios": "^9.0.0"
},
"lint-staged": {
"{src,Example}/**/*.{js,ts,tsx}": "yarn format-js",
"src/**/*.{js,ts,tsx}": "yarn lint",
@@ -110,12 +121,11 @@
},
"nativePackage": true,
"codegenConfig": {
"libraries": [
{
"name": "rnsvg",
"type": "components",
"jsSrcsDir": "./src/fabric"
"type": "all",
"jsSrcsDir": "./src/fabric",
"android": {
"javaPackageName": "com.horcrux.rnsvg"
}
]
}
}

42
react-native.config.js Normal file
View File

@@ -0,0 +1,42 @@
let supportsCodegenConfig = false;
try {
const rnCliAndroidVersion =
require('@react-native-community/cli-platform-android/package.json').version;
const [major] = rnCliAndroidVersion.split('.');
supportsCodegenConfig = major >= 9;
} catch (e) {
// ignore
}
module.exports = {
dependency: {
platforms: {
android: supportsCodegenConfig ? {
componentDescriptors: [
"RNSVGCircleComponentDescriptor",
"RNSVGClipPathComponentDescriptor",
"RNSVGDefsComponentDescriptor",
"RNSVGEllipseComponentDescriptor",
"RNSVGForeignObjectComponentDescriptor",
"RNSVGGroupComponentDescriptor",
"RNSVGImageComponentDescriptor",
"RNSVGLinearGradientComponentDescriptor",
"RNSVGLineComponentDescriptor",
"RNSVGMarkerComponentDescriptor",
"RNSVGMaskComponentDescriptor",
"RNSVGPathComponentDescriptor",
"RNSVGPatternComponentDescriptor",
"RNSVGRadialGradientComponentDescriptor",
"RNSVGRectComponentDescriptor",
"RNSVGSvgViewAndroidComponentDescriptor",
"RNSVGSymbolComponentDescriptor",
"RNSVGTextComponentDescriptor",
"RNSVGTextPathComponentDescriptor",
"RNSVGTSpanComponentDescriptor",
"RNSVGUseComponentDescriptor"
],
cmakeListsPath: "../android/src/main/jni/CMakeLists.txt"
} : {},
},
},
}

View File

@@ -1,16 +1,10 @@
import React, { useState, useEffect, Component } from 'react';
import {
NativeModules,
Platform,
Image,
ImageSourcePropType,
} from 'react-native';
import { Platform, Image, ImageSourcePropType } from 'react-native';
import { fetchText } from './xml';
import { SvgCss, SvgWithCss } from './css';
import { SvgProps } from './elements/Svg';
const { getRawResource } = NativeModules.RNSVGRenderableManager || {};
import type { Spec } from './fabric/NativeSvgRenderableModule';
export function getUriFromSource(source: ImageSourcePropType) {
const resolvedAssetSource = Image.resolveAssetSource(source);
@@ -28,7 +22,9 @@ export function isUriAnAndroidResourceIdentifier(uri?: string) {
export async function loadAndroidRawResource(uri: string) {
try {
return await getRawResource(uri);
const RNSVGRenderableModule: Spec =
require('./fabric/NativeSvgRenderableModule').default;
return await RNSVGRenderableModule.getRawResource(uri);
} catch (e) {
console.error(
'Error in RawResourceUtils while trying to natively load an Android raw resource: ',
@@ -60,7 +56,7 @@ export type LocalState = { xml: string | null };
export function LocalSvg(props: LocalProps) {
const { asset, ...rest } = props;
const [xml, setXml] = useState(null);
const [xml, setXml] = useState<string | null>(null);
useEffect(() => {
loadLocalRawResource(asset).then(setXml);
}, [asset]);

View File

@@ -49,13 +49,14 @@ import {
RNSVGPattern,
RNSVGRadialGradient,
RNSVGRect,
RNSVGSvg,
RNSVGSvgAndroid,
RNSVGSvgIOS,
RNSVGSymbol,
RNSVGText,
RNSVGTextPath,
RNSVGTSpan,
RNSVGUse,
} from './elements/NativeComponents';
} from './fabric';
export type { RectProps } from './elements/Rect';
export type { CircleProps } from './elements/Circle';
@@ -144,7 +145,8 @@ export {
RNSVGEllipse,
RNSVGCircle,
RNSVGRect,
RNSVGSvg,
RNSVGSvgAndroid,
RNSVGSvgIOS,
RNSVGForeignObject,
};

View File

@@ -2,7 +2,8 @@ import React from 'react';
import { extract, stringifyPropsForFabric } from '../lib/extract/extractProps';
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGCircle } from './NativeComponents';
import { RNSVGCircle } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface CircleProps extends CommonPathProps {
cx?: NumberProp;
@@ -28,6 +29,11 @@ export default class Circle extends Shape<CircleProps> {
...stringifyPropsForFabric({ cx, cy, r }),
};
return <RNSVGCircle ref={this.refMethod} {...circleProps} />;
return (
<RNSVGCircle
ref={(ref) => this.refMethod(ref as (Circle & NativeMethods) | null)}
{...circleProps}
/>
);
}
}

View File

@@ -1,7 +1,7 @@
import React, { ReactNode } from 'react';
import { extract } from '../lib/extract/extractProps';
import Shape from './Shape';
import { RNSVGClipPath } from './NativeComponents';
import { RNSVGClipPath } from '../ReactNativeSVG';
export interface ClipPathProps {
children?: ReactNode;

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { RNSVGDefs } from './NativeComponents';
import { RNSVGDefs } from '../ReactNativeSVG';
export default class Defs extends Component<React.PropsWithChildren<{}>> {
static displayName = 'Defs';

View File

@@ -2,7 +2,8 @@ import React from 'react';
import { extract, stringifyPropsForFabric } from '../lib/extract/extractProps';
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGEllipse } from './NativeComponents';
import { RNSVGEllipse } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface EllipseProps extends CommonPathProps {
cx?: NumberProp;
@@ -29,6 +30,11 @@ export default class Ellipse extends Shape<EllipseProps> {
...extract(this, props),
...stringifyPropsForFabric({ cx, cy, rx, ry }),
};
return <RNSVGEllipse ref={this.refMethod} {...ellipseProps} />;
return (
<RNSVGEllipse
ref={(ref) => this.refMethod(ref as (Ellipse & NativeMethods) | null)}
{...ellipseProps}
/>
);
}
}

View File

@@ -5,7 +5,8 @@ import {
} from '../lib/extract/extractProps';
import { NumberProp } from '../lib/extract/types';
import G from './G';
import { RNSVGForeignObject } from './NativeComponents';
import { RNSVGForeignObject } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface ForeignObjectProps {
children?: ReactNode;
@@ -31,7 +32,9 @@ export default class ForeignObject extends G<ForeignObjectProps> {
const foreignObjectProps = stringifyPropsForFabric({ x, y, width, height });
return (
<RNSVGForeignObject
ref={this.refMethod}
ref={(ref) =>
this.refMethod(ref as (ForeignObject & NativeMethods) | null)
}
{...withoutXY(this, props)}
{...foreignObjectProps}
>

View File

@@ -9,7 +9,8 @@ import {
TransformProps,
} from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGGroup } from './NativeComponents';
import { RNSVGGroup } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface GProps extends CommonPathProps, FontProps {
children?: ReactNode;
@@ -40,7 +41,10 @@ export default class G<P> extends Shape<GProps & P> {
extractedProps.font = font;
}
return (
<RNSVGGroup ref={this.refMethod} {...extractedProps}>
<RNSVGGroup
ref={(ref) => this.refMethod(ref as (G<P> & NativeMethods) | null)}
{...extractedProps}
>
{props.children}
</RNSVGGroup>
);

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { Image, ImageProps as RNImageProps } from 'react-native';
import { Image, ImageProps as RNImageProps, NativeMethods } from 'react-native';
import { alignEnum, meetOrSliceTypes } from '../lib/extract/extractViewBox';
import {
stringifyPropsForFabric,
@@ -14,7 +14,7 @@ import {
TouchableProps,
} from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGImage } from './NativeComponents';
import { RNSVGImage } from '../ReactNativeSVG';
const spacesRegExp = /\s+/;
@@ -82,7 +82,7 @@ export default class SvgImage extends Shape<ImageProps> {
};
return (
<RNSVGImage
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (SvgImage & NativeMethods) | null)}
{...withoutXY(this, props)}
{...imageProps}
/>

View File

@@ -2,7 +2,8 @@ import React from 'react';
import { extract, stringifyPropsForFabric } from '../lib/extract/extractProps';
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGLine } from './NativeComponents';
import { RNSVGLine } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface LineProps extends CommonPathProps {
opacity?: NumberProp;
@@ -29,6 +30,11 @@ export default class Line extends Shape<LineProps> {
...extract(this, props),
...stringifyPropsForFabric({ x1, y1, x2, y2 }),
};
return <RNSVGLine ref={this.refMethod} {...lineProps} />;
return (
<RNSVGLine
ref={(ref) => this.refMethod(ref as (Line & NativeMethods) | null)}
{...lineProps}
/>
);
}
}

View File

@@ -2,8 +2,9 @@ import React, { ReactElement } from 'react';
import extractGradient from '../lib/extract/extractGradient';
import { NumberProp, TransformProps, Units } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGLinearGradient } from './NativeComponents';
import { RNSVGLinearGradient } from '../ReactNativeSVG';
import { stringifyPropsForFabric } from '../lib/extract/extractProps';
import { NativeMethods } from 'react-native';
export interface LinearGradientProps {
children?: ReactElement[];
@@ -32,7 +33,9 @@ export default class LinearGradient extends Shape<LinearGradientProps> {
const linearGradientProps = stringifyPropsForFabric({ x1, y1, x2, y2 });
return (
<RNSVGLinearGradient
ref={this.refMethod}
ref={(ref) =>
this.refMethod(ref as (LinearGradient & NativeMethods) | null)
}
{...linearGradientProps}
{...extractGradient(props, this)}
/>

View File

@@ -2,8 +2,9 @@ import React, { ReactNode } from 'react';
import extractViewBox from '../lib/extract/extractViewBox';
import { NumberProp } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGMarker } from './NativeComponents';
import { RNSVGMarker } from '../ReactNativeSVG';
import { stringifyPropsForFabric } from '../lib/extract/extractProps';
import { NativeMethods } from 'react-native';
export type MarkerUnits = 'strokeWidth' | 'userSpaceOnUse';
@@ -60,7 +61,7 @@ export default class Marker extends Shape<MarkerProps> {
return (
<RNSVGMarker
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Marker & NativeMethods) | null)}
{...markerProps}
{...extractViewBox({ viewBox, preserveAspectRatio })}
>

View File

@@ -6,7 +6,8 @@ import {
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import units from '../lib/units';
import Shape from './Shape';
import { RNSVGMask } from './NativeComponents';
import { RNSVGMask } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export type TMaskUnits = 'userSpaceOnUse' | 'objectBoundingBox';
@@ -48,7 +49,7 @@ export default class Mask extends Shape<MaskProps> {
};
return (
<RNSVGMask
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Mask & NativeMethods) | null)}
{...withoutXY(this, props)}
{...strigifiedMaskProps}
{...maskProps}

View File

@@ -1,31 +0,0 @@
import { requireNativeComponent as rnc } from 'react-native';
import React from 'react';
declare module 'react-native' {
function requireNativeComponent(
viewName: string,
): // eslint-disable-next-line @typescript-eslint/no-explicit-any
React.ComponentType<React.PropsWithChildren<any>>;
}
export const RNSVGSvg = rnc('RNSVGSvgView');
export const RNSVGCircle = rnc('RNSVGCircle');
export const RNSVGClipPath = rnc('RNSVGClipPath');
export const RNSVGDefs = rnc('RNSVGDefs');
export const RNSVGEllipse = rnc('RNSVGEllipse');
export const RNSVGForeignObject = rnc('RNSVGForeignObject');
export const RNSVGGroup = rnc('RNSVGGroup');
export const RNSVGImage = rnc('RNSVGImage');
export const RNSVGLine = rnc('RNSVGLine');
export const RNSVGLinearGradient = rnc('RNSVGLinearGradient');
export const RNSVGMarker = rnc('RNSVGMarker');
export const RNSVGMask = rnc('RNSVGMask');
export const RNSVGPath = rnc('RNSVGPath');
export const RNSVGPattern = rnc('RNSVGPattern');
export const RNSVGRadialGradient = rnc('RNSVGRadialGradient');
export const RNSVGRect = rnc('RNSVGRect');
export const RNSVGSymbol = rnc('RNSVGSymbol');
export const RNSVGText = rnc('RNSVGText');
export const RNSVGTextPath = rnc('RNSVGTextPath');
export const RNSVGTSpan = rnc('RNSVGTSpan');
export const RNSVGUse = rnc('RNSVGUse');

View File

@@ -1,8 +1,9 @@
import React from 'react';
import { extract } from '../lib/extract/extractProps';
import Shape from './Shape';
import { RNSVGPath } from './NativeComponents';
import { RNSVGPath } from '../ReactNativeSVG';
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import { NativeMethods } from 'react-native';
export interface PathProps extends CommonPathProps {
d?: string;
@@ -16,6 +17,12 @@ export default class Path extends Shape<PathProps> {
const { props } = this;
const { d } = props;
const pathProps = { ...extract(this, props), d };
return <RNSVGPath ref={this.refMethod} {...pathProps} />;
return (
<RNSVGPath
ref={(ref) => this.refMethod(ref as (Path & NativeMethods) | null)}
{...pathProps}
/>
);
}
}

View File

@@ -4,8 +4,9 @@ import extractViewBox from '../lib/extract/extractViewBox';
import { NumberProp, TransformProps, Units } from '../lib/extract/types';
import units from '../lib/units';
import Shape from './Shape';
import { RNSVGPattern } from './NativeComponents';
import { RNSVGPattern } from '../ReactNativeSVG';
import { stringifyPropsForFabric } from '../lib/extract/extractProps';
import { NativeMethods } from 'react-native';
export interface PatternProps extends TransformProps {
children?: ReactNode;
@@ -63,7 +64,7 @@ export default class Pattern extends Shape<PatternProps> {
};
return (
<RNSVGPattern
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Pattern & NativeMethods) | null)}
{...strigifiedPatternProps}
{...patternProps}
{...extractViewBox({ viewBox, preserveAspectRatio })}

View File

@@ -2,8 +2,9 @@ import React, { ReactElement } from 'react';
import extractGradient from '../lib/extract/extractGradient';
import { NumberProp, TransformProps, Units } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGRadialGradient } from './NativeComponents';
import { RNSVGRadialGradient } from '../ReactNativeSVG';
import { stringifyPropsForFabric } from '../lib/extract/extractProps';
import { NativeMethods } from 'react-native';
export interface RadialGradientProps {
children?: ReactElement[];
@@ -41,7 +42,9 @@ export default class RadialGradient extends Shape<RadialGradientProps> {
});
return (
<RNSVGRadialGradient
ref={this.refMethod}
ref={(ref) =>
this.refMethod(ref as (RadialGradient & NativeMethods) | null)
}
{...radialGradientProps}
{...extractGradient(props, this)}
/>

View File

@@ -5,7 +5,8 @@ import {
} from '../lib/extract/extractProps';
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import Shape from './Shape';
import { RNSVGRect } from './NativeComponents';
import { RNSVGRect } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface RectProps extends CommonPathProps {
x?: NumberProp;
@@ -33,7 +34,7 @@ export default class Rect extends Shape<RectProps> {
const rectProps = stringifyPropsForFabric({ x, y, width, height, rx, ry });
return (
<RNSVGRect
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Rect & NativeMethods) | null)}
{...withoutXY(this, props)}
{...rectProps}
/>

View File

@@ -1,11 +1,11 @@
import { Component } from 'react';
import SvgTouchableMixin from '../lib/SvgTouchableMixin';
import { NativeModules, findNodeHandle, NativeMethods } from 'react-native';
import { findNodeHandle, NativeMethods } from 'react-native';
import {
ColumnMajorTransformMatrix,
TransformProps,
} from '../lib/extract/types';
const { RNSVGRenderableManager } = NativeModules;
import type { Spec } from '../fabric/NativeSvgRenderableModule';
export interface SVGBoundingBoxOptions {
fill?: boolean;
@@ -242,27 +242,33 @@ export default class Shape<P> extends Component<P> {
) => {
this.root = instance;
};
// Hack to make Animated work with Shape components.
getNativeScrollRef(): (Shape<P> & NativeMethods) | null {
return this.root;
}
setNativeProps = (
props: Object & {
matrix?: ColumnMajorTransformMatrix;
} & TransformProps,
) => {
this.root && this.root.setNativeProps(props);
this.root?.setNativeProps(props);
};
/*
* The following native methods are experimental and likely broken in some
* ways. If you have a use case for these, please open an issue with a
* representative example / reproduction.
* */
getBBox = (options?: SVGBoundingBoxOptions): SVGRect => {
getBBox = (options?: SVGBoundingBoxOptions): SVGRect | undefined => {
const {
fill = true,
stroke = true,
markers = true,
clipped = true,
} = options || {};
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.getBBox(handle, {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule =
require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.getBBox(handle, {
fill,
stroke,
markers,
@@ -270,29 +276,41 @@ export default class Shape<P> extends Component<P> {
});
};
getCTM = (): SVGMatrix => {
const handle = findNodeHandle(this.root as Component);
return new SVGMatrix(RNSVGRenderableManager.getCTM(handle));
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return new SVGMatrix(RNSVGRenderableModule.getCTM(handle));
};
getScreenCTM = (): SVGMatrix => {
const handle = findNodeHandle(this.root as Component);
return new SVGMatrix(RNSVGRenderableManager.getScreenCTM(handle));
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return new SVGMatrix(RNSVGRenderableModule.getScreenCTM(handle));
};
isPointInFill = (options: DOMPointInit): boolean => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.isPointInFill(handle, options);
isPointInFill = (options: DOMPointInit): boolean | undefined => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.isPointInFill(handle, options);
};
isPointInStroke = (options: DOMPointInit): boolean => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.isPointInStroke(handle, options);
isPointInStroke = (options: DOMPointInit): boolean | undefined => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.isPointInStroke(handle, options);
};
getTotalLength = (): number => {
const handle = findNodeHandle(this.root as Component);
return RNSVGRenderableManager.getTotalLength(handle);
getTotalLength = (): number | undefined => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.getTotalLength(handle);
};
getPointAtLength = (length: number): SVGPoint => {
const handle = findNodeHandle(this.root as Component);
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule: Spec =
require('../fabric/NativeSvgRenderableModule').default;
return new SVGPoint(
RNSVGRenderableManager.getPointAtLength(handle, { length }),
RNSVGRenderableModule.getPointAtLength(handle, { length }),
);
};
}

View File

@@ -5,7 +5,8 @@ import {
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
NativeModules,
NativeMethods,
Platform,
StyleProp,
StyleSheet,
ViewProps,
@@ -20,9 +21,8 @@ import extractResponder from '../lib/extract/extractResponder';
import extractViewBox from '../lib/extract/extractViewBox';
import Shape from './Shape';
import G, { GProps } from './G';
import { RNSVGSvg } from './NativeComponents';
const RNSVGSvgViewManager = NativeModules.RNSVGSvgViewManager;
import { RNSVGSvgAndroid, RNSVGSvgIOS } from '../ReactNativeSVG';
import type { Spec } from '../fabric/NativeSvgViewModule';
const styles = StyleSheet.create({
svg: {
@@ -91,7 +91,9 @@ export default class Svg extends Shape<SvgProps> {
return;
}
const handle = findNodeHandle(this.root as Component);
RNSVGSvgViewManager.toDataURL(handle, options, callback);
const RNSVGSvgViewModule: Spec =
require('../fabric/NativeSvgViewModule').default;
RNSVGSvgViewModule.toDataURL(handle, options, callback);
};
render() {
@@ -116,7 +118,6 @@ export default class Svg extends Shape<SvgProps> {
// Inherited G properties
font,
transform,
fill,
fillOpacity,
fillRule,
@@ -181,18 +182,24 @@ export default class Svg extends Shape<SvgProps> {
props.onLayout = onLayout;
}
// transform should not be passed down since it is already used in svgView
// and would be doubled in G causing double transformations
const gStyle = Object.assign({}, style) as ViewStyle;
gStyle.transform = undefined;
const RNSVGSvg = Platform.OS === 'android' ? RNSVGSvgAndroid : RNSVGSvgIOS;
return (
<RNSVGSvg
{...props}
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Svg & NativeMethods) | null)}
{...extractViewBox({ viewBox, preserveAspectRatio })}
>
<G
{...{
children,
style,
style: gStyle,
font,
transform,
fill,
fillOpacity,
fillRule,

View File

@@ -1,8 +1,9 @@
import React, { ReactNode } from 'react';
import extractViewBox from '../lib/extract/extractViewBox';
import Shape from './Shape';
import { RNSVGSymbol } from './NativeComponents';
import { RNSVGSymbol } from '../ReactNativeSVG';
import { NumberProp } from '../lib/extract/types';
import { NativeMethods } from 'react-native';
export interface SymbolProps {
children?: ReactNode;
@@ -21,7 +22,7 @@ export default class Symbol extends Shape<SymbolProps> {
const symbolProps = { name: id };
return (
<RNSVGSymbol
ref={this.refMethod}
ref={(ref) => this.refMethod(ref as (Symbol & NativeMethods) | null)}
{...symbolProps}
{...extractViewBox(props)}
>

View File

@@ -12,7 +12,7 @@ import {
NumberProp,
TransformProps,
} from '../lib/extract/types';
import { RNSVGTSpan } from './NativeComponents';
import { RNSVGTSpan } from '../ReactNativeSVG';
export interface TSpanProps extends CommonPathProps, FontProps {
children?: TextChild;

View File

@@ -12,7 +12,7 @@ import {
import { pickNotNil } from '../lib/util';
import Shape from './Shape';
import './TSpan';
import { RNSVGText } from './NativeComponents';
import { RNSVGText } from '../ReactNativeSVG';
export interface TextProps extends TextSpecificProps {
children?: ReactNode;

View File

@@ -14,7 +14,7 @@ import extractText, { TextChild } from '../lib/extract/extractText';
import { idPattern, pickNotNil } from '../lib/util';
import Shape from './Shape';
import TSpan from './TSpan';
import { RNSVGTextPath } from './NativeComponents';
import { RNSVGTextPath } from '../ReactNativeSVG';
export interface TextPathProps extends TextSpecificProps {
children?: TextChild;

View File

@@ -6,7 +6,8 @@ import {
import { CommonPathProps, NumberProp } from '../lib/extract/types';
import { idPattern } from '../lib/util';
import Shape from './Shape';
import { RNSVGUse } from './NativeComponents';
import { RNSVGUse } from '../ReactNativeSVG';
import { NativeMethods } from 'react-native';
export interface UseProps extends CommonPathProps {
children?: ReactNode;
@@ -59,7 +60,11 @@ export default class Use extends Shape<UseProps> {
height,
});
return (
<RNSVGUse ref={this.refMethod} {...withoutXY(this, props)} {...useProps}>
<RNSVGUse
ref={(ref) => this.refMethod(ref as (Use & NativeMethods) | null)}
{...withoutXY(this, props)}
{...useProps}
>
{children}
</RNSVGUse>
);

View File

@@ -0,0 +1,77 @@
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type { ColorValue } from 'react-native';
import type {
Double,
Float,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes';
import type { ViewProps } from './utils';
type NativeBackgroundProp = Readonly<{
type?: string;
color?: Float;
borderless?: boolean;
rippleRadius?: Float;
}>;
type HitSlop = Readonly<{
left?: Float;
top?: Float;
right?: Float;
bottom?: Float;
}>;
interface NativeProps extends ViewProps {
bbWidth?: string;
bbHeight?: string;
minX?: Float;
minY?: Float;
vbWidth?: Float;
vbHeight?: Float;
align?: string;
meetOrSlice?: Int32;
tintColor?: ColorValue;
color?: ColorValue;
pointerEvents?: string;
// props needed for Android SvgView
hasTVPreferredFocus?: boolean;
borderTopEndRadius?: Float;
borderBottomStartRadius?: Float;
borderBottomColor?: ColorValue;
nextFocusDown?: Int32;
borderRightColor?: ColorValue;
nextFocusRight?: Int32;
borderLeftColor?: ColorValue;
borderColor?: ColorValue;
removeClippedSubviews?: boolean;
nextFocusForward?: Int32;
nextFocusUp?: Int32;
accessible?: boolean;
borderStartColor?: ColorValue;
borderBottomEndRadius?: Float;
borderEndColor?: ColorValue;
focusable?: boolean;
nativeBackgroundAndroid?: NativeBackgroundProp; // maybe there should a value accepted by codegen for this?
borderTopStartRadius?: Float;
nativeForegroundAndroid?: NativeBackgroundProp; // maybe there should a value accepted by codegen for this?
backfaceVisibility?: string;
borderStyle?: string;
needsOffscreenAlphaCompositing?: boolean;
hitSlop?: HitSlop;
borderTopColor?: ColorValue;
nextFocusLeft?: Int32;
// TODO: those props are present in the `ReactPropGroup` but are not supported
// (https://github.com/facebook/react-native/blob/35556dba600fbb28e0f41340a74b6c4a59bc6018/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java#L613)
// and static view config validator says that they are missing.
// We pass them as doubles although they should be floats, and cast them to floats again on the native side.
borderTopRightRadius?: Double;
borderBottomRightRadius?: Double;
borderRadius?: Double;
borderBottomLeftRadius?: Double;
borderTopLeftRadius?: Double;
}
export default codegenNativeComponent<NativeProps>('RNSVGSvgViewAndroid', {
excludedPlatforms: ['iOS'],
});

View File

@@ -4,17 +4,19 @@ import type { Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
import type { ViewProps } from './utils';
interface NativeProps extends ViewProps {
bbWidth: string;
bbHeight: string;
minX: Float;
minY: Float;
vbWidth: Float;
vbHeight: Float;
align: string;
meetOrSlice: Int32;
tintColor: ColorValue;
color: ColorValue;
bbWidth?: string;
bbHeight?: string;
minX?: Float;
minY?: Float;
vbWidth?: Float;
vbHeight?: Float;
align?: string;
meetOrSlice?: Int32;
tintColor?: ColorValue;
color?: ColorValue;
pointerEvents?: string;
}
export default codegenNativeComponent<NativeProps>('RNSVGSvgView');
export default codegenNativeComponent<NativeProps>('RNSVGSvgView', {
excludedPlatforms: ['android'],
});

View File

@@ -56,9 +56,11 @@ interface NativeProps
y?: string;
width?: string;
height?: string;
src?: ImageSource;
src?: ImageSource | null;
align?: string;
meetOrSlice?: Int32;
}
export default codegenNativeComponent<NativeProps>('RNSVGImage');
export default codegenNativeComponent<NativeProps>('RNSVGImage', {
interfaceOnly: true,
});

View File

@@ -28,7 +28,7 @@ interface NativeProps extends ViewProps, SvgNodeCommonProps {
y2?: string;
gradient?: ReadonlyArray<Float>;
gradientUnits?: Int32;
gradientTransform?: ReadonlyArray<Float>;
gradientTransform?: ReadonlyArray<Float> | null;
}
export default codegenNativeComponent<NativeProps>('RNSVGLinearGradient');

View File

@@ -0,0 +1,36 @@
import { TurboModuleRegistry, TurboModule } from 'react-native';
import { Int32, Float } from 'react-native/Libraries/Types/CodegenTypes';
type Rect = {
x: Float;
y: Float;
width: Float;
height: Float;
};
type Matrix = {
a: Float;
b: Float;
c: Float;
d: Float;
e: Float;
f: Float;
};
type Point = {
x: Float;
y: Float;
};
export interface Spec extends TurboModule {
isPointInFill(tag: Int32 | null, options?: Object): boolean;
isPointInStroke(tag: Int32 | null, options?: Object): boolean;
getTotalLength(tag: Int32 | null): Float;
getPointAtLength(tag: Int32 | null, options?: Object): Point;
getBBox(tag: Int32 | null, options?: Object): Rect;
getCTM(tag: Int32 | null): Matrix;
getScreenCTM(tag: Int32 | null): Matrix;
getRawResource(name: string): Promise<string>;
}
export default TurboModuleRegistry.getEnforcing<Spec>('RNSVGRenderableModule');

View File

@@ -0,0 +1,12 @@
import { TurboModuleRegistry, TurboModule } from 'react-native';
import { Int32 } from 'react-native/Libraries/Types/CodegenTypes';
export interface Spec extends TurboModule {
toDataURL(
tag: Int32 | null,
options?: Object,
callback?: (base64: string) => void,
): void;
}
export default TurboModuleRegistry.getEnforcing<Spec>('RNSVGSvgViewModule');

View File

@@ -10,7 +10,7 @@ import type { ViewProps } from './utils';
interface SvgNodeCommonProps {
name?: string;
opacity?: WithDefault<Float, 1.0>;
matrix?: ReadonlyArray<Float>;
matrix?: ReadonlyArray<Float> | null;
mask?: string;
markerStart?: string;
markerMid?: string;
@@ -78,7 +78,7 @@ interface NativeProps
width?: string;
patternUnits?: Int32;
patternContentUnits?: Int32;
patternTransform?: ReadonlyArray<Float>;
patternTransform?: ReadonlyArray<Float> | null;
minX?: Float;
minY?: Float;
vbWidth?: Float;

View File

@@ -30,7 +30,7 @@ interface NativeProps extends ViewProps, SvgNodeCommonProps {
ry?: string;
gradient?: ReadonlyArray<Float>;
gradientUnits?: Int32;
gradientTransform?: ReadonlyArray<Float>;
gradientTransform?: ReadonlyArray<Float> | null;
}
export default codegenNativeComponent<NativeProps>('RNSVGRadialGradient');

View File

@@ -13,7 +13,8 @@ import RNSVGPath from './PathNativeComponent';
import RNSVGPattern from './PatternNativeComponent';
import RNSVGRadialGradient from './RadialGradientNativeComponent';
import RNSVGRect from './RectNativeComponent';
import RNSVGSvg from './SvgViewNativeComponent';
import RNSVGSvgAndroid from './AndroidSvgViewNativeComponent';
import RNSVGSvgIOS from './IOSSvgViewNativeComponent';
import RNSVGSymbol from './SymbolNativeComponent';
import RNSVGText from './TextNativeComponent';
import RNSVGTextPath from './TextPathNativeComponent';
@@ -36,7 +37,8 @@ export {
RNSVGPattern,
RNSVGRadialGradient,
RNSVGRect,
RNSVGSvg,
RNSVGSvgAndroid,
RNSVGSvgIOS,
RNSVGSymbol,
RNSVGText,
RNSVGTextPath,

2287
yarn.lock

File diff suppressed because it is too large Load Diff