Repository: software-mansion/react-native-svg Branch: main Commit: 2845b815c1ea Files: 1052 Total size: 7.1 MB Directory structure: gitextract_xdt6b6x5/ ├── .clang-format ├── .eslintignore ├── .eslintrc.js ├── .git-blame-ignore-revs ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yaml │ │ └── config.yml │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── android-build-test.yml │ ├── check-archs-consistency.yml │ ├── close-when-stale.yml │ ├── e2e-android.yml │ ├── e2e-ios.yml │ ├── ios-build-test.yml │ ├── js-build-test.yml │ ├── macos-build-test.yml │ ├── needs-more-info.yml │ ├── needs-repro.yml │ └── windows-build-test.yml ├── .gitignore ├── .husky/ │ └── pre-commit ├── .npmignore ├── .prettierrc.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RNSVG.podspec ├── USAGE.md ├── __tests__/ │ ├── __snapshots__/ │ │ └── css.test.tsx.snap │ ├── css.test.tsx │ └── e2e/ │ └── GeneralSvgRenderingTest.spec.tsx ├── android/ │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── proguard-rules.pro │ ├── spotless.gradle │ └── src/ │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── horcrux/ │ │ │ └── svg/ │ │ │ ├── Brush.java │ │ │ ├── CircleView.java │ │ │ ├── ClipPathView.java │ │ │ ├── CustomFilter.java │ │ │ ├── DefinitionView.java │ │ │ ├── DefsView.java │ │ │ ├── EllipseView.java │ │ │ ├── FeBlendView.java │ │ │ ├── FeColorMatrixView.java │ │ │ ├── FeCompositeView.java │ │ │ ├── FeFloodView.java │ │ │ ├── FeGaussianBlurView.java │ │ │ ├── FeMergeView.java │ │ │ ├── FeOffsetView.java │ │ │ ├── FilterPrimitiveView.java │ │ │ ├── FilterProperties.java │ │ │ ├── FilterRegion.java │ │ │ ├── FilterUtils.java │ │ │ ├── FilterView.java │ │ │ ├── FontData.java │ │ │ ├── ForeignObjectView.java │ │ │ ├── GlyphContext.java │ │ │ ├── GlyphPathBag.java │ │ │ ├── GroupView.java │ │ │ ├── ImageView.java │ │ │ ├── LineView.java │ │ │ ├── LinearGradientView.java │ │ │ ├── MarkerView.java │ │ │ ├── MaskView.java │ │ │ ├── PathParser.java │ │ │ ├── PathView.java │ │ │ ├── PatternView.java │ │ │ ├── PropHelper.java │ │ │ ├── RNSVGMarkerPosition.java │ │ │ ├── RNSVGRenderableManager.java │ │ │ ├── RadialGradientView.java │ │ │ ├── RectView.java │ │ │ ├── RenderableView.java │ │ │ ├── RenderableViewManager.java │ │ │ ├── SVGLength.java │ │ │ ├── SvgPackage.java │ │ │ ├── SvgView.java │ │ │ ├── SvgViewManager.java │ │ │ ├── SvgViewModule.java │ │ │ ├── SymbolView.java │ │ │ ├── TSpanView.java │ │ │ ├── TextLayoutAlgorithm.java │ │ │ ├── TextPathView.java │ │ │ ├── TextProperties.java │ │ │ ├── TextView.java │ │ │ ├── UseView.java │ │ │ ├── ViewBox.java │ │ │ ├── VirtualView.java │ │ │ └── events/ │ │ │ ├── SvgLoadEvent.java │ │ │ └── SvgOnLayoutEvent.java │ │ └── jni/ │ │ ├── CMakeLists.txt │ │ ├── rnsvg.cpp │ │ └── rnsvg.h │ └── paper/ │ └── java/ │ └── com/ │ ├── facebook/ │ │ └── react/ │ │ └── viewmanagers/ │ │ ├── RNSVGCircleManagerDelegate.java │ │ ├── RNSVGCircleManagerInterface.java │ │ ├── RNSVGClipPathManagerDelegate.java │ │ ├── RNSVGClipPathManagerInterface.java │ │ ├── RNSVGDefsManagerDelegate.java │ │ ├── RNSVGDefsManagerInterface.java │ │ ├── RNSVGEllipseManagerDelegate.java │ │ ├── RNSVGEllipseManagerInterface.java │ │ ├── RNSVGFeBlendManagerDelegate.java │ │ ├── RNSVGFeBlendManagerInterface.java │ │ ├── RNSVGFeColorMatrixManagerDelegate.java │ │ ├── RNSVGFeColorMatrixManagerInterface.java │ │ ├── RNSVGFeCompositeManagerDelegate.java │ │ ├── RNSVGFeCompositeManagerInterface.java │ │ ├── RNSVGFeFloodManagerDelegate.java │ │ ├── RNSVGFeFloodManagerInterface.java │ │ ├── RNSVGFeGaussianBlurManagerDelegate.java │ │ ├── RNSVGFeGaussianBlurManagerInterface.java │ │ ├── RNSVGFeMergeManagerDelegate.java │ │ ├── RNSVGFeMergeManagerInterface.java │ │ ├── RNSVGFeOffsetManagerDelegate.java │ │ ├── RNSVGFeOffsetManagerInterface.java │ │ ├── RNSVGFilterManagerDelegate.java │ │ ├── RNSVGFilterManagerInterface.java │ │ ├── RNSVGForeignObjectManagerDelegate.java │ │ ├── RNSVGForeignObjectManagerInterface.java │ │ ├── RNSVGGroupManagerDelegate.java │ │ ├── RNSVGGroupManagerInterface.java │ │ ├── RNSVGImageManagerDelegate.java │ │ ├── RNSVGImageManagerInterface.java │ │ ├── RNSVGLineManagerDelegate.java │ │ ├── RNSVGLineManagerInterface.java │ │ ├── RNSVGLinearGradientManagerDelegate.java │ │ ├── RNSVGLinearGradientManagerInterface.java │ │ ├── RNSVGMarkerManagerDelegate.java │ │ ├── RNSVGMarkerManagerInterface.java │ │ ├── RNSVGMaskManagerDelegate.java │ │ ├── RNSVGMaskManagerInterface.java │ │ ├── RNSVGPathManagerDelegate.java │ │ ├── RNSVGPathManagerInterface.java │ │ ├── RNSVGPatternManagerDelegate.java │ │ ├── RNSVGPatternManagerInterface.java │ │ ├── RNSVGRadialGradientManagerDelegate.java │ │ ├── RNSVGRadialGradientManagerInterface.java │ │ ├── RNSVGRectManagerDelegate.java │ │ ├── RNSVGRectManagerInterface.java │ │ ├── RNSVGSvgViewAndroidManagerDelegate.java │ │ ├── RNSVGSvgViewAndroidManagerInterface.java │ │ ├── RNSVGSymbolManagerDelegate.java │ │ ├── RNSVGSymbolManagerInterface.java │ │ ├── RNSVGTSpanManagerDelegate.java │ │ ├── RNSVGTSpanManagerInterface.java │ │ ├── RNSVGTextManagerDelegate.java │ │ ├── RNSVGTextManagerInterface.java │ │ ├── RNSVGTextPathManagerDelegate.java │ │ ├── RNSVGTextPathManagerInterface.java │ │ ├── RNSVGUseManagerDelegate.java │ │ └── RNSVGUseManagerInterface.java │ └── horcrux/ │ └── svg/ │ ├── NativeSvgRenderableModuleSpec.java │ └── NativeSvgViewModuleSpec.java ├── apple/ │ ├── .npmignore │ ├── Brushes/ │ │ ├── RNSVGBrush.h │ │ ├── RNSVGBrush.mm │ │ ├── RNSVGBrushType.h │ │ ├── RNSVGContextBrush.h │ │ ├── RNSVGContextBrush.mm │ │ ├── RNSVGPainter.h │ │ ├── RNSVGPainter.mm │ │ ├── RNSVGPainterBrush.h │ │ ├── RNSVGPainterBrush.mm │ │ ├── RNSVGSolidColorBrush.h │ │ └── RNSVGSolidColorBrush.mm │ ├── Elements/ │ │ ├── RNSVGClipPath.h │ │ ├── RNSVGClipPath.mm │ │ ├── RNSVGDefs.h │ │ ├── RNSVGDefs.mm │ │ ├── RNSVGForeignObject.h │ │ ├── RNSVGForeignObject.mm │ │ ├── RNSVGGroup.h │ │ ├── RNSVGGroup.mm │ │ ├── RNSVGImage.h │ │ ├── RNSVGImage.mm │ │ ├── RNSVGLinearGradient.h │ │ ├── RNSVGLinearGradient.mm │ │ ├── RNSVGMarker.h │ │ ├── RNSVGMarker.mm │ │ ├── RNSVGMask.h │ │ ├── RNSVGMask.mm │ │ ├── RNSVGPath.h │ │ ├── RNSVGPath.mm │ │ ├── RNSVGPattern.h │ │ ├── RNSVGPattern.mm │ │ ├── RNSVGRadialGradient.h │ │ ├── RNSVGRadialGradient.mm │ │ ├── RNSVGSvgView.h │ │ ├── RNSVGSvgView.mm │ │ ├── RNSVGSymbol.h │ │ ├── RNSVGSymbol.mm │ │ ├── RNSVGUse.h │ │ └── RNSVGUse.mm │ ├── Filters/ │ │ ├── MetalCI/ │ │ │ ├── RNSVGArithmeticFilter.appletvos.air │ │ │ ├── RNSVGArithmeticFilter.appletvos.metallib │ │ │ ├── RNSVGArithmeticFilter.h │ │ │ ├── RNSVGArithmeticFilter.iphoneos.air │ │ │ ├── RNSVGArithmeticFilter.iphoneos.metallib │ │ │ ├── RNSVGArithmeticFilter.macosx.air │ │ │ ├── RNSVGArithmeticFilter.macosx.metallib │ │ │ ├── RNSVGArithmeticFilter.metal │ │ │ ├── RNSVGArithmeticFilter.mm │ │ │ ├── RNSVGArithmeticFilter.xros.air │ │ │ ├── RNSVGArithmeticFilter.xros.metallib │ │ │ ├── RNSVGCompositeXor.appletvos.air │ │ │ ├── RNSVGCompositeXor.appletvos.metallib │ │ │ ├── RNSVGCompositeXor.h │ │ │ ├── RNSVGCompositeXor.iphoneos.air │ │ │ ├── RNSVGCompositeXor.iphoneos.metallib │ │ │ ├── RNSVGCompositeXor.macosx.air │ │ │ ├── RNSVGCompositeXor.macosx.metallib │ │ │ ├── RNSVGCompositeXor.metal │ │ │ ├── RNSVGCompositeXor.mm │ │ │ ├── RNSVGCompositeXor.xros.air │ │ │ ├── RNSVGCompositeXor.xros.metallib │ │ │ ├── RNSVGCustomFilter.h │ │ │ └── RNSVGCustomFilter.mm │ │ ├── RNSVGBlendMode.h │ │ ├── RNSVGColorMatrixType.h │ │ ├── RNSVGCompositeOperator.h │ │ ├── RNSVGEdgeMode.h │ │ ├── RNSVGFeBlend.h │ │ ├── RNSVGFeBlend.mm │ │ ├── RNSVGFeColorMatrix.h │ │ ├── RNSVGFeColorMatrix.mm │ │ ├── RNSVGFeComposite.h │ │ ├── RNSVGFeComposite.mm │ │ ├── RNSVGFeFlood.h │ │ ├── RNSVGFeFlood.mm │ │ ├── RNSVGFeGaussianBlur.h │ │ ├── RNSVGFeGaussianBlur.mm │ │ ├── RNSVGFeMerge.h │ │ ├── RNSVGFeMerge.mm │ │ ├── RNSVGFeOffset.h │ │ ├── RNSVGFeOffset.mm │ │ ├── RNSVGFilter.h │ │ ├── RNSVGFilter.mm │ │ ├── RNSVGFilterPrimitive.h │ │ ├── RNSVGFilterPrimitive.mm │ │ ├── RNSVGFilterRegion.h │ │ └── RNSVGFilterRegion.mm │ ├── RNSVG.xcodeproj/ │ │ └── project.pbxproj │ ├── RNSVGContainer.h │ ├── RNSVGNode.h │ ├── RNSVGNode.mm │ ├── RNSVGRenderable.h │ ├── RNSVGRenderable.mm │ ├── RNSVGRenderableModule.h │ ├── RNSVGRenderableModule.mm │ ├── RNSVGSvgViewModule.h │ ├── RNSVGSvgViewModule.mm │ ├── RNSVGUIKit.h │ ├── RNSVGUIKit.macos.mm │ ├── Shapes/ │ │ ├── RNSVGCircle.h │ │ ├── RNSVGCircle.mm │ │ ├── RNSVGEllipse.h │ │ ├── RNSVGEllipse.mm │ │ ├── RNSVGLine.h │ │ ├── RNSVGLine.mm │ │ ├── RNSVGRect.h │ │ └── RNSVGRect.mm │ ├── Text/ │ │ ├── RNSVGFontData.h │ │ ├── RNSVGFontData.mm │ │ ├── RNSVGGlyphContext.h │ │ ├── RNSVGGlyphContext.mm │ │ ├── RNSVGPropHelper.h │ │ ├── RNSVGPropHelper.mm │ │ ├── RNSVGTSpan.h │ │ ├── RNSVGTSpan.mm │ │ ├── RNSVGText.h │ │ ├── RNSVGText.mm │ │ ├── RNSVGTextPath.h │ │ ├── RNSVGTextPath.mm │ │ ├── RNSVGTextProperties.h │ │ ├── RNSVGTextProperties.mm │ │ ├── RNSVGTopAlignedLabel.h │ │ ├── RNSVGTopAlignedLabel.ios.mm │ │ └── RNSVGTopAlignedLabel.macos.mm │ ├── Utils/ │ │ ├── RCTConvert+RNSVG.h │ │ ├── RCTConvert+RNSVG.mm │ │ ├── RNSVGBezierElement.h │ │ ├── RNSVGBezierElement.mm │ │ ├── RNSVGCGFCRule.h │ │ ├── RNSVGConvert.h │ │ ├── RNSVGConvert.mm │ │ ├── RNSVGFabricConversions.h │ │ ├── RNSVGLength.h │ │ ├── RNSVGLength.mm │ │ ├── RNSVGMarkerPosition.h │ │ ├── RNSVGMarkerPosition.mm │ │ ├── RNSVGMaskType.h │ │ ├── RNSVGPathMeasure.h │ │ ├── RNSVGPathMeasure.mm │ │ ├── RNSVGPathParser.h │ │ ├── RNSVGPathParser.mm │ │ ├── RNSVGRenderUtils.h │ │ ├── RNSVGRenderUtils.mm │ │ ├── RNSVGUnits.h │ │ ├── RNSVGVBMOS.h │ │ ├── RNSVGVectorEffect.h │ │ ├── RNSVGViewBox.h │ │ └── RNSVGViewBox.mm │ └── ViewManagers/ │ ├── RNSVGCircleManager.h │ ├── RNSVGCircleManager.mm │ ├── RNSVGClipPathManager.h │ ├── RNSVGClipPathManager.mm │ ├── RNSVGDefsManager.h │ ├── RNSVGDefsManager.mm │ ├── RNSVGEllipseManager.h │ ├── RNSVGEllipseManager.mm │ ├── RNSVGFeBlendManager.h │ ├── RNSVGFeBlendManager.mm │ ├── RNSVGFeColorMatrixManager.h │ ├── RNSVGFeColorMatrixManager.mm │ ├── RNSVGFeCompositeManager.h │ ├── RNSVGFeCompositeManager.mm │ ├── RNSVGFeFloodManager.h │ ├── RNSVGFeFloodManager.mm │ ├── RNSVGFeGaussianBlurManager.h │ ├── RNSVGFeGaussianBlurManager.mm │ ├── RNSVGFeMergeManager.h │ ├── RNSVGFeMergeManager.mm │ ├── RNSVGFeOffsetManager.h │ ├── RNSVGFeOffsetManager.mm │ ├── RNSVGFilterManager.h │ ├── RNSVGFilterManager.mm │ ├── RNSVGFilterPrimitiveManager.h │ ├── RNSVGFilterPrimitiveManager.mm │ ├── RNSVGForeignObjectManager.h │ ├── RNSVGForeignObjectManager.mm │ ├── RNSVGGroupManager.h │ ├── RNSVGGroupManager.mm │ ├── RNSVGImageManager.h │ ├── RNSVGImageManager.mm │ ├── RNSVGLineManager.h │ ├── RNSVGLineManager.mm │ ├── RNSVGLinearGradientManager.h │ ├── RNSVGLinearGradientManager.mm │ ├── RNSVGMarkerManager.h │ ├── RNSVGMarkerManager.mm │ ├── RNSVGMaskManager.h │ ├── RNSVGMaskManager.mm │ ├── RNSVGNodeManager.h │ ├── RNSVGNodeManager.mm │ ├── RNSVGPathManager.h │ ├── RNSVGPathManager.mm │ ├── RNSVGPatternManager.h │ ├── RNSVGPatternManager.mm │ ├── RNSVGRadialGradientManager.h │ ├── RNSVGRadialGradientManager.mm │ ├── RNSVGRectManager.h │ ├── RNSVGRectManager.mm │ ├── RNSVGRenderableManager.h │ ├── RNSVGRenderableManager.mm │ ├── RNSVGSvgViewManager.h │ ├── RNSVGSvgViewManager.mm │ ├── RNSVGSymbolManager.h │ ├── RNSVGSymbolManager.mm │ ├── RNSVGTSpanManager.h │ ├── RNSVGTSpanManager.mm │ ├── RNSVGTextManager.h │ ├── RNSVGTextManager.mm │ ├── RNSVGTextPathManager.h │ ├── RNSVGTextPathManager.mm │ ├── RNSVGUseManager.h │ └── RNSVGUseManager.mm ├── apps/ │ ├── common/ │ │ ├── .eslintrc.js │ │ ├── .prettierrc.js │ │ ├── example/ │ │ │ ├── ListScreen.tsx │ │ │ ├── e2e/ │ │ │ │ ├── TestingView.tsx │ │ │ │ ├── icon.tsx │ │ │ │ ├── index.macos.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── index.web.tsx │ │ │ │ └── index.windows.tsx │ │ │ ├── examples/ │ │ │ │ ├── Circle.tsx │ │ │ │ ├── Clipping.tsx │ │ │ │ ├── Ellipse.tsx │ │ │ │ ├── Empty.tsx │ │ │ │ ├── FilterImage/ │ │ │ │ │ ├── FilterPicker.tsx │ │ │ │ │ ├── LocalImage.tsx │ │ │ │ │ ├── RemoteImage.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Filters/ │ │ │ │ │ ├── FeBlend.tsx │ │ │ │ │ ├── FeColorMatrix.tsx │ │ │ │ │ ├── FeComposite.tsx │ │ │ │ │ ├── FeDropShadow.tsx │ │ │ │ │ ├── FeFlood.tsx │ │ │ │ │ ├── FeGaussianBlur.tsx │ │ │ │ │ ├── FeMerge.tsx │ │ │ │ │ ├── FeOffset.tsx │ │ │ │ │ ├── ReanimatedFeColorMatrix.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ForeignObject.tsx │ │ │ │ ├── G.tsx │ │ │ │ ├── Gradients.tsx │ │ │ │ ├── Image.tsx │ │ │ │ ├── Line.tsx │ │ │ │ ├── Markers.tsx │ │ │ │ ├── Mask.tsx │ │ │ │ ├── PanResponder.tsx │ │ │ │ ├── Path.tsx │ │ │ │ ├── Polygon.tsx │ │ │ │ ├── Polyline.tsx │ │ │ │ ├── Reanimated.tsx │ │ │ │ ├── Reanimated.windows.tsx │ │ │ │ ├── Rect.tsx │ │ │ │ ├── Reusable.tsx │ │ │ │ ├── Stroking.tsx │ │ │ │ ├── Svg.tsx │ │ │ │ ├── Text.tsx │ │ │ │ ├── Text.windows.tsx │ │ │ │ ├── TouchEvents.tsx │ │ │ │ ├── Transforms.tsx │ │ │ │ ├── complex/ │ │ │ │ │ ├── PolygonBunny.tsx │ │ │ │ │ ├── WorldMap.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── index.tsx │ │ │ ├── index.tsx │ │ │ └── utils/ │ │ │ ├── commonStyles.ts │ │ │ ├── composeComponent.tsx │ │ │ ├── types.ts │ │ │ └── usePersistNavigation.ts │ │ ├── index.tsx │ │ ├── noNavigationApp.tsx │ │ ├── test/ │ │ │ ├── ColorTest.tsx │ │ │ ├── MountUnmount.tsx │ │ │ ├── PointerEventsBoxNone.tsx │ │ │ ├── Test1318.tsx │ │ │ ├── Test1374.tsx │ │ │ ├── Test1442.tsx │ │ │ ├── Test1451.tsx │ │ │ ├── Test1718.tsx │ │ │ ├── Test1790.tsx │ │ │ ├── Test1813.tsx │ │ │ ├── Test1845.tsx │ │ │ ├── Test1986.tsx │ │ │ ├── Test2071.tsx │ │ │ ├── Test2080.tsx │ │ │ ├── Test2086.tsx │ │ │ ├── Test2089.tsx │ │ │ ├── Test2142.tsx │ │ │ ├── Test2148.tsx │ │ │ ├── Test2170.tsx │ │ │ ├── Test2196.tsx │ │ │ ├── Test2233.tsx │ │ │ ├── Test2248.tsx │ │ │ ├── Test2266.tsx │ │ │ ├── Test2276.tsx │ │ │ ├── Test2327.tsx │ │ │ ├── Test2363.tsx │ │ │ ├── Test2366.tsx │ │ │ ├── Test2380.tsx │ │ │ ├── Test2397.tsx │ │ │ ├── Test2403.tsx │ │ │ ├── Test2407.tsx │ │ │ ├── Test2417.tsx │ │ │ ├── Test2455.tsx │ │ │ ├── Test2471.tsx │ │ │ ├── Test2520.tsx │ │ │ ├── Test2670.tsx │ │ │ └── index.tsx │ │ └── tsconfig.json │ ├── fabric-example/ │ │ ├── .bundle/ │ │ │ └── config │ │ ├── .gitignore │ │ ├── .watchmanconfig │ │ ├── Gemfile │ │ ├── android/ │ │ │ ├── app/ │ │ │ │ ├── build.gradle │ │ │ │ ├── debug.keystore │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ ├── debug/ │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── fabricexample/ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ └── values/ │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── build.gradle │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradle.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ └── settings.gradle │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── ios/ │ │ │ ├── .xcode.env │ │ │ ├── FabricExample/ │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── Images.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Info.plist │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── PrivacyInfo.xcprivacy │ │ │ ├── FabricExample.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── FabricExample.xcscheme │ │ │ ├── FabricExample.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── Podfile │ │ ├── jest.config.js │ │ ├── metro.config.js │ │ ├── package.json │ │ └── patches/ │ │ └── react-native-view-shot+4.0.0-alpha.2.patch │ ├── fabric-macos-example/ │ │ ├── .bundle/ │ │ │ └── config │ │ ├── .gitignore │ │ ├── .prettierrc.js │ │ ├── .watchmanconfig │ │ ├── Gemfile │ │ ├── __tests__/ │ │ │ └── App.test.tsx │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── jest.config.js │ │ ├── macos/ │ │ │ ├── .gitignore │ │ │ ├── .xcode.env │ │ │ ├── FabricMacOSExample-macOS/ │ │ │ │ ├── AppDelegate.h │ │ │ │ ├── AppDelegate.mm │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── FabricMacOSExample.entitlements │ │ │ │ ├── Info.plist │ │ │ │ └── main.m │ │ │ ├── FabricMacOSExample.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── FabricMacOSExample-macOS.xcscheme │ │ │ ├── FabricMacOSExample.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ ├── Podfile │ │ │ └── PrivacyInfo.xcprivacy │ │ ├── metro.config.js │ │ └── package.json │ ├── fabric-windows-example/ │ │ ├── .gitignore │ │ ├── .prettierrc.js │ │ ├── .ruby-version │ │ ├── .watchmanconfig │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── jest.config.js │ │ ├── jest.config.windows.js │ │ ├── metro.config.js │ │ ├── package.json │ │ └── windows/ │ │ ├── .gitignore │ │ ├── ExperimentalFeatures.props │ │ ├── FabricExample/ │ │ │ ├── .gitignore │ │ │ ├── AutolinkedNativeModules.g.cpp │ │ │ ├── AutolinkedNativeModules.g.h │ │ │ ├── AutolinkedNativeModules.g.props │ │ │ ├── AutolinkedNativeModules.g.targets │ │ │ ├── FabricExample.cpp │ │ │ ├── FabricExample.h │ │ │ ├── FabricExample.rc │ │ │ ├── FabricExample.vcxproj │ │ │ ├── FabricExample.vcxproj.filters │ │ │ ├── packages.lock.json │ │ │ ├── pch.cpp │ │ │ ├── pch.h │ │ │ ├── resource.h │ │ │ └── targetver.h │ │ ├── FabricExample.Package/ │ │ │ ├── FabricExample.Package.wapproj │ │ │ ├── Package.appxmanifest │ │ │ └── packages.lock.json │ │ └── FabricExample.sln │ ├── paper-example/ │ │ ├── .bundle/ │ │ │ └── config │ │ ├── .gitignore │ │ ├── .watchmanconfig │ │ ├── Gemfile │ │ ├── README.md │ │ ├── android/ │ │ │ ├── app/ │ │ │ │ ├── build.gradle │ │ │ │ ├── debug.keystore │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ ├── debug/ │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── paperexample/ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ └── values/ │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── build.gradle │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradle.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ └── settings.gradle │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── ios/ │ │ │ ├── .xcode.env │ │ │ ├── PaperExample/ │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── Images.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Info.plist │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── PrivacyInfo.xcprivacy │ │ │ ├── PaperExample.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── PaperExample.xcscheme │ │ │ ├── PaperExample.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── Podfile │ │ ├── jest.config.js │ │ ├── metro.config.js │ │ ├── package.json │ │ └── patches/ │ │ └── react-native-view-shot+4.0.0-alpha.2.patch │ ├── paper-macos-example/ │ │ ├── .bundle/ │ │ │ └── config │ │ ├── .gitignore │ │ ├── .prettierrc.js │ │ ├── .watchmanconfig │ │ ├── Gemfile │ │ ├── __tests__/ │ │ │ └── App.test.tsx │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── jest.config.js │ │ ├── macos/ │ │ │ ├── .gitignore │ │ │ ├── .xcode.env │ │ │ ├── PaperMacOSExample-macOS/ │ │ │ │ ├── AppDelegate.h │ │ │ │ ├── AppDelegate.mm │ │ │ │ ├── Assets.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Base.lproj/ │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── Info.plist │ │ │ │ ├── PaperMacOSExample.entitlements │ │ │ │ └── main.m │ │ │ ├── PaperMacOSExample.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── PaperMacOSExample-macOS.xcscheme │ │ │ ├── PaperMacOSExample.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ ├── Podfile │ │ │ └── PrivacyInfo.xcprivacy │ │ ├── metro.config.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── paper-windows-example/ │ │ ├── .gitignore │ │ ├── .watchmanconfig │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── jest.config.js │ │ ├── metro.config.js │ │ ├── msbuild.binlog │ │ ├── package.json │ │ ├── patches/ │ │ │ └── react-native-windows+0.74.23.patch │ │ └── windows/ │ │ ├── .gitignore │ │ ├── Example/ │ │ │ ├── .gitignore │ │ │ ├── App.cpp │ │ │ ├── App.h │ │ │ ├── App.idl │ │ │ ├── App.xaml │ │ │ ├── AutolinkedNativeModules.g.cpp │ │ │ ├── AutolinkedNativeModules.g.h │ │ │ ├── AutolinkedNativeModules.g.props │ │ │ ├── AutolinkedNativeModules.g.targets │ │ │ ├── Example.vcxproj │ │ │ ├── Example.vcxproj.filters │ │ │ ├── MainPage.cpp │ │ │ ├── MainPage.h │ │ │ ├── MainPage.idl │ │ │ ├── MainPage.xaml │ │ │ ├── Package.appxmanifest │ │ │ ├── PropertySheet.props │ │ │ ├── ReactPackageProvider.cpp │ │ │ ├── ReactPackageProvider.h │ │ │ ├── packages.lock.json │ │ │ ├── pch.cpp │ │ │ └── pch.h │ │ ├── Example.sln │ │ ├── ExperimentalFeatures.props │ │ └── NuGet.Config │ ├── tests-example/ │ │ ├── .bundle/ │ │ │ └── config │ │ ├── .gitignore │ │ ├── .watchmanconfig │ │ ├── Gemfile │ │ ├── __tests__/ │ │ │ └── App.test.tsx │ │ ├── android/ │ │ │ ├── app/ │ │ │ │ ├── build.gradle │ │ │ │ ├── debug.keystore │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── testsexample/ │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ └── values/ │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── build.gradle │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradle.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ └── settings.gradle │ │ ├── app.json │ │ ├── babel.config.js │ │ ├── index.js │ │ ├── ios/ │ │ │ ├── .xcode.env │ │ │ ├── Podfile │ │ │ ├── TestsExample/ │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── Images.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Info.plist │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── PrivacyInfo.xcprivacy │ │ │ ├── TestsExample.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ └── TestsExample.xcscheme │ │ │ └── TestsExample.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── jest.config.js │ │ ├── metro.config.js │ │ └── package.json │ └── web-example/ │ ├── .gitignore │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── metro.config.js │ ├── package.json │ ├── patches/ │ │ └── react-native-worklets+0.6.0.patch │ └── tsconfig.json ├── babel.config.js ├── common/ │ └── cpp/ │ └── react/ │ └── renderer/ │ └── components/ │ └── rnsvg/ │ ├── RNSVGComponentDescriptors.h │ ├── RNSVGConcreteShadowNode.h │ ├── RNSVGImageComponentDescriptor.h │ ├── RNSVGImageShadowNode.cpp │ ├── RNSVGImageShadowNode.h │ ├── RNSVGImageState.cpp │ ├── RNSVGImageState.h │ ├── RNSVGLayoutableShadowNode.cpp │ ├── RNSVGLayoutableShadowNode.h │ ├── RNSVGShadowNodes.cpp │ └── RNSVGShadowNodes.h ├── css/ │ └── package.json ├── e2e/ │ ├── env.ts │ ├── failedCases.json │ ├── generateReferences.ts │ ├── globals.d.ts │ ├── helpers.ts │ ├── matchTestCases.ts │ ├── readFailedCases.ts │ ├── setupJest.ts │ ├── teardownJest.ts │ └── types.ts ├── filter-image/ │ └── package.json ├── jest.config.ts ├── package.json ├── react-native.config.js ├── scripts/ │ ├── codegen-check-consistency.js │ ├── codegen-sync-archs.js │ ├── codegen-utils.js │ ├── format-java.js │ ├── metal.js │ └── rnsvg_utils.rb ├── src/ │ ├── ReactNativeSVG.ts │ ├── ReactNativeSVG.web.ts │ ├── css/ │ │ ├── LocalSvg.tsx │ │ ├── css.tsx │ │ └── index.tsx │ ├── deprecated.tsx │ ├── elements/ │ │ ├── Circle.tsx │ │ ├── ClipPath.tsx │ │ ├── Defs.tsx │ │ ├── Ellipse.tsx │ │ ├── ForeignObject.tsx │ │ ├── G.tsx │ │ ├── Image.tsx │ │ ├── Line.tsx │ │ ├── LinearGradient.tsx │ │ ├── Marker.tsx │ │ ├── Mask.tsx │ │ ├── Path.tsx │ │ ├── Pattern.tsx │ │ ├── Polygon.tsx │ │ ├── Polyline.tsx │ │ ├── RadialGradient.tsx │ │ ├── Rect.tsx │ │ ├── Shape.tsx │ │ ├── Stop.tsx │ │ ├── Svg.tsx │ │ ├── Symbol.tsx │ │ ├── TSpan.tsx │ │ ├── Text.tsx │ │ ├── TextPath.tsx │ │ ├── Use.tsx │ │ └── filters/ │ │ ├── FeBlend.tsx │ │ ├── FeColorMatrix.tsx │ │ ├── FeComponentTransfer.tsx │ │ ├── FeComponentTransferFunction.tsx │ │ ├── FeComposite.tsx │ │ ├── FeConvolveMatrix.tsx │ │ ├── FeDiffuseLighting.tsx │ │ ├── FeDisplacementMap.tsx │ │ ├── FeDistantLight.tsx │ │ ├── FeDropShadow.tsx │ │ ├── FeFlood.tsx │ │ ├── FeGaussianBlur.tsx │ │ ├── FeImage.tsx │ │ ├── FeMerge.tsx │ │ ├── FeMergeNode.tsx │ │ ├── FeMorphology.tsx │ │ ├── FeOffset.tsx │ │ ├── FePointLight.tsx │ │ ├── FeSpecularLighting.tsx │ │ ├── FeSpotLight.tsx │ │ ├── FeTile.tsx │ │ ├── FeTurbulence.tsx │ │ ├── Filter.tsx │ │ ├── FilterPrimitive.tsx │ │ └── types.ts │ ├── elements.ts │ ├── elements.web.ts │ ├── fabric/ │ │ ├── AndroidSvgViewNativeComponent.ts │ │ ├── CircleNativeComponent.ts │ │ ├── ClipPathNativeComponent.ts │ │ ├── DefsNativeComponent.ts │ │ ├── EllipseNativeComponent.ts │ │ ├── FeBlendNativeComponent.ts │ │ ├── FeColorMatrixNativeComponent.ts │ │ ├── FeCompositeNativeComponent.ts │ │ ├── FeFloodNativeComponent.ts │ │ ├── FeGaussianBlurNativeComponent.ts │ │ ├── FeMergeNativeComponent.ts │ │ ├── FeOffsetNativeComponent.ts │ │ ├── FilterNativeComponent.ts │ │ ├── ForeignObjectNativeComponent.ts │ │ ├── GroupNativeComponent.ts │ │ ├── IOSSvgViewNativeComponent.ts │ │ ├── ImageNativeComponent.ts │ │ ├── LineNativeComponent.ts │ │ ├── LinearGradientNativeComponent.ts │ │ ├── MarkerNativeComponent.ts │ │ ├── MaskNativeComponent.ts │ │ ├── NativeSvgRenderableModule.ts │ │ ├── NativeSvgViewModule.ts │ │ ├── PathNativeComponent.ts │ │ ├── PatternNativeComponent.ts │ │ ├── RadialGradientNativeComponent.ts │ │ ├── RectNativeComponent.ts │ │ ├── SymbolNativeComponent.ts │ │ ├── TSpanNativeComponent.ts │ │ ├── TextNativeComponent.ts │ │ ├── TextPathNativeComponent.ts │ │ ├── UseNativeComponent.ts │ │ ├── codegenUtils.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── filter-image/ │ │ ├── FilterImage.tsx │ │ ├── extract/ │ │ │ ├── extractFilters.ts │ │ │ ├── extractFiltersString.d.ts │ │ │ ├── extractFiltersString.js │ │ │ ├── extractFiltersString.pegjs │ │ │ └── extractImage.ts │ │ ├── index.tsx │ │ └── types.ts │ ├── index.ts │ ├── lib/ │ │ ├── Matrix2D.ts │ │ ├── SvgTouchableMixin.ts │ │ ├── extract/ │ │ │ ├── colors.ts │ │ │ ├── extractBrush.ts │ │ │ ├── extractFill.ts │ │ │ ├── extractFilter.ts │ │ │ ├── extractGradient.ts │ │ │ ├── extractLengthList.ts │ │ │ ├── extractOpacity.ts │ │ │ ├── extractPolyPoints.ts │ │ │ ├── extractProps.ts │ │ │ ├── extractProps.windows.ts │ │ │ ├── extractResponder.ts │ │ │ ├── extractStroke.ts │ │ │ ├── extractText.tsx │ │ │ ├── extractTransform.ts │ │ │ ├── extractViewBox.ts │ │ │ ├── transform.d.ts │ │ │ ├── transform.js │ │ │ ├── transform.peg │ │ │ ├── transformToRn.d.ts │ │ │ ├── transformToRn.js │ │ │ ├── transformToRn.pegjs │ │ │ └── types.ts │ │ ├── maskType.ts │ │ ├── resolve.ts │ │ ├── resolveAssetUri.ts │ │ ├── units.ts │ │ ├── util.ts │ │ └── utils/ │ │ └── convertPercentageColor.ts │ ├── utils/ │ │ └── fetchData.ts │ ├── web/ │ │ ├── WebShape.ts │ │ ├── types.ts │ │ └── utils/ │ │ ├── convertInt32Color.ts │ │ ├── hasProperty.ts │ │ ├── index.ts │ │ ├── parseTransform.ts │ │ └── prepare.ts │ ├── xml.tsx │ └── xmlTags.ts ├── tsconfig.json └── windows/ ├── .clang-format ├── .gitignore ├── ExperimentalFeatures.props ├── NuGet.Config ├── RNSVG/ │ ├── BrushView.cpp │ ├── BrushView.h │ ├── CircleView.cpp │ ├── CircleView.h │ ├── CircleViewManager.cpp │ ├── CircleViewManager.h │ ├── ClipPathView.cpp │ ├── ClipPathView.h │ ├── ClipPathViewManager.cpp │ ├── ClipPathViewManager.h │ ├── D2DBrush.cpp │ ├── D2DBrush.h │ ├── D2DDevice.cpp │ ├── D2DDevice.h │ ├── D2DDeviceContext.cpp │ ├── D2DDeviceContext.h │ ├── D2DGeometry.cpp │ ├── D2DGeometry.h │ ├── D2DHelpers.h │ ├── DefsView.cpp │ ├── DefsView.h │ ├── DefsViewManager.cpp │ ├── DefsViewManager.h │ ├── DirectXDeviceManager.cpp │ ├── DirectXDeviceManager.h │ ├── EllipseView.cpp │ ├── EllipseView.h │ ├── EllipseViewManager.cpp │ ├── EllipseViewManager.h │ ├── Fabric/ │ │ ├── CircleView.cpp │ │ ├── CircleView.h │ │ ├── ClipPathView.cpp │ │ ├── ClipPathView.h │ │ ├── D2DHelpers.h │ │ ├── DefsView.cpp │ │ ├── DefsView.h │ │ ├── EllipseView.cpp │ │ ├── EllipseView.h │ │ ├── GroupView.cpp │ │ ├── GroupView.h │ │ ├── ImageView.cpp │ │ ├── ImageView.h │ │ ├── LineView.cpp │ │ ├── LineView.h │ │ ├── LinearGradientView.cpp │ │ ├── LinearGradientView.h │ │ ├── PathView.cpp │ │ ├── PathView.h │ │ ├── RadialGradientView.cpp │ │ ├── RadialGradientView.h │ │ ├── RectView.cpp │ │ ├── RectView.h │ │ ├── RenderableView.cpp │ │ ├── RenderableView.h │ │ ├── SvgStrings.h │ │ ├── SvgView.cpp │ │ ├── SvgView.h │ │ ├── UnsupportedSvgView.cpp │ │ ├── UnsupportedSvgView.h │ │ ├── UseView.cpp │ │ └── UseView.h │ ├── GroupView.cpp │ ├── GroupView.h │ ├── GroupViewManager.cpp │ ├── GroupViewManager.h │ ├── ImageView.cpp │ ├── ImageView.h │ ├── ImageViewManager.cpp │ ├── ImageViewManager.h │ ├── LineView.cpp │ ├── LineView.h │ ├── LineViewManager.cpp │ ├── LineViewManager.h │ ├── LinearGradientView.cpp │ ├── LinearGradientView.h │ ├── LinearGradientViewManager.cpp │ ├── LinearGradientViewManager.h │ ├── MarkerView.cpp │ ├── MarkerView.h │ ├── MarkerViewManager.cpp │ ├── MarkerViewManager.h │ ├── MaskView.cpp │ ├── MaskView.h │ ├── MaskViewManager.cpp │ ├── MaskViewManager.h │ ├── Paper.idl │ ├── PathView.cpp │ ├── PathView.h │ ├── PathViewManager.cpp │ ├── PathViewManager.h │ ├── PatternView.cpp │ ├── PatternView.h │ ├── PatternViewManager.cpp │ ├── PatternViewManager.h │ ├── PropertySheet.props │ ├── RNSVG.def │ ├── RNSVG.rc │ ├── RNSVG.vcxproj │ ├── RNSVG.vcxproj.filters │ ├── RNSVGModule.h │ ├── RadialGradientView.cpp │ ├── RadialGradientView.h │ ├── RadialGradientViewManager.cpp │ ├── RadialGradientViewManager.h │ ├── ReactPackageProvider.cpp │ ├── ReactPackageProvider.h │ ├── ReactPackageProvider.idl │ ├── RectView.cpp │ ├── RectView.h │ ├── RectViewManager.cpp │ ├── RectViewManager.h │ ├── RenderableView.cpp │ ├── RenderableView.h │ ├── RenderableViewManager.cpp │ ├── RenderableViewManager.h │ ├── SVGLength.cpp │ ├── SVGLength.h │ ├── SvgView.cpp │ ├── SvgView.h │ ├── SvgViewManager.cpp │ ├── SvgViewManager.h │ ├── SymbolView.cpp │ ├── SymbolView.h │ ├── SymbolViewManager.cpp │ ├── SymbolViewManager.h │ ├── TSpanView.cpp │ ├── TSpanView.h │ ├── TSpanViewManager.cpp │ ├── TSpanViewManager.h │ ├── TextView.cpp │ ├── TextView.h │ ├── TextViewManager.cpp │ ├── TextViewManager.h │ ├── Types.idl │ ├── UnsupportedSvgViewManager.cpp │ ├── UnsupportedSvgViewManager.h │ ├── UseView.cpp │ ├── UseView.h │ ├── UseViewManager.cpp │ ├── UseViewManager.h │ ├── Utils.h │ ├── ViewManagers.idl │ ├── Views.idl │ ├── packages.lock.json │ ├── pch.cpp │ ├── pch.h │ ├── resource.h │ ├── targetver.h │ └── versionoverrides.rc └── RNSVG.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- AccessModifierOffset: -1 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: true AlignOperands: false AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false BeforeCatch: false BeforeElse: false IndentBraces: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ] IncludeCategories: - Regex: '^<.*\.h(pp)?>' Priority: 1 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 3 IndentCaseLabels: true IndentWidth: 2 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Right ReflowComments: true SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never --- Language: ObjC ColumnLimit: 120 BreakBeforeBraces: WebKit ... ================================================ FILE: .eslintignore ================================================ **/node_modules/ apps/**/node_modules/ apps/**/android/ apps/**/ios/ apps/**/windows/ apps/**/macos/ screenshots/ android/ apple/ windows/ src/lib/extract/transform.js ================================================ FILE: .eslintrc.js ================================================ module.exports = { root: true, parser: '@typescript-eslint/parser', extends: [ 'standard', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:import/typescript', ], plugins: [ 'react', 'react-native', 'import', '@typescript-eslint', 'react-hooks', ], env: { 'react-native/react-native': true, }, settings: { 'import/core-modules': [ 'react-native-svg', 'react-native-svg/css', 'react-native-svg/filter-image', ], 'import/resolver': { 'babel-module': { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, rules: { 'import/no-unresolved': 'error', 'react/jsx-uses-vars': 'error', 'react/jsx-uses-react': 'error', 'no-use-before-define': 'off', '@typescript-eslint/ban-ts-comment': [ 'error', { 'ts-ignore': 'allow-with-description', 'ts-expect-error': 'allow-with-description', }, ], '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/no-var-requires': 'warn', eqeqeq: 'error', 'no-unreachable': 'error', }, }; ================================================ FILE: .git-blame-ignore-revs ================================================ # .git-blame-ignore-revs # chore: add CI for JS, iOS and Android formatting (#1782) 98c14b4f4588d55ecf1beb92a16e704e4489dd4f ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .github/FUNDING.yml ================================================ github: software-mansion ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.yaml ================================================ name: Bug report description: Report an issue with SVG here. body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report! Before you proceed: - Make sure to check whether there are similar issues in the repository - Make sure to clean cache in your project. Depending on your setup this could be done by: - `yarn start --reset-cache` or - `npm start -- --reset-cache` or - `expo start --clear` - type: markdown attributes: value: | ## Required information - type: textarea id: description attributes: label: Description description: Please provide a clear, concise and descriptive explanation of what the bug is. Include screenshots or a video if needed. Tell us what were you expecting to happen instead of what is happening now. validations: required: true - type: textarea id: steps-to-reproduce attributes: label: Steps to reproduce description: Provide a detailed list of steps that reproduce the issue. placeholder: | 1. 2. 3. validations: required: true - type: input id: repro attributes: label: Snack or a link to a repository description: | Please provide a Snack (https://snack.expo.io/) or a link to a repository on GitHub under your username that reproduces the issue. Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve. Issues without a reproduction are likely to stale. placeholder: Link to a Snack or a GitHub repository validations: required: true - type: input id: react-native-svg-version attributes: label: SVG version description: What version of react-native-svg are you using? placeholder: 15.3.0 validations: required: true - type: input id: react-native-version attributes: label: React Native version description: What version of react-native are you using? placeholder: 0.73.1 validations: required: true - type: dropdown id: platforms attributes: label: Platforms description: On what platform your application is running on? multiple: true options: - Android - iOS - macOS - Web validations: required: true - type: markdown attributes: value: | ## Additional information Providing as much information as possible greatly helps us with reproducing the issues. - type: dropdown id: runtime attributes: label: JavaScript runtime description: What runtime is your application using? options: - JSC - Hermes - V8 - type: dropdown id: workflow attributes: label: Workflow description: How is your application managed? options: - React Native - Expo Go - Expo Dev Client - type: dropdown id: architecture attributes: label: Architecture description: What React Native architecture your application is running on? Currently, the default architecture on React Native is Paper so if you haven't changed it in your application select this option. options: - Paper (Old Architecture) - Fabric (New Architecture) - type: dropdown id: build-type attributes: label: Build type description: What is the build configuration/variant of your native app and JavaScript bundle mode? options: - Debug app & dev bundle - Release app & production bundle - Debug app & production bundle - Release app & dev bundle - Other (please specify) - type: dropdown id: emulator attributes: label: Device description: How are you running your application? options: - iOS simulator - Android emulator - Real device - type: input id: device-model attributes: label: Device model description: What device you are experiencing this problem on? Specify full device name along with the version of the operating system it's running. placeholder: ex. Samsung Galaxy A22 (Android 12) - type: dropdown id: acknowledgements attributes: label: Acknowledgements description: I searched for similar issues in the repository. options: - 'Yes' validations: required: true ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Question url: https://github.com/software-mansion/react-native-svg/discussions/categories/q-a about: Please ask and answer questions here. - name: Feature request url: https://github.com/software-mansion/react-native-svg/discussions/categories/ideas about: Please submit feature requests here. ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ # No Template 👉 Please follow one of the issue templates provided by the repo - if you are seeing this message, it means you haven't. If you don't follow the issue template, we may immediately close it. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ # Summary Explain the **motivation** for making this change: here are some points to help you: * What issues does the pull request solve? Please tag them so that they will get automatically closed once the PR is merged * What is the feature? (if applicable) * How did you implement the solution? * What areas of the library does it impact? ## Test Plan Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. ### What's required for testing (prerequisites)? ### What are the steps to reproduce (after prerequisites)? ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅❌ | | MacOS | ✅❌ | | Android | ✅❌ | | Web | ✅❌ | ## Checklist - [ ] I have tested this on a device and a simulator - [ ] I added documentation in `README.md` - [ ] I updated the typed files (typescript) - [ ] I added a test for the API in the `__tests__` folder ================================================ FILE: .github/workflows/android-build-test.yml ================================================ name: Example Android check on: pull_request: paths: - .github/workflows/android-build-test.yml - 'android/**' - 'src/fabric/**' - 'package.json' - 'apps/paper-example/android/**' - 'apps/paper-example/package.json' - 'apps/fabric-example/android/**' - 'apps/fabric-example/package.json' push: branches: - main workflow_dispatch: jobs: build: runs-on: ubuntu-latest strategy: matrix: working-directory: [paper-example, fabric-example] fail-fast: false concurrency: group: android-${{ matrix.working-directory }}-${{ github.ref }} cancel-in-progress: true steps: - name: Checkout Git repository uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: '17' - name: Get react-native-svg node_modules cache uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install react-native-svg node_modules run: yarn install --frozen-lockfile - name: Get app node_modules cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/node_modules key: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}-${{ hashFiles(format('{0}/yarn.lock', matrix.working-directory)) }} restore-keys: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}- - name: Install app node_modules working-directory: apps/${{ matrix.working-directory }} run: yarn install --frozen-lockfile - name: Get build cache uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{matrix.working-directory}}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle-${{matrix.working-directory}}- - name: Build app working-directory: apps/${{ matrix.working-directory }}/android run: ./gradlew assembleDebug --build-cache --console=plain -PreactNativeArchitectures=arm64-v8a ================================================ FILE: .github/workflows/check-archs-consistency.yml ================================================ name: Test consistency between Paper & Fabric on: pull_request: branches: - main paths: - src/fabric/** - android/src/paper/java/com/facebook/react/viewmanagers/** - android/src/paper/java/com/horcrux/svg/** jobs: check: runs-on: ubuntu-latest concurrency: group: check-archs-consistency-${{ github.ref }} cancel-in-progress: true steps: - name: checkout uses: actions/checkout@v4 - name: Use Node.js 18 uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' - name: Install node dependencies run: yarn - name: Check Android Paper & Fabric generated interfaces consistency run: yarn check-archs-consistency ================================================ FILE: .github/workflows/close-when-stale.yml ================================================ name: Check for stale issues on: schedule: - cron: '37 21 * * *' # at 21:37 every day issues: types: [edited] issue_comment: types: [created, edited] workflow_dispatch: jobs: main: if: github.repository == 'software-mansion/react-native-svg' runs-on: ubuntu-latest steps: - name: Checkout Actions uses: actions/checkout@v4 with: repository: 'software-mansion-labs/swmansion-bot' ref: stable - uses: actions/cache@v3 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - name: Install Actions run: yarn install - name: Close when stale uses: ./close-when-stale with: close-when-stale-label: 'Close when stale' days-to-close: 20 ================================================ FILE: .github/workflows/e2e-android.yml ================================================ name: E2E Android on: pull_request: paths: - .github/workflows/e2e-android.yml - apps/common/example/** - android/** - src/** - e2e/** - package.json # push: # branches: # - main workflow_dispatch: jobs: test: runs-on: ubuntu-latest timeout-minutes: 60 env: WORKING_DIRECTORY: paper-example API_LEVEL: 34 SYSTEM_IMAGES: system-images;android-34;google_apis;x86_64 AVD_NAME: rn-svg-avd concurrency: group: android-e2e-example-${{ github.ref }} cancel-in-progress: true steps: - name: Checkout uses: actions/checkout@v4 - name: Free Disk Space (Ubuntu) uses: jlumbroso/free-disk-space@main with: tool-cache: true android: false - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'zulu' cache: 'gradle' - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 22 cache: 'yarn' - name: Install AVD dependencies # libxkbfile1 is removed by "Free Disk Space (Ubuntu)" step first. Here we install it again # as it seems to be needed by the emulator. run: | sudo apt update sudo apt-get install -y libpulse0 libgl1 libxkbfile1 - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: AVD cache uses: actions/cache@v4 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-${{ env.API_LEVEL }} - name: Run emulator, Metro, and E2E uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ env.API_LEVEL }} target: default profile: pixel_7 ram-size: '4096M' disk-size: '5G' disable-animations: false force-avd-creation: false emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none avd-name: e2e_emulator arch: x86_64 script: | # Install root node dependencies yarn install # Install example app node dependencies yarn --cwd apps/${{ env.WORKING_DIRECTORY }} install # Set up ADB reverse for Metro $ANDROID_HOME/platform-tools/adb reverse tcp:8081 tcp:8081 # Start Metro in the background E2E=true yarn --cwd apps/${{ env.WORKING_DIRECTORY }} start &> output.log & # Build the Android app cd apps/${{ env.WORKING_DIRECTORY }}/android && ./gradlew assembleDebug # Install the app APK $ANDROID_HOME/platform-tools/adb install -r apps/${{ env.WORKING_DIRECTORY }}/android/app/build/outputs/apk/debug/app-debug.apk # Launch the app using bash bash -c 'until $ANDROID_HOME/platform-tools/adb shell monkey -p com.paperexample 1 | grep -q "Events injected: 1"; do sleep 1; echo "Retrying app launch..."; done' # Run E2E tests yarn e2e # Kill Metro lsof -ti:8081 | xargs -r kill - name: Upload test report uses: actions/upload-artifact@v4 with: name: report path: | report.html jest-html-reporters-attach/ ================================================ FILE: .github/workflows/e2e-ios.yml ================================================ name: E2E iOS on: pull_request: paths: - .github/workflows/e2e-ios.yml - apps/common/example/** - apple/** - src/** - e2e/** - package.json # push: # branches: # - main workflow_dispatch: jobs: test: runs-on: macos-latest timeout-minutes: 60 strategy: matrix: working-directory: [paper-example] fail-fast: false env: DEVICE: iPhone 17 Pro steps: - name: Checkout Git repository uses: actions/checkout@v4 - name: Use latest stable Xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '16.4' - name: Get react-native-svg node_modules cache uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install react-native-svg node_modules run: yarn install --frozen-lockfile - name: Get app node_modules cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/node_modules key: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/yarn.lock', matrix.working-directory)) }} restore-keys: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}- - name: Install app node_modules working-directory: apps/${{ matrix.working-directory }} run: yarn install --frozen-lockfile - name: Get Pods cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/ios/Pods key: ${{ runner.os }}-pods-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/ios/Podfile.lock', matrix.working-directory)) }} restore-keys: | ${{ runner.os }}-pods-${{ matrix.working-directory }}- - name: Install Pods id: install_pods continue-on-error: true working-directory: apps/${{ matrix.working-directory }}/ios run: bundle install && bundle exec pod install - if: steps.install_pods.outcome == 'failure' id: remove_pods name: Remove pods working-directory: apps/${{ matrix.working-directory }}/ios run: rm -rf build Pods Podfile.lock - if: steps.remove_pods.outcome == 'success' id: reinstall_pods name: Reinstall pods working-directory: apps/${{ matrix.working-directory }}/ios run: bundle install && bundle exec pod install - name: Get build artifacts cache uses: actions/cache@v4 with: path: ~/Library/Developer/Xcode/DerivedData key: ${{ runner.os }}-ios-derived-data-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/ios/Podfile.lock', matrix.working-directory)) }} restore-keys: | ${{ runner.os }}-ios-derived-data-${{ matrix.working-directory }}- - name: Start Metro server working-directory: apps/${{ matrix.working-directory }} run: E2E=true yarn start &> output.log & - name: Build app working-directory: apps/${{ matrix.working-directory }} run: E2E=true npx react-native run-ios --simulator="${{ env.DEVICE }}" --mode Debug --verbose - name: Run e2e Tests run: E2E=true yarn e2e - name: Upload test report uses: actions/upload-artifact@v4 with: name: report path: | report.html jest-html-reporters-attach/ ================================================ FILE: .github/workflows/ios-build-test.yml ================================================ name: Example iOS check on: pull_request: paths: - .github/workflows/ios-build-test.yml - RNSVG.podspec - apple/** - src/fabric/** - package.json - apps/paper-example/package.json - apps/paper-example/ios/** - apps/fabric-example/package.json - apps/fabric-example/ios/** push: branches: - main workflow_dispatch: jobs: build: runs-on: macos-latest strategy: matrix: working-directory: [paper-example, fabric-example] fail-fast: false env: DEVICE: iPhone 17 Pro concurrency: group: ios-${{ matrix.working-directory }}-${{ github.ref }} cancel-in-progress: true steps: - name: Checkout Git repository uses: actions/checkout@v4 - name: Use latest stable Xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '16.4' - name: Get react-native-svg node_modules cache uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install react-native-svg node_modules run: yarn install --frozen-lockfile - name: Get app node_modules cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/node_modules key: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/yarn.lock', matrix.working-directory)) }} restore-keys: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}- - name: Install app node_modules working-directory: apps/${{ matrix.working-directory }} run: yarn install --frozen-lockfile - name: Get Pods cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/ios/Pods key: ${{ runner.os }}-pods-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/ios/Podfile.lock', matrix.working-directory)) }} restore-keys: | ${{ runner.os }}-pods-${{ matrix.working-directory }}- - name: Install Pods id: install_pods continue-on-error: true working-directory: apps/${{ matrix.working-directory }}/ios run: bundle install && bundle exec pod install - if: steps.install_pods.outcome == 'failure' id: remove_pods name: Remove pods working-directory: apps/${{ matrix.working-directory }}/ios run: rm -rf build Pods Podfile.lock - if: steps.remove_pods.outcome == 'success' id: reinstall_pods name: Reinstall pods working-directory: apps/${{ matrix.working-directory }}/ios run: bundle install && bundle exec pod install - name: Get build artifacts cache uses: actions/cache@v4 with: path: ~/Library/Developer/Xcode/DerivedData key: ${{ runner.os }}-ios-derived-data-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/ios/Podfile.lock', matrix.working-directory)) }} restore-keys: | ${{ runner.os }}-ios-derived-data-${{ matrix.working-directory }}- - name: Build app working-directory: apps/${{ matrix.working-directory }} run: npx react-native run-ios --simulator="${{ env.DEVICE }}" --mode Debug --verbose --no-packager ================================================ FILE: .github/workflows/js-build-test.yml ================================================ name: Test JS build concurrency: group: js-${{ github.ref }} cancel-in-progress: true on: pull_request: branches: - main push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4 - name: Get react-native-svg node_modules cache uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install react-native-svg node_modules run: yarn install --frozen-lockfile - name: Build run: yarn bob - name: Test and lint run: yarn test ================================================ FILE: .github/workflows/macos-build-test.yml ================================================ name: Example macOS check on: pull_request: paths: - .github/workflows/macos-build-test.yml - RNSVG.podspec - apple/** - src/fabric/** - package.json - apps/paper-macos-example/package.json - apps/paper-macos-example/ios/** - apps/fabric-macos-example/package.json - apps/fabric-macos-example/ios/** push: branches: - main jobs: build: if: github.repository == 'software-mansion/react-native-svg' runs-on: macos-latest strategy: matrix: working-directory: [paper-macos-example, fabric-macos-example] fail-fast: false concurrency: group: macos-${{ matrix.working-directory }}-${{ github.ref }} cancel-in-progress: true steps: - name: Checkout Git repository uses: actions/checkout@v4 - name: Use latest stable Xcode uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: '16.4' - name: Get react-native-svg node_modules cache uses: actions/cache@v4 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install react-native-svg node_modules run: yarn install --frozen-lockfile - name: Get app node_modules cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/node_modules key: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/yarn.lock', matrix.working-directory)) }} restore-keys: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}- - name: Install app node_modules working-directory: apps/${{ matrix.working-directory }} run: yarn install --frozen-lockfile - name: Get Pods cache uses: actions/cache@v4 with: path: apps/${{ matrix.working-directory }}/macos/Pods key: ${{ runner.os }}-pods-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/macos/Podfile.lock', matrix.working-directory)) }} restore-keys: | ${{ runner.os }}-pods-${{ matrix.working-directory }}- - name: Install Pods id: install_pods continue-on-error: true working-directory: apps/${{ matrix.working-directory }}/macos run: bundle install && bundle exec pod install - if: steps.install_pods.outcome == 'failure' id: remove_pods name: Remove pods working-directory: apps/${{ matrix.working-directory }}/macos run: rm -rf build Pods Podfile.lock - if: steps.remove_pods.outcome == 'success' id: reinstall_pods name: Reinstall pods working-directory: apps/${{ matrix.working-directory }}/macos run: bundle install && bundle exec pod install - name: Get build artifacts cache uses: actions/cache@v4 with: path: ~/Library/Developer/Xcode/DerivedData key: ${{ runner.os }}-macos-derived-data-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/macos/Podfile.lock', matrix.working-directory)) }} - name: Build app working-directory: apps/${{ matrix.working-directory }} run: yarn macos ================================================ FILE: .github/workflows/needs-more-info.yml ================================================ name: Check issue template env: YARN_ENABLE_HARDENED_MODE: 0 on: issues: types: [opened, edited] jobs: main: if: ${{ github.repository == 'software-mansion/react-native-svg' && !contains(github.event.issue.labels.*.name, 'Maintainer issue') }} runs-on: ubuntu-latest concurrency: group: needs-more-info-${{ github.event.issue.number }} cancel-in-progress: true steps: - name: Checkout Actions uses: actions/checkout@v4 with: repository: 'software-mansion-labs/swmansion-bot' ref: stable - uses: actions/cache@v3 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - name: Install Actions run: yarn install - name: Needs More Info uses: ./needs-more-info with: github-token: ${{ secrets.GITHUB_TOKEN }} needs-more-info-label: 'Missing info' required-sections: 'Description;Steps to reproduce;Snack or a link to a repository;SVG version;React Native version;Platforms' needs-more-info-response: "Hey! 👋 \n\nIt looks like you've omitted a few important sections from the issue template." check-issues-only-created-after: 2024-06-14 # This action also appends something like: "Please complete X, Y and Z sections." to the response. # Code responsible for this can be found here: https://github.com/software-mansion-labs/swmansion-bot/blob/main/needs-more-info/MissingSectionsFormatter.js ================================================ FILE: .github/workflows/needs-repro.yml ================================================ name: Check for reproduction on: issues: types: [opened, edited] issue_comment: types: [created, edited, deleted] jobs: main: if: ${{ github.repository == 'software-mansion/react-native-svg' && !contains(github.event.issue.labels.*.name, 'Maintainer issue') }} runs-on: ubuntu-latest concurrency: group: needs-repro-${{ github.event.issue.number }} cancel-in-progress: true steps: - name: Checkout Actions uses: actions/checkout@v4 with: repository: 'software-mansion-labs/swmansion-bot' ref: stable - uses: actions/cache@v3 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - name: Install Actions run: yarn install - name: Needs Repro uses: ./needs-repro with: github-token: ${{ secrets.GITHUB_TOKEN }} needs-repro-label: 'Missing repro' needs-repro-response: "Hey! 👋 \n\nThe issue doesn't seem to contain a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example).\n\nCould you provide a [snack](https://snack.expo.dev/) or a link to a GitHub repository under your username that reproduces the problem?" repro-provided-label: 'Repro provided' check-issues-only-created-after: 2024-06-14 ================================================ FILE: .github/workflows/windows-build-test.yml ================================================ name: Test Windows build on: pull_request: paths: - '.github/workflows/windows-build-test.yml' - 'windows/**' - 'src/fabric/**' - 'package.json' - 'apps/paper-windows-example/windows/**' - 'apps/paper-windows-example/package.json' - 'apps/fabric-windows-example/windows/**' - 'apps/fabric-windows-example/package.json' push: branches: - main jobs: build: runs-on: windows-2022 strategy: matrix: working-directory: [paper-windows-example, fabric-windows-example] concurrency: group: windows-${{ matrix.working-directory }}-${{ github.ref }} cancel-in-progress: true steps: - name: Check out Git repository uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: '^18' - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 - name: Restore react-native-svg node_modules from cache uses: actions/cache@v3 with: path: node_modules key: ${{ runner.os }}-node-modules-svg-${{ hashFiles('yarn.lock') }} restore-keys: ${{ runner.os }}-node-modules-svg- - name: Install svg node_modules run: yarn install --frozen-lockfile - name: Restore app node_modules from cache uses: actions/cache@v3 with: path: apps/${{ matrix.working-directory }}/node_modules key: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}-${{ hashFiles(format('apps/{0}/yarn.lock', matrix.working-directory)) }} restore-keys: ${{ runner.os }}-node-modules-${{ matrix.working-directory }}- - name: Install app node_modules working-directory: apps/${{ matrix.working-directory }} run: yarn --frozen-lockfile - name: Build app working-directory: apps/${{ matrix.working-directory }}/windows run: npx react-native run-windows --logging --no-packager --no-deploy --no-autolink ================================================ FILE: .gitignore ================================================ # OSX # .DS_Store .yarn .yarnrc.yml # Xcode # *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa project.xcworkspace # Android/IJ # .idea .gradle local.properties build/ # node.js # node_modules npm-debug.log # webstorm # *.iml # unfinished documents # cn-doc.md # experimental code # experimental/ /lib/ # VS Code .vscode/ # E2E reports jest-html-reporters-attach/ report.html ================================================ FILE: .husky/pre-commit ================================================ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" yarn lint-staged ================================================ FILE: .npmignore ================================================ screenshots/ apps/ ================================================ FILE: .prettierrc.js ================================================ module.exports = { bracketSameLine: true, printWidth: 80, singleQuote: true, trailingComma: 'es5', tabWidth: 2, arrowParens: 'always', }; ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at msand@abo.fi. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to React Native Svg Thank you for helping out with react-native-svg! We'd like to make contributions as pleasant as possible, so here's a small guide of how we see it. Happy to hear your feedback about anything, so please let us know. ### Modifying react-native-svg 1. Fork this repository 2. Clone your fork 3. Make a branch for your feature or bug fix (i.e. `git checkout -b added-getfoobar`) 4. Work your magic 5. Execute `yarn link` when done. ### Testing your changes Add test example in [tests-example](https://github.com/react-native-svg/react-native-svg/tree/main/tests-example) concerning your change following the convention of `TestX.tsx` where `X` is your PR number. ## Tests We use `typescript` for type checks, `eslint` with `prettier` for linting/formatting. All tests are run by github actions for all opened pull requests. - `yarn test`: Run all tests, except for e2e (see note below). - `yarn lint`: Run `eslint` check. - `yarn tsc`: Run `typescript` check. - `yarn jest`: Run `jest` type check. - `yarn e2e`: Run E2E tests (see section below) ### Running E2E tests: > [!WARNING] > Reference images in this repository are generated with [pixel ratio](https://reactnative.dev/docs/pixelratio) = `3`. > Make sure to run tests on a device that also has pixel ratio equal 3. Otherwise tests will fail. > In order to use device with different pixel ratio, adjust it in `e2e/generateRefereces.ts` viewport and regenerate > references. 1. Navigate to the example application's directory and initiate the Metro server using the yarn start command. 2. To run the example application on your preferred platform (note: currently only Android and iOS are supported), execute the command `yarn android` or `yarn ios` within the example app's directory. 3. Start the Jest server by running `yarn e2e` in the project's root directory. 4. In the example application, select the E2E tab. 5. Allow the tests to complete. 6. The test results, along with any differences (i.e. the actual rendered svg versus the reference image), can be viewed in the `e2e/diffs` directory. ### To add new E2E test cases, proceed as follows: 1. Put an SVG file of your selection into the `e2e/cases` directory. 2. Execute `yarn generateE2eRefrences`. This action launches a headless Chrome browser via Puppeteer, capturing snapshots of all rendered SVGs as .png files. These files will serve as a reference during testing. 3. Check the `e2e/references` directory to observe newly created .png files. 4. When you rerun the E2E tests, the new test case(s) you've added will be incorporated. ## Sending a pull request When you're sending a pull request: - Communication is a key. If you want fix/add something, please consider either opening a new issue or finding an existing one so we can further discuss it. - We prefer small pull requests focused on one change, as those are easier to test/check. - Please make sure that all tests are passing on your local machine. - Follow the template when opening a PR. ## Commits and versioning All PRs are merged into the `main` branch and released with `release-it`. Most notably prefixes you'll see: - **fix**: Bug fixes - **feat**: New feature implemented - **chore**: Changes that are not affecting end user (CI config changes, scripts, ["grunt work"](https://stackoverflow.com/a/26944812/3510245)) - **docs**: Documentation changes. - **perf**: A code change that improves performance. - **refactor**: A code change that neither fixes a bug nor adds a feature. - **test**: Adding missing tests or correcting existing tests. ## Release process We use [release-it](https://github.com/release-it/release-it) to release new versions of library from `main` branch. ## Reporting issues You can report issues on our [bug tracker](https://github.com/react-native-community/react-native-svg/issues). Please search for existing issues and follow the issue template when opening one. ## License By contributing to React Native Svg, you agree that your contributions will be licensed under the **MIT** license. ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) [2015-2016] [Horcrux] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ React Native SVG at Software Mansion [![Version](https://img.shields.io/npm/v/react-native-svg.svg)](https://www.npmjs.com/package/react-native-svg) [![NPM](https://img.shields.io/npm/dm/react-native-svg.svg)](https://www.npmjs.com/package/react-native-svg) `react-native-svg` provides SVG support to React Native on iOS, Android, macOS, Windows, and a compatibility layer for the web. [Check out the Example app](https://github.com/software-mansion/react-native-svg/tree/main/apps/common/example) - [Features](#features) - [Installation](#installation) - [Troubleshooting](#troubleshooting) - [Opening issues](#opening-issues) - [Usage](#usage) - [Known issues](#known-issues) ## Features 1. Supports most SVG elements and properties (Rect, Circle, Line, Polyline, Polygon, G ...). 2. Easy to [convert SVG code](https://svgr.now.sh/) to react-native-svg. ## Installation ### With expo > ✅ The [Expo client app](https://expo.io/tools) comes with the native code installed! Install the JavaScript with: ```bash npx expo install react-native-svg ``` 📚 See the [**Expo docs**](https://docs.expo.io/versions/latest/sdk/svg/) for more info or jump ahead to [Usage](#usage). ### With react-native-cli 1. Install library from npm ```bash npm install react-native-svg ``` from yarn ```bash yarn add react-native-svg ``` 2. Link native code ```bash cd ios && pod install ``` ## Supported react-native versions | react-native-svg | react-native | | ---------------- | ------------ | | 3.2.0 | 0.29 | | 4.2.0 | 0.32 | | 4.3.0 | 0.33 | | 4.4.0 | 0.38 | | 4.5.0 | 0.40 | | 5.1.8 | 0.44 | | 5.2.0 | 0.45 | | 5.3.0 | 0.46 | | 5.4.1 | 0.47 | | 5.5.1 | >=0.50 | | >=6 | >=0.50 | | >=7 | >=0.57.4 | | >=8 | >=0.57.4 | | >=9 | >=0.57.4 | | >=12.3.0 | >=0.64.0 | | >=15.0.0 | >=0.70.0 | | >=15.8.0 | >=0.73.0 | | >=15.13.0 | >=0.78.0 | ## Support for Fabric [Fabric](https://reactnative.dev/architecture/fabric-renderer) is React Native's new rendering system. As of [version `13.0.0`](https://github.com/react-native-svg/react-native-svg/releases/tag/v13.0.0) of this project, Fabric is supported only for react-native 0.69.0+. Support for earlier versions is not possible due to breaking changes in configuration. | react-native-svg | react-native | | ---------------- | ------------ | | >=13.0.0 | 0.69.0+ | | >=13.6.0 | 0.70.0+ | | >=13.10.0 | 0.72.0+ | ## Troubleshooting ### Unexpected behavior If you have unexpected behavior, please create a clean project with the latest versions of react-native and react-native-svg ```bash react-native init CleanProject cd CleanProject/ yarn add react-native-svg cd ios && pod install && cd .. ``` Make a reproduction of the problem in `App.js` ```bash react-native run-ios react-native run-android ``` ### Adding Windows support 1. `npx react-native-windows-init --overwrite` 2. `react-native run-windows` ## Opening issues Verify that it is still an issue with the latest version as specified in the previous step. If so, open a new issue, include the entire `App.js` file, specify what platforms you've tested, and the results of running this command: ```bash react-native info ``` If you suspect that you've found a spec conformance bug, then you can test using your component in a react-native-web project by forking this codesandbox, to see how different browsers render the same content: If any evergreen browser with significant userbase or other svg user agent renders some svg content better, or supports more of the svg and related specs, please open an issue asap. ## Usage To check how to use the library, see [USAGE.md](https://github.com/react-native-svg/react-native-svg/blob/main/USAGE.md) ## Known issues: 1. Unable to apply focus point of RadialGradient on Android. ## React Native SVG is maintained by Software Mansion Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – [Hire us](https://swmansion.com/contact/projects?utm_source=svg&utm_medium=readme). ================================================ FILE: RNSVG.podspec ================================================ require 'json' require_relative './scripts/rnsvg_utils' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) svgConfig = rnsvg_find_config() fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' Pod::Spec.new do |s| s.name = 'RNSVG' s.version = package['version'] s.summary = package['description'] s.license = package['license'] s.homepage = package['homepage'] s.authors = 'Horcrux Chen' s.source = { :git => 'https://github.com/react-native-community/react-native-svg.git', :tag => "v#{s.version}" } s.source_files = 'apple/**/*.{h,m,mm}' s.ios.exclude_files = '**/*.macos.{h,m,mm}' s.tvos.exclude_files = '**/*.macos.{h,m,mm}' s.visionos.exclude_files = '**/*.macos.{h,m,mm}' if s.respond_to?(:visionos) s.osx.exclude_files = '**/*.ios.{h,m,mm}' s.requires_arc = true s.platforms = { :osx => "10.14", :ios => "12.4", :tvos => "12.4", :visionos => "1.0" } s.osx.resource_bundles = {'RNSVGFilters' => ['apple/**/*.macosx.metallib']} s.ios.resource_bundles = {'RNSVGFilters' => ['apple/**/*.iphoneos.metallib']} s.tvos.resource_bundles = {'RNSVGFilters' => ['apple/**/*.appletvos.metallib']} s.visionos.resource_bundles = {'RNSVGFilters' => ['apple/**/*.xros.metallib']} s.xcconfig = { "OTHER_CFLAGS" => "$(inherited) -DREACT_NATIVE_MINOR_VERSION=#{svgConfig[:react_native_minor_version]}", } if fabric_enabled install_modules_dependencies(s) 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.exclude_files = 'apple/Utils/RNSVGFabricConversions.h' s.dependency 'React-Core' end end ================================================ FILE: USAGE.md ================================================ # Usage Here's a simple example. To render output like this: ![SVG example](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/svg.png) Use the following code: ```jsx import Svg, { Circle, Ellipse, G, Text, TSpan, TextPath, Path, Polygon, Polyline, Line, Rect, Use, Image, Symbol, Defs, LinearGradient, RadialGradient, Stop, ClipPath, Pattern, Mask, } from 'react-native-svg'; import React from 'react'; import { View, StyleSheet } from 'react-native'; export default class SvgExample extends React.Component { render() { return ( ); } } ``` [Try this on Snack](https://snack.expo.io/@msand/react-native-svg-example) # Use with content loaded from uri ```jsx import * as React from 'react'; import { SvgUri } from 'react-native-svg'; export default () => ( ); ``` ## CSS Support If remote SVG file contains CSS in ` `; export default () => ; ``` # Common props: | Name | Default | Description | | ---------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | fill | '#000' | The fill prop refers to the color inside the shape. | | fillOpacity | 1 | This prop specifies the opacity of the color or the content the current object is filled with. | | fillRule | nonzero | The fillRule prop determines what side of a path is inside a shape, which determines how fill will paint the shape, can be `nonzero` or `evenodd` | | stroke | 'none' | The stroke prop controls how the outline of a shape appears. | | strokeWidth | 1 | The strokeWidth prop specifies the width of the outline on the current object. | | strokeOpacity | 1 | The strokeOpacity prop specifies the opacity of the outline on the current object. | | strokeLinecap | 'square' | The strokeLinecap prop specifies the shape to be used at the end of open subpaths when they are stroked. Can be either `'butt'`, `'square'` or `'round'`. | | strokeLinejoin | 'miter' | The strokeLinejoin prop specifies the shape to be used at the corners of paths or basic shapes when they are stroked. Can be either `'miter'`, `'bevel'` or `'round'`. | | strokeDasharray | [] | The strokeDasharray prop controls the pattern of dashes and gaps used to stroke paths. | | strokeDashoffset | null | The strokeDashoffset prop specifies the distance into the dash pattern to start the dash. | | x | 0 | Translate distance on x-axis. | | y | 0 | Translate distance on y-axis. | | rotation | 0 | Rotation degree value on the current object. | | scale | 1 | Scale value on the current object. | | origin | 0, 0 | Transform origin coordinates for the current object. | | originX | 0 | Transform originX coordinates for the current object. | | originY | 0 | Transform originY coordinates for the current object. | # Supported elements: ## Svg ```jsx ``` Colors set in the Svg element are inherited by its children: ```jsx ``` ![Pencil](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/pencil.png) Code explanation: - The fill prop defines the color inside the object. - The stroke prop defines the color of the line drawn around the object. - The color prop is a bit special in the sense that it won't color anything by itself, but define a kind of color variable that can be used by children elements. In this example we're defining a "green" color in the Svg element and using it in the second Path element via stroke="currentColor". The "currentColor" is what refers to that "green" value, and it can be used in other props that accept colors too, e.g. fill="currentColor". ## Rect The element is used to create a rectangle and variations of a rectangle shape: ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/rect.png) Code explanation: - The width and height props of the element define the height and the width of the rectangle. - The x prop defines the left position of the rectangle (e.g. x="25" places the rectangle 25 px from the left margin). - The y prop defines the top position of the rectangle (e.g. y="5" places the rectangle 5 px from the top margin). ## Circle The element is used to create a circle: ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/circle.png) Code explanation: - The cx and cy props define the x and y coordinates of the center of the circle. If cx and cy are omitted, the circle's center is set to (0,0) - The r prop defines the radius of the circle ## Ellipse The element is used to create an ellipse. An ellipse is closely related to a circle. The difference is that an ellipse has an x and a y radius that differs from each other, while a circle has equal x and y radius. ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/ellipse.png) Code explanation: - The cx prop defines the x coordinate of the center of the ellipse - The cy prop defines the y coordinate of the center of the ellipse - The rx prop defines the horizontal radius - The ry prop defines the vertical radius ## Line The element is an SVG basic shape, used to create a line connecting two points. ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/line.png) Code explanation: - The x1 prop defines the start of the line on the x-axis. - The y1 prop defines the start of the line on the y-axis. - The x2 prop defines the end of the line on the x-axis. - The y2 prop defines the end of the line on the y-axis. ## Polygon The element is used to create a graphic that contains at least three sides. Polygons are made of straight lines, and the shape is "closed" (all the lines connect up). ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/polygon.png) Code explanation: - The points prop defines the x and y coordinates for each corner of the polygon ## Polyline The element is used to create any shape that consists of only straight lines: ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/polyline.png) Code explanation: - The points prop defines the x and y coordinates for each point of the polyline ## Path The element is used to define a path. The following commands are available for path data: - M = moveto - L = lineto - H = horizontal lineto - V = vertical lineto - C = curveto - S = smooth curveto - Q = quadratic Bézier curve - T = smooth quadratic Bézier curveto - A = elliptical Arc - Z = closepath `Note:` All of the commands above can also be expressed with lower letters. Capital letters means absolutely positioned, lower cases means relatively positioned. See [Path document of SVG](https://www.w3.org/TR/SVG/paths.html) to know parameters for each command. ```jsx ``` ![Rect](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/path.png) ## Text The element is used to define text. ```jsx STROKED TEXT ``` ![Text](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/text.png) ## TSpan The element is used to draw multiple lines of text in SVG. Rather than having to position each line of text absolutely, the element makes it possible to position a line of text relatively to the previous line of text. ```jsx tspan line 1 tspan line 2 tspan line 3 12345 6 7 89a delta on text ``` ![TSpan](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/tspan.png) ## TextPath In addition to text drawn in a straight line, SVG also includes the ability to place text along the shape of a element. To specify that a block of text is to be rendered along the shape of a , include the given text within a element which includes an href attribute with a reference to a element. ```jsx We go up and down, then up again ``` ![TextPath](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/text-path.png) ## G The element is a container used to group other SVG elements. Transformations applied to the g element are performed on all of its child elements, and any of its props are inherited by its child elements. It can also group multiple elements to be referenced later with the [<Use />](#use) element. ```jsx Text grouped with shapes ``` ![G](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/g.png) ## Use The element can reuse an SVG shape from elsewhere in the SVG document, including elements and elements. The reused shape can be defined inside the [<Defs>](#defs) element (which makes the shape invisible until used) or outside. ```jsx ``` This example shows a element defined inside a [<Defs>](#defs) element. This makes the invisible unless referenced by a element. Before the element can be referenced, it must have an ID set on it via its id prop. The element references the element via its `href` prop. Notice the # in front of the ID in the prop value. The element specifies where to show the reused shapes via its x and y props. Notice that the shapes inside the element are located at 0,0. That is done because their position is added to the position specified in the element. ![use](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/use.png) ## Symbol The SVG element is used to define reusable symbols. The shapes nested inside a are not displayed unless referenced by a element. ```jsx ``` ![Symbol](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/symbol.png) ## Defs The element is used to embed definitions that can be reused inside an SVG image. For instance, you can group SVG shapes together and reuse them as a single shape. ## Image The element allows a raster image to be included in an Svg component. ```jsx HOGWARTS ``` ![Image](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/image.png) ## ClipPath The SVG element defines a clipping path. A clipping path is used/referenced using the clipPath property ```jsx Q ``` ![ClipPath](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/clip-path.png) ## LinearGradient The element is used to define a linear gradient. The element must be nested within a [<Defs>](#defs) tag. The [<Defs>](#defs) tag is short for definitions and contains definition of special elements (such as gradients). Linear gradients can be defined as horizontal, vertical or angular gradients: - Horizontal gradients are created when y1 and y2 are equal and x1 and x2 differ - Vertical gradients are created when x1 and x2 are equal and y1 and y2 differ - Angular gradients are created when x1 and x2 differ and y1 and y2 differ ```jsx ``` Code explanation: - The id prop of the tag defines a unique name for the gradient - The x1, x2, y1,y2 props of the tag define the start and end position of the gradient - The color range for a gradient can be composed of two or more colors. Each color is specified with a tag. The offset prop is used to define where the gradient color begin and end - The fill prop links the ellipse element to the gradient ![LinearGradient](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/lineargradient.png) _NOTICE:_ LinearGradient also supports percentage as prop: ```jsx ``` This result is same as the example before. But it's recommend to use exact number instead; it has performance advantages over using percentages. ## RadialGradient The element is used to define a radial gradient. The element must be nested within a [<Defs>](#defs) tag. The [<Defs>](#defs) tag is short for definitions and contains definition of special elements (such as gradients). ```jsx ``` Code explanation: - The id prop of the tag defines a unique name for the gradient - The cx, cy and r props define the outermost circle and the fx and fy define the innermost circle - The color range for a gradient can be composed of two or more colors. Each color is specified with a tag. The offset prop is used to define where the gradient color begin and end - The fill prop links the ellipse element to the gradient ![RadialGradient](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/radialgradient.png) ## Mask In SVG, you can specify that any other graphics object or ‘G’ element can be used as an alpha mask for compositing the current object into the background. A mask is defined with a ‘Mask’ element. A mask is used/referenced using the ‘mask’ property. A ‘Mask’ can contain any graphical elements or container elements such as a ‘G’. The element must be nested within a [<Defs>](#defs) tag. The [<Defs>](#defs) tag is short for definitions and contains definition of special elements (such as gradients). ```jsx Masked text ``` Code explanation: ![Mask](https://www.w3.org/TR/SVG11/images/masking/mask01.svg) v10 adds experimental support for using masks together with native elements. If you had native elements inside any Svg root before (which was unsupported), then your content might change appearance when upgrading, as e.g. transforms and masks now take effect. ## Pattern A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted. Patterns are defined using a ‘pattern’ element and then referenced by properties ‘fill’ and ‘stroke’ on a given graphics element to indicate that the given element shall be filled or stroked with the referenced pattern. The element must be nested within a [<Defs>](#defs) tag. The [<Defs>](#defs) tag is short for definitions and contains definition of special elements (such as gradients). ```jsx ``` Code explanation: ![Pattern](https://www.w3.org/TR/SVG11/images/pservers/pattern01.svg) ## Marker A marker is a symbol which is attached to one or more vertices of ‘path’, ‘line’, ‘polyline’ and ‘polygon’ elements. Typically, markers are used to make arrowheads or polymarkers. Arrowheads can be defined by attaching a marker to the start or end vertices of ‘path’, ‘line’ or ‘polyline’ elements. Polymarkers can be defined by attaching a marker to all vertices of a ‘path’, ‘line’, ‘polyline’ or ‘polygon’ element. The graphics for a marker are defined by a ‘marker’ element. To indicate that a particular ‘marker’ element should be rendered at the vertices of a particular ‘path’, ‘line’, ‘polyline’ or ‘polygon’ element, set one or more marker properties (‘marker’, ‘marker-start’, ‘marker-mid’ or ‘marker-end’) to reference the given ‘marker’ element. ```jsx ``` Code explanation: ![Marker](https://www.w3.org/TR/SVG11/images/painting/marker.svg) ```jsx import React from 'react'; import { StyleSheet, View } from 'react-native'; import { SvgXml } from 'react-native-svg'; const markerRendering = ` `; export default class App extends React.Component { render() { return ( ); } } const styles = StyleSheet.create({ container: { backgroundColor: 'white', justifyContent: 'center', alignItems: 'center', flex: 1, }, }); ``` ![MarkerDoubled](https://www.w3.org/TR/SVG2/images/painting/marker-doubled.svg) ```jsx import React from 'react'; import { StyleSheet, View } from 'react-native'; import { SvgXml } from 'react-native-svg'; const markerRendering = ` `; export default class App extends React.Component { render() { return ( ); } } const styles = StyleSheet.create({ container: { backgroundColor: 'white', justifyContent: 'center', alignItems: 'center', flex: 1, }, }); ``` ![MarkerRendering](https://www.w3.org/TR/SVG2/images/painting/marker-rendering.svg) Code explanation: ## ForeignObject SVG is designed to be compatible with other XML languages for describing and rendering other types of content. The ‘foreignObject’ element allows for inclusion of elements in a non-SVG namespace which is rendered within a region of the SVG graphic using other user agent processes. The included foreign graphical content is subject to SVG transformations, filters, clipping, masking and compositing. One goal for SVG is to provide a mechanism by which other XML language processors can render into an area within an SVG drawing, with those renderings subject to the various transformations and compositing parameters that are currently active at a given point within the SVG content tree. One particular example of this is to provide a frame for XML content styled with CSS or XSL so that dynamically reflowing text (subject to SVG transformations and compositing) could be inserted into the middle of some SVG content. https://svgwg.org/svg2-draft/embedded.html#ForeignObjectElement https://www.w3.org/TR/SVG11/extend.html#ForeignObjectElement ```jsx import React, { Component } from 'react'; import { Text, View, Image } from 'react-native'; import { Svg, Defs, LinearGradient, Stop, Mask, Rect, G, Circle, ForeignObject, } from 'react-native-svg'; export default class App extends Component { render() { return ( Testing Testing2 ); } } ``` ## Touch Events Touch events are supported in react-native-svg. These include: - `disabled` - `onPress` - `onPressIn` - `onPressOut` - `onLongPress` - `delayPressIn` - `delayPressOut` - `delayLongPress` You can use these events to provide interactivity to your react-native-svg components. ```jsx alert('Press on Circle')} /> ``` ![TouchEvents](https://raw.githubusercontent.com/react-native-community/react-native-svg/master/screenshots/touchevents.gif) For more examples of touch in action, checkout the [TouchEvents.js examples](https://github.com/magicismight/react-native-svg-example/blob/master/examples/TouchEvents.js). # Serialize ```jsx import * as React from 'react'; import { Platform, StyleSheet, TouchableOpacity } from 'react-native'; import { Svg, Rect } from 'react-native-svg'; import ReactDOMServer from 'react-dom/server'; const isWeb = Platform.OS === 'web'; const childToWeb = (child) => { const { type, props } = child; const name = type && type.displayName; const webName = name && name[0].toLowerCase() + name.slice(1); const Tag = webName ? webName : type; return {toWeb(props.children)}; }; const toWeb = (children) => React.Children.map(children, childToWeb); export default class App extends React.Component { renderSvg() { return ( ); } serialize = () => { const element = this.renderSvg(); const webJsx = isWeb ? element : toWeb(element); const svgString = ReactDOMServer.renderToStaticMarkup(webJsx); console.log(svgString); }; render() { return ( {this.renderSvg()} ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#ecf0f1', padding: 8, }, }); ``` ## Filters Filter effects are a way of processing an element’s rendering before it is displayed in the document. Typically, rendering an element via CSS or SVG can conceptually be described as if the element, including its children, are drawn into a buffer (such as a raster image) and then that buffer is composited into the elements parent. Filters apply an effect before the compositing stage. Examples of such effects are blurring, changing color intensity and warping the image. > [!NOTE] > Not all filters have been implemented on native platforms yet. However, they do work on the Web, so we added them. Some filters will display a warning indicating they are not currently supported. The following filters have been implemented: - FeBlend - FeComposite - FeColorMatrix - FeDropShadow - FeFlood - FeGaussianBlur - FeMerge - FeOffset Not supported yet: - FeComponentTransfer - FeConvolveMatrix - FeDiffuseLighting - FeDisplacementMap - FeFuncA - FeFuncB - FeFuncG - FeFuncR - FeImage - FeMorphology - FePointLight - FeSpecularLighting - FeSpotLight - FeTile - FeTurbulence Exmaple use of filters: ```jsx import React from 'react'; import { FeColorMatrix, Filter, Rect, Svg } from 'react-native-svg'; export default () => { return ( ); }; ``` ![FeColorMatrix](./screenshots/feColorMatrix.png) More info: ## FilterImage `FilterImage` is a new component that is not strictly related to SVG. Its behavior should be the same as a regular `Image` component from React Native with one exception - the additional prop `filters`, which accepts an array of filters to apply to the image. Filters can be applied in two ways - through `filters` prop - or with CSS API through style prop https://developer.mozilla.org/en-US/docs/Web/CSS/filter ### Examples #### CSS filter API ```tsx import React from 'react'; import { StyleSheet } from 'react-native'; import { FilterImage } from 'react-native-svg/filter-image'; const myImage = require('./myImage.jpg'); export default () => { return ; }; const styles = StyleSheet.create({ image: { width: 200, height: 200, filter: 'saturate(3) grayscale(100%)', }, }); ``` #### `filters` prop ```tsx import React from 'react'; import { StyleSheet } from 'react-native'; import { FilterImage } from 'react-native-svg/filter-image'; const myImage = require('./myImage.jpg'); export default () => { return ( ); }; const styles = StyleSheet.create({ image: { width: 200, height: 200, }, }); ``` ![FilterImage](./screenshots/filterImage.png) ================================================ FILE: __tests__/__snapshots__/css.test.tsx.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`inlines styles 1`] = ` Object { "Tag": [Function], "children": Array [ /* tag selector */ rect { stroke: blue; fill: yellow } /* class selector */ .redbox { fill: red; } /* multiple selectors */ g .class-1, g .class-2 { stroke-width: 16 } /* two classes */ .class-2.transparent { fill-opacity: 0.3; } /* Commented out rect { fill: black; } */ , , , ], "parent": null, "props": Object { "height": "100%", "version": 1.1, "viewBox": "0 0 1000 500", "width": "100%", "xmlns": "http://www.w3.org/2000/svg", }, "tag": "svg", } `; exports[`supports CSS in style element 1`] = ` " xmlns="http://www.w3.org/2000/svg" > `; ================================================ FILE: __tests__/css.test.tsx ================================================ import * as React from 'react'; import renderer from 'react-test-renderer'; import { parse } from '../src/ReactNativeSVG'; import { SvgCss, inlineStyles } from '../css'; const xml = ` `; test('inlines styles', () => { const ast = parse(xml, inlineStyles); expect(ast).toMatchSnapshot(); }); test('supports CSS in style element', () => { const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); ================================================ FILE: __tests__/e2e/GeneralSvgRenderingTest.spec.tsx ================================================ import { SvgFromXml } from 'react-native-svg'; import * as fs from 'node:fs'; import { compareImages, sendToDeviceAndReceive } from '../../e2e/helpers'; import { HandshakeMessageData, RenderResponse } from '../../e2e/types'; import path from 'path'; import { addAttach as attachImageToReport, addMsg as addMessageToReport, } from 'jest-html-reporters/helper'; import { PNG } from 'pngjs'; import failedCases from '../../e2e/failedCases.json'; import { verifyComparisons } from '../../e2e/matchTestCases'; import { height, targetPixelRatio, width } from '../../e2e/env'; const testCases = fs.readdirSync(path.resolve('e2e', 'cases')); testCases.forEach((testCase) => { jest.setTimeout(90_000); test(`Web browser rendered SVG should have less than 0.05% differences between device rendered SVG (${testCase})`, async () => { await addMessageToReport({ message: JSON.stringify({ os: global.os, arch: global.arch, }), }); const testCaseSvg = path.resolve('e2e', 'cases', testCase); const svgXml = fs.readFileSync(testCaseSvg).toString('utf-8'); const response = await sendToDeviceAndReceive({ type: 'renderRequest', data: , height, width, }); const referenceFilePath = path.resolve( 'e2e', global.os === 'android' ? 'references/android' : 'references/ios', testCase.replace('.svg', '.png') ); const renderedFilePath = path.resolve( 'e2e', 'rendered', `${testCase.replace('.svg', '')}-${global.os}-${global.arch}-rendered.png` ); const diffFilePath = path.resolve( 'e2e', 'diffs', `${testCase.replace('.svg', '')}-${global.os}-${global.arch}-diff.png` ); const referenceFileBuffer = fs.readFileSync(referenceFilePath); const renderedDataBuffer = Buffer.from(response.data, 'base64'); // We use await everywhere instead Promise.all as we need to maintain order for ease of inspecting tests // Adding reference & rendered before comparison in case compareImages fails, so we can see why it failed await attachImageToReport({ attach: fs.readFileSync(referenceFilePath), description: 'Reference image', bufferFormat: 'png', }); await attachImageToReport({ attach: PNG.sync.write(PNG.sync.read(renderedDataBuffer)), description: 'Actual rendered image', bufferFormat: 'png', }); // Compare reference file (from /e2e/references) with SVG rendered on actual device. // Reference files can be generated off of /e2e/cases with `yarn generateE2eReferences`. const amountOfDifferentPixels = compareImages( referenceFileBuffer, renderedDataBuffer, { width, height, pixelRatio: targetPixelRatio, diffFilePath, renderedFilePath, } ); await attachImageToReport({ attach: fs.readFileSync(diffFilePath), description: 'Differences', bufferFormat: 'png', }); // Check if there is more than 0.5% different pixels in whole snapshot verifyComparisons( amountOfDifferentPixels, failedCases, global as unknown as HandshakeMessageData, testCase ); }); }); ================================================ FILE: android/build.gradle ================================================ buildscript { // The Android Gradle plugin is only required when opening the android folder stand-alone. // This avoids unnecessary downloads and potential conflicts when the library is included as a // module dependency in an application project. if (project == rootProject) { repositories { mavenCentral() google() } dependencies { classpath("com.android.tools.build:gradle:7.4.2") classpath "com.diffplug.spotless:spotless-plugin-gradle:6.17.0" } } } def isNewArchitectureEnabled() { // To opt-in for the New Architecture, you can either: // - Set `newArchEnabled` to true inside the `gradle.properties` file // - Invoke gradle with `-newArchEnabled=true` // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" } if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" } if (project == rootProject) { apply from: 'spotless.gradle' } apply plugin: 'com.android.library' def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } def resolveReactNativeDirectory() { def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null) if (reactNativeLocation != null) { return file(reactNativeLocation) } // Fallback to node resolver for custom directory structures like monorepos. def reactNativePackage = file( providers.exec { workingDir(rootDir) commandLine("node", "--print", "require.resolve('react-native/package.json')") }.standardOutput.asText.get().trim() ) if (reactNativePackage.exists()) { return reactNativePackage.parentFile } throw new GradleException("[react-native-svg] Unable to resolve react-native location in node_modules. Your app should define `REACT_NATIVE_NODE_MODULES_DIR` extension property in `app/build.gradle` with a path to react-native in node_modules.") } def reactNativeRootDir = resolveReactNativeDirectory() def reactNativeProperties = new Properties() file("$reactNativeRootDir/ReactAndroid/gradle.properties").withInputStream { reactNativeProperties.load(it) } def REACT_NATIVE_VERSION = reactNativeProperties.getProperty("VERSION_NAME") def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() def getFrescoVersion() { def reactNativeRootDir = resolveReactNativeDirectory() def frescoVersion = null file("$reactNativeRootDir/gradle/libs.versions.toml").withInputStream { stream -> stream.eachLine { line -> if (line.contains("fresco") && !line.contains("ref")) { def keyValue = line.split("=") if (keyValue.size() == 2) { frescoVersion = keyValue[1].trim().replaceAll(/["']/, "") } } } } if (!frescoVersion) { return "3.2.0" } return frescoVersion } def FRESCO_VERSION = getFrescoVersion() android { compileSdkVersion safeExtGet('compileSdkVersion', 28) namespace "com.horcrux.svg" def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION if (agpVersion.tokenize('.')[0].toInteger() >= 8) { buildFeatures { buildConfig = true } } // Used to override the NDK path/version on internal CI or by allowing // users to customize the NDK path/version from their root project (e.g. for M1 support) if (rootProject.hasProperty("ndkPath")) { ndkPath rootProject.ext.ndkPath } if (rootProject.hasProperty("ndkVersion")) { ndkVersion rootProject.ext.ndkVersion } defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 16) //noinspection OldTargetApi targetSdkVersion safeExtGet('targetSdkVersion', 28) buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() consumerProguardFiles 'proguard-rules.pro' } lintOptions { abortOnError false } sourceSets.main { java { if (!isNewArchitectureEnabled()) { srcDirs += [ "src/paper/java", ] } } } } repositories { mavenCentral() mavenLocal() google() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" } } dependencies { implementation 'com.facebook.react:react-native:+' implementation("com.facebook.fresco:fresco:${FRESCO_VERSION}") { exclude group: 'com.facebook.soloader' } implementation("com.facebook.fresco:imagepipeline-okhttp3:${FRESCO_VERSION}") { exclude group: 'com.facebook.soloader' } implementation("com.facebook.fresco:middleware:${FRESCO_VERSION}") } ================================================ FILE: android/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: android/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in # double quotes to make sure that they get re-expanded; and # * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: android/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: android/proguard-rules.pro ================================================ -keep public class com.horcrux.svg.** {*;} ================================================ FILE: android/spotless.gradle ================================================ // formatter & linter configuration for java apply plugin: 'com.diffplug.spotless' spotless { java { target 'src/main/java/**/*.java' googleJavaFormat() } } ================================================ FILE: android/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/src/main/java/com/horcrux/svg/Brush.java ================================================ /* * 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. */ package com.horcrux.svg; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; class Brush { private final BrushType mType; private final SVGLength[] mPoints; private ReadableArray mColors; private final boolean mUseObjectBoundingBox; // TODO implement pattern units @SuppressWarnings({"unused"}) private boolean mUseContentObjectBoundingBoxUnits; private Matrix mMatrix; private Rect mUserSpaceBoundingBox; private PatternView mPattern; Brush(BrushType type, SVGLength[] points, BrushUnits units) { mType = type; mPoints = points; mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX; } void setContentUnits(BrushUnits units) { mUseContentObjectBoundingBoxUnits = units == BrushUnits.OBJECT_BOUNDING_BOX; } void setPattern(PatternView pattern) { mPattern = pattern; } enum BrushType { LINEAR_GRADIENT, RADIAL_GRADIENT, PATTERN } enum BrushUnits { OBJECT_BOUNDING_BOX, USER_SPACE_ON_USE } private static void parseGradientStops( ReadableArray value, int stopsCount, float[] stops, int[] stopsColors, float opacity) { for (int i = 0; i < stopsCount; i++) { int stopIndex = i * 2; stops[i] = (float) value.getDouble(stopIndex); int color = value.getInt(stopIndex + 1); int alpha = color >>> 24; int combined = Math.round((float) alpha * opacity); stopsColors[i] = combined << 24 | (color & 0x00ffffff); } } void setUserSpaceBoundingBox(Rect userSpaceBoundingBox) { mUserSpaceBoundingBox = userSpaceBoundingBox; } void setGradientColors(ReadableArray colors) { mColors = colors; } void setGradientTransform(Matrix matrix) { mMatrix = matrix; } private RectF getPaintRect(RectF pathBoundingBox) { RectF rect = mUseObjectBoundingBox ? pathBoundingBox : new RectF(mUserSpaceBoundingBox); float width = rect.width(); float height = rect.height(); float x = 0f; float y = 0f; if (mUseObjectBoundingBox) { x = rect.left; y = rect.top; } return new RectF(x, y, x + width, y + height); } private double getVal(SVGLength length, double relative, float scale, float textSize) { return PropHelper.fromRelative( length, relative, 0, mUseObjectBoundingBox && length.unit == SVGLength.UnitType.NUMBER ? relative : scale, textSize); } void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) { RectF rect = getPaintRect(pathBoundingBox); float width = rect.width(); float height = rect.height(); float offsetX = rect.left; float offsetY = rect.top; float textSize = paint.getTextSize(); if (mType == BrushType.PATTERN) { double x = getVal(mPoints[0], width, scale, textSize); double y = getVal(mPoints[1], height, scale, textSize); double w = getVal(mPoints[2], width, scale, textSize); double h = getVal(mPoints[3], height, scale, textSize); if (!(w > 1 && h > 1)) { return; } Bitmap bitmap = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); RectF vbRect = mPattern.getViewBox(); if (vbRect != null && vbRect.width() > 0 && vbRect.height() > 0) { RectF eRect = new RectF((float) x, (float) y, (float) w, (float) h); Matrix mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice); canvas.concat(mViewBoxMatrix); } if (mUseContentObjectBoundingBoxUnits) { canvas.scale(width / scale, height / scale); } mPattern.draw(canvas, new Paint(), opacity); Matrix patternMatrix = new Matrix(); if (mMatrix != null) { patternMatrix.preConcat(mMatrix); } BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); bitmapShader.setLocalMatrix(patternMatrix); paint.setShader(bitmapShader); return; } int size = mColors.size(); if (size == 0) { FLog.w(ReactConstants.TAG, "Gradient contains no stops"); return; } int stopsCount = size / 2; int[] stopsColors = new int[stopsCount]; float[] stops = new float[stopsCount]; parseGradientStops(mColors, stopsCount, stops, stopsColors, opacity); if (stops.length == 1) { // Gradient with only one stop will make LinearGradient/RadialGradient // throw. It may happen when source SVG contains only one stop or // two stops at the same spot (see lib/extract/extractGradient.js). // Although it's mistake SVGs like this can be produced by vector // editors or other tools, so let's handle that gracefully. stopsColors = new int[] {stopsColors[0], stopsColors[0]}; stops = new float[] {stops[0], stops[0]}; FLog.w(ReactConstants.TAG, "Gradient contains only one stop"); } if (mType == BrushType.LINEAR_GRADIENT) { double x1 = getVal(mPoints[0], width, scale, textSize) + offsetX; double y1 = getVal(mPoints[1], height, scale, textSize) + offsetY; double x2 = getVal(mPoints[2], width, scale, textSize) + offsetX; double y2 = getVal(mPoints[3], height, scale, textSize) + offsetY; Shader linearGradient = new LinearGradient( (float) x1, (float) y1, (float) x2, (float) y2, stopsColors, stops, Shader.TileMode.CLAMP); if (mMatrix != null) { Matrix m = new Matrix(); m.preConcat(mMatrix); linearGradient.setLocalMatrix(m); } paint.setShader(linearGradient); } else if (mType == BrushType.RADIAL_GRADIENT) { double rx = getVal(mPoints[2], width, scale, textSize); double ry = getVal(mPoints[3], height, scale, textSize); if (rx <= 0 || ry <= 0) { // Gradient with radius = 0 should be rendered as solid color of the last stop rx = width; ry = height; stops = new float[] {stops[0], stops[stops.length - 1]}; stopsColors = new int[] {stopsColors[stopsColors.length - 1], stopsColors[stopsColors.length - 1]}; } double ratio = ry / rx; double cx = getVal(mPoints[4], width, scale, textSize) + offsetX; double cy = getVal(mPoints[5], height / ratio, scale, textSize) + offsetY / ratio; // TODO: support focus point. // double fx = PropHelper.fromRelative(mPoints[0], width, offsetX, scale); // double fy = PropHelper.fromRelative(mPoints[1], height, offsetY, scale) / (ry / rx); Shader radialGradient = new RadialGradient( (float) cx, (float) cy, (float) rx, stopsColors, stops, Shader.TileMode.CLAMP); Matrix radialMatrix = new Matrix(); radialMatrix.preScale(1f, (float) ratio); if (mMatrix != null) { radialMatrix.preConcat(mMatrix); } radialGradient.setLocalMatrix(radialMatrix); paint.setShader(radialGradient); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/CircleView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.ArrayList; @SuppressLint("ViewConstructor") class CircleView extends RenderableView { private SVGLength mCx; private SVGLength mCy; private SVGLength mR; public CircleView(ReactContext reactContext) { super(reactContext); } public void setCx(Dynamic cx) { mCx = SVGLength.from(cx); invalidate(); } public void setCy(Dynamic cy) { mCy = SVGLength.from(cy); invalidate(); } public void setR(Dynamic r) { mR = SVGLength.from(r); invalidate(); } @Override Path getPath(Canvas canvas, Paint paint) { Path path = new Path(); double cx = relativeOnWidth(mCx); double cy = relativeOnHeight(mCy); double r = relativeOnOther(mR); path.addCircle((float) cx, (float) cy, (float) r, Path.Direction.CW); elements = new ArrayList<>(); elements.add( new PathElement( ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(cx, cy - r)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx, cy - r), new Point(cx + r, cy)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx + r, cy), new Point(cx, cy + r)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx, cy + r), new Point(cx - r, cy)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx - r, cy), new Point(cx, cy - r)})); return path; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/ClipPathView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.ReactConstants; @SuppressLint("ViewConstructor") class ClipPathView extends GroupView { public ClipPathView(ReactContext reactContext) { super(reactContext); } @Override void draw(Canvas canvas, Paint paint, float opacity) { FLog.w( ReactConstants.TAG, "RNSVG: ClipPath can't be drawn, it should be defined as a child component for `Defs` "); } @Override void saveDefinition() { getSvgView().defineClipPath(this, mName); } @Override boolean isResponsible() { return false; } @Override int hitTest(float[] src) { return -1; } @Override void mergeProperties(RenderableView target) {} @Override void resetProperties() {} } ================================================ FILE: android/src/main/java/com/horcrux/svg/CustomFilter.java ================================================ package com.horcrux.svg; import android.graphics.Bitmap; interface CustomFilterFunction { float[] execute(float[] src, float[] dst); } public class CustomFilter { public static Bitmap apply(Bitmap srcBmp, Bitmap dstBmp, CustomFilterFunction func) { int width = srcBmp.getWidth(); int height = srcBmp.getHeight(); int[] srcPixels = new int[width * height]; int[] dstPixels = new int[width * height]; int[] resPixels = new int[width * height]; int srcArgb = 0; float[] src = new float[] {0, 0, 0, 0}; int dstArgb = 0; float[] dst = new float[] {0, 0, 0, 0}; try { srcBmp.getPixels(srcPixels, 0, width, 0, 0, width, height); dstBmp.getPixels(dstPixels, 0, width, 0, 0, width, height); } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException ignored) { } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { srcArgb = srcPixels[y * width + x]; src[0] = ((srcArgb >> 24) & 0xff) / 255f; src[1] = ((srcArgb >> 16) & 0xff) / 255f; src[2] = ((srcArgb >> 8) & 0xff) / 255f; src[3] = (srcArgb & 0xff) / 255f; dstArgb = dstPixels[y * width + x]; dst[0] = ((dstArgb >> 24) & 0xff) / 255f; dst[1] = ((dstArgb >> 16) & 0xff) / 255f; dst[2] = ((dstArgb >> 8) & 0xff) / 255f; dst[3] = (dstArgb & 0xff) / 255f; resPixels[y * width + x] = normalizeFromFloats(func.execute(src, dst)); } } return Bitmap.createBitmap(resPixels, width, height, Bitmap.Config.ARGB_8888); } public static int normalizeFromFloat(float c) { return Math.min(255, Math.max(0, Math.round(c * 255))); } public static int normalizeFromFloats(float[] res) { if (res.length < 4 || normalizeFromFloat(res[0]) <= 0) { return 0; } return (normalizeFromFloat(res[0]) << 24) | (normalizeFromFloat(res[1] / res[0]) << 16) | (normalizeFromFloat(res[2] / res[0]) << 8) | normalizeFromFloat(res[3] / res[0]); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/DefinitionView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class DefinitionView extends VirtualView { DefinitionView(ReactContext reactContext) { super(reactContext); } @SuppressWarnings("EmptyMethod") void draw(Canvas canvas, Paint paint, float opacity) {} @Override boolean isResponsible() { return false; } @Override Path getPath(Canvas canvas, Paint paint) { return null; } @Override int hitTest(float[] src) { return -1; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/DefsView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.view.View; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class DefsView extends DefinitionView { public DefsView(ReactContext reactContext) { super(reactContext); } @Override void draw(Canvas canvas, Paint paint, float opacity) {} void saveDefinition() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof VirtualView) { ((VirtualView) child).saveDefinition(); } } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/EllipseView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.ArrayList; @SuppressLint("ViewConstructor") class EllipseView extends RenderableView { private SVGLength mCx; private SVGLength mCy; private SVGLength mRx; private SVGLength mRy; public EllipseView(ReactContext reactContext) { super(reactContext); } public void setCx(Dynamic cx) { mCx = SVGLength.from(cx); invalidate(); } public void setCy(Dynamic cy) { mCy = SVGLength.from(cy); invalidate(); } public void setRx(Dynamic rx) { mRx = SVGLength.from(rx); invalidate(); } public void setRy(Dynamic ry) { mRy = SVGLength.from(ry); invalidate(); } @Override Path getPath(Canvas canvas, Paint paint) { Path path = new Path(); double cx = relativeOnWidth(mCx); double cy = relativeOnHeight(mCy); double rx = relativeOnWidth(mRx); double ry = relativeOnHeight(mRy); RectF oval = new RectF((float) (cx - rx), (float) (cy - ry), (float) (cx + rx), (float) (cy + ry)); path.addOval(oval, Path.Direction.CW); elements = new ArrayList<>(); elements.add( new PathElement( ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(cx, cy - ry)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx, cy - ry), new Point(cx + rx, cy)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx + rx, cy), new Point(cx, cy + ry)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx, cy + ry), new Point(cx - rx, cy)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(cx - rx, cy), new Point(cx, cy - ry)})); return path; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeBlendView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeBlendView extends FilterPrimitiveView { String mIn1; String mIn2; FilterProperties.FeBlendMode mMode; public FeBlendView(ReactContext reactContext) { super(reactContext); super.mFilterSubregion.mX = new SVGLength(0); super.mFilterSubregion.mY = new SVGLength(0); super.mFilterSubregion.mW = new SVGLength("100%"); super.mFilterSubregion.mH = new SVGLength("100%"); } public void setIn1(String in1) { this.mIn1 = in1; invalidate(); } public void setIn2(String in2) { this.mIn2 = in2; invalidate(); } public void setMode(String mode) { this.mMode = FilterProperties.FeBlendMode.getEnum(mode); invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap in1 = getSource(resultsMap, prevResult, this.mIn1); Bitmap in2 = getSource(resultsMap, prevResult, this.mIn2); if (this.mMode == FilterProperties.FeBlendMode.MULTIPLY) { CustomFilterFunction multiply = (src, dst) -> { float[] res = new float[4]; res[0] = 1f - (1f - src[0]) * (1f - dst[0]); res[1] = src[1] * src[0] * (1f - dst[0]) + dst[1] * dst[0] * (1f - src[0]) + src[1] * src[0] * dst[1] * dst[0]; res[2] = src[2] * src[0] * (1f - dst[0]) + dst[2] * dst[0] * (1f - src[0]) + src[2] * src[0] * dst[2] * dst[0]; res[3] = src[3] * src[0] * (1f - dst[0]) + dst[3] * dst[0] * (1f - src[0]) + src[3] * src[0] * dst[3] * dst[0]; return res; }; return CustomFilter.apply(in1, in2, multiply); } Bitmap result = Bitmap.createBitmap(in1.getWidth(), in1.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(result); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); canvas.drawBitmap(in1, 0, 0, paint); switch (this.mMode) { case UNKNOWN: case NORMAL: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); break; case SCREEN: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); break; case LIGHTEN: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN)); break; case DARKEN: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); break; case MULTIPLY: break; } canvas.drawBitmap(in2, 0, 0, paint); return result; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeColorMatrixView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.ColorMatrix; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeColorMatrixView extends FilterPrimitiveView { String mIn1; FilterProperties.FeColorMatrixType mType; ReadableArray mValues; public FeColorMatrixView(ReactContext reactContext) { super(reactContext); } public void setIn1(String in1) { this.mIn1 = in1; invalidate(); } public void setType(String type) { this.mType = FilterProperties.FeColorMatrixType.getEnum(type); invalidate(); } public void setValues(ReadableArray values) { this.mValues = values; invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap source = getSource(resultsMap, prevResult, this.mIn1); ColorMatrix colorMatrix = new ColorMatrix(); switch (this.mType) { case MATRIX: if (this.mValues.size() < 20) return source; float[] rawMatrix = new float[mValues.size()]; for (int i = 0; i < this.mValues.size(); i++) { rawMatrix[i] = (float) this.mValues.getDouble(i) * (i % 5 == 4 ? 255 : 1); } colorMatrix.set(rawMatrix); break; case SATURATE: if (this.mValues.size() != 1) return source; colorMatrix.setSaturation((float) this.mValues.getDouble(0)); break; case HUE_ROTATE: if (this.mValues.size() != 1) return source; float hue = (float) this.mValues.getDouble(0); float cosHue = (float) Math.cos(hue * Math.PI / 180); float sinHue = (float) Math.sin(hue * Math.PI / 180); colorMatrix.set( new float[] { 0.213f + cosHue * 0.787f - sinHue * 0.213f, // 0 0.715f - cosHue * 0.715f - sinHue * 0.715f, // 1 0.072f - cosHue * 0.072f + sinHue * 0.928f, // 2 0, // 3 0, // 4 0.213f - cosHue * 0.213f + sinHue * 0.143f, // 5 0.715f + cosHue * 0.285f + sinHue * 0.140f, // 6 0.072f - cosHue * 0.072f - sinHue * 0.283f, // 7 0, // 8 0, // 9 0.213f - cosHue * 0.213f - sinHue * 0.787f, // 10 0.715f - cosHue * 0.715f + sinHue * 0.715f, // 11 0.072f + cosHue * 0.928f + sinHue * 0.072f, // 12 0, // 13 0, // 14 0, // 15 0, // 16 0, // 17 1, // 18 0, // 19 }); break; case LUMINANCE_TO_ALPHA: colorMatrix.set( new float[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2125f, 0.7154f, 0.0721f, 0, 0, }); break; } return FilterUtils.getBitmapWithColorMatrix(colorMatrix, source); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeCompositeView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeCompositeView extends FilterPrimitiveView { String mIn1; String mIn2; float mK1; float mK2; float mK3; float mK4; FilterProperties.FeCompositeOperator mOperator; public FeCompositeView(ReactContext reactContext) { super(reactContext); } public void setIn1(String in1) { this.mIn1 = in1; invalidate(); } public void setIn2(String in2) { this.mIn2 = in2; invalidate(); } public void setK1(Float value) { this.mK1 = value; invalidate(); } public void setK2(Float value) { this.mK2 = value; invalidate(); } public void setK3(Float value) { this.mK3 = value; invalidate(); } public void setK4(Float value) { this.mK4 = value; invalidate(); } public void setOperator(String operator) { this.mOperator = FilterProperties.FeCompositeOperator.getEnum(operator); invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap in1 = getSource(resultsMap, prevResult, this.mIn1); Bitmap in2 = getSource(resultsMap, prevResult, this.mIn2); Bitmap result = Bitmap.createBitmap(in1.getWidth(), in1.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(result); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); canvas.drawBitmap(in1, 0, 0, paint); switch (this.mOperator) { case OVER: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); break; case IN: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); break; case OUT: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); break; case ATOP: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); break; case XOR: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); break; case ARITHMETIC: // result = k1*i1*i2 + k2*i1 + k3*i2 + k4 int nPixels = result.getWidth() * result.getHeight(); int[] pixels1 = new int[nPixels]; int[] pixels2 = new int[nPixels]; result.getPixels( pixels1, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight()); in2.getPixels(pixels2, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight()); for (int i = 0; i < nPixels; i++) { int color1 = pixels1[i]; int color2 = pixels2[i]; int r1 = (color1 >> 16) & 0xFF; int g1 = (color1 >> 8) & 0xFF; int b1 = color1 & 0xFF; int a1 = (color1 >>> 24); int r2 = (color2 >> 16) & 0xFF; int g2 = (color2 >> 8) & 0xFF; int b2 = color2 & 0xFF; int a2 = (color2 >>> 24); int rResult = (int) (mK1 * r1 * r2 + mK2 * r1 + mK3 * r2 + mK4); int gResult = (int) (mK1 * g1 * g2 + mK2 * g1 + mK3 * g2 + mK4); int bResult = (int) (mK1 * b1 * b2 + mK2 * b1 + mK3 * b2 + mK4); int aResult = (int) (mK1 * a1 * a2 + mK2 * a1 + mK3 * a2 + mK4); rResult = Math.min(255, Math.max(0, rResult)); gResult = Math.min(255, Math.max(0, gResult)); bResult = Math.min(255, Math.max(0, bResult)); aResult = Math.min(255, Math.max(0, aResult)); int pixel = (aResult << 24) | (rResult << 16) | (gResult << 8) | bResult; pixels1[i] = pixel; } result.setPixels( pixels1, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight()); break; } if (this.mOperator != FilterProperties.FeCompositeOperator.ARITHMETIC) { canvas.drawBitmap(in2, 0, 0, paint); } return result; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeFloodView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.facebook.react.bridge.ColorPropConverter; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class FeFloodView extends FilterPrimitiveView { private static final Pattern regex = Pattern.compile("[0-9.-]+"); public @Nullable ReadableArray floodColor; public float floodOpacity = 1; public FeFloodView(ReactContext reactContext) { super(reactContext); } public void setFloodColor(@Nullable Dynamic color) { if (color == null || color.isNull()) { floodColor = null; invalidate(); return; } ReadableType strokeType = color.getType(); if (strokeType.equals(ReadableType.Map)) { ReadableMap colorMap = color.asMap(); setFloodColor(colorMap); return; } // This code will probably never be reached with current changes ReadableType type = color.getType(); if (type.equals(ReadableType.Number)) { floodColor = JavaOnlyArray.of(0, color.asInt()); } else if (type.equals(ReadableType.Array)) { floodColor = color.asArray(); } else { JavaOnlyArray arr = new JavaOnlyArray(); arr.pushInt(0); Matcher m = regex.matcher(color.asString()); int i = 0; while (m.find()) { double parsed = Double.parseDouble(m.group()); arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); } floodColor = arr; } invalidate(); } public void setFloodColor(@Nullable ReadableMap color) { if (color == null) { this.floodColor = null; invalidate(); return; } int type = color.getInt("type"); if (type == 0) { ReadableType payloadType = color.getType("payload"); if (payloadType.equals(ReadableType.Number)) { this.floodColor = JavaOnlyArray.of(0, color.getInt("payload")); } else if (payloadType.equals(ReadableType.Map)) { this.floodColor = JavaOnlyArray.of(0, color.getMap("payload")); } } else if (type == 1) { this.floodColor = JavaOnlyArray.of(1, color.getString("brushRef")); } else { this.floodColor = JavaOnlyArray.of(type); } invalidate(); } public void setFloodOpacity(float opacity) { this.floodOpacity = opacity; invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap floodBitmap = Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888); Canvas floodCanvas = new Canvas(floodBitmap); Paint paint = new Paint(); paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG); paint.setStyle(Paint.Style.FILL); this.setupPaint(paint, this.floodOpacity, this.floodColor); floodCanvas.drawPaint(paint); return floodBitmap; } private void setupPaint(Paint paint, float opacity, @Nullable ReadableArray colors) { int colorType = colors.getInt(0); switch (colorType) { case 0: if (colors.size() == 2) { int color; if (colors.getType(1) == ReadableType.Map) { color = ColorPropConverter.getColor(colors.getMap(1), getContext()); } else { color = colors.getInt(1); } int alpha = color >>> 24; int combined = Math.round((float) alpha * opacity); paint.setColor(combined << 24 | (color & 0x00ffffff)); } else { // solid color paint.setARGB( (int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255), (int) (colors.getDouble(1) * 255), (int) (colors.getDouble(2) * 255), (int) (colors.getDouble(3) * 255)); } break; // TODO: handle currentColor } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeGaussianBlurView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeGaussianBlurView extends FilterPrimitiveView { String mIn1; float mStdDeviationX; float mStdDeviationY; FilterProperties.EdgeMode mEdgeMode; public FeGaussianBlurView(ReactContext reactContext) { super(reactContext); } public void setIn1(String in1) { this.mIn1 = in1; invalidate(); } public void setStdDeviationX(float stdDeviationX) { this.mStdDeviationX = stdDeviationX; invalidate(); } public void setStdDeviationY(float stdDeviationY) { this.mStdDeviationY = stdDeviationY; invalidate(); } public void setEdgeMode(String edgeMode) { this.mEdgeMode = FilterProperties.EdgeMode.getEnum(edgeMode); invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap source = getSource(resultsMap, prevResult, this.mIn1); return blur(getContext(), source); } private Bitmap blur(Context context, Bitmap bitmap) { // Android blur radius is much weaker than SVG's, so we need to scale it up. float stdDeviation = Math.max(mStdDeviationX, mStdDeviationY) * 2; if (stdDeviation <= 0) return bitmap; final float maxRadius = 25.0f; float radius = Math.min(stdDeviation, maxRadius); Bitmap outputBitmap = Bitmap.createBitmap(bitmap); // Create a RenderScript with blur RenderScript rs = RenderScript.create(context); ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // Allocate memory for Renderscript to work with Allocation tmpIn = Allocation.createFromBitmap(rs, bitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); // Set the radius of the blur, allocation input, and output blurScript.setRadius(radius); blurScript.setInput(tmpIn); blurScript.forEach(tmpOut); // Copy the allocation output to the output bitmap and release memory tmpOut.copyTo(outputBitmap); tmpIn.destroy(); tmpOut.destroy(); rs.destroy(); return Bitmap.createScaledBitmap(outputBitmap, bitmap.getWidth(), bitmap.getHeight(), false); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeMergeView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeMergeView extends FilterPrimitiveView { private ReadableArray mNodes; public FeMergeView(ReactContext reactContext) { super(reactContext); } public void setNodes(ReadableArray nodes) { this.mNodes = nodes; invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap result = Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(result); int nodesSize = this.mNodes.size(); for (int i = 0; i < nodesSize; i++) { String nodeKey = this.mNodes.getString(i); Bitmap sourceFromResults = nodeKey.isEmpty() ? prevResult : resultsMap.get(nodeKey); if (sourceFromResults != null) { canvas.drawBitmap(sourceFromResults, 0, 0, new Paint()); } } return result; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FeOffsetView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.RectF; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FeOffsetView extends FilterPrimitiveView { String mIn1; SVGLength mDx; SVGLength mDy; public FeOffsetView(ReactContext reactContext) { super(reactContext); } public void setIn1(String in1) { this.mIn1 = in1; invalidate(); } public void setDx(Dynamic dx) { mDx = SVGLength.from(dx); invalidate(); } public void setDy(Dynamic dy) { mDy = SVGLength.from(dy); invalidate(); } @Override public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { Bitmap source = getSource(resultsMap, prevResult, this.mIn1); Bitmap result = Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(result); float dx = this.mDx != null ? (float) this.relativeOnWidth(this.mDx) : 0; float dy = this.mDy != null ? (float) this.relativeOnHeight(this.mDy) : 0; RectF frame = new RectF(0, 0, dx, dy); this.getSvgView().getCtm().mapRect(frame); dx = frame.left < 0 ? frame.left : frame.width(); dy = frame.top < 0 ? frame.top : frame.height(); canvas.drawBitmap(source, dx, dy, null); return result; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FilterPrimitiveView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FilterPrimitiveView extends DefinitionView { private String mResult; public final FilterRegion mFilterSubregion; public FilterPrimitiveView(ReactContext reactContext) { super(reactContext); mFilterSubregion = new FilterRegion(); } public void setX(Dynamic x) { mFilterSubregion.setX(x); invalidate(); } public void setY(Dynamic y) { mFilterSubregion.setY(y); invalidate(); } public void setWidth(Dynamic width) { mFilterSubregion.setWidth(width); invalidate(); } public void setHeight(Dynamic height) { mFilterSubregion.setHeight(height); invalidate(); } public void setResult(String result) { mResult = result; invalidate(); } public String getResult() { return mResult; } protected static Bitmap getSource( HashMap resultsMap, Bitmap prevResult, String in1) { Bitmap sourceFromResults = in1 != null ? resultsMap.get(in1) : null; return sourceFromResults != null ? sourceFromResults : prevResult; } public Bitmap applyFilter(HashMap resultsMap, Bitmap prevResult) { return null; } @Override void saveDefinition() {} } ================================================ FILE: android/src/main/java/com/horcrux/svg/FilterProperties.java ================================================ package com.horcrux.svg; import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; class FilterProperties { enum Units { OBJECT_BOUNDING_BOX("objectBoundingBox"), USER_SPACE_ON_USE("userSpaceOnUse"), ; private final String units; Units(String units) { this.units = units; } static Units getEnum(String strVal) { if (!unitsToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown 'Unit' Value: " + strVal); } return unitsToEnum.get(strVal); } private static final Map unitsToEnum = new HashMap<>(); static { for (final Units en : Units.values()) { unitsToEnum.put(en.units, en); } } @Nonnull @Override public String toString() { return units; } } enum EdgeMode { UNKNOWN("unknown"), DUPLICATE("duplicate"), WRAP("wrap"), NONE("none"), ; private final String edgeMode; EdgeMode(String edgeMode) { this.edgeMode = edgeMode; } static EdgeMode getEnum(String strVal) { if (!edgeModeToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown 'edgeMode' Value: " + strVal); } return edgeModeToEnum.get(strVal); } private static final Map edgeModeToEnum = new HashMap<>(); static { for (final EdgeMode en : EdgeMode.values()) { edgeModeToEnum.put(en.edgeMode, en); } } @Nonnull @Override public String toString() { return edgeMode; } } enum FeBlendMode { UNKNOWN("unknown"), NORMAL("normal"), MULTIPLY("multiply"), SCREEN("screen"), DARKEN("darken"), LIGHTEN("lighten"), ; private final String mode; FeBlendMode(String mode) { this.mode = mode; } static FeBlendMode getEnum(String strVal) { if (!typeToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown String Value: " + strVal); } return typeToEnum.get(strVal); } private static final Map typeToEnum = new HashMap<>(); static { for (final FeBlendMode en : FeBlendMode.values()) { typeToEnum.put(en.mode, en); } } @Nonnull @Override public String toString() { return mode; } } enum FeColorMatrixType { MATRIX("matrix"), SATURATE("saturate"), HUE_ROTATE("hueRotate"), LUMINANCE_TO_ALPHA("luminanceToAlpha"), ; private final String type; FeColorMatrixType(String type) { this.type = type; } static FeColorMatrixType getEnum(String strVal) { if (!typeToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown String Value: " + strVal); } return typeToEnum.get(strVal); } private static final Map typeToEnum = new HashMap<>(); static { for (final FeColorMatrixType en : FeColorMatrixType.values()) { typeToEnum.put(en.type, en); } } @Nonnull @Override public String toString() { return type; } } enum FeCompositeOperator { OVER("over"), IN("in"), OUT("out"), ATOP("atop"), XOR("xor"), ARITHMETIC("arithmetic"), ; private final String type; FeCompositeOperator(String type) { this.type = type; } static FeCompositeOperator getEnum(String strVal) { if (!typeToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown String Value: " + strVal); } return typeToEnum.get(strVal); } private static final Map typeToEnum = new HashMap<>(); static { for (final FeCompositeOperator en : FeCompositeOperator.values()) { typeToEnum.put(en.type, en); } } @Nonnull @Override public String toString() { return type; } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FilterRegion.java ================================================ package com.horcrux.svg; import android.graphics.Rect; import android.graphics.RectF; import com.facebook.react.bridge.Dynamic; public class FilterRegion { SVGLength mX; SVGLength mY; SVGLength mW; SVGLength mH; public void setX(Dynamic x) { mX = SVGLength.from(x); } public void setY(Dynamic y) { mY = SVGLength.from(y); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); } private double getRelativeOrDefault( VirtualView view, SVGLength value, float relativeOn, double defaultValue) { if (value == null || value.unit == SVGLength.UnitType.UNKNOWN) { return defaultValue; } return view.relativeOn(value, relativeOn); } public Rect getCropRect(VirtualView view, FilterProperties.Units units, RectF bounds) { double x, y, width, height; if (bounds == null) { return new Rect(0, 0, 0, 0); } if (units == FilterProperties.Units.OBJECT_BOUNDING_BOX) { x = bounds.left + view.relativeOnFraction(this.mX, bounds.width()); y = bounds.top + view.relativeOnFraction(this.mY, bounds.height()); width = view.relativeOnFraction(this.mW, bounds.width()); height = view.relativeOnFraction(this.mH, bounds.height()); } else { // FilterProperties.Units.USER_SPACE_ON_USE float canvasWidth = view.getSvgView().getCanvasWidth(); float canvasHeight = view.getSvgView().getCanvasHeight(); x = getRelativeOrDefault(view, mX, canvasWidth, bounds.left); y = getRelativeOrDefault(view, mY, canvasHeight, bounds.top); width = getRelativeOrDefault(view, mW, canvasWidth, bounds.width()); height = getRelativeOrDefault(view, mH, canvasHeight, bounds.height()); } return new Rect((int) x, (int) y, (int) (x + width), (int) (y + height)); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FilterUtils.java ================================================ package com.horcrux.svg; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; public class FilterUtils { public static Bitmap getBitmapWithColorMatrix(ColorMatrix colorMatrix, Bitmap sourceBitmap) { Bitmap results = Bitmap.createBitmap( sourceBitmap.getWidth(), sourceBitmap.getHeight(), sourceBitmap.getConfig()); Canvas canvas = new Canvas(results); Paint paint = new Paint(); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(sourceBitmap, 0, 0, paint); return results; } public static Bitmap applySourceAlphaFilter(Bitmap source) { ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.set( new float[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }); return getBitmapWithColorMatrix(colorMatrix, source); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FilterView.java ================================================ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.View; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.HashMap; @SuppressLint("ViewConstructor") class FilterView extends DefinitionView { private final HashMap mResultsMap = new HashMap<>(); private FilterProperties.Units mFilterUnits; private FilterProperties.Units mPrimitiveUnits; private final FilterRegion mFilterRegion; public FilterView(ReactContext reactContext) { super(reactContext); mFilterRegion = new FilterRegion(); } public void setX(Dynamic x) { mFilterRegion.setX(x); invalidate(); } public void setY(Dynamic y) { mFilterRegion.setY(y); invalidate(); } public void setWidth(Dynamic width) { mFilterRegion.setWidth(width); invalidate(); } public void setHeight(Dynamic height) { mFilterRegion.setHeight(height); invalidate(); } public void setFilterUnits(String filterUnits) { mFilterUnits = FilterProperties.Units.getEnum(filterUnits); invalidate(); } public void setPrimitiveUnits(String primitiveUnits) { mPrimitiveUnits = FilterProperties.Units.getEnum(primitiveUnits); invalidate(); } public FilterRegion getFilterRegion() { return mFilterRegion; } @Override void saveDefinition() { if (mName != null) { SvgView svg = getSvgView(); if (svg != null) { svg.defineFilter(this, mName); } } } public Bitmap applyFilter(Bitmap source, Bitmap background, RectF renderableBounds) { mResultsMap.clear(); mResultsMap.put("SourceGraphic", source); mResultsMap.put("SourceAlpha", FilterUtils.applySourceAlphaFilter(source)); mResultsMap.put("BackgroundImage", background); mResultsMap.put("BackgroundAlpha", FilterUtils.applySourceAlphaFilter(background)); Bitmap res = source; Bitmap resultBitmap = Bitmap.createBitmap(res.getWidth(), res.getHeight(), res.getConfig()); Canvas canvas = new Canvas(resultBitmap); Rect filterRegionRect = this.mFilterRegion.getCropRect(this, this.mFilterUnits, renderableBounds); Rect cropRect; for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof FilterPrimitiveView) { FilterPrimitiveView currentFilter = (FilterPrimitiveView) node; resultBitmap.eraseColor(Color.TRANSPARENT); cropRect = currentFilter.mFilterSubregion.getCropRect( currentFilter, this.mPrimitiveUnits, this.mPrimitiveUnits == FilterProperties.Units.USER_SPACE_ON_USE ? new RectF(filterRegionRect) : renderableBounds); canvas.drawBitmap(currentFilter.applyFilter(mResultsMap, res), cropRect, cropRect, null); res = resultBitmap.copy(Bitmap.Config.ARGB_8888, true); String resultName = currentFilter.getResult(); if (resultName != null) { mResultsMap.put(resultName, res); } } else { Log.e("RNSVG", "Invalid `Filter` child: Filter children can only be `Fe...` components"); } } // crop Bitmap to filter coordinates resultBitmap.eraseColor(Color.TRANSPARENT); canvas.drawBitmap(res, filterRegionRect, filterRegionRect, null); return resultBitmap; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/FontData.java ================================================ package com.horcrux.svg; import static com.facebook.react.uimanager.ViewProps.FONT_FAMILY; import static com.facebook.react.uimanager.ViewProps.FONT_SIZE; import static com.facebook.react.uimanager.ViewProps.FONT_STYLE; import static com.facebook.react.uimanager.ViewProps.FONT_WEIGHT; import static com.horcrux.svg.TextProperties.*; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; class FontData { static class AbsoluteFontWeight { static final int normal = 400; private static final FontWeight[] WEIGHTS = new FontWeight[] { FontWeight.w100, FontWeight.w100, FontWeight.w200, FontWeight.w300, FontWeight.Normal, FontWeight.w500, FontWeight.w600, FontWeight.Bold, FontWeight.w800, FontWeight.w900, FontWeight.w900, }; static FontWeight nearestFontWeight(int absoluteFontWeight) { return WEIGHTS[Math.round(absoluteFontWeight / 100f)]; } private static final int[] absoluteFontWeights = new int[] {400, 700, 100, 200, 300, 400, 500, 600, 700, 800, 900}; // https://drafts.csswg.org/css-fonts-4/#relative-weights static int from(FontWeight fontWeight, FontData parent) { if (fontWeight == FontWeight.Bolder) { return bolder(parent.absoluteFontWeight); } else if (fontWeight == FontWeight.Lighter) { return lighter(parent.absoluteFontWeight); } else { return absoluteFontWeights[fontWeight.ordinal()]; } } private static int bolder(int inherited) { if (inherited < 350) { return 400; } else if (inherited < 550) { return 700; } else if (inherited < 900) { return 900; } else { return inherited; } } private static int lighter(int inherited) { if (inherited < 100) { return inherited; } else if (inherited < 550) { return 100; } else if (inherited < 750) { return 400; } else { return 700; } } } static final double DEFAULT_FONT_SIZE = 12d; private static final double DEFAULT_KERNING = 0d; private static final double DEFAULT_WORD_SPACING = 0d; private static final double DEFAULT_LETTER_SPACING = 0d; private static final String KERNING = "kerning"; private static final String FONT_DATA = "fontData"; private static final String TEXT_ANCHOR = "textAnchor"; private static final String WORD_SPACING = "wordSpacing"; private static final String LETTER_SPACING = "letterSpacing"; private static final String TEXT_DECORATION = "textDecoration"; private static final String FONT_FEATURE_SETTINGS = "fontFeatureSettings"; private static final String FONT_VARIATION_SETTINGS = "fontVariationSettings"; private static final String FONT_VARIANT_LIGATURES = "fontVariantLigatures"; final double fontSize; final String fontFamily; final FontStyle fontStyle; final ReadableMap fontData; FontWeight fontWeight; int absoluteFontWeight; final String fontFeatureSettings; final String fontVariationSettings; final FontVariantLigatures fontVariantLigatures; final TextAnchor textAnchor; private final TextDecoration textDecoration; final double kerning; final double wordSpacing; final double letterSpacing; final boolean manualKerning; static final FontData Defaults = new FontData(); private FontData() { fontData = null; fontFamily = ""; fontStyle = FontStyle.normal; fontWeight = FontWeight.Normal; absoluteFontWeight = AbsoluteFontWeight.normal; fontFeatureSettings = ""; fontVariationSettings = ""; fontVariantLigatures = FontVariantLigatures.normal; textAnchor = TextAnchor.start; textDecoration = TextDecoration.None; manualKerning = false; kerning = DEFAULT_KERNING; fontSize = DEFAULT_FONT_SIZE; wordSpacing = DEFAULT_WORD_SPACING; letterSpacing = DEFAULT_LETTER_SPACING; } private double toAbsolute( ReadableMap font, String prop, double scale, double fontSize, double relative) { ReadableType propType = font.getType(prop); if (propType == ReadableType.Number) { return font.getDouble(prop) * scale; } else { String string = font.getString(prop); return PropHelper.fromRelative(string, relative, scale, fontSize); } } private void setInheritedWeight(FontData parent) { absoluteFontWeight = parent.absoluteFontWeight; fontWeight = parent.fontWeight; } private void handleNumericWeight(FontData parent, double number) { long weight = Math.round(number); if (weight >= 1 && weight <= 1000) { absoluteFontWeight = (int) weight; fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight); } else { setInheritedWeight(parent); } } FontData(ReadableMap font, FontData parent, double scale) { double parentFontSize = parent.fontSize; if (font.hasKey(FONT_SIZE)) { fontSize = toAbsolute(font, FONT_SIZE, 1, parentFontSize, parentFontSize); } else { fontSize = parentFontSize; } if (font.hasKey(FONT_WEIGHT)) { ReadableType fontWeightType = font.getType(FONT_WEIGHT); if (fontWeightType == ReadableType.Number) { handleNumericWeight(parent, font.getDouble(FONT_WEIGHT)); } else { String string = font.getString(FONT_WEIGHT); if (FontWeight.hasEnum(string)) { absoluteFontWeight = AbsoluteFontWeight.from(FontWeight.get(string), parent); fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight); } else if (string != null) { handleNumericWeight(parent, Double.parseDouble(string)); } else { setInheritedWeight(parent); } } } else { setInheritedWeight(parent); } fontData = font.hasKey(FONT_DATA) ? font.getMap(FONT_DATA) : parent.fontData; fontFamily = font.hasKey(FONT_FAMILY) ? font.getString(FONT_FAMILY) : parent.fontFamily; fontStyle = font.hasKey(FONT_STYLE) ? FontStyle.valueOf(font.getString(FONT_STYLE)) : parent.fontStyle; fontFeatureSettings = font.hasKey(FONT_FEATURE_SETTINGS) ? font.getString(FONT_FEATURE_SETTINGS) : parent.fontFeatureSettings; fontVariationSettings = font.hasKey(FONT_VARIATION_SETTINGS) ? font.getString(FONT_VARIATION_SETTINGS) : parent.fontVariationSettings; fontVariantLigatures = font.hasKey(FONT_VARIANT_LIGATURES) ? FontVariantLigatures.valueOf(font.getString(FONT_VARIANT_LIGATURES)) : parent.fontVariantLigatures; textAnchor = font.hasKey(TEXT_ANCHOR) ? TextAnchor.valueOf(font.getString(TEXT_ANCHOR)) : parent.textAnchor; textDecoration = font.hasKey(TEXT_DECORATION) ? TextDecoration.getEnum(font.getString(TEXT_DECORATION)) : parent.textDecoration; final boolean hasKerning = font.hasKey(KERNING); manualKerning = hasKerning || parent.manualKerning; // https://www.w3.org/TR/SVG11/text.html#SpacingProperties // https://drafts.csswg.org/css-text-3/#spacing // calculated values for units in: kerning, word-spacing, and, letter-spacing. kerning = hasKerning ? toAbsolute(font, KERNING, scale, fontSize, 0) : parent.kerning; wordSpacing = font.hasKey(WORD_SPACING) ? toAbsolute(font, WORD_SPACING, scale, fontSize, 0) : parent.wordSpacing; letterSpacing = font.hasKey(LETTER_SPACING) ? toAbsolute(font, LETTER_SPACING, scale, fontSize, 0) : parent.letterSpacing; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/ForeignObjectView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.view.View; import androidx.annotation.NonNull; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class ForeignObjectView extends GroupView { SVGLength mX; SVGLength mY; SVGLength mW; SVGLength mH; public ForeignObjectView(ReactContext reactContext) { super(reactContext); } @Override void draw(Canvas canvas, Paint paint, float opacity) { float x = (float) relativeOnWidth(mX); float y = (float) relativeOnHeight(mY); float w = (float) relativeOnWidth(mW); float h = (float) relativeOnHeight(mH); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); super.draw(canvas, paint, opacity); } @Override public void onDescendantInvalidated(@NonNull View child, @NonNull View target) { super.onDescendantInvalidated(child, target); invalidate(); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } @Override public void invalidate() { super.invalidate(); SvgView svgView = getSvgView(); if (svgView != null) { svgView.invalidate(); } } void drawGroup(final Canvas canvas, final Paint paint, final float opacity) { pushGlyphContext(); final SvgView svg = getSvgView(); final GroupView self = this; final RectF groupRect = new RectF(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof MaskView) { continue; } if (child instanceof VirtualView) { VirtualView node = ((VirtualView) child); if ("none".equals(node.mDisplay)) { continue; } if (node instanceof RenderableView) { ((RenderableView) node).mergeProperties(self); } int count = node.saveAndSetupCanvas(canvas, mCTM); node.render(canvas, paint, opacity * mOpacity); RectF r = node.getClientRect(); if (r != null) { groupRect.union(r); } node.restoreCanvas(canvas, count); if (node instanceof RenderableView) { ((RenderableView) node).resetProperties(); } if (node.isResponsible()) { svg.enableTouchEvents(); } } else if (child instanceof SvgView) { SvgView svgView = (SvgView) child; svgView.drawChildren(canvas); if (svgView.isResponsible()) { svg.enableTouchEvents(); } } else { // Enable rendering other native ancestor views in e.g. masks final int saveCount = canvas.save(); int left = child.getLeft(); int top = child.getTop(); canvas.translate(left, top); Matrix childMatrix = child.getMatrix(); if (!childMatrix.isIdentity()) { canvas.concat(childMatrix); } child.draw(canvas); canvas.restoreToCount(saveCount); } } this.setClientRect(groupRect); popGlyphContext(); } // Enable rendering other native ancestor views in e.g. masks, but don't render them another time Bitmap fakeBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas fake = new Canvas(fakeBitmap); @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(fake); } protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return super.drawChild(fake, child, drawingTime); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/GlyphContext.java ================================================ /* * 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. */ package com.horcrux.svg; import com.facebook.react.bridge.ReadableMap; import java.util.ArrayList; import javax.annotation.Nullable; // https://www.w3.org/TR/SVG/text.html#TSpanElement class GlyphContext { // Current stack (one per node push/pop) final ArrayList mFontContext = new ArrayList<>(); // Unique input attribute lists (only added if node sets a value) private final ArrayList mXsContext = new ArrayList<>(); private final ArrayList mYsContext = new ArrayList<>(); private final ArrayList mDXsContext = new ArrayList<>(); private final ArrayList mDYsContext = new ArrayList<>(); private final ArrayList mRsContext = new ArrayList<>(); // Unique index into attribute list (one per unique list) private final ArrayList mXIndices = new ArrayList<>(); private final ArrayList mYIndices = new ArrayList<>(); private final ArrayList mDXIndices = new ArrayList<>(); private final ArrayList mDYIndices = new ArrayList<>(); private final ArrayList mRIndices = new ArrayList<>(); // Index of unique context used (one per node push/pop) private final ArrayList mXsIndices = new ArrayList<>(); private final ArrayList mYsIndices = new ArrayList<>(); private final ArrayList mDXsIndices = new ArrayList<>(); private final ArrayList mDYsIndices = new ArrayList<>(); private final ArrayList mRsIndices = new ArrayList<>(); // Calculated on push context, percentage and em length depends on parent font size private double mFontSize = FontData.DEFAULT_FONT_SIZE; private FontData topFont = FontData.Defaults; // Current accumulated values // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate // syntax is the same as that for private double mX; private double mY; // https://www.w3.org/TR/SVG/types.html#Length private double mDX; private double mDY; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates // https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute private SVGLength[] mXs = new SVGLength[] {}; // https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute private SVGLength[] mYs = new SVGLength[] {}; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeLengths // https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute private SVGLength[] mDXs = new SVGLength[] {}; // https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute private SVGLength[] mDYs = new SVGLength[] {}; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeNumbers // https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute private double[] mRs = new double[] {0}; // Current attribute list index private int mXsIndex; private int mYsIndex; private int mDXsIndex; private int mDYsIndex; private int mRsIndex; // Current value index in current attribute list private int mXIndex = -1; private int mYIndex = -1; private int mDXIndex = -1; private int mDYIndex = -1; private int mRIndex = -1; // Top index of stack private int mTop; // Constructor parameters private final float mScale; private final float mWidth; private final float mHeight; private void pushIndices() { mXsIndices.add(mXsIndex); mYsIndices.add(mYsIndex); mDXsIndices.add(mDXsIndex); mDYsIndices.add(mDYsIndex); mRsIndices.add(mRsIndex); } GlyphContext(float scale, float width, float height) { mScale = scale; mWidth = width; mHeight = height; mXsContext.add(mXs); mYsContext.add(mYs); mDXsContext.add(mDXs); mDYsContext.add(mDYs); mRsContext.add(mRs); mXIndices.add(mXIndex); mYIndices.add(mYIndex); mDXIndices.add(mDXIndex); mDYIndices.add(mDYIndex); mRIndices.add(mRIndex); mFontContext.add(topFont); pushIndices(); } private void reset() { mXsIndex = mYsIndex = mDXsIndex = mDYsIndex = mRsIndex = 0; mXIndex = mYIndex = mDXIndex = mDYIndex = mRIndex = -1; mX = mY = mDX = mDY = 0; } FontData getFont() { return topFont; } private FontData getTopOrParentFont(GroupView child) { if (mTop > 0) { return topFont; } else { GroupView parentRoot = child.getParentTextRoot(); while (parentRoot != null) { FontData map = parentRoot.getGlyphContext().getFont(); if (map != FontData.Defaults) { return map; } parentRoot = parentRoot.getParentTextRoot(); } return FontData.Defaults; } } private void pushNodeAndFont(GroupView node, @Nullable ReadableMap font) { FontData parent = getTopOrParentFont(node); mTop++; if (font == null) { mFontContext.add(parent); return; } FontData data = new FontData(font, parent, mScale); mFontSize = data.fontSize; mFontContext.add(data); topFont = data; } void pushContext(GroupView node, @Nullable ReadableMap font) { pushNodeAndFont(node, font); pushIndices(); } private SVGLength[] getStringArrayFromReadableArray(ArrayList readableArray) { int size = readableArray.size(); SVGLength[] strings = new SVGLength[size]; for (int i = 0; i < size; i++) { strings[i] = readableArray.get(i); } return strings; } private double[] getDoubleArrayFromReadableArray(ArrayList readableArray) { int size = readableArray.size(); double[] doubles = new double[size]; for (int i = 0; i < size; i++) { SVGLength length = readableArray.get(i); doubles[i] = length.value; } return doubles; } void pushContext( boolean reset, TextView node, @Nullable ReadableMap font, @Nullable ArrayList x, @Nullable ArrayList y, @Nullable ArrayList deltaX, @Nullable ArrayList deltaY, @Nullable ArrayList rotate) { if (reset) { this.reset(); } pushNodeAndFont(node, font); if (x != null && x.size() != 0) { mXsIndex++; mXIndex = -1; mXIndices.add(mXIndex); mXs = getStringArrayFromReadableArray(x); mXsContext.add(mXs); } if (y != null && y.size() != 0) { mYsIndex++; mYIndex = -1; mYIndices.add(mYIndex); mYs = getStringArrayFromReadableArray(y); mYsContext.add(mYs); } if (deltaX != null && deltaX.size() != 0) { mDXsIndex++; mDXIndex = -1; mDXIndices.add(mDXIndex); mDXs = getStringArrayFromReadableArray(deltaX); mDXsContext.add(mDXs); } if (deltaY != null && deltaY.size() != 0) { mDYsIndex++; mDYIndex = -1; mDYIndices.add(mDYIndex); mDYs = getStringArrayFromReadableArray(deltaY); mDYsContext.add(mDYs); } if (rotate != null && rotate.size() != 0) { mRsIndex++; mRIndex = -1; mRIndices.add(mRIndex); mRs = getDoubleArrayFromReadableArray(rotate); mRsContext.add(mRs); } pushIndices(); } void popContext() { mFontContext.remove(mTop); mXsIndices.remove(mTop); mYsIndices.remove(mTop); mDXsIndices.remove(mTop); mDYsIndices.remove(mTop); mRsIndices.remove(mTop); mTop--; int x = mXsIndex; int y = mYsIndex; int dx = mDXsIndex; int dy = mDYsIndex; int r = mRsIndex; topFont = mFontContext.get(mTop); mXsIndex = mXsIndices.get(mTop); mYsIndex = mYsIndices.get(mTop); mDXsIndex = mDXsIndices.get(mTop); mDYsIndex = mDYsIndices.get(mTop); mRsIndex = mRsIndices.get(mTop); if (x != mXsIndex) { mXsContext.remove(x); mXs = mXsContext.get(mXsIndex); mXIndex = mXIndices.get(mXsIndex); } if (y != mYsIndex) { mYsContext.remove(y); mYs = mYsContext.get(mYsIndex); mYIndex = mYIndices.get(mYsIndex); } if (dx != mDXsIndex) { mDXsContext.remove(dx); mDXs = mDXsContext.get(mDXsIndex); mDXIndex = mDXIndices.get(mDXsIndex); } if (dy != mDYsIndex) { mDYsContext.remove(dy); mDYs = mDYsContext.get(mDYsIndex); mDYIndex = mDYIndices.get(mDYsIndex); } if (r != mRsIndex) { mRsContext.remove(r); mRs = mRsContext.get(mRsIndex); mRIndex = mRIndices.get(mRsIndex); } } private static void incrementIndices(ArrayList indices, int topIndex) { for (int index = topIndex; index >= 0; index--) { int xIndex = indices.get(index); indices.set(index, xIndex + 1); } } // https://www.w3.org/TR/SVG11/text.html#FontSizeProperty /** * Get font size from context. * *

‘font-size’ Value: < absolute-size > | < relative-size > | < length > | < percentage > | * inherit Initial: medium Applies to: text content elements Inherited: yes, the computed value is * inherited Percentages: refer to parent element's font size Media: visual Animatable: yes * *

This property refers to the size of the font from baseline to baseline when multiple lines * of text are set solid in a multiline layout environment. * *

For SVG, if a < length > is provided without a unit identifier (e.g., an unqualified number * such as 128), the SVG user agent processes the < length > as a height value in the current user * coordinate system. * *

If a < length > is provided with one of the unit identifiers (e.g., 12pt or 10%), then the * SVG user agent converts the < length > into a corresponding value in the current user * coordinate system by applying the rules described in Units. * *

Except for any additional information provided in this specification, the normative * definition of the property is in CSS2 ([CSS2], section 15.2.4). */ double getFontSize() { return mFontSize; } double nextX(double advance) { incrementIndices(mXIndices, mXsIndex); int nextIndex = mXIndex + 1; if (nextIndex < mXs.length) { mDX = 0; mXIndex = nextIndex; SVGLength string = mXs[nextIndex]; mX = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize); } mX += advance; return mX; } double nextY() { incrementIndices(mYIndices, mYsIndex); int nextIndex = mYIndex + 1; if (nextIndex < mYs.length) { mDY = 0; mYIndex = nextIndex; SVGLength string = mYs[nextIndex]; mY = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize); } return mY; } double nextDeltaX() { incrementIndices(mDXIndices, mDXsIndex); int nextIndex = mDXIndex + 1; if (nextIndex < mDXs.length) { mDXIndex = nextIndex; SVGLength string = mDXs[nextIndex]; double val = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize); mDX += val; } return mDX; } double nextDeltaY() { incrementIndices(mDYIndices, mDYsIndex); int nextIndex = mDYIndex + 1; if (nextIndex < mDYs.length) { mDYIndex = nextIndex; SVGLength string = mDYs[nextIndex]; double val = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize); mDY += val; } return mDY; } double nextRotation() { incrementIndices(mRIndices, mRsIndex); mRIndex = Math.min(mRIndex + 1, mRs.length - 1); return mRs[mRIndex]; } float getWidth() { return mWidth; } float getHeight() { return mHeight; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/GlyphPathBag.java ================================================ package com.horcrux.svg; import android.graphics.Paint; import android.graphics.Path; import java.util.ArrayList; class GlyphPathBag { private final ArrayList paths = new ArrayList<>(); private final int[][] data = new int[256][]; private final Paint paint; GlyphPathBag(Paint paint) { this.paint = paint; // Make indexed-by-one, to allow zero to represent non-cached paths.add(new Path()); } Path getOrCreateAndCache(char ch, String current) { int index = getIndex(ch); Path cached; if (index != 0) { cached = paths.get(index); } else { cached = new Path(); paint.getTextPath(current, 0, 1, 0, 0, cached); int[] bin = data[ch >> 8]; if (bin == null) { bin = data[ch >> 8] = new int[256]; } bin[ch & 0xFF] = paths.size(); paths.add(cached); } Path glyph = new Path(); glyph.addPath(cached); return glyph; } private int getIndex(char ch) { int[] bin = data[ch >> 8]; if (bin == null) return 0; return bin[ch & 0xFF]; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/GroupView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Build; import android.view.View; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import java.util.ArrayList; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class GroupView extends RenderableView { @Nullable ReadableMap mFont; private GlyphContext mGlyphContext; private Bitmap mLayerBitmap; private Canvas mLayerCanvas; private final Paint mLayerPaint; public GroupView(ReactContext reactContext) { super(reactContext); mLayerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } public void setFont(Dynamic dynamic) { if (dynamic.getType() == ReadableType.Map) { mFont = dynamic.asMap(); } else { mFont = null; } invalidate(); } public void setFont(@Nullable ReadableMap font) { mFont = font; invalidate(); } void setupGlyphContext(Canvas canvas) { RectF clipBounds = new RectF(canvas.getClipBounds()); if (mMatrix != null) { mMatrix.mapRect(clipBounds); } mGlyphContext = new GlyphContext(mScale, clipBounds.width(), clipBounds.height()); } GlyphContext getGlyphContext() { return mGlyphContext; } private static T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } GlyphContext getTextRootGlyphContext() { return requireNonNull(getTextRoot()).getGlyphContext(); } void pushGlyphContext() { getTextRootGlyphContext().pushContext(this, mFont); } void popGlyphContext() { getTextRootGlyphContext().popContext(); } void draw(final Canvas canvas, final Paint paint, final float opacity) { setupGlyphContext(canvas); clip(canvas, paint); drawGroup(canvas, paint, opacity); renderMarkers(canvas, paint, opacity); } void drawGroup(final Canvas canvas, final Paint paint, final float opacity) { pushGlyphContext(); final SvgView svg = getSvgView(); final GroupView self = this; final RectF groupRect = new RectF(); if (mOpacity != 1) { if (mLayerBitmap == null) { mLayerBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); mLayerCanvas = new Canvas(mLayerBitmap); } else { mLayerBitmap.recycle(); mLayerBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); mLayerCanvas.setBitmap(mLayerBitmap); } // Copy current matrix from original canvas mLayerCanvas.save(); mLayerCanvas.setMatrix(canvas.getMatrix()); } else { mLayerCanvas = canvas; } elements = new ArrayList<>(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof MaskView || child instanceof ClipPathView) { ((RenderableView) child).mergeProperties(self); continue; } if (child instanceof VirtualView) { VirtualView node = ((VirtualView) child); if ("none".equals(node.mDisplay)) { continue; } if (node instanceof RenderableView) { ((RenderableView) node).mergeProperties(self); } int count = node.saveAndSetupCanvas(mLayerCanvas, mCTM); node.render(mLayerCanvas, paint, opacity); RectF r = node.getClientRect(); if (r != null) { groupRect.union(r); } node.restoreCanvas(mLayerCanvas, count); if (node instanceof RenderableView) { ((RenderableView) node).resetProperties(); } if (node.isResponsible()) { svg.enableTouchEvents(); } if (node.elements != null) { elements.addAll(node.elements); } } else if (child instanceof SvgView) { SvgView svgView = (SvgView) child; // Merge properties with inner Svg element. if (svgView.getChildCount() > 0) { View viewNode = svgView.getChildAt(0); if (viewNode instanceof GroupView) { ((GroupView) viewNode).mergeProperties(self); } } svgView.drawChildren(canvas); if (svgView.isResponsible()) { svg.enableTouchEvents(); } } } if (mOpacity != 1) { // Restore copied canvas and temporary reset original canvas matrix to draw bitmap 1:1 mLayerCanvas.restore(); int saveCount = canvas.save(); canvas.setMatrix(null); mLayerPaint.setAlpha((int) (mOpacity * 255)); if (mLayerBitmap != null) { canvas.drawBitmap(mLayerBitmap, 0, 0, mLayerPaint); } canvas.restoreToCount(saveCount); } this.setClientRect(groupRect); popGlyphContext(); } void drawPath(Canvas canvas, Paint paint, float opacity) { super.draw(canvas, paint, opacity); } @Override Path getPath(final Canvas canvas, final Paint paint) { if (mPath != null) { return mPath; } mPath = new Path(); for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof MaskView) { continue; } if (node instanceof VirtualView) { VirtualView n = (VirtualView) node; Matrix transform = n.mMatrix; Path path = n.getPath(canvas, paint); if (path != null) { mPath.addPath(path, transform); } } } return mPath; } Path getPath(final Canvas canvas, final Paint paint, final Region.Op op) { final Path path = new Path(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { final Path.Op pop = Path.Op.valueOf(op.name()); for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof MaskView) { continue; } if (node instanceof VirtualView) { VirtualView n = (VirtualView) node; Matrix transform = n.mMatrix; Path p2; if (n instanceof GroupView) { p2 = ((GroupView) n).getPath(canvas, paint, op); } else { p2 = n.getPath(canvas, paint); } p2.transform(transform); path.op(p2, pop); } } } else { Rect clipBounds = canvas.getClipBounds(); final Region bounds = new Region(clipBounds); final Region r = new Region(); for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof MaskView) { continue; } if (node instanceof VirtualView) { VirtualView n = (VirtualView) node; Matrix transform = n.mMatrix; Path p2; if (n instanceof GroupView) { p2 = ((GroupView) n).getPath(canvas, paint, op); } else { p2 = n.getPath(canvas, paint); } if (transform != null) { p2.transform(transform); } Region r2 = new Region(); r2.setPath(p2, bounds); r.op(r2, op); } } path.addPath(r.getBoundaryPath()); } return path; } @Override int hitTest(final float[] src) { if (!mInvertible) { return -1; } float[] dst = new float[2]; mInvMatrix.mapPoints(dst, src); int x = Math.round(dst[0]); int y = Math.round(dst[1]); Path clipPath = getClipPath(); if (clipPath != null) { if (mClipRegionPath != clipPath) { mClipRegionPath = clipPath; mClipBounds = new RectF(); clipPath.computeBounds(mClipBounds, true); mClipRegion = getRegion(clipPath, mClipBounds); } if (!mClipRegion.contains(x, y)) { return -1; } } for (int i = getChildCount() - 1; i >= 0; i--) { View child = getChildAt(i); if (child instanceof VirtualView) { if (child instanceof MaskView) { continue; } VirtualView node = (VirtualView) child; int hitChild = node.hitTest(dst); if (hitChild != -1) { return (node.isResponsible() || hitChild != child.getId()) ? hitChild : getId(); } } else if (child instanceof SvgView) { SvgView node = (SvgView) child; int hitChild = node.reactTagForTouch(dst[0], dst[1]); if (hitChild != child.getId()) { return hitChild; } } } return -1; } void saveDefinition() { if (mName != null) { getSvgView().defineTemplate(this, mName); } for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof VirtualView) { ((VirtualView) node).saveDefinition(); } } } @Override void resetProperties() { for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof RenderableView) { ((RenderableView) node).resetProperties(); } } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/ImageView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.net.Uri; import com.facebook.common.executors.UiThreadImmediateExecutorService; import com.facebook.common.logging.FLog; import com.facebook.common.references.CloseableReference; import com.facebook.datasource.DataSource; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; import com.facebook.imagepipeline.image.CloseableBitmap; import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.imagehelper.ImageSource; import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; import com.horcrux.svg.events.SvgLoadEvent; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nonnull; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class ImageView extends RenderableView { private SVGLength mX; private SVGLength mY; private SVGLength mW; private SVGLength mH; private String uriString; private int mImageWidth; private int mImageHeight; private String mAlign; private int mMeetOrSlice; private final AtomicBoolean mLoading = new AtomicBoolean(false); public ImageView(ReactContext reactContext) { super(reactContext); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } public void setSrc(@Nullable ReadableMap src) { if (src != null) { uriString = src.getString("uri"); if (uriString == null || uriString.isEmpty()) { // TODO: give warning about this return; } if (src.hasKey("width") && src.hasKey("height")) { mImageWidth = src.getInt("width"); mImageHeight = src.getInt("height"); } else { mImageWidth = 0; mImageHeight = 0; } Uri mUri = Uri.parse(uriString); if (mUri.getScheme() == null) { ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(mContext, uriString); } } } public void setAlign(String align) { mAlign = align; invalidate(); } public void setMeetOrSlice(int meetOrSlice) { mMeetOrSlice = meetOrSlice; invalidate(); } @Override void draw(final Canvas canvas, final Paint paint, final float opacity) { if (!mLoading.get()) { ImagePipeline imagePipeline = Fresco.getImagePipeline(); ImageSource imageSource = new ImageSource(mContext, uriString); ImageRequest request = ImageRequest.fromUri(imageSource.getUri()); boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(request); if (inMemoryCache) { tryRenderFromBitmapCache(imagePipeline, request, canvas, paint, opacity * mOpacity); } else { loadBitmap(imagePipeline, request); } } } @Override Path getPath(Canvas canvas, Paint paint) { mPath = new Path(); mPath.addRect(getRect(), Path.Direction.CW); return mPath; } private void loadBitmap(final ImagePipeline imagePipeline, final ImageRequest request) { mLoading.set(true); final DataSource> dataSource = imagePipeline.fetchDecodedImage(request, mContext); BaseBitmapDataSubscriber subscriber = new BaseBitmapDataSubscriber() { @Override public void onNewResultImpl(Bitmap bitmap) { final EventDispatcher mEventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(mContext, getId()); mEventDispatcher.dispatchEvent( new SvgLoadEvent( UIManagerHelper.getSurfaceId(ImageView.this), getId(), mContext, uriString, bitmap.getWidth(), bitmap.getHeight())); mLoading.set(false); SvgView view = getSvgView(); if (view != null) { view.invalidate(); } } @Override public void onFailureImpl(DataSource dataSource) { // No cleanup required here. // TODO: more details about this failure mLoading.set(false); FLog.w( ReactConstants.TAG, dataSource.getFailureCause(), "RNSVG: fetchDecodedImage failed!"); } }; dataSource.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance()); } @Nonnull private RectF getRect() { double x = relativeOnWidth(mX); double y = relativeOnHeight(mY); double w = relativeOnWidth(mW); double h = relativeOnHeight(mH); if (w == 0) { w = mImageWidth * mScale; } if (h == 0) { h = mImageHeight * mScale; } return new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)); } private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) { if (mImageWidth == 0 || mImageHeight == 0) { mImageWidth = bitmap.getWidth(); mImageHeight = bitmap.getHeight(); } RectF renderRect = getRect(); RectF vbRect = new RectF(0, 0, mImageWidth, mImageHeight); Matrix transform = ViewBox.getTransform(vbRect, renderRect, mAlign, mMeetOrSlice); transform.mapRect(vbRect); canvas.clipPath(getPath(canvas, paint)); Path clipPath = getClipPath(canvas, paint); if (clipPath != null) { canvas.clipPath(clipPath); } Paint alphaPaint = new Paint(); alphaPaint.setAlpha((int) (opacity * 255)); canvas.drawBitmap(bitmap, null, vbRect, alphaPaint); mCTM.mapRect(vbRect); this.setClientRect(vbRect); } private void tryRenderFromBitmapCache( ImagePipeline imagePipeline, ImageRequest request, Canvas canvas, Paint paint, float opacity) { final DataSource> dataSource = imagePipeline.fetchImageFromBitmapCache(request, mContext); try { final CloseableReference imageReference = dataSource.getResult(); if (imageReference == null) { return; } try { CloseableImage closeableImage = imageReference.get(); if (!(closeableImage instanceof CloseableBitmap)) { return; } CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage; final Bitmap bitmap = closeableBitmap.getUnderlyingBitmap(); if (bitmap == null) { return; } doRender(canvas, paint, bitmap, opacity); } catch (Exception e) { throw new IllegalStateException(e); } finally { CloseableReference.closeSafely(imageReference); } } catch (Exception e) { throw new IllegalStateException(e); } finally { dataSource.close(); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/LineView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.ArrayList; @SuppressLint("ViewConstructor") class LineView extends RenderableView { private SVGLength mX1; private SVGLength mY1; private SVGLength mX2; private SVGLength mY2; public LineView(ReactContext reactContext) { super(reactContext); } public void setX1(Dynamic x1) { mX1 = SVGLength.from(x1); invalidate(); } public void setY1(Dynamic y1) { mY1 = SVGLength.from(y1); invalidate(); } public void setX2(Dynamic x2) { mX2 = SVGLength.from(x2); invalidate(); } public void setY2(Dynamic y2) { mY2 = SVGLength.from(y2); invalidate(); } @Override Path getPath(Canvas canvas, Paint paint) { Path path = new Path(); double x1 = relativeOnWidth(mX1); double y1 = relativeOnHeight(mY1); double x2 = relativeOnWidth(mX2); double y2 = relativeOnHeight(mY2); path.moveTo((float) x1, (float) y1); path.lineTo((float) x2, (float) y2); elements = new ArrayList<>(); elements.add( new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x1, y1)})); elements.add( new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x2, y2)})); return path; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/LinearGradientView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Matrix; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class LinearGradientView extends DefinitionView { private SVGLength mX1; private SVGLength mY1; private SVGLength mX2; private SVGLength mY2; private ReadableArray mGradient; private Brush.BrushUnits mGradientUnits; private static final float[] sRawMatrix = new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; private Matrix mMatrix = null; public LinearGradientView(ReactContext reactContext) { super(reactContext); } public void setX1(Dynamic x1) { mX1 = SVGLength.from(x1); invalidate(); } public void setY1(Dynamic y1) { mY1 = SVGLength.from(y1); invalidate(); } public void setX2(Dynamic x2) { mX2 = SVGLength.from(x2); invalidate(); } public void setY2(Dynamic y2) { mY2 = SVGLength.from(y2); invalidate(); } public void setGradient(ReadableArray gradient) { mGradient = gradient; invalidate(); } public void setGradientUnits(int gradientUnits) { switch (gradientUnits) { case 0: mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public void setGradientTransform(@Nullable ReadableArray matrixArray) { if (matrixArray != null) { int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); if (matrixSize == 6) { if (mMatrix == null) { mMatrix = new Matrix(); } mMatrix.setValues(sRawMatrix); } else if (matrixSize != -1) { FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); } } else { mMatrix = null; } invalidate(); } @Override void saveDefinition() { if (mName != null) { SVGLength[] points = new SVGLength[] {mX1, mY1, mX2, mY2}; Brush brush = new Brush(Brush.BrushType.LINEAR_GRADIENT, points, mGradientUnits); brush.setGradientColors(mGradient); if (mMatrix != null) { brush.setGradientTransform(mMatrix); } SvgView svg = getSvgView(); if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); } svg.defineBrush(brush, mName); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/MarkerView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.view.View; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class MarkerView extends GroupView { private SVGLength mRefX; private SVGLength mRefY; private SVGLength mMarkerWidth; private SVGLength mMarkerHeight; private String mMarkerUnits; private String mOrient; private float mMinX; private float mMinY; private float mVbWidth; private float mVbHeight; String mAlign; int mMeetOrSlice; Matrix markerTransform = new Matrix(); public MarkerView(ReactContext reactContext) { super(reactContext); } public void setRefX(Dynamic refX) { mRefX = SVGLength.from(refX); invalidate(); } public void setRefY(Dynamic refY) { mRefY = SVGLength.from(refY); invalidate(); } public void setMarkerWidth(Dynamic markerWidth) { mMarkerWidth = SVGLength.from(markerWidth); invalidate(); } public void setMarkerHeight(Dynamic markerHeight) { mMarkerHeight = SVGLength.from(markerHeight); invalidate(); } public void setMarkerUnits(String markerUnits) { mMarkerUnits = markerUnits; invalidate(); } public void setOrient(String orient) { mOrient = orient; invalidate(); } public void setMinX(float minX) { mMinX = minX; invalidate(); } public void setMinY(float minY) { mMinY = minY; invalidate(); } public void setVbWidth(float vbWidth) { mVbWidth = vbWidth; invalidate(); } public void setVbHeight(float vbHeight) { mVbHeight = vbHeight; invalidate(); } public void setAlign(String align) { mAlign = align; invalidate(); } public void setMeetOrSlice(int meetOrSlice) { mMeetOrSlice = meetOrSlice; invalidate(); } @Override void saveDefinition() { if (mName != null) { SvgView svg = getSvgView(); svg.defineMarker(this, mName); for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof VirtualView) { ((VirtualView) node).saveDefinition(); } } } } void renderMarker( Canvas canvas, Paint paint, float opacity, RNSVGMarkerPosition position, float strokeWidth) { int count = saveAndSetupCanvas(canvas, mCTM); markerTransform.reset(); Point origin = position.origin; markerTransform.setTranslate((float) origin.x, (float) origin.y); double markerAngle = "auto".equals(mOrient) ? -1 : Double.parseDouble(mOrient); float degrees = 180 + (float) (markerAngle == -1 ? position.angle : markerAngle); markerTransform.preRotate(degrees); boolean useStrokeWidth = "strokeWidth".equals(mMarkerUnits); if (useStrokeWidth) { markerTransform.preScale(strokeWidth / mScale, strokeWidth / mScale); } double width = relativeOnWidth(mMarkerWidth); double height = relativeOnHeight(mMarkerHeight); RectF eRect = new RectF(0, 0, (float) width, (float) height); if (mAlign != null) { RectF vbRect = new RectF( mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); float[] values = new float[9]; viewBoxMatrix.getValues(values); markerTransform.preScale(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]); } double x = relativeOnWidth(mRefX); double y = relativeOnHeight(mRefY); markerTransform.preTranslate((float) -x, (float) -y); canvas.concat(markerTransform); drawGroup(canvas, paint, opacity); restoreCanvas(canvas, count); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/MaskView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class MaskView extends GroupView { SVGLength mX; SVGLength mY; SVGLength mW; SVGLength mH; // TODO implement proper support for units @SuppressWarnings({"FieldCanBeLocal", "unused"}) private Brush.BrushUnits mMaskUnits; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private Brush.BrushUnits mMaskContentUnits; MaskType mMaskType; enum MaskType { LUMINANCE, ALPHA } public MaskView(ReactContext reactContext) { super(reactContext); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } public Brush.BrushUnits getMaskUnits() { return mMaskUnits; } public void setMaskUnits(int maskUnits) { switch (maskUnits) { case 0: mMaskUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mMaskUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public void setMaskContentUnits(int maskContentUnits) { switch (maskContentUnits) { case 0: mMaskContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mMaskContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public MaskType getMaskType() { return mMaskType; } public void setMaskType(int maskType) { switch (maskType) { case 0: mMaskType = MaskType.LUMINANCE; break; case 1: mMaskType = MaskType.ALPHA; break; } invalidate(); } @Override void saveDefinition() { if (mName != null) { SvgView svg = getSvgView(); svg.defineMask(this, mName); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/PathParser.java ================================================ package com.horcrux.svg; import android.graphics.Path; import android.graphics.RectF; import java.util.ArrayList; class PathElement { ElementType type; Point[] points; PathElement(ElementType type, Point[] points) { this.type = type; this.points = points; } } class PathParser { static float mScale; private static int i; private static int l; private static String s; private static Path mPath; static ArrayList elements; private static float mPenX; private static float mPenY; private static float mPivotX; private static float mPivotY; private static float mPenDownX; private static float mPenDownY; private static boolean mPenDown; static Path parse(String d) { elements = new ArrayList<>(); mPath = new Path(); if (d == null) { return mPath; } char prev_cmd = ' '; l = d.length(); s = d; i = 0; mPenX = 0f; mPenY = 0f; mPivotX = 0f; mPivotY = 0f; mPenDownX = 0f; mPenDownY = 0f; mPenDown = false; while (i < l) { skip_spaces(); if (i >= l) { break; } boolean has_prev_cmd = prev_cmd != ' '; char first_char = s.charAt(i); if (!has_prev_cmd && first_char != 'M' && first_char != 'm') { // The first segment must be a MoveTo. throw new IllegalArgumentException( String.format("Unexpected character '%c' (i=%d, s=%s)", first_char, i, s)); } // TODO: simplify boolean is_implicit_move_to; char cmd; if (is_cmd(first_char)) { is_implicit_move_to = false; cmd = first_char; i += 1; } else if (is_number_start(first_char) && has_prev_cmd) { if (prev_cmd == 'Z' || prev_cmd == 'z') { // ClosePath cannot be followed by a number. throw new IllegalArgumentException( String.format("Unexpected number after 'z' (s=%s)", s)); } if (prev_cmd == 'M' || prev_cmd == 'm') { // 'If a moveto is followed by multiple pairs of coordinates, // the subsequent pairs are treated as implicit lineto commands.' // So we parse them as LineTo. is_implicit_move_to = true; if (is_absolute(prev_cmd)) { cmd = 'L'; } else { cmd = 'l'; } } else { is_implicit_move_to = false; cmd = prev_cmd; } } else { throw new IllegalArgumentException( String.format("Unexpected character '%c' (i=%d, s=%s)", first_char, i, s)); } boolean absolute = is_absolute(cmd); switch (cmd) { case 'm': { move(parse_list_number(), parse_list_number()); break; } case 'M': { moveTo(parse_list_number(), parse_list_number()); break; } case 'l': { line(parse_list_number(), parse_list_number()); break; } case 'L': { lineTo(parse_list_number(), parse_list_number()); break; } case 'h': { line(parse_list_number(), 0); break; } case 'H': { lineTo(parse_list_number(), mPenY); break; } case 'v': { line(0, parse_list_number()); break; } case 'V': { lineTo(mPenX, parse_list_number()); break; } case 'c': { curve( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 'C': { curveTo( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 's': { smoothCurve( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 'S': { smoothCurveTo( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 'q': { quadraticBezierCurve( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 'Q': { quadraticBezierCurveTo( parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number()); break; } case 't': { smoothQuadraticBezierCurve(parse_list_number(), parse_list_number()); break; } case 'T': { smoothQuadraticBezierCurveTo(parse_list_number(), parse_list_number()); break; } case 'a': { arc( parse_list_number(), parse_list_number(), parse_list_number(), parse_flag(), parse_flag(), parse_list_number(), parse_list_number()); break; } case 'A': { arcTo( parse_list_number(), parse_list_number(), parse_list_number(), parse_flag(), parse_flag(), parse_list_number(), parse_list_number()); break; } case 'z': case 'Z': { close(); break; } default: { throw new IllegalArgumentException( String.format("Unexpected comand '%c' (s=%s)", cmd, s)); } } if (is_implicit_move_to) { if (absolute) { prev_cmd = 'M'; } else { prev_cmd = 'm'; } } else { prev_cmd = cmd; } } return mPath; } private static void move(float x, float y) { moveTo(x + mPenX, y + mPenY); } private static void moveTo(float x, float y) { // FLog.w(ReactConstants.TAG, "move x: " + x + " y: " + y); mPenDownX = mPivotX = mPenX = x; mPenDownY = mPivotY = mPenY = y; mPath.moveTo(x * mScale, y * mScale); elements.add( new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x, y)})); } private static void line(float x, float y) { lineTo(x + mPenX, y + mPenY); } private static void lineTo(float x, float y) { // FLog.w(ReactConstants.TAG, "line x: " + x + " y: " + y); setPenDown(); mPivotX = mPenX = x; mPivotY = mPenY = y; mPath.lineTo(x * mScale, y * mScale); elements.add( new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y)})); } private static void curve(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { curveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY, ex + mPenX, ey + mPenY); } private static void curveTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { // FLog.w(ReactConstants.TAG, "curve c1x: " + c1x + " c1y: " + c1y + "ex: " + ex + " ey: " + // ey); mPivotX = c2x; mPivotY = c2y; cubicTo(c1x, c1y, c2x, c2y, ex, ey); } private static void cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { setPenDown(); mPenX = ex; mPenY = ey; mPath.cubicTo(c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale, ey * mScale); elements.add( new PathElement( ElementType.kCGPathElementAddCurveToPoint, new Point[] {new Point(c1x, c1y), new Point(c2x, c2y), new Point(ex, ey)})); } private static void smoothCurve(float c1x, float c1y, float ex, float ey) { smoothCurveTo(c1x + mPenX, c1y + mPenY, ex + mPenX, ey + mPenY); } private static void smoothCurveTo(float c1x, float c1y, float ex, float ey) { // FLog.w(ReactConstants.TAG, "smoothcurve c1x: " + c1x + " c1y: " + c1y + "ex: " + ex + " ey: " // + ey); float c2x = c1x; float c2y = c1y; c1x = (mPenX * 2) - mPivotX; c1y = (mPenY * 2) - mPivotY; mPivotX = c2x; mPivotY = c2y; cubicTo(c1x, c1y, c2x, c2y, ex, ey); } private static void quadraticBezierCurve(float c1x, float c1y, float c2x, float c2y) { quadraticBezierCurveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY); } private static void quadraticBezierCurveTo(float c1x, float c1y, float c2x, float c2y) { // FLog.w(ReactConstants.TAG, "quad c1x: " + c1x + " c1y: " + c1y + "c2x: " + c2x + " c2y: " + // c2y); mPivotX = c1x; mPivotY = c1y; float ex = c2x; float ey = c2y; c2x = (ex + c1x * 2) / 3; c2y = (ey + c1y * 2) / 3; c1x = (mPenX + c1x * 2) / 3; c1y = (mPenY + c1y * 2) / 3; cubicTo(c1x, c1y, c2x, c2y, ex, ey); } private static void smoothQuadraticBezierCurve(float c1x, float c1y) { smoothQuadraticBezierCurveTo(c1x + mPenX, c1y + mPenY); } private static void smoothQuadraticBezierCurveTo(float c1x, float c1y) { // FLog.w(ReactConstants.TAG, "smoothquad c1x: " + c1x + " c1y: " + c1y); float c2x = c1x; float c2y = c1y; c1x = (mPenX * 2) - mPivotX; c1y = (mPenY * 2) - mPivotY; quadraticBezierCurveTo(c1x, c1y, c2x, c2y); } private static void arc( float rx, float ry, float rotation, boolean outer, boolean clockwise, float x, float y) { arcTo(rx, ry, rotation, outer, clockwise, x + mPenX, y + mPenY); } private static void arcTo( float rx, float ry, float rotation, boolean outer, boolean clockwise, float x, float y) { // FLog.w(ReactConstants.TAG, "arc rx: " + rx + " ry: " + ry + " rotation: " + rotation + " // outer: " + outer + " clockwise: " + clockwise + " x: " + x + " y: " + y); float tX = mPenX; float tY = mPenY; ry = Math.abs(ry == 0 ? (rx == 0 ? (y - tY) : rx) : ry); rx = Math.abs(rx == 0 ? (x - tX) : rx); if (rx == 0 || ry == 0 || (x == tX && y == tY)) { lineTo(x, y); return; } float rad = (float) Math.toRadians(rotation); float cos = (float) Math.cos(rad); float sin = (float) Math.sin(rad); x -= tX; y -= tY; // Ellipse Center float cx = cos * x / 2 + sin * y / 2; float cy = -sin * x / 2 + cos * y / 2; float rxry = rx * rx * ry * ry; float rycx = ry * ry * cx * cx; float rxcy = rx * rx * cy * cy; float a = rxry - rxcy - rycx; if (a < 0) { a = (float) Math.sqrt(1 - a / rxry); rx *= a; ry *= a; cx = x / 2; cy = y / 2; } else { a = (float) Math.sqrt(a / (rxcy + rycx)); if (outer == clockwise) { a = -a; } float cxd = -a * cy * rx / ry; float cyd = a * cx * ry / rx; cx = cos * cxd - sin * cyd + x / 2; cy = sin * cxd + cos * cyd + y / 2; } // Rotation + Scale Transform float xx = cos / rx; float yx = sin / rx; float xy = -sin / ry; float yy = cos / ry; // Start and End Angle float sa = (float) Math.atan2(xy * -cx + yy * -cy, xx * -cx + yx * -cy); float ea = (float) Math.atan2(xy * (x - cx) + yy * (y - cy), xx * (x - cx) + yx * (y - cy)); cx += tX; cy += tY; x += tX; y += tY; setPenDown(); mPenX = mPivotX = x; mPenY = mPivotY = y; if (rx != ry || rad != 0f) { arcToBezier(cx, cy, rx, ry, sa, ea, clockwise, rad); } else { float start = (float) Math.toDegrees(sa); float end = (float) Math.toDegrees(ea); float sweep = Math.abs((start - end) % 360); if (outer) { if (sweep < 180) { sweep = 360 - sweep; } } else { if (sweep > 180) { sweep = 360 - sweep; } } if (!clockwise) { sweep = -sweep; } RectF oval = new RectF((cx - rx) * mScale, (cy - rx) * mScale, (cx + rx) * mScale, (cy + rx) * mScale); mPath.arcTo(oval, start, sweep); elements.add( new PathElement( ElementType.kCGPathElementAddCurveToPoint, new Point[] {new Point(x, y)})); } } private static void close() { if (mPenDown) { mPenX = mPenDownX; mPenY = mPenDownY; mPenDown = false; mPath.close(); elements.add( new PathElement( ElementType.kCGPathElementCloseSubpath, new Point[] {new Point(mPenX, mPenY)})); } } private static void arcToBezier( float cx, float cy, float rx, float ry, float sa, float ea, boolean clockwise, float rad) { // Inverse Rotation + Scale Transform float cos = (float) Math.cos(rad); float sin = (float) Math.sin(rad); float xx = cos * rx; float yx = -sin * ry; float xy = sin * rx; float yy = cos * ry; // Bezier Curve Approximation float arc = ea - sa; if (arc < 0 && clockwise) { arc += Math.PI * 2; } else if (arc > 0 && !clockwise) { arc -= Math.PI * 2; } int n = (int) Math.ceil(Math.abs(round(arc / (Math.PI / 2)))); float step = arc / n; float k = (float) ((4 / 3.0) * Math.tan(step / 4)); float x = (float) Math.cos(sa); float y = (float) Math.sin(sa); for (int i = 0; i < n; i++) { float cp1x = x - k * y; float cp1y = y + k * x; sa += step; x = (float) Math.cos(sa); y = (float) Math.sin(sa); float cp2x = x + k * y; float cp2y = y - k * x; float c1x = (cx + xx * cp1x + yx * cp1y); float c1y = (cy + xy * cp1x + yy * cp1y); float c2x = (cx + xx * cp2x + yx * cp2y); float c2y = (cy + xy * cp2x + yy * cp2y); float ex = (cx + xx * x + yx * y); float ey = (cy + xy * x + yy * y); mPath.cubicTo( c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale, ey * mScale); elements.add( new PathElement( ElementType.kCGPathElementAddCurveToPoint, new Point[] {new Point(c1x, c1y), new Point(c2x, c2y), new Point(ex, ey)})); } } private static void setPenDown() { if (!mPenDown) { mPenDownX = mPenX; mPenDownY = mPenY; mPenDown = true; } } private static double round(double val) { double multiplier = Math.pow(10, 4); return Math.round(val * multiplier) / multiplier; } private static void skip_spaces() { while (i < l && Character.isWhitespace(s.charAt(i))) i++; } private static boolean is_cmd(char c) { switch (c) { case 'M': case 'm': case 'Z': case 'z': case 'L': case 'l': case 'H': case 'h': case 'V': case 'v': case 'C': case 'c': case 'S': case 's': case 'Q': case 'q': case 'T': case 't': case 'A': case 'a': return true; } return false; } private static boolean is_number_start(char c) { return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+'; } private static boolean is_absolute(char c) { return Character.isUpperCase(c); } // By the SVG spec 'large-arc' and 'sweep' must contain only one char // and can be written without any separators, e.g.: 10 20 30 01 10 20. private static boolean parse_flag() { skip_spaces(); char c = s.charAt(i); switch (c) { case '0': case '1': { i += 1; if (i < l && s.charAt(i) == ',') { i += 1; } skip_spaces(); break; } default: throw new Error(String.format("Unexpected flag '%c' (i=%d, s=%s)", c, i, s)); } return c == '1'; } private static float parse_list_number() { if (i == l) { throw new Error(String.format("Unexpected end (s=%s)", s)); } float n = parse_number(); skip_spaces(); parse_list_separator(); return n; } private static float parse_number() { // Strip off leading whitespaces. skip_spaces(); if (i == l) { throw new Error(String.format("Unexpected end (s=%s)", s)); } int start = i; char c = s.charAt(i); // Consume sign. if (c == '-' || c == '+') { i += 1; c = s.charAt(i); } // Consume integer. if (c >= '0' && c <= '9') { skip_digits(); if (i < l) { c = s.charAt(i); } } else if (c != '.') { throw new IllegalArgumentException( String.format("Invalid number formating character '%c' (i=%d, s=%s)", c, i, s)); } // Consume fraction. if (c == '.') { i += 1; skip_digits(); if (i < l) { c = s.charAt(i); } } if ((c == 'e' || c == 'E') && i + 1 < l) { char c2 = s.charAt(i + 1); // Check for `em`/`ex`. if (c2 != 'm' && c2 != 'x') { i += 1; c = s.charAt(i); if (c == '+' || c == '-') { i += 1; skip_digits(); } else if (c >= '0' && c <= '9') { skip_digits(); } else { throw new IllegalArgumentException( String.format("Invalid number formating character '%c' (i=%d, s=%s)", c, i, s)); } } } String num = s.substring(start, i); float n = Float.parseFloat(num); // inf, nan, etc. are an error. if (Float.isInfinite(n) || Float.isNaN(n)) { throw new IllegalArgumentException( String.format("Invalid number '%s' (start=%d, i=%d, s=%s)", num, start, i, s)); } return n; } private static void parse_list_separator() { if (i < l && s.charAt(i) == ',') { i += 1; } } private static void skip_digits() { while (i < l && Character.isDigit(s.charAt(i))) i++; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/PathView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class PathView extends RenderableView { private Path mPath; public PathView(ReactContext reactContext) { super(reactContext); PathParser.mScale = mScale; mPath = new Path(); } public void setD(String d) { mPath = PathParser.parse(d); elements = PathParser.elements; for (PathElement elem : elements) { for (Point point : elem.points) { point.x *= mScale; point.y *= mScale; } } invalidate(); } @Override Path getPath(Canvas canvas, Paint paint) { return mPath; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/PatternView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Matrix; import android.graphics.RectF; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class PatternView extends GroupView { private SVGLength mX; private SVGLength mY; private SVGLength mW; private SVGLength mH; private Brush.BrushUnits mPatternUnits; private Brush.BrushUnits mPatternContentUnits; private float mMinX; private float mMinY; private float mVbWidth; private float mVbHeight; String mAlign; int mMeetOrSlice; private static final float[] sRawMatrix = new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; private Matrix mMatrix = null; public PatternView(ReactContext reactContext) { super(reactContext); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } public void setPatternUnits(int patternUnits) { switch (patternUnits) { case 0: mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public void setPatternContentUnits(int patternContentUnits) { switch (patternContentUnits) { case 0: mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public void setPatternTransform(@Nullable ReadableArray matrixArray) { if (matrixArray != null) { int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); if (matrixSize == 6) { if (mMatrix == null) { mMatrix = new Matrix(); } mMatrix.setValues(sRawMatrix); } else if (matrixSize != -1) { FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); } } else { mMatrix = null; } invalidate(); } public void setMinX(float minX) { mMinX = minX; invalidate(); } public void setMinY(float minY) { mMinY = minY; invalidate(); } public void setVbWidth(float vbWidth) { mVbWidth = vbWidth; invalidate(); } public void setVbHeight(float vbHeight) { mVbHeight = vbHeight; invalidate(); } public void setAlign(String align) { mAlign = align; invalidate(); } public void setMeetOrSlice(int meetOrSlice) { mMeetOrSlice = meetOrSlice; invalidate(); } RectF getViewBox() { return new RectF( mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); } @Override void saveDefinition() { if (mName != null) { SVGLength[] points = new SVGLength[] {mX, mY, mW, mH}; Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits); brush.setContentUnits(mPatternContentUnits); brush.setPattern(this); if (mMatrix != null) { brush.setGradientTransform(mMatrix); } SvgView svg = getSvgView(); if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE || mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); } svg.defineBrush(brush, mName); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/PropHelper.java ================================================ /* * 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. */ package com.horcrux.svg; import com.facebook.react.bridge.ReadableArray; /** Contains static helper methods for accessing props. */ class PropHelper { private static final int inputMatrixDataSize = 6; /** * Converts given {@link ReadableArray} to a matrix data array, {@code float[6]}. Writes result to * the array passed in {@param into}. This method will write exactly six items to the output array * from the input array. * *

If the input array has a different size, then only the size is returned; Does not check * output array size. Ensure space for at least six elements. * * @param value input array * @param sRawMatrix output matrix * @param mScale current resolution scaling * @return size of input array */ static int toMatrixData(ReadableArray value, float[] sRawMatrix, float mScale) { int fromSize = value.size(); if (fromSize != inputMatrixDataSize) { return fromSize; } sRawMatrix[0] = (float) value.getDouble(0); sRawMatrix[1] = (float) value.getDouble(2); sRawMatrix[2] = (float) value.getDouble(4) * mScale; sRawMatrix[3] = (float) value.getDouble(1); sRawMatrix[4] = (float) value.getDouble(3); sRawMatrix[5] = (float) value.getDouble(5) * mScale; return inputMatrixDataSize; } /** * Converts length string into px / user units in the current user coordinate system * * @param length length string * @param relative relative size for percentages * @param scale scaling parameter * @param fontSize current font size * @return value in the current user coordinate system */ static double fromRelative(String length, double relative, double scale, double fontSize) { /* TODO list unit relative to em font size of the element ex x-height of the element’s font ch width of the "0" (ZERO, U+0030) glyph in the element’s font rem font size of the root element vw 1% of viewport’s width vh 1% of viewport’s height vmin 1% of viewport’s smaller dimension vmax 1% of viewport’s larger dimension relative-size [ larger | smaller ] absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ] https://www.w3.org/TR/css3-values/#relative-lengths https://www.w3.org/TR/css3-values/#absolute-lengths https://drafts.csswg.org/css-cascade-4/#computed-value https://drafts.csswg.org/css-fonts-3/#propdef-font-size https://drafts.csswg.org/css2/fonts.html#propdef-font-size */ length = length.trim(); int stringLength = length.length(); int percentIndex = stringLength - 1; if (stringLength == 0 || length.equals("normal")) { return 0d; } else if (length.codePointAt(percentIndex) == '%') { return Double.valueOf(length.substring(0, percentIndex)) / 100 * relative; } else { int twoLetterUnitIndex = stringLength - 2; if (twoLetterUnitIndex > 0) { String lastTwo = length.substring(twoLetterUnitIndex); int end = twoLetterUnitIndex; double unit = 1; switch (lastTwo) { case "px": break; case "em": unit = fontSize; break; /* "1pt" equals "1.25px" (and therefore 1.25 user units) "1pc" equals "15px" (and therefore 15 user units) "1mm" would be "3.543307px" (3.543307 user units) "1cm" equals "35.43307px" (and therefore 35.43307 user units) "1in" equals "90px" (and therefore 90 user units) */ case "pt": unit = 1.25d; break; case "pc": unit = 15; break; case "mm": unit = 3.543307d; break; case "cm": unit = 35.43307d; break; case "in": unit = 90; break; default: end = stringLength; } return Double.valueOf(length.substring(0, end)) * unit * scale; } else { return Double.valueOf(length) * scale; } } } /** * Converts SVGLength into px / user units in the current user coordinate system * * @param length length string * @param relative relative size for percentages * @param offset offset for all units * @param scale scaling parameter * @param fontSize current font size * @return value in the current user coordinate system */ static double fromRelative( SVGLength length, double relative, double offset, double scale, double fontSize) { /* TODO list unit relative to em font size of the element ex x-height of the element’s font ch width of the "0" (ZERO, U+0030) glyph in the element’s font rem font size of the root element vw 1% of viewport’s width vh 1% of viewport’s height vmin 1% of viewport’s smaller dimension vmax 1% of viewport’s larger dimension relative-size [ larger | smaller ] absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ] https://www.w3.org/TR/css3-values/#relative-lengths https://www.w3.org/TR/css3-values/#absolute-lengths https://drafts.csswg.org/css-cascade-4/#computed-value https://drafts.csswg.org/css-fonts-3/#propdef-font-size https://drafts.csswg.org/css2/fonts.html#propdef-font-size */ if (length == null) { return offset; } SVGLength.UnitType unitType = length.unit; double value = length.value; double unit = 1; switch (unitType) { case NUMBER: case PX: break; case PERCENTAGE: return value / 100 * relative + offset; case EMS: unit = fontSize; break; case EXS: unit = fontSize / 2; break; case CM: unit = 35.43307; break; case MM: unit = 3.543307; break; case IN: unit = 90; break; case PT: unit = 1.25; break; case PC: unit = 15; break; default: case UNKNOWN: return value * scale + offset; } return value * unit * scale + offset; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/RNSVGMarkerPosition.java ================================================ package com.horcrux.svg; import java.util.ArrayList; enum RNSVGMarkerType { kStartMarker, kMidMarker, kEndMarker } enum ElementType { kCGPathElementAddCurveToPoint, kCGPathElementAddQuadCurveToPoint, kCGPathElementMoveToPoint, kCGPathElementAddLineToPoint, kCGPathElementCloseSubpath } class Point { double x; double y; Point(double x, double y) { this.x = x; this.y = y; } } class SegmentData { Point start_tangent; // Tangent in the start point of the segment. Point end_tangent; // Tangent in the end point of the segment. Point position; // The end point of the segment. } class RNSVGMarkerPosition { private static ArrayList positions_; private static int element_index_; private static Point origin_; private static Point subpath_start_; private static Point in_slope_; private static Point out_slope_; @SuppressWarnings("unused") private static boolean auto_start_reverse_; // TODO RNSVGMarkerType type; Point origin; double angle; private RNSVGMarkerPosition(RNSVGMarkerType type, Point origin, double angle) { this.type = type; this.origin = origin; this.angle = angle; } static ArrayList fromPath(ArrayList elements) { positions_ = new ArrayList<>(); element_index_ = 0; origin_ = new Point(0, 0); subpath_start_ = new Point(0, 0); for (PathElement e : elements) { UpdateFromPathElement(e); } PathIsDone(); return positions_; } private static void PathIsDone() { double angle = CurrentAngle(RNSVGMarkerType.kEndMarker); positions_.add(new RNSVGMarkerPosition(RNSVGMarkerType.kEndMarker, origin_, angle)); } private static double BisectingAngle(double in_angle, double out_angle) { // WK193015: Prevent bugs due to angles being non-continuous. if (Math.abs(in_angle - out_angle) > 180) in_angle += 360; return (in_angle + out_angle) / 2; } private static double rad2deg(double rad) { double RNSVG_radToDeg = 180 / Math.PI; return rad * RNSVG_radToDeg; } private static double SlopeAngleRadians(Point p) { return Math.atan2(p.y, p.x); } private static double CurrentAngle(RNSVGMarkerType type) { // For details of this calculation, see: // http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement double in_angle = rad2deg(SlopeAngleRadians(in_slope_)); double out_angle = rad2deg(SlopeAngleRadians(out_slope_)); switch (type) { case kStartMarker: if (auto_start_reverse_) out_angle += 180; return out_angle; case kMidMarker: return BisectingAngle(in_angle, out_angle); case kEndMarker: return in_angle; } return 0; } private static Point subtract(Point p1, Point p2) { return new Point(p2.x - p1.x, p2.y - p1.y); } private static boolean isZero(Point p) { return p.x == 0 && p.y == 0; } private static void ComputeQuadTangents(SegmentData data, Point start, Point control, Point end) { data.start_tangent = subtract(control, start); data.end_tangent = subtract(end, control); if (isZero(data.start_tangent)) data.start_tangent = data.end_tangent; else if (isZero(data.end_tangent)) data.end_tangent = data.start_tangent; } private static SegmentData ExtractPathElementFeatures(PathElement element) { SegmentData data = new SegmentData(); Point[] points = element.points; switch (element.type) { case kCGPathElementAddCurveToPoint: data.position = points[2]; data.start_tangent = subtract(points[0], origin_); data.end_tangent = subtract(points[2], points[1]); if (isZero(data.start_tangent)) ComputeQuadTangents(data, points[0], points[1], points[2]); else if (isZero(data.end_tangent)) ComputeQuadTangents(data, origin_, points[0], points[1]); break; case kCGPathElementAddQuadCurveToPoint: data.position = points[1]; ComputeQuadTangents(data, origin_, points[0], points[1]); break; case kCGPathElementMoveToPoint: case kCGPathElementAddLineToPoint: data.position = points[0]; data.start_tangent = subtract(data.position, origin_); data.end_tangent = subtract(data.position, origin_); break; case kCGPathElementCloseSubpath: data.position = subpath_start_; data.start_tangent = subtract(data.position, origin_); data.end_tangent = subtract(data.position, origin_); break; } return data; } private static void UpdateFromPathElement(PathElement element) { SegmentData segment_data = ExtractPathElementFeatures(element); // First update the outgoing slope for the previous element. out_slope_ = segment_data.start_tangent; // Record the marker for the previous element. if (element_index_ > 0) { RNSVGMarkerType marker_type = element_index_ == 1 ? RNSVGMarkerType.kStartMarker : RNSVGMarkerType.kMidMarker; double angle = CurrentAngle(marker_type); positions_.add(new RNSVGMarkerPosition(marker_type, origin_, angle)); } // Update the incoming slope for this marker position. in_slope_ = segment_data.end_tangent; // Update marker position. origin_ = segment_data.position; // If this is a 'move to' segment, save the point for use with 'close'. if (element.type == ElementType.kCGPathElementMoveToPoint) subpath_start_ = element.points[0]; else if (element.type == ElementType.kCGPathElementCloseSubpath) subpath_start_ = new Point(0, 0); ++element_index_; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/RNSVGRenderableManager.java ================================================ /* * 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. */ package com.horcrux.svg; import static java.nio.charset.StandardCharsets.UTF_8; import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.RectF; 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.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.annotations.ReactModule; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import javax.annotation.Nonnull; @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 NAME; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public boolean isPointInFill(Double tag, ReadableMap options) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return false; } float scale = svg.mScale; float x = (float) options.getDouble("x") * scale; float y = (float) options.getDouble("y") * scale; int i = svg.hitTest(new float[] {x, y}); return i != -1; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public boolean isPointInStroke(Double tag, ReadableMap options) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return false; } try { svg.getPath(null, null); } catch (NullPointerException e) { svg.invalidate(); return false; } svg.initBounds(); float scale = svg.mScale; int x = (int) (options.getDouble("x") * scale); int y = (int) (options.getDouble("y") * scale); Region strokeRegion = svg.mStrokeRegion; return strokeRegion != null && strokeRegion.contains(x, y); } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public double getTotalLength(Double tag) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return 0; } Path path; try { path = svg.getPath(null, null); } catch (NullPointerException e) { svg.invalidate(); return -1; } PathMeasure pm = new PathMeasure(path, false); return pm.getLength() / svg.mScale; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public WritableMap getPointAtLength(Double tag, ReadableMap options) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return Arguments.createMap(); } Path path; try { path = svg.getPath(null, null); } catch (NullPointerException e) { svg.invalidate(); return Arguments.createMap(); } PathMeasure pm = new PathMeasure(path, false); float length = (float) options.getDouble("length"); float scale = svg.mScale; float[] pos = new float[2]; float[] tan = new float[2]; float distance = Math.max(0, Math.min(length * scale, pm.getLength())); pm.getPosTan(distance, pos, tan); double angle = Math.atan2(tan[1], tan[0]); WritableMap result = Arguments.createMap(); result.putDouble("x", pos[0] / scale); result.putDouble("y", pos[1] / scale); result.putDouble("angle", angle); return result; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public WritableMap getBBox(Double tag, ReadableMap options) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return Arguments.createMap(); } boolean fill = options.getBoolean("fill"); boolean stroke = options.getBoolean("stroke"); boolean markers = options.getBoolean("markers"); boolean clipped = options.getBoolean("clipped"); try { svg.getPath(null, null); } catch (NullPointerException e) { svg.invalidate(); return Arguments.createMap(); } float scale = svg.mScale; svg.initBounds(); RectF bounds = new RectF(); RectF fillBounds = svg.mFillBounds; RectF strokeBounds = svg.mStrokeBounds; RectF markerBounds = svg.mMarkerBounds; RectF clipBounds = svg.mClipBounds; if (fill && fillBounds != null) { bounds.union(fillBounds); } if (stroke && strokeBounds != null) { bounds.union(strokeBounds); } if (markers && markerBounds != null) { bounds.union(markerBounds); } if (clipped && clipBounds != null) { bounds.intersect(clipBounds); } WritableMap result = Arguments.createMap(); result.putDouble("x", bounds.left / scale); result.putDouble("y", bounds.top / scale); result.putDouble("width", bounds.width() / scale); result.putDouble("height", bounds.height() / scale); return result; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @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); 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]; ctm.getValues(values); WritableMap result = Arguments.createMap(); result.putDouble("a", values[Matrix.MSCALE_X]); result.putDouble("b", values[Matrix.MSKEW_Y]); result.putDouble("c", values[Matrix.MSKEW_X]); result.putDouble("d", values[Matrix.MSCALE_Y]); result.putDouble("e", values[Matrix.MTRANS_X] / scale); result.putDouble("f", values[Matrix.MTRANS_Y] / scale); return result; } @SuppressWarnings("unused") @ReactMethod(isBlockingSynchronousMethod = true) @Override public WritableMap getScreenCTM(Double tag) { RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag.intValue()); if (svg == null) { return Arguments.createMap(); } float[] values = new float[9]; svg.mCTM.getValues(values); float scale = svg.mScale; WritableMap result = Arguments.createMap(); result.putDouble("a", values[Matrix.MSCALE_X]); result.putDouble("b", values[Matrix.MSKEW_Y]); result.putDouble("c", values[Matrix.MSKEW_X]); result.putDouble("d", values[Matrix.MSCALE_Y]); result.putDouble("e", values[Matrix.MTRANS_X] / scale); result.putDouble("f", values[Matrix.MTRANS_Y] / scale); return result; } @ReactMethod @Override public void getRawResource(String name, Promise promise) { try { ReactApplicationContext context = getReactApplicationContext(); Resources resources = context.getResources(); String packageName = context.getPackageName(); int id = resources.getIdentifier(name, "raw", packageName); InputStream stream = resources.openRawResource(id); try { InputStreamReader reader = new InputStreamReader(stream, UTF_8); char[] buffer = new char[DEFAULT_BUFFER_SIZE]; StringBuilder builder = new StringBuilder(); int n; while ((n = reader.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != EOF) { builder.append(buffer, 0, n); } String result = builder.toString(); promise.resolve(result); } finally { try { stream.close(); } catch (IOException ioe) { // ignore } } } catch (Exception e) { e.printStackTrace(); promise.reject(e); } } private static final int EOF = -1; private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; } ================================================ FILE: android/src/main/java/com/horcrux/svg/RadialGradientView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Matrix; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class RadialGradientView extends DefinitionView { private SVGLength mFx; private SVGLength mFy; private SVGLength mRx; private SVGLength mRy; private SVGLength mCx; private SVGLength mCy; private ReadableArray mGradient; private Brush.BrushUnits mGradientUnits; private static final float[] sRawMatrix = new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; private Matrix mMatrix = null; public RadialGradientView(ReactContext reactContext) { super(reactContext); } public void setFx(Dynamic fx) { mFx = SVGLength.from(fx); invalidate(); } public void setFy(Dynamic fy) { mFy = SVGLength.from(fy); invalidate(); } public void setRx(Dynamic rx) { mRx = SVGLength.from(rx); invalidate(); } public void setRy(Dynamic ry) { mRy = SVGLength.from(ry); invalidate(); } public void setCx(Dynamic cx) { mCx = SVGLength.from(cx); invalidate(); } public void setCy(Dynamic cy) { mCy = SVGLength.from(cy); invalidate(); } public void setGradient(ReadableArray gradient) { mGradient = gradient; invalidate(); } public void setGradientUnits(int gradientUnits) { switch (gradientUnits) { case 0: mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX; break; case 1: mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE; break; } invalidate(); } public void setGradientTransform(@Nullable ReadableArray matrixArray) { if (matrixArray != null) { int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); if (matrixSize == 6) { if (mMatrix == null) { mMatrix = new Matrix(); } mMatrix.setValues(sRawMatrix); } else if (matrixSize != -1) { FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); } } else { mMatrix = null; } invalidate(); } @Override void saveDefinition() { if (mName != null) { SVGLength[] points = new SVGLength[] {mFx, mFy, mRx, mRy, mCx, mCy}; Brush brush = new Brush(Brush.BrushType.RADIAL_GRADIENT, points, mGradientUnits); brush.setGradientColors(mGradient); if (mMatrix != null) { brush.setGradientTransform(mMatrix); } SvgView svg = getSvgView(); if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) { brush.setUserSpaceBoundingBox(svg.getCanvasBounds()); } svg.defineBrush(brush, mName); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/RectView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.os.Build; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.ArrayList; @SuppressLint("ViewConstructor") class RectView extends RenderableView { private SVGLength mX; private SVGLength mY; private SVGLength mW; private SVGLength mH; private SVGLength mRx; private SVGLength mRy; public RectView(ReactContext reactContext) { super(reactContext); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } public void setRx(Dynamic rx) { mRx = SVGLength.from(rx); invalidate(); } public void setRy(Dynamic ry) { mRy = SVGLength.from(ry); invalidate(); } @Override Path getPath(Canvas canvas, Paint paint) { Path path = new Path(); double x = relativeOnWidth(mX); double y = relativeOnHeight(mY); double w = relativeOnWidth(mW); double h = relativeOnHeight(mH); if (mRx != null || mRy != null) { double rx = 0d; double ry = 0d; if (mRx == null) { ry = relativeOnHeight(mRy); rx = ry; } else if (mRy == null) { rx = relativeOnWidth(mRx); ry = rx; } else { rx = relativeOnWidth(mRx); ry = relativeOnHeight(mRy); } if (rx > w / 2) { rx = w / 2; } if (ry > h / 2) { ry = h / 2; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { path.addRoundRect( (float) x, (float) y, (float) (x + w), (float) (y + h), (float) rx, (float) ry, Path.Direction.CW); } else { path.addRoundRect( new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)), (float) rx, (float) ry, Path.Direction.CW); } } else { path.addRect((float) x, (float) y, (float) (x + w), (float) (y + h), Path.Direction.CW); path.close(); // Ensure isSimplePath = false such that rect doesn't become represented using // integers } elements = new ArrayList<>(); elements.add( new PathElement(ElementType.kCGPathElementMoveToPoint, new Point[] {new Point(x, y)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x + w, y)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x + w, y + h)})); elements.add( new PathElement( ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y + h)})); elements.add( new PathElement(ElementType.kCGPathElementAddLineToPoint, new Point[] {new Point(x, y)})); return path; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/RenderableView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.DashPathEffect; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.view.ViewParent; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ColorPropConverter; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import com.facebook.react.bridge.WritableMap; import com.facebook.react.touch.ReactHitSlopView; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.PointerEvents; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; @SuppressWarnings({"WeakerAccess", "RedundantSuppression"}) public abstract class RenderableView extends VirtualView implements ReactHitSlopView { RenderableView(ReactContext reactContext) { super(reactContext); setPivotX(0); setPivotY(0); } static RenderableView contextElement; // strokeLinecap private static final int CAP_BUTT = 0; static final int CAP_ROUND = 1; private static final int CAP_SQUARE = 2; // strokeLinejoin private static final int JOIN_BEVEL = 2; private static final int JOIN_MITER = 0; static final int JOIN_ROUND = 1; // fillRule private static final int FILL_RULE_EVENODD = 0; static final int FILL_RULE_NONZERO = 1; // vectorEffect private static final int VECTOR_EFFECT_DEFAULT = 0; private static final int VECTOR_EFFECT_NON_SCALING_STROKE = 1; // static final int VECTOR_EFFECT_INHERIT = 2; // static final int VECTOR_EFFECT_URI = 3; /* Used in mergeProperties, keep public */ public int vectorEffect = VECTOR_EFFECT_DEFAULT; public @Nullable ReadableArray stroke; public @Nullable SVGLength[] strokeDasharray; public SVGLength strokeWidth = new SVGLength(1); public float strokeOpacity = 1; public float strokeMiterlimit = 4; public float strokeDashoffset = 0; public Paint.Cap strokeLinecap = Paint.Cap.BUTT; public Paint.Join strokeLinejoin = Paint.Join.MITER; private int mCurrentColor = 0; public @Nullable ReadableArray fill; public float fillOpacity = 1; public Path.FillType fillRule = Path.FillType.WINDING; /* End merged properties */ private @Nullable ArrayList mLastMergedList; private @Nullable ArrayList mOriginProperties; private @Nullable ArrayList mPropList; private @Nullable ArrayList mAttributeList; private @Nullable RenderableView mCaller; public void onReceiveNativeEvent() { WritableMap event = Arguments.createMap(); ReactContext reactContext = (ReactContext)getContext(); reactContext .getJSModule(RCTEventEmitter.class) .receiveEvent(getId(), "topSvgLayout", event); } @Nullable String mFilter; private static final Pattern regex = Pattern.compile("[0-9.-]+"); @Nullable public Rect getHitSlopRect() { /* * In order to make the isTouchPointInView fail we need to return a very improbable Rect for the View * This way an SVG with box_none carrying its last descendent with box_none will have the expected behavior of just having events on the actual painted area */ if (mPointerEvents == PointerEvents.BOX_NONE) { return new Rect(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); } return null; } @Override public void setId(int id) { super.setId(id); RenderableViewManager.setRenderableView(id, this); } public void setVectorEffect(int vectorEffect) { this.vectorEffect = vectorEffect; invalidate(); } public void setCurrentColor(Integer color) { mCurrentColor = color != null ? color : 0; invalidate(); clearChildCache(); } int getCurrentColor() { if (this.mCurrentColor != 0) { return this.mCurrentColor; } if (this.mCaller != null) { return this.mCaller.getCurrentColor(); } ViewParent parent = this.getParent(); if (parent instanceof VirtualView) { return ((RenderableView) parent).getCurrentColor(); } else if (parent instanceof SvgView) { return ((SvgView) parent).mCurrentColor; } return 0; } public void setFill(@Nullable Dynamic fill) { if (fill == null || fill.isNull()) { this.fill = null; invalidate(); return; } ReadableType fillType = fill.getType(); if (fillType.equals(ReadableType.Map)) { ReadableMap fillMap = fill.asMap(); setFill(fillMap); return; } // This code will probably never be reached with current changes if (fillType.equals(ReadableType.Number)) { this.fill = JavaOnlyArray.of(0, fill.asInt()); } else if (fillType.equals(ReadableType.Array)) { this.fill = fill.asArray(); } else { JavaOnlyArray arr = new JavaOnlyArray(); arr.pushInt(0); Matcher m = regex.matcher(fill.asString()); int i = 0; while (m.find()) { double parsed = Double.parseDouble(m.group()); arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); } this.fill = arr; } invalidate(); } public void setFill(ReadableMap fill) { if (fill == null) { this.fill = null; invalidate(); return; } int type = fill.getInt("type"); if (type == 0) { ReadableType valueType = fill.getType("payload"); if (valueType.equals(ReadableType.Number)) { this.fill = JavaOnlyArray.of(0, fill.getInt("payload")); } else if (valueType.equals(ReadableType.Map)) { this.fill = JavaOnlyArray.of(0, fill.getMap("payload")); } } else if (type == 1) { this.fill = JavaOnlyArray.of(1, fill.getString("brushRef")); } else { this.fill = JavaOnlyArray.of(type); } invalidate(); } public void setFillOpacity(float fillOpacity) { this.fillOpacity = fillOpacity; invalidate(); } public void setFillRule(int fillRule) { switch (fillRule) { case FILL_RULE_EVENODD: this.fillRule = Path.FillType.EVEN_ODD; break; case FILL_RULE_NONZERO: break; default: throw new JSApplicationIllegalArgumentException("fillRule " + fillRule + " unrecognized"); } invalidate(); } public void setStroke(@Nullable Dynamic strokeColors) { if (strokeColors == null || strokeColors.isNull()) { stroke = null; invalidate(); return; } ReadableType strokeType = strokeColors.getType(); if (strokeType.equals(ReadableType.Map)) { ReadableMap strokeMap = strokeColors.asMap(); setStroke(strokeMap); return; } // This code will probably never be reached with current changes ReadableType type = strokeColors.getType(); if (type.equals(ReadableType.Number)) { stroke = JavaOnlyArray.of(0, strokeColors.asInt()); } else if (type.equals(ReadableType.Array)) { stroke = strokeColors.asArray(); } else { JavaOnlyArray arr = new JavaOnlyArray(); arr.pushInt(0); Matcher m = regex.matcher(strokeColors.asString()); int i = 0; while (m.find()) { double parsed = Double.parseDouble(m.group()); arr.pushDouble(i++ < 3 ? parsed / 255 : parsed); } stroke = arr; } invalidate(); } public void setStroke(@Nullable ReadableMap stroke) { if (stroke == null) { this.stroke = null; invalidate(); return; } int type = stroke.getInt("type"); if (type == 0) { ReadableType payloadType = stroke.getType("payload"); if (payloadType.equals(ReadableType.Number)) { this.stroke = JavaOnlyArray.of(0, stroke.getInt("payload")); } else if (payloadType.equals(ReadableType.Map)) { this.stroke = JavaOnlyArray.of(0, stroke.getMap("payload")); } } else if (type == 1) { this.stroke = JavaOnlyArray.of(1, stroke.getString("brushRef")); } else { this.stroke = JavaOnlyArray.of(type); } invalidate(); } public void setStrokeOpacity(float strokeOpacity) { this.strokeOpacity = strokeOpacity; invalidate(); } public void setStrokeDasharray(Dynamic dynamicStrokeDasharray) { ArrayList arrayList = SVGLength.arrayFrom(dynamicStrokeDasharray); if (arrayList != null) { if (arrayList.size() % 2 == 1) { arrayList.addAll(arrayList); } this.strokeDasharray = arrayList.toArray(new SVGLength[0]); } else { this.strokeDasharray = null; } invalidate(); } public void setStrokeDashoffset(float strokeDashoffset) { this.strokeDashoffset = strokeDashoffset * mScale; invalidate(); } public void setStrokeWidth(Dynamic strokeWidth) { this.strokeWidth = strokeWidth.isNull() ? new SVGLength(1) : SVGLength.from(strokeWidth); invalidate(); } public void setStrokeMiterlimit(float strokeMiterlimit) { this.strokeMiterlimit = strokeMiterlimit; invalidate(); } public void setStrokeLinecap(int strokeLinecap) { switch (strokeLinecap) { case CAP_BUTT: this.strokeLinecap = Paint.Cap.BUTT; break; case CAP_SQUARE: this.strokeLinecap = Paint.Cap.SQUARE; break; case CAP_ROUND: this.strokeLinecap = Paint.Cap.ROUND; break; default: throw new JSApplicationIllegalArgumentException( "strokeLinecap " + strokeLinecap + " unrecognized"); } invalidate(); } public void setStrokeLinejoin(int strokeLinejoin) { switch (strokeLinejoin) { case JOIN_MITER: this.strokeLinejoin = Paint.Join.MITER; break; case JOIN_BEVEL: this.strokeLinejoin = Paint.Join.BEVEL; break; case JOIN_ROUND: this.strokeLinejoin = Paint.Join.ROUND; break; default: throw new JSApplicationIllegalArgumentException( "strokeLinejoin " + strokeLinejoin + " unrecognized"); } invalidate(); } public void setPropList(@Nullable ReadableArray propList) { if (propList != null) { mPropList = mAttributeList = new ArrayList<>(); for (int i = 0; i < propList.size(); i++) { mPropList.add(propList.getString(i)); } } invalidate(); } public void setFilter(String filter) { mFilter = filter; invalidate(); } void render(Canvas canvas, Paint paint, float opacity) { MaskView mask = null; FilterView filter = null; if (mMask != null) { SvgView root = getSvgView(); mask = (MaskView) root.getDefinedMask(mMask); } if (mFilter != null) { SvgView root = getSvgView(); filter = (FilterView) root.getDefinedFilter(mFilter); } if (mask != null || filter != null) { if (filter != null) { Paint bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); canvas.saveLayer(null, bitmapPaint); Bitmap backgroundBitmap = this.getSvgView().getCurrentBitmap(); // draw element to self bitmap Bitmap elementBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); Canvas elementCanvas = new Canvas(elementBitmap); elementCanvas.setMatrix(canvas.getMatrix()); draw(elementCanvas, paint, opacity); // get renderableBounds this.initBounds(); RectF clientRect = this.getClientRect(); if (this instanceof ImageView && clientRect == null) { return; } // apply filters elementBitmap = filter.applyFilter(elementBitmap, backgroundBitmap, clientRect); // draw bitmap 1:1 to canvas int saveCount = canvas.save(); canvas.setMatrix(null); canvas.drawBitmap(elementBitmap, 0, 0, bitmapPaint); canvas.restoreToCount(saveCount); } else { canvas.saveLayer(null, new Paint()); draw(canvas, paint, opacity); } if (mask != null) { // https://www.w3.org/TR/SVG11/masking.html // Adding a mask involves several steps // 1. applying luminanceToAlpha to the mask element // 2. merging the alpha channel of the element with the alpha channel from the previous step // 3. applying the result from step 2 to the target element Paint dstInPaint = new Paint(); dstInPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); // prepare step 3 - combined layer canvas.saveLayer(null, dstInPaint); if (mask.getMaskType() == MaskView.MaskType.LUMINANCE) { // step 1 - luminance layer // prepare maskPaint with luminanceToAlpha // https://www.w3.org/TR/SVG11/filters.html#InterfaceSVGFEMergeElement:~:text=not%20applicable.%20A-,luminanceToAlpha,-operation%20is%20equivalent Paint luminancePaint = new Paint(); ColorMatrix luminanceToAlpha = new ColorMatrix( new float[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2125f, 0.7154f, 0.0721f, 0, 0 }); luminancePaint.setColorFilter(new ColorMatrixColorFilter(luminanceToAlpha)); canvas.saveLayer(null, luminancePaint); } else { canvas.saveLayer(null, paint); } // calculate mask bounds RectF maskBounds; if (mask.getMaskUnits() == Brush.BrushUnits.USER_SPACE_ON_USE) { float maskX = (float) relativeOnWidth(mask.mX); float maskY = (float) relativeOnHeight(mask.mY); float maskWidth = (float) relativeOnWidth(mask.mW); float maskHeight = (float) relativeOnHeight(mask.mH); maskBounds = new RectF(maskX, maskY, maskX + maskWidth, maskY + maskHeight); } else { // Brush.BrushUnits.OBJECT_BOUNDING_BOX RectF clientRect = this.getClientRect(); if (this instanceof ImageView && clientRect == null) { return; } mInvCTM.mapRect(clientRect); float maskX = (float) relativeOnFraction(mask.mX, clientRect.width()); float maskY = (float) relativeOnFraction(mask.mY, clientRect.height()); float maskWidth = (float) relativeOnFraction(mask.mW, clientRect.width()); float maskHeight = (float) relativeOnFraction(mask.mH, clientRect.height()); maskBounds = new RectF( clientRect.left + maskX, clientRect.top + maskY, clientRect.left + maskX + maskWidth, clientRect.top + maskY + maskHeight); } // clip to mask bounds canvas.clipRect(maskBounds); mask.draw(canvas, paint, 1f); // close luminance layer canvas.restore(); // step 2 - alpha layer canvas.saveLayer(null, dstInPaint); // clip to mask bounds canvas.clipRect(maskBounds); mask.draw(canvas, paint, 1f); // close alpha layer canvas.restore(); // close combined layer canvas.restore(); } // close element layer canvas.restore(); } else { draw(canvas, paint, opacity); } } @Override void draw(Canvas canvas, Paint paint, float opacity) { opacity *= mOpacity; boolean computePaths = mPath == null; if (computePaths) { mPath = getPath(canvas, paint); mPath.setFillType(fillRule); } boolean nonScalingStroke = vectorEffect == VECTOR_EFFECT_NON_SCALING_STROKE; Path path = mPath; if (nonScalingStroke) { Path scaled = new Path(); //noinspection deprecation mPath.transform(mCTM, scaled); canvas.setMatrix(null); path = scaled; } if (computePaths || path != mPath) { mBox = new RectF(); path.computeBounds(mBox, true); } RectF clientRect = new RectF(mBox); mCTM.mapRect(clientRect); this.setClientRect(clientRect); clip(canvas, paint); if (setupFillPaint(paint, opacity * fillOpacity)) { if (computePaths) { mFillPath = new Path(); paint.getFillPath(path, mFillPath); } canvas.drawPath(path, paint); } if (setupStrokePaint(paint, opacity * strokeOpacity)) { if (computePaths) { mStrokePath = new Path(); paint.getFillPath(path, mStrokePath); } canvas.drawPath(path, paint); } renderMarkers(canvas, paint, opacity); } void renderMarkers(Canvas canvas, Paint paint, float opacity) { MarkerView markerStart = (MarkerView) getSvgView().getDefinedMarker(mMarkerStart); MarkerView markerMid = (MarkerView) getSvgView().getDefinedMarker(mMarkerMid); MarkerView markerEnd = (MarkerView) getSvgView().getDefinedMarker(mMarkerEnd); if (elements != null && (markerStart != null || markerMid != null || markerEnd != null)) { contextElement = this; ArrayList positions = RNSVGMarkerPosition.fromPath(elements); float width = (float) (this.strokeWidth != null ? relativeOnOther(this.strokeWidth) : 1); mMarkerPath = new Path(); for (RNSVGMarkerPosition position : positions) { RNSVGMarkerType type = position.type; MarkerView marker = null; switch (type) { case kStartMarker: marker = markerStart; break; case kMidMarker: marker = markerMid; break; case kEndMarker: marker = markerEnd; break; } if (marker == null) { continue; } marker.renderMarker(canvas, paint, opacity, position, width); Matrix transform = marker.markerTransform; mMarkerPath.addPath(marker.getPath(canvas, paint), transform); } contextElement = null; } } /** * Sets up paint according to the props set on a view. Returns {@code true} if the fill should be * drawn, {@code false} if not. */ boolean setupFillPaint(Paint paint, float opacity) { if (fill != null && fill.size() > 0) { paint.reset(); paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); paint.setStyle(Paint.Style.FILL); setupPaint(paint, opacity, fill); return true; } return false; } /** * Sets up paint according to the props set on a view. Returns {@code true} if the stroke should * be drawn, {@code false} if not. */ boolean setupStrokePaint(Paint paint, float opacity) { paint.reset(); double strokeWidth = relativeOnOther(this.strokeWidth); if (strokeWidth == 0 || stroke == null || stroke.size() == 0) { return false; } paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(strokeLinecap); paint.setStrokeJoin(strokeLinejoin); paint.setStrokeMiter(strokeMiterlimit * mScale); paint.setStrokeWidth((float) strokeWidth); setupPaint(paint, opacity, stroke); if (strokeDasharray != null) { int length = strokeDasharray.length; float[] intervals = new float[length]; for (int i = 0; i < length; i++) { intervals[i] = (float) relativeOnOther(strokeDasharray[i]); } paint.setPathEffect(new DashPathEffect(intervals, strokeDashoffset)); } return true; } private void setupPaint(Paint paint, float opacity, ReadableArray colors) { int colorType = colors.getInt(0); switch (colorType) { case 0: if (colors.size() == 2) { int color; if (colors.getType(1) == ReadableType.Map) { color = ColorPropConverter.getColor(colors.getMap(1), getContext()); } else { color = colors.getInt(1); } int alpha = color >>> 24; int combined = Math.round((float) alpha * opacity); paint.setColor(combined << 24 | (color & 0x00ffffff)); } else { // solid color paint.setARGB( (int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255), (int) (colors.getDouble(1) * 255), (int) (colors.getDouble(2) * 255), (int) (colors.getDouble(3) * 255)); } break; case 1: { Brush brush = getSvgView().getDefinedBrush(colors.getString(1)); if (brush != null) { brush.setupPaint(paint, mBox, mScale, opacity); } break; } case 2: { int color = this.getCurrentColor(); int alpha = color >>> 24; alpha = Math.round((float) alpha * opacity); paint.setColor(alpha << 24 | (color & 0x00ffffff)); break; } case 3: { if (contextElement != null && contextElement.fill != null) { setupPaint(paint, opacity, contextElement.fill); } break; } case 4: { if (contextElement != null && contextElement.stroke != null) { setupPaint(paint, opacity, contextElement.stroke); } break; } } } abstract Path getPath(Canvas canvas, Paint paint); @Override int hitTest(final float[] src) { if (mPath == null || !mInvertible) { return -1; } if (mPointerEvents == PointerEvents.NONE) { return -1; } float[] dst = new float[2]; mInvMatrix.mapPoints(dst, src); int x = Math.round(dst[0]); int y = Math.round(dst[1]); initBounds(); if ((mRegion == null || !mRegion.contains(x, y)) && (mStrokeRegion == null || !mStrokeRegion.contains(x, y) && (mMarkerRegion == null || !mMarkerRegion.contains(x, y)))) { return -1; } Path clipPath = getClipPath(); if (clipPath != null) { if (!mClipRegion.contains(x, y)) { return -1; } } return getId(); } void initBounds() { if (mRegion == null && mFillPath != null) { mFillBounds = new RectF(); mFillPath.computeBounds(mFillBounds, true); mRegion = getRegion(mFillPath, mFillBounds); } if (mRegion == null && mPath != null) { mFillBounds = new RectF(); mPath.computeBounds(mFillBounds, true); mRegion = getRegion(mPath, mFillBounds); } if (mStrokeRegion == null && mStrokePath != null) { mStrokeBounds = new RectF(); mStrokePath.computeBounds(mStrokeBounds, true); mStrokeRegion = getRegion(mStrokePath, mStrokeBounds); } if (mMarkerRegion == null && mMarkerPath != null) { mMarkerBounds = new RectF(); mMarkerPath.computeBounds(mMarkerBounds, true); mMarkerRegion = getRegion(mMarkerPath, mMarkerBounds); } Path clipPath = getClipPath(); if (clipPath != null) { if (mClipRegionPath != clipPath) { mClipRegionPath = clipPath; mClipBounds = new RectF(); clipPath.computeBounds(mClipBounds, true); mClipRegion = getRegion(clipPath, mClipBounds); } } } Region getRegion(Path path, RectF rectF) { Region region = new Region(); region.setPath( path, new Region( (int) Math.floor(rectF.left), (int) Math.floor(rectF.top), (int) Math.ceil(rectF.right), (int) Math.ceil(rectF.bottom))); return region; } private ArrayList getAttributeList() { return mAttributeList; } void mergeProperties(RenderableView target) { mCaller = target; ArrayList targetAttributeList = target.getAttributeList(); if (targetAttributeList == null || targetAttributeList.size() == 0) { return; } mOriginProperties = new ArrayList<>(); mAttributeList = mPropList == null ? new ArrayList() : new ArrayList<>(mPropList); for (int i = 0, size = targetAttributeList.size(); i < size; i++) { try { String fieldName = targetAttributeList.get(i); Field field = getClass().getField(fieldName); Object value = field.get(target); mOriginProperties.add(field.get(this)); if (!hasOwnProperty(fieldName)) { mAttributeList.add(fieldName); field.set(this, value); } } catch (Exception e) { throw new IllegalStateException(e); } } mLastMergedList = targetAttributeList; } void resetProperties() { if (mLastMergedList != null && mOriginProperties != null) { try { for (int i = mLastMergedList.size() - 1; i >= 0; i--) { Field field = getClass().getField(mLastMergedList.get(i)); field.set(this, mOriginProperties.get(i)); } } catch (Exception e) { throw new IllegalStateException(e); } mLastMergedList = null; mOriginProperties = null; mAttributeList = mPropList; mCaller = null; } } private boolean hasOwnProperty(String propName) { return mAttributeList != null && mAttributeList.contains(propName); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/RenderableViewManager.java ================================================ /* * 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. */ package com.horcrux.svg; import static com.facebook.react.uimanager.ViewProps.ALIGN_CONTENT; import static com.facebook.react.uimanager.ViewProps.ALIGN_ITEMS; import static com.facebook.react.uimanager.ViewProps.ALIGN_SELF; import static com.facebook.react.uimanager.ViewProps.BORDER_BOTTOM_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_END_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_LEFT_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_RIGHT_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_START_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_TOP_WIDTH; import static com.facebook.react.uimanager.ViewProps.BORDER_WIDTH; import static com.facebook.react.uimanager.ViewProps.BOTTOM; import static com.facebook.react.uimanager.ViewProps.COLLAPSABLE; import static com.facebook.react.uimanager.ViewProps.DISPLAY; import static com.facebook.react.uimanager.ViewProps.END; import static com.facebook.react.uimanager.ViewProps.FLEX; import static com.facebook.react.uimanager.ViewProps.FLEX_BASIS; import static com.facebook.react.uimanager.ViewProps.FLEX_DIRECTION; import static com.facebook.react.uimanager.ViewProps.FLEX_GROW; import static com.facebook.react.uimanager.ViewProps.FLEX_SHRINK; import static com.facebook.react.uimanager.ViewProps.FLEX_WRAP; import static com.facebook.react.uimanager.ViewProps.HEIGHT; import static com.facebook.react.uimanager.ViewProps.JUSTIFY_CONTENT; import static com.facebook.react.uimanager.ViewProps.LEFT; import static com.facebook.react.uimanager.ViewProps.MARGIN; import static com.facebook.react.uimanager.ViewProps.MARGIN_BOTTOM; import static com.facebook.react.uimanager.ViewProps.MARGIN_END; import static com.facebook.react.uimanager.ViewProps.MARGIN_HORIZONTAL; import static com.facebook.react.uimanager.ViewProps.MARGIN_LEFT; import static com.facebook.react.uimanager.ViewProps.MARGIN_RIGHT; import static com.facebook.react.uimanager.ViewProps.MARGIN_START; import static com.facebook.react.uimanager.ViewProps.MARGIN_TOP; import static com.facebook.react.uimanager.ViewProps.MARGIN_VERTICAL; import static com.facebook.react.uimanager.ViewProps.MAX_HEIGHT; import static com.facebook.react.uimanager.ViewProps.MAX_WIDTH; import static com.facebook.react.uimanager.ViewProps.MIN_HEIGHT; import static com.facebook.react.uimanager.ViewProps.MIN_WIDTH; import static com.facebook.react.uimanager.ViewProps.OVERFLOW; import static com.facebook.react.uimanager.ViewProps.PADDING; import static com.facebook.react.uimanager.ViewProps.PADDING_BOTTOM; import static com.facebook.react.uimanager.ViewProps.PADDING_END; import static com.facebook.react.uimanager.ViewProps.PADDING_HORIZONTAL; import static com.facebook.react.uimanager.ViewProps.PADDING_LEFT; import static com.facebook.react.uimanager.ViewProps.PADDING_RIGHT; import static com.facebook.react.uimanager.ViewProps.PADDING_START; import static com.facebook.react.uimanager.ViewProps.PADDING_TOP; import static com.facebook.react.uimanager.ViewProps.PADDING_VERTICAL; import static com.facebook.react.uimanager.ViewProps.POSITION; import static com.facebook.react.uimanager.ViewProps.RIGHT; import static com.facebook.react.uimanager.ViewProps.START; import static com.facebook.react.uimanager.ViewProps.TOP; import static com.facebook.react.uimanager.ViewProps.WIDTH; import static com.horcrux.svg.RenderableView.CAP_ROUND; import static com.horcrux.svg.RenderableView.FILL_RULE_NONZERO; import static com.horcrux.svg.RenderableView.JOIN_ROUND; import android.graphics.Matrix; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.LayoutShadowNode; import com.facebook.react.uimanager.MatrixMathHelper; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.TransformHelper; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.ViewManagerDelegate; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactPropGroup; import com.facebook.react.viewmanagers.RNSVGCircleManagerDelegate; import com.facebook.react.viewmanagers.RNSVGCircleManagerInterface; import com.facebook.react.viewmanagers.RNSVGClipPathManagerDelegate; import com.facebook.react.viewmanagers.RNSVGClipPathManagerInterface; import com.facebook.react.viewmanagers.RNSVGDefsManagerDelegate; import com.facebook.react.viewmanagers.RNSVGDefsManagerInterface; import com.facebook.react.viewmanagers.RNSVGEllipseManagerDelegate; import com.facebook.react.viewmanagers.RNSVGEllipseManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeBlendManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeBlendManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeCompositeManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeCompositeManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeFloodManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeFloodManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeMergeManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeMergeManagerInterface; import com.facebook.react.viewmanagers.RNSVGFeOffsetManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFeOffsetManagerInterface; import com.facebook.react.viewmanagers.RNSVGFilterManagerDelegate; import com.facebook.react.viewmanagers.RNSVGFilterManagerInterface; import com.facebook.react.viewmanagers.RNSVGForeignObjectManagerDelegate; import com.facebook.react.viewmanagers.RNSVGForeignObjectManagerInterface; import com.facebook.react.viewmanagers.RNSVGGroupManagerDelegate; import com.facebook.react.viewmanagers.RNSVGGroupManagerInterface; import com.facebook.react.viewmanagers.RNSVGImageManagerDelegate; import com.facebook.react.viewmanagers.RNSVGImageManagerInterface; import com.facebook.react.viewmanagers.RNSVGLineManagerDelegate; import com.facebook.react.viewmanagers.RNSVGLineManagerInterface; import com.facebook.react.viewmanagers.RNSVGLinearGradientManagerDelegate; import com.facebook.react.viewmanagers.RNSVGLinearGradientManagerInterface; import com.facebook.react.viewmanagers.RNSVGMarkerManagerDelegate; import com.facebook.react.viewmanagers.RNSVGMarkerManagerInterface; import com.facebook.react.viewmanagers.RNSVGMaskManagerDelegate; import com.facebook.react.viewmanagers.RNSVGMaskManagerInterface; import com.facebook.react.viewmanagers.RNSVGPathManagerDelegate; import com.facebook.react.viewmanagers.RNSVGPathManagerInterface; import com.facebook.react.viewmanagers.RNSVGPatternManagerDelegate; import com.facebook.react.viewmanagers.RNSVGPatternManagerInterface; import com.facebook.react.viewmanagers.RNSVGRadialGradientManagerDelegate; import com.facebook.react.viewmanagers.RNSVGRadialGradientManagerInterface; import com.facebook.react.viewmanagers.RNSVGRectManagerDelegate; import com.facebook.react.viewmanagers.RNSVGRectManagerInterface; import com.facebook.react.viewmanagers.RNSVGSymbolManagerDelegate; import com.facebook.react.viewmanagers.RNSVGSymbolManagerInterface; import com.facebook.react.viewmanagers.RNSVGTSpanManagerDelegate; import com.facebook.react.viewmanagers.RNSVGTSpanManagerInterface; import com.facebook.react.viewmanagers.RNSVGTextManagerDelegate; import com.facebook.react.viewmanagers.RNSVGTextManagerInterface; 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 com.horcrux.svg.events.SvgLoadEvent; import com.horcrux.svg.events.SvgOnLayoutEvent; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** ViewManager for DefinitionView RNSVG views */ class VirtualViewManager extends ViewGroupManager { protected final SVGClass svgClass; protected final String mClassName; protected VirtualViewManager(SVGClass svgclass) { svgClass = svgclass; mClassName = svgclass.toString(); } protected ViewManagerDelegate mDelegate; protected ViewManagerDelegate getDelegate() { return mDelegate; } static class RenderableShadowNode extends LayoutShadowNode { @SuppressWarnings({"unused", "EmptyMethod"}) @ReactPropGroup( names = { ALIGN_SELF, ALIGN_ITEMS, COLLAPSABLE, FLEX, FLEX_BASIS, FLEX_DIRECTION, FLEX_GROW, FLEX_SHRINK, FLEX_WRAP, JUSTIFY_CONTENT, OVERFLOW, ALIGN_CONTENT, DISPLAY, /* position */ POSITION, RIGHT, TOP, BOTTOM, LEFT, START, END, /* dimensions */ WIDTH, HEIGHT, MIN_WIDTH, MAX_WIDTH, MIN_HEIGHT, MAX_HEIGHT, /* margins */ MARGIN, MARGIN_VERTICAL, MARGIN_HORIZONTAL, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOTTOM, MARGIN_START, MARGIN_END, /* paddings */ PADDING, PADDING_VERTICAL, PADDING_HORIZONTAL, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, PADDING_BOTTOM, PADDING_START, PADDING_END, BORDER_WIDTH, BORDER_START_WIDTH, BORDER_END_WIDTH, BORDER_TOP_WIDTH, BORDER_BOTTOM_WIDTH, BORDER_LEFT_WIDTH, BORDER_RIGHT_WIDTH, }) public void ignoreLayoutProps(int index, Dynamic value) {} } @Override public LayoutShadowNode createShadowNodeInstance() { return new RenderableShadowNode(); } @Override public Class getShadowNodeClass() { return RenderableShadowNode.class; } private static final MatrixMathHelper.MatrixDecompositionContext sMatrixDecompositionContext = new MatrixMathHelper.MatrixDecompositionContext(); private static final double[] sTransformDecompositionArray = new double[16]; private static final int PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX = 2; private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = 5; private static float sanitizeFloatPropertyValue(float value) { if (value >= -Float.MAX_VALUE && value <= Float.MAX_VALUE) { return value; } if (value < -Float.MAX_VALUE || value == Float.NEGATIVE_INFINITY) { return -Float.MAX_VALUE; } if (value > Float.MAX_VALUE || value == Float.POSITIVE_INFINITY) { return Float.MAX_VALUE; } if (Float.isNaN(value)) { return 0; } // Shouldn't be possible to reach this point. throw new IllegalStateException("Invalid float property value: " + value); } protected void setTransformProperty(VirtualView view, ReadableArray transforms) { if (transforms == null) { view.setTranslationX(PixelUtil.toPixelFromDIP(0)); view.setTranslationY(PixelUtil.toPixelFromDIP(0)); view.setRotation(0); view.setRotationX(0); view.setRotationY(0); view.setScaleX(1); view.setScaleY(1); view.setCameraDistance(0); return; } sMatrixDecompositionContext.reset(); TransformHelper.processTransform( transforms, sTransformDecompositionArray, view.getWidth(), view.getHeight(), null, false); MatrixMathHelper.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext); view.setTranslationX( PixelUtil.toPixelFromDIP( sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.translation[0]))); view.setTranslationY( PixelUtil.toPixelFromDIP( sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.translation[1]))); view.setRotation( sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.rotationDegrees[2])); view.setRotationX( sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.rotationDegrees[0])); view.setRotationY( sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.rotationDegrees[1])); view.setScaleX(sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.scale[0])); view.setScaleY(sanitizeFloatPropertyValue((float) sMatrixDecompositionContext.scale[1])); double[] perspectiveArray = sMatrixDecompositionContext.perspective; if (perspectiveArray.length > PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX) { float invertedCameraDistance = (float) perspectiveArray[PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX]; if (invertedCameraDistance == 0) { // Default camera distance, before scale multiplier (1280) invertedCameraDistance = 0.00078125f; } float cameraDistance = -1 / invertedCameraDistance; float scale = DisplayMetricsHolder.getScreenDisplayMetrics().density; // The following converts the matrix's perspective to a camera distance // such that the camera perspective looks the same on Android and iOS. // The native Android implementation removed the screen density from the // calculation, so squaring and a normalization value of // sqrt(5) produces an exact replica with iOS. // For more information, see https://github.com/facebook/react-native/pull/18302 float normalizedCameraDistance = scale * scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER; view.setCameraDistance(normalizedCameraDistance); } } @Nonnull public String getName() { return mClassName; } @ReactProp(name = "mask") public void setMask(V node, String mask) { node.setMask(mask); } @ReactProp(name = "markerStart") public void setMarkerStart(V node, String markerStart) { node.setMarkerStart(markerStart); } @ReactProp(name = "markerMid") public void setMarkerMid(V node, String markerMid) { node.setMarkerMid(markerMid); } @ReactProp(name = "markerEnd") public void setMarkerEnd(V node, String markerEnd) { node.setMarkerEnd(markerEnd); } @ReactProp(name = "clipPath") public void setClipPath(V node, String clipPath) { node.setClipPath(clipPath); } @ReactProp(name = "clipRule") public void setClipRule(V node, int clipRule) { node.setClipRule(clipRule); } @ReactProp(name = "opacity", defaultFloat = 1f) public void setOpacity(@Nonnull V node, float opacity) { node.setOpacity(opacity); } @ReactProp(name = "responsible") public void setResponsible(V node, boolean responsible) { node.setResponsible(responsible); } @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("-", "_")); view.setPointerEvents(pointerEvents); } } @ReactProp(name = "name") public void setName(V node, String name) { node.setName(name); } @ReactProp(name = "display") public void setDisplay(V node, String display) { node.setDisplay(display); } @ReactProp(name = "matrix") public void setMatrix(V node, Dynamic matrixArray) { node.setMatrix(matrixArray); } public void setMatrix(V view, @Nullable ReadableArray value) { view.setMatrix(value); } @Override public void setTransform(VirtualView node, @Nullable ReadableArray matrix) { setTransformProperty(node, matrix); Matrix m = node.getMatrix(); node.mMatrix = m; node.mInvertible = m.invert(node.mInvMatrix); } @ReactProp(name = "transform") public void setTransform(V node, Dynamic matrix) { if (matrix.getType() != ReadableType.Array) { return; } ReadableArray ma = matrix.asArray(); setTransform(node, ma); } private void invalidateSvgView(V node) { SvgView view = node.getSvgView(); if (view != null) { view.invalidate(); } if (node instanceof TextView) { ((TextView) node).getTextContainer().clearChildCache(); } } @Override protected void addEventEmitters( @Nonnull ThemedReactContext reactContext, @Nonnull VirtualView view) { super.addEventEmitters(reactContext, view); view.setOnHierarchyChangeListener( new ViewGroup.OnHierarchyChangeListener() { @Override public void onChildViewAdded(View view, View view1) { if (view instanceof VirtualView) { invalidateSvgView((V) view); } } @Override public void onChildViewRemoved(View view, View view1) { if (view instanceof VirtualView) { invalidateSvgView((V) view); } } }); } /** * Callback that will be triggered after all properties are updated in current update transaction * (all @ReactProp handlers for properties updated in current transaction have been called). If * you want to override this method you should call super.onAfterUpdateTransaction from it as the * parent class of the ViewManager may rely on callback being executed. */ @Override protected void onAfterUpdateTransaction(@Nonnull VirtualView node) { super.onAfterUpdateTransaction(node); invalidateSvgView((V) node); } protected enum SVGClass { RNSVGGroup, RNSVGPath, RNSVGText, RNSVGTSpan, RNSVGTextPath, RNSVGImage, RNSVGCircle, RNSVGEllipse, RNSVGLine, RNSVGRect, RNSVGClipPath, RNSVGDefs, RNSVGUse, RNSVGSymbol, RNSVGLinearGradient, RNSVGRadialGradient, RNSVGPattern, RNSVGMask, RNSVGFilter, RNSVGFeBlend, RNSVGFeColorMatrix, RNSVGFeComposite, RNSVGFeFlood, RNSVGFeGaussianBlur, RNSVGFeMerge, RNSVGFeOffset, RNSVGMarker, RNSVGForeignObject, } @Nonnull @Override protected VirtualView createViewInstance(@Nonnull ThemedReactContext reactContext) { switch (svgClass) { case RNSVGGroup: return new GroupView(reactContext); case RNSVGPath: return new PathView(reactContext); case RNSVGCircle: return new CircleView(reactContext); case RNSVGEllipse: return new EllipseView(reactContext); case RNSVGLine: return new LineView(reactContext); case RNSVGRect: return new RectView(reactContext); case RNSVGText: return new TextView(reactContext); case RNSVGTSpan: return new TSpanView(reactContext); case RNSVGTextPath: return new TextPathView(reactContext); case RNSVGImage: return new ImageView(reactContext); case RNSVGClipPath: return new ClipPathView(reactContext); case RNSVGDefs: return new DefsView(reactContext); case RNSVGUse: return new UseView(reactContext); case RNSVGSymbol: return new SymbolView(reactContext); case RNSVGLinearGradient: return new LinearGradientView(reactContext); case RNSVGRadialGradient: return new RadialGradientView(reactContext); case RNSVGPattern: return new PatternView(reactContext); case RNSVGMask: return new MaskView(reactContext); case RNSVGFilter: return new FilterView(reactContext); case RNSVGFeBlend: return new FeBlendView(reactContext); case RNSVGFeColorMatrix: return new FeColorMatrixView(reactContext); case RNSVGFeComposite: return new FeCompositeView(reactContext); case RNSVGFeFlood: return new FeFloodView(reactContext); case RNSVGFeGaussianBlur: return new FeGaussianBlurView(reactContext); case RNSVGFeMerge: return new FeMergeView(reactContext); case RNSVGFeOffset: return new FeOffsetView(reactContext); case RNSVGMarker: return new MarkerView(reactContext); case RNSVGForeignObject: return new ForeignObjectView(reactContext); default: throw new IllegalStateException("Unexpected type " + svgClass.toString()); } } private static final SparseArray mTagToRenderableView = new SparseArray<>(); private static final SparseArray mTagToRunnable = new SparseArray<>(); static void setRenderableView(int tag, RenderableView svg) { mTagToRenderableView.put(tag, svg); Runnable task = mTagToRunnable.get(tag); if (task != null) { task.run(); mTagToRunnable.delete(tag); } } static void runWhenViewIsAvailable(int tag, Runnable task) { mTagToRunnable.put(tag, task); } static @Nullable RenderableView getRenderableViewByTag(int tag) { return mTagToRenderableView.get(tag); } @Override public void onDropViewInstance(@Nonnull VirtualView view) { super.onDropViewInstance(view); mTagToRenderableView.remove(view.getId()); } } /** ViewManager for Renderable RNSVG views */ class RenderableViewManager extends VirtualViewManager { RenderableViewManager(SVGClass svgclass) { super(svgclass); } public Map getExportedCustomDirectEventTypeConstants() { Map eventTypes = new HashMap<>(); eventTypes.put(SvgOnLayoutEvent.EVENT_NAME, MapBuilder.of("registrationName", "onSvgLayout")); return eventTypes; } static class GroupViewManagerAbstract extends RenderableViewManager { GroupViewManagerAbstract(SVGClass svgClass) { super(svgClass); } @ReactProp(name = "font") public void setFont(U node, Dynamic font) { node.setFont(font); } @ReactProp(name = "fontSize") public void setFontSize(U node, Dynamic fontSize) { JavaOnlyMap map = new JavaOnlyMap(); switch (fontSize.getType()) { case Number: map.putDouble("fontSize", fontSize.asDouble()); break; case String: map.putString("fontSize", fontSize.asString()); break; default: return; } node.setFont(map); } @ReactProp(name = "fontWeight") public void setFontWeight(U node, Dynamic fontWeight) { JavaOnlyMap map = new JavaOnlyMap(); switch (fontWeight.getType()) { case Number: map.putDouble("fontWeight", fontWeight.asDouble()); break; case String: map.putString("fontWeight", fontWeight.asString()); break; default: return; } node.setFont(map); } } static class GroupViewManager extends GroupViewManagerAbstract implements RNSVGGroupManagerInterface { GroupViewManager() { super(SVGClass.RNSVGGroup); mDelegate = new RNSVGGroupManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGGroup"; } static class PathViewManager extends RenderableViewManager implements RNSVGPathManagerInterface { PathViewManager() { super(SVGClass.RNSVGPath); mDelegate = new RNSVGPathManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGPath"; @ReactProp(name = "d") public void setD(PathView node, String d) { node.setD(d); } } static class TextViewManagerAbstract extends GroupViewManagerAbstract { TextViewManagerAbstract(SVGClass svgClass) { super(svgClass); } @ReactProp(name = "inlineSize") public void setInlineSize(K node, Dynamic inlineSize) { node.setInlineSize(inlineSize); } @ReactProp(name = "textLength") public void setTextLength(K node, Dynamic length) { node.setTextLength(length); } @ReactProp(name = "lengthAdjust") public void setLengthAdjust(K node, @Nullable String adjustment) { node.setLengthAdjust(adjustment); } @ReactProp(name = "alignmentBaseline") public void setMethod(K node, @Nullable String alignment) { node.setMethod(alignment); } @ReactProp(name = "baselineShift") public void setBaselineShift(K node, Dynamic baselineShift) { node.setBaselineShift(baselineShift); } @ReactProp(name = "verticalAlign") public void setVerticalAlign(K node, @Nullable Dynamic verticalAlign) { node.setVerticalAlign(verticalAlign); } @ReactProp(name = "rotate") public void setRotate(K node, Dynamic rotate) { node.setRotate(rotate); } @ReactProp(name = "dx") public void setDx(K node, Dynamic deltaX) { node.setDeltaX(deltaX); } @ReactProp(name = "dy") public void setDy(K node, Dynamic deltaY) { node.setDeltaY(deltaY); } @ReactProp(name = "x") public void setX(K node, Dynamic positionX) { node.setPositionX(positionX); } @ReactProp(name = "y") public void setY(K node, Dynamic positionY) { node.setPositionY(positionY); } @ReactProp(name = "font") public void setFont(K node, Dynamic font) { node.setFont(font); } public void setAlignmentBaseline(K view, @Nullable String value) { view.setMethod(value); } } static class TextViewManager extends TextViewManagerAbstract implements RNSVGTextManagerInterface { TextViewManager() { super(SVGClass.RNSVGText); mDelegate = new RNSVGTextManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGText"; TextViewManager(SVGClass svgClass) { super(svgClass); mDelegate = new RNSVGTextManagerDelegate(this); } } static class TSpanViewManager extends TextViewManagerAbstract implements RNSVGTSpanManagerInterface { TSpanViewManager() { super(SVGClass.RNSVGTSpan); mDelegate = new RNSVGTSpanManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGTSpan"; TSpanViewManager(SVGClass svgClass) { super(svgClass); mDelegate = new RNSVGTSpanManagerDelegate(this); } @ReactProp(name = "content") public void setContent(TSpanView node, @Nullable String content) { node.setContent(content); } } static class TextPathViewManager extends TextViewManagerAbstract implements RNSVGTextPathManagerInterface { TextPathViewManager() { super(SVGClass.RNSVGTextPath); mDelegate = new RNSVGTextPathManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGTextPath"; TextPathViewManager(SVGClass svgClass) { super(svgClass); mDelegate = new RNSVGTextPathManagerDelegate(this); } @ReactProp(name = "href") public void setHref(TextPathView node, String href) { node.setHref(href); } @ReactProp(name = "startOffset") public void setStartOffset(TextPathView node, Dynamic startOffset) { node.setStartOffset(startOffset); } @ReactProp(name = "method") public void setMethod(TextPathView node, @Nullable String method) { node.setMethod(method); } @Override public void setMidLine(TextPathView view, @Nullable String value) { view.setSharp(value); } @ReactProp(name = "spacing") public void setSpacing(TextPathView node, @Nullable String spacing) { node.setSpacing(spacing); } @ReactProp(name = "side") public void setSide(TextPathView node, @Nullable String side) { node.setSide(side); } @ReactProp(name = "midLine") public void setSharp(TextPathView node, @Nullable String midLine) { node.setSharp(midLine); } } static class ImageViewManager extends RenderableViewManager implements RNSVGImageManagerInterface { ImageViewManager() { super(SVGClass.RNSVGImage); mDelegate = new RNSVGImageManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGImage"; @ReactProp(name = "x") public void setX(ImageView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(ImageView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(ImageView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(ImageView node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "src", customType = "ImageSource") public void setSrc(ImageView node, @Nullable ReadableMap src) { node.setSrc(src); } @ReactProp(name = "align") public void setAlign(ImageView node, String align) { node.setAlign(align); } @ReactProp(name = "meetOrSlice") public void setMeetOrSlice(ImageView node, int meetOrSlice) { node.setMeetOrSlice(meetOrSlice); } public Map getExportedCustomDirectEventTypeConstants() { Map eventTypes = new HashMap<>(); eventTypes.put(SvgLoadEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoad")); return eventTypes; } } static class CircleViewManager extends RenderableViewManager implements RNSVGCircleManagerInterface { CircleViewManager() { super(SVGClass.RNSVGCircle); mDelegate = new RNSVGCircleManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGCircle"; @ReactProp(name = "cx") public void setCx(CircleView node, Dynamic cx) { node.setCx(cx); } @ReactProp(name = "cy") public void setCy(CircleView node, Dynamic cy) { node.setCy(cy); } @ReactProp(name = "r") public void setR(CircleView node, Dynamic r) { node.setR(r); } } static class EllipseViewManager extends RenderableViewManager implements RNSVGEllipseManagerInterface { EllipseViewManager() { super(SVGClass.RNSVGEllipse); mDelegate = new RNSVGEllipseManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGEllipse"; @ReactProp(name = "cx") public void setCx(EllipseView node, Dynamic cx) { node.setCx(cx); } @ReactProp(name = "cy") public void setCy(EllipseView node, Dynamic cy) { node.setCy(cy); } @ReactProp(name = "rx") public void setRx(EllipseView node, Dynamic rx) { node.setRx(rx); } @ReactProp(name = "ry") public void setRy(EllipseView node, Dynamic ry) { node.setRy(ry); } } static class LineViewManager extends RenderableViewManager implements RNSVGLineManagerInterface { LineViewManager() { super(SVGClass.RNSVGLine); mDelegate = new RNSVGLineManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGLine"; @ReactProp(name = "x1") public void setX1(LineView node, Dynamic x1) { node.setX1(x1); } @ReactProp(name = "y1") public void setY1(LineView node, Dynamic y1) { node.setY1(y1); } @ReactProp(name = "x2") public void setX2(LineView node, Dynamic x2) { node.setX2(x2); } @ReactProp(name = "y2") public void setY2(LineView node, Dynamic y2) { node.setY2(y2); } } static class RectViewManager extends RenderableViewManager implements RNSVGRectManagerInterface { RectViewManager() { super(SVGClass.RNSVGRect); mDelegate = new RNSVGRectManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGRect"; @ReactProp(name = "x") public void setX(RectView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(RectView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(RectView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(RectView node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "rx") public void setRx(RectView node, Dynamic rx) { node.setRx(rx); } @ReactProp(name = "ry") public void setRy(RectView node, Dynamic ry) { node.setRy(ry); } } static class ClipPathViewManager extends GroupViewManagerAbstract implements RNSVGClipPathManagerInterface { ClipPathViewManager() { super(SVGClass.RNSVGClipPath); mDelegate = new RNSVGClipPathManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGClipPath"; } static class DefsViewManager extends VirtualViewManager implements RNSVGDefsManagerInterface { DefsViewManager() { super(SVGClass.RNSVGDefs); mDelegate = new RNSVGDefsManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGDefs"; } static class UseViewManager extends RenderableViewManager implements RNSVGUseManagerInterface { UseViewManager() { super(SVGClass.RNSVGUse); mDelegate = new RNSVGUseManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGUse"; @ReactProp(name = "href") public void setHref(UseView node, String href) { node.setHref(href); } @ReactProp(name = "x") public void setX(UseView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(UseView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(UseView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(UseView node, Dynamic height) { node.setHeight(height); } } static class SymbolManager extends GroupViewManagerAbstract implements RNSVGSymbolManagerInterface { SymbolManager() { super(SVGClass.RNSVGSymbol); mDelegate = new RNSVGSymbolManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGSymbol"; @ReactProp(name = "minX") public void setMinX(SymbolView node, float minX) { node.setMinX(minX); } @ReactProp(name = "minY") public void setMinY(SymbolView node, float minY) { node.setMinY(minY); } @ReactProp(name = "vbWidth") public void setVbWidth(SymbolView node, float vbWidth) { node.setVbWidth(vbWidth); } @ReactProp(name = "vbHeight") public void setVbHeight(SymbolView node, float vbHeight) { node.setVbHeight(vbHeight); } @ReactProp(name = "align") public void setAlign(SymbolView node, String align) { node.setAlign(align); } @ReactProp(name = "meetOrSlice") public void setMeetOrSlice(SymbolView node, int meetOrSlice) { node.setMeetOrSlice(meetOrSlice); } } static class PatternManager extends GroupViewManagerAbstract implements RNSVGPatternManagerInterface { PatternManager() { super(SVGClass.RNSVGPattern); mDelegate = new RNSVGPatternManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGPattern"; @ReactProp(name = "x") public void setX(PatternView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(PatternView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(PatternView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(PatternView node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "patternUnits") public void setPatternUnits(PatternView node, int patternUnits) { node.setPatternUnits(patternUnits); } @ReactProp(name = "patternContentUnits") public void setPatternContentUnits(PatternView node, int patternContentUnits) { node.setPatternContentUnits(patternContentUnits); } @ReactProp(name = "patternTransform") public void setPatternTransform(PatternView node, @Nullable ReadableArray matrixArray) { node.setPatternTransform(matrixArray); } @ReactProp(name = "minX") public void setMinX(PatternView node, float minX) { node.setMinX(minX); } @ReactProp(name = "minY") public void setMinY(PatternView node, float minY) { node.setMinY(minY); } @ReactProp(name = "vbWidth") public void setVbWidth(PatternView node, float vbWidth) { node.setVbWidth(vbWidth); } @ReactProp(name = "vbHeight") public void setVbHeight(PatternView node, float vbHeight) { node.setVbHeight(vbHeight); } @ReactProp(name = "align") public void setAlign(PatternView node, String align) { node.setAlign(align); } @ReactProp(name = "meetOrSlice") public void setMeetOrSlice(PatternView node, int meetOrSlice) { node.setMeetOrSlice(meetOrSlice); } } static class MaskManager extends GroupViewManagerAbstract implements RNSVGMaskManagerInterface { MaskManager() { super(SVGClass.RNSVGMask); mDelegate = new RNSVGMaskManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGMask"; @ReactProp(name = "x") public void setX(MaskView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(MaskView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(MaskView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(MaskView node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "maskUnits") public void setMaskUnits(MaskView node, int maskUnits) { node.setMaskUnits(maskUnits); } @ReactProp(name = "maskContentUnits") public void setMaskContentUnits(MaskView node, int maskContentUnits) { node.setMaskContentUnits(maskContentUnits); } @ReactProp(name = "maskType") public void setMaskType(MaskView node, int maskType) { node.setMaskType(maskType); } } static class ForeignObjectManager extends GroupViewManagerAbstract implements RNSVGForeignObjectManagerInterface { ForeignObjectManager() { super(SVGClass.RNSVGForeignObject); mDelegate = new RNSVGForeignObjectManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGForeignObject"; @ReactProp(name = "x") public void setX(ForeignObjectView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(ForeignObjectView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(ForeignObjectView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(ForeignObjectView node, Dynamic height) { node.setHeight(height); } } static class MarkerManager extends GroupViewManagerAbstract implements RNSVGMarkerManagerInterface { MarkerManager() { super(SVGClass.RNSVGMarker); mDelegate = new RNSVGMarkerManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGMarker"; @ReactProp(name = "refX") public void setRefX(MarkerView node, Dynamic refX) { node.setRefX(refX); } @ReactProp(name = "refY") public void setRefY(MarkerView node, Dynamic refY) { node.setRefY(refY); } @ReactProp(name = "markerWidth") public void setMarkerWidth(MarkerView node, Dynamic markerWidth) { node.setMarkerWidth(markerWidth); } @ReactProp(name = "markerHeight") public void setMarkerHeight(MarkerView node, Dynamic markerHeight) { node.setMarkerHeight(markerHeight); } @ReactProp(name = "markerUnits") public void setMarkerUnits(MarkerView node, String markerUnits) { node.setMarkerUnits(markerUnits); } @ReactProp(name = "orient") public void setOrient(MarkerView node, String orient) { node.setOrient(orient); } @ReactProp(name = "minX") public void setMinX(MarkerView node, float minX) { node.setMinX(minX); } @ReactProp(name = "minY") public void setMinY(MarkerView node, float minY) { node.setMinY(minY); } @ReactProp(name = "vbWidth") public void setVbWidth(MarkerView node, float vbWidth) { node.setVbWidth(vbWidth); } @ReactProp(name = "vbHeight") public void setVbHeight(MarkerView node, float vbHeight) { node.setVbHeight(vbHeight); } @ReactProp(name = "align") public void setAlign(MarkerView node, String align) { node.setAlign(align); } @ReactProp(name = "meetOrSlice") public void setMeetOrSlice(MarkerView node, int meetOrSlice) { node.setMeetOrSlice(meetOrSlice); } } static class LinearGradientManager extends VirtualViewManager implements RNSVGLinearGradientManagerInterface { LinearGradientManager() { super(SVGClass.RNSVGLinearGradient); mDelegate = new RNSVGLinearGradientManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGLinearGradient"; @ReactProp(name = "x1") public void setX1(LinearGradientView node, Dynamic x1) { node.setX1(x1); } @ReactProp(name = "y1") public void setY1(LinearGradientView node, Dynamic y1) { node.setY1(y1); } @ReactProp(name = "x2") public void setX2(LinearGradientView node, Dynamic x2) { node.setX2(x2); } @ReactProp(name = "y2") public void setY2(LinearGradientView node, Dynamic y2) { node.setY2(y2); } @ReactProp(name = "gradient") public void setGradient(LinearGradientView node, ReadableArray gradient) { node.setGradient(gradient); } @ReactProp(name = "gradientUnits") public void setGradientUnits(LinearGradientView node, int gradientUnits) { node.setGradientUnits(gradientUnits); } @ReactProp(name = "gradientTransform") public void setGradientTransform(LinearGradientView node, @Nullable ReadableArray matrixArray) { node.setGradientTransform(matrixArray); } } static class RadialGradientManager extends VirtualViewManager implements RNSVGRadialGradientManagerInterface { RadialGradientManager() { super(SVGClass.RNSVGRadialGradient); mDelegate = new RNSVGRadialGradientManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGRadialGradient"; @ReactProp(name = "fx") public void setFx(RadialGradientView node, Dynamic fx) { node.setFx(fx); } @ReactProp(name = "fy") public void setFy(RadialGradientView node, Dynamic fy) { node.setFy(fy); } @ReactProp(name = "rx") public void setRx(RadialGradientView node, Dynamic rx) { node.setRx(rx); } @ReactProp(name = "ry") public void setRy(RadialGradientView node, Dynamic ry) { node.setRy(ry); } @ReactProp(name = "cx") public void setCx(RadialGradientView node, Dynamic cx) { node.setCx(cx); } @ReactProp(name = "cy") public void setCy(RadialGradientView node, Dynamic cy) { node.setCy(cy); } @ReactProp(name = "gradient") public void setGradient(RadialGradientView node, ReadableArray gradient) { node.setGradient(gradient); } @ReactProp(name = "gradientUnits") public void setGradientUnits(RadialGradientView node, int gradientUnits) { node.setGradientUnits(gradientUnits); } @ReactProp(name = "gradientTransform") public void setGradientTransform(RadialGradientView node, @Nullable ReadableArray matrixArray) { node.setGradientTransform(matrixArray); } } static class FilterManager extends VirtualViewManager implements RNSVGFilterManagerInterface { FilterManager() { super(SVGClass.RNSVGFilter); mDelegate = new RNSVGFilterManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFilter"; @ReactProp(name = "x") public void setX(FilterView node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(FilterView node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(FilterView node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(FilterView node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "filterUnits") public void setFilterUnits(FilterView node, String filterUnits) { node.setFilterUnits(filterUnits); } @ReactProp(name = "primitiveUnits") public void setPrimitiveUnits(FilterView node, String primitiveUnits) { node.setPrimitiveUnits(primitiveUnits); } } static class FilterPrimitiveManager extends VirtualViewManager { protected FilterPrimitiveManager(SVGClass svgclass) { super(svgclass); } @ReactProp(name = "x") public void setX(T node, Dynamic x) { node.setX(x); } @ReactProp(name = "y") public void setY(T node, Dynamic y) { node.setY(y); } @ReactProp(name = "width") public void setWidth(T node, Dynamic width) { node.setWidth(width); } @ReactProp(name = "height") public void setHeight(T node, Dynamic height) { node.setHeight(height); } @ReactProp(name = "result") public void setResult(T node, String result) { node.setResult(result); } } static class FeBlendManager extends FilterPrimitiveManager implements RNSVGFeBlendManagerInterface { FeBlendManager() { super(SVGClass.RNSVGFeBlend); mDelegate = new RNSVGFeBlendManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeBlend"; @ReactProp(name = "in1") public void setIn1(FeBlendView node, String in1) { node.setIn1(in1); } @ReactProp(name = "in2") public void setIn2(FeBlendView node, String in2) { node.setIn2(in2); } @ReactProp(name = "mode") public void setMode(FeBlendView node, String mode) { node.setMode(mode); } } static class FeColorMatrixManager extends FilterPrimitiveManager implements RNSVGFeColorMatrixManagerInterface { FeColorMatrixManager() { super(SVGClass.RNSVGFeColorMatrix); mDelegate = new RNSVGFeColorMatrixManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeColorMatrix"; @ReactProp(name = "in1") public void setIn1(FeColorMatrixView node, String in1) { node.setIn1(in1); } @ReactProp(name = "type") public void setType(FeColorMatrixView node, String type) { node.setType(type); } @ReactProp(name = "values") public void setValues(FeColorMatrixView node, @Nullable ReadableArray values) { node.setValues(values); } } static class FeCompositeManager extends FilterPrimitiveManager implements RNSVGFeCompositeManagerInterface { FeCompositeManager() { super(SVGClass.RNSVGFeComposite); mDelegate = new RNSVGFeCompositeManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeComposite"; @ReactProp(name = "in1") public void setIn1(FeCompositeView node, String in1) { node.setIn1(in1); } @ReactProp(name = "in2") public void setIn2(FeCompositeView node, String in2) { node.setIn2(in2); } @ReactProp(name = "operator1") public void setOperator1(FeCompositeView node, String operator) { node.setOperator(operator); } @ReactProp(name = "k1") public void setK1(FeCompositeView node, float value) { node.setK1(value); } @ReactProp(name = "k2") public void setK2(FeCompositeView node, float value) { node.setK2(value); } @ReactProp(name = "k3") public void setK3(FeCompositeView node, float value) { node.setK3(value); } @ReactProp(name = "k4") public void setK4(FeCompositeView node, float value) { node.setK4(value); } } static class FeFloodManager extends FilterPrimitiveManager implements RNSVGFeFloodManagerInterface { FeFloodManager() { super(SVGClass.RNSVGFeFlood); mDelegate = new RNSVGFeFloodManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeFlood"; @ReactProp(name = "floodColor") public void setFloodColor(FeFloodView node, @Nullable Dynamic strokeColors) { node.setFloodColor(strokeColors); } public void setFloodColor(FeFloodView view, @Nullable ReadableMap value) { view.setFloodColor(value); } @ReactProp(name = "floodOpacity", defaultFloat = 1f) public void setFloodOpacity(FeFloodView node, float strokeOpacity) { node.setFloodOpacity(strokeOpacity); } } static class FeGaussianBlurManager extends FilterPrimitiveManager implements RNSVGFeGaussianBlurManagerInterface { FeGaussianBlurManager() { super(SVGClass.RNSVGFeGaussianBlur); mDelegate = new RNSVGFeGaussianBlurManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeGaussianBlur"; @ReactProp(name = "in1") public void setIn1(FeGaussianBlurView node, String in1) { node.setIn1(in1); } @ReactProp(name = "stdDeviationX") public void setStdDeviationX(FeGaussianBlurView node, float stdDeviationX) { node.setStdDeviationX(stdDeviationX); } @ReactProp(name = "stdDeviationY") public void setStdDeviationY(FeGaussianBlurView node, float stdDeviationY) { node.setStdDeviationY(stdDeviationY); } @ReactProp(name = "values") public void setEdgeMode(FeGaussianBlurView node, String edgeMode) { node.setEdgeMode(edgeMode); } } static class FeMergeManager extends FilterPrimitiveManager implements RNSVGFeMergeManagerInterface { FeMergeManager() { super(SVGClass.RNSVGFeMerge); mDelegate = new RNSVGFeMergeManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeMerge"; @ReactProp(name = "nodes") public void setNodes(FeMergeView node, ReadableArray nodes) { node.setNodes(nodes); } } static class FeOffsetManager extends FilterPrimitiveManager implements RNSVGFeOffsetManagerInterface { FeOffsetManager() { super(SVGClass.RNSVGFeOffset); mDelegate = new RNSVGFeOffsetManagerDelegate(this); } public static final String REACT_CLASS = "RNSVGFeOffset"; @ReactProp(name = "in1") public void setIn1(FeOffsetView node, String in1) { node.setIn1(in1); } @ReactProp(name = "dx") public void setDx(FeOffsetView node, Dynamic dx) { node.setDx(dx); } @ReactProp(name = "dy") public void setDy(FeOffsetView node, Dynamic dy) { node.setDy(dy); } } @ReactProp(name = "filter") public void setFilter(T node, String filter) { node.setFilter(filter); } @ReactProp(name = "color", customType = "Color") public void setColor(T node, Integer color) { node.setCurrentColor(color); } @ReactProp(name = "fill") public void setFill(T node, @Nullable Dynamic fill) { node.setFill(fill); } public void setFill(T view, @Nullable ReadableMap value) { view.setFill(value); } @ReactProp(name = "fillOpacity", defaultFloat = 1f) public void setFillOpacity(T node, float fillOpacity) { node.setFillOpacity(fillOpacity); } @ReactProp(name = "fillRule", defaultInt = FILL_RULE_NONZERO) public void setFillRule(T node, int fillRule) { node.setFillRule(fillRule); } @ReactProp(name = "stroke") public void setStroke(T node, @Nullable Dynamic strokeColors) { node.setStroke(strokeColors); } public void setStroke(T view, @Nullable ReadableMap value) { view.setStroke(value); } @ReactProp(name = "strokeOpacity", defaultFloat = 1f) public void setStrokeOpacity(T node, float strokeOpacity) { node.setStrokeOpacity(strokeOpacity); } @ReactProp(name = "strokeDasharray") public void setStrokeDasharray(T node, Dynamic strokeDasharray) { node.setStrokeDasharray(strokeDasharray); } @ReactProp(name = "strokeDashoffset") public void setStrokeDashoffset(T node, float strokeDashoffset) { node.setStrokeDashoffset(strokeDashoffset); } @ReactProp(name = "strokeWidth") public void setStrokeWidth(T node, Dynamic strokeWidth) { node.setStrokeWidth(strokeWidth); } @ReactProp(name = "strokeMiterlimit", defaultFloat = 4f) public void setStrokeMiterlimit(T node, float strokeMiterlimit) { node.setStrokeMiterlimit(strokeMiterlimit); } @ReactProp(name = "strokeLinecap", defaultInt = CAP_ROUND) public void setStrokeLinecap(T node, int strokeLinecap) { node.setStrokeLinecap(strokeLinecap); } @ReactProp(name = "strokeLinejoin", defaultInt = JOIN_ROUND) public void setStrokeLinejoin(T node, int strokeLinejoin) { node.setStrokeLinejoin(strokeLinejoin); } @ReactProp(name = "vectorEffect") public void setVectorEffect(T node, int vectorEffect) { node.setVectorEffect(vectorEffect); } @ReactProp(name = "propList") public void setPropList(T node, @Nullable ReadableArray propList) { node.setPropList(propList); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SVGLength.java ================================================ package com.horcrux.svg; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableArray; import java.util.ArrayList; class SVGLength { // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength public enum UnitType { UNKNOWN, NUMBER, PERCENTAGE, EMS, EXS, PX, CM, MM, IN, PT, PC, } final double value; final UnitType unit; private SVGLength() { value = 0; unit = UnitType.UNKNOWN; } SVGLength(double number) { value = number; unit = UnitType.NUMBER; } SVGLength(String length) { length = length.trim(); int stringLength = length.length(); int percentIndex = stringLength - 1; if (stringLength == 0 || length.equals("normal")) { unit = UnitType.UNKNOWN; value = 0; } else if (length.codePointAt(percentIndex) == '%') { unit = UnitType.PERCENTAGE; value = Double.valueOf(length.substring(0, percentIndex)); } else { int twoLetterUnitIndex = stringLength - 2; if (twoLetterUnitIndex > 0) { String lastTwo = length.substring(twoLetterUnitIndex); int end = twoLetterUnitIndex; switch (lastTwo) { case "px": unit = UnitType.NUMBER; break; case "em": unit = UnitType.EMS; break; case "ex": unit = UnitType.EXS; break; case "pt": unit = UnitType.PT; break; case "pc": unit = UnitType.PC; break; case "mm": unit = UnitType.MM; break; case "cm": unit = UnitType.CM; break; case "in": unit = UnitType.IN; break; default: unit = UnitType.NUMBER; end = stringLength; } value = Double.valueOf(length.substring(0, end)); } else { unit = UnitType.NUMBER; value = Double.valueOf(length); } } } static SVGLength from(Dynamic dynamic) { switch (dynamic.getType()) { case Number: return new SVGLength(dynamic.asDouble()); case String: return new SVGLength(dynamic.asString()); default: return new SVGLength(); } } static SVGLength from(String string) { return string != null ? new SVGLength(string) : new SVGLength(); } static SVGLength from(Double value) { return value != null ? new SVGLength(value) : new SVGLength(); } static String toString(Dynamic dynamic) { switch (dynamic.getType()) { case Number: return String.valueOf(dynamic.asDouble()); case String: return dynamic.asString(); default: return null; } } static ArrayList arrayFrom(Dynamic dynamic) { switch (dynamic.getType()) { case Number: { ArrayList list = new ArrayList<>(1); list.add(new SVGLength(dynamic.asDouble())); return list; } case Array: { ReadableArray arr = dynamic.asArray(); int size = arr.size(); ArrayList list = new ArrayList<>(size); for (int i = 0; i < size; i++) { Dynamic val = arr.getDynamic(i); list.add(from(val)); } return list; } case String: { String stringValue = dynamic.asString().trim(); stringValue = stringValue.replaceAll(",", " "); String[] strings = stringValue.split(" "); ArrayList list = new ArrayList<>(strings.length); for (String length : strings) { list.add(new SVGLength(length)); } return list; } default: return null; } } static ArrayList arrayFrom(ReadableArray arr) { int size = arr.size(); ArrayList list = new ArrayList<>(size); for (int i = 0; i < size; i++) { Dynamic val = arr.getDynamic(i); list.add(from(val)); } return list; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SvgPackage.java ================================================ /* * 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. */ package com.horcrux.svg; import static com.horcrux.svg.RenderableViewManager.*; import androidx.annotation.Nullable; import com.facebook.react.BaseReactPackage; 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.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Nonnull; import javax.inject.Provider; @ReactModuleList( nativeModules = { SvgViewModule.class, RNSVGRenderableManager.class, }) public class SvgPackage extends BaseReactPackage implements ViewManagerOnDemandReactPackage { private @Nullable Map mViewManagers; private Map getViewManagersMap(final ReactApplicationContext reactContext) { if (mViewManagers == null) { Map specs = MapBuilder.newHashMap(); specs.put( GroupViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new GroupViewManager(); } })); specs.put( PathViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new PathViewManager(); } })); specs.put( CircleViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new CircleViewManager(); } })); specs.put( EllipseViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new EllipseViewManager(); } })); specs.put( LineViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new LineViewManager(); } })); specs.put( RectViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new RectViewManager(); } })); specs.put( TextViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new TextViewManager(); } })); specs.put( TSpanViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new TSpanViewManager(); } })); specs.put( TextPathViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new TextPathViewManager(); } })); specs.put( ImageViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new ImageViewManager(); } })); specs.put( ClipPathViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new ClipPathViewManager(); } })); specs.put( DefsViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new DefsViewManager(); } })); specs.put( UseViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new UseViewManager(); } })); specs.put( SymbolManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new SymbolManager(); } })); specs.put( LinearGradientManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new LinearGradientManager(); } })); specs.put( RadialGradientManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new RadialGradientManager(); } })); specs.put( PatternManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new PatternManager(); } })); specs.put( MaskManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new MaskManager(); } })); specs.put( FilterManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FilterManager(); } })); specs.put( FeBlendManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeBlendManager(); } })); specs.put( FeColorMatrixManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeColorMatrixManager(); } })); specs.put( FeCompositeManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeCompositeManager(); } })); specs.put( FeFloodManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeFloodManager(); } })); specs.put( FeGaussianBlurManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeGaussianBlurManager(); } })); specs.put( FeMergeManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeMergeManager(); } })); specs.put( FeOffsetManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new FeOffsetManager(); } })); specs.put( ForeignObjectManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new ForeignObjectManager(); } })); specs.put( MarkerManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new MarkerManager(); } })); specs.put( SvgViewManager.REACT_CLASS, ModuleSpec.viewManagerSpec( new Provider() { @Override public NativeModule get() { return new SvgViewManager(); } })); mViewManagers = specs; } return mViewManagers; } /** {@inheritDoc} */ @Override public List getViewManagerNames(ReactApplicationContext reactContext) { return new ArrayList<>(getViewManagersMap(reactContext).keySet()); } @Override protected List 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 new ReactModuleInfoProvider() { @Override public Map getReactModuleInfos() { final Map reactModuleInfoMap = new HashMap<>(); Class[] moduleList = new Class[] { SvgViewModule.class, RNSVGRenderableManager.class, }; for (Class moduleClass : moduleList) { ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); reactModuleInfoMap.put( reactModule.name(), new ReactModuleInfo( reactModule.name(), moduleClass.getName(), reactModule.canOverrideExistingModule(), reactModule.needsEagerInit(), reactModule.isCxxModule(), true)); } return reactModuleInfoMap; } }; } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException( "No ReactModuleInfoProvider for MyPackage$$ReactModuleInfoProvider", e); } } @SuppressWarnings("unused") public List> createJSModules() { return Collections.emptyList(); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SvgView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.util.Base64; import android.view.View; import android.view.ViewParent; import android.view.accessibility.AccessibilityNodeInfo; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.ReactCompoundView; import com.facebook.react.uimanager.ReactCompoundViewGroup; import com.facebook.react.views.view.ReactViewGroup; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** Custom {@link View} implementation that draws an RNSVGSvg React view and its children. */ @SuppressLint("ViewConstructor") public class SvgView extends ReactViewGroup implements ReactCompoundView, ReactCompoundViewGroup { @Override public boolean interceptsTouchEvent(float touchX, float touchY) { return true; } @SuppressWarnings("unused") public enum Events { EVENT_DATA_URL("onDataURL"); private final String mName; Events(final String name) { mName = name; } @Nonnull public String toString() { return mName; } } private @Nullable Bitmap mBitmap; private @Nullable Bitmap mCurrentBitmap; private boolean mRemovalTransitionStarted; public SvgView(ReactContext reactContext) { super(reactContext); mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; mPaint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG); mPaint.setTypeface(Typeface.DEFAULT); // for some reason on Fabric the `onDraw` won't be called without it setWillNotDraw(false); } @Override public void setId(int id) { super.setId(id); SvgViewManager.setSvgView(id, this); } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); Rect r = new Rect(); boolean isVisible = this.getGlobalVisibleRect(r); info.setVisibleToUser(isVisible); info.setClassName(this.getClass().getCanonicalName()); } @Override public void invalidate() { super.invalidate(); ViewParent parent = getParent(); if (parent instanceof VirtualView) { if (!mRendered) { return; } mRendered = false; ((VirtualView) parent).getSvgView().invalidate(); return; } if (!mRemovalTransitionStarted) { // when view is removed from the view hierarchy, we want to recycle the mBitmap when // the view is detached from window, in order to preserve it for during animation, see // https://github.com/react-native-svg/react-native-svg/pull/1542 if (mBitmap != null) { mBitmap.recycle(); } mBitmap = null; } } @Override public void startViewTransition(View view) { mRemovalTransitionStarted = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mBitmap != null) { mBitmap.recycle(); } mBitmap = null; } @Override protected void onDraw(Canvas canvas) { if (getParent() instanceof VirtualView) { return; } super.onDraw(canvas); if (mBitmap == null) { mBitmap = drawOutput(); } if (mBitmap != null) { mPaint.reset(); mPaint.setFlags( Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG | Paint.FILTER_BITMAP_FLAG); mPaint.setTypeface(Typeface.DEFAULT); canvas.drawBitmap(mBitmap, 0, 0, mPaint); if (toDataUrlTask != null) { toDataUrlTask.run(); toDataUrlTask = null; } } } private Runnable toDataUrlTask = null; void setToDataUrlTask(Runnable task) { toDataUrlTask = task; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.invalidate(); } @Override public int reactTagForTouch(float touchX, float touchY) { return hitTest(touchX, touchY); } private boolean mResponsible = false; private final Map mDefinedClipPaths = new HashMap<>(); private final Map mDefinedTemplates = new HashMap<>(); private final Map mDefinedMarkers = new HashMap<>(); private final Map mDefinedMasks = new HashMap<>(); private final Map mDefinedFilters = new HashMap<>(); private final Map mDefinedBrushes = new HashMap<>(); private Canvas mCanvas; private final float mScale; private final Paint mPaint = new Paint(); private float mMinX; private float mMinY; private float mVbWidth; private float mVbHeight; private SVGLength mbbWidth; private SVGLength mbbHeight; private String mAlign; private int mMeetOrSlice; final Matrix mInvViewBoxMatrix = new Matrix(); private boolean mInvertible = true; private boolean mRendered = false; int mCurrentColor = Color.BLACK; boolean notRendered() { return !mRendered; } private void clearChildCache() { if (!mRendered) { return; } mRendered = false; for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof VirtualView) { VirtualView n = ((VirtualView) node); n.clearChildCache(); } } } public void setCurrentColor(Integer color) { mCurrentColor = color != null ? color : 0; invalidate(); clearChildCache(); } public void setMinX(float minX) { mMinX = minX; invalidate(); clearChildCache(); } public void setMinY(float minY) { mMinY = minY; invalidate(); clearChildCache(); } public void setVbWidth(float vbWidth) { mVbWidth = vbWidth; invalidate(); clearChildCache(); } public void setVbHeight(float vbHeight) { mVbHeight = vbHeight; invalidate(); clearChildCache(); } public void setBbWidth(Dynamic bbWidth) { mbbWidth = SVGLength.from(bbWidth); invalidate(); clearChildCache(); } public void setBbHeight(Dynamic bbHeight) { mbbHeight = SVGLength.from(bbHeight); invalidate(); clearChildCache(); } public void setAlign(String align) { mAlign = align; invalidate(); clearChildCache(); } public void setMeetOrSlice(int meetOrSlice) { mMeetOrSlice = meetOrSlice; invalidate(); clearChildCache(); } private Bitmap drawOutput() { mRendered = true; float width = getWidth(); float height = getHeight(); boolean invalid = Float.isNaN(width) || Float.isNaN(height) || width < 1 || height < 1 || (Math.log10(width) + Math.log10(height) > 42); if (invalid) { return null; } Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888); mCurrentBitmap = bitmap; drawChildren(new Canvas(bitmap)); return bitmap; } Rect getCanvasBounds() { return mCanvas.getClipBounds(); } float getCanvasWidth() { return mCanvas.getWidth(); } float getCanvasHeight() { return mCanvas.getHeight(); } Matrix getCtm() { return mCanvas.getMatrix(); } synchronized void drawChildren(final Canvas canvas) { mRendered = true; mCanvas = canvas; Matrix mViewBoxMatrix = new Matrix(); if (mAlign != null) { RectF vbRect = getViewBox(); float width = canvas.getWidth(); float height = canvas.getHeight(); boolean nested = getParent() instanceof VirtualView; if (nested) { width = (float) PropHelper.fromRelative(mbbWidth, width, 0f, mScale, 12); height = (float) PropHelper.fromRelative(mbbHeight, height, 0f, mScale, 12); } RectF eRect = new RectF(0, 0, width, height); if (nested) { canvas.clipRect(eRect); } mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); mInvertible = mViewBoxMatrix.invert(mInvViewBoxMatrix); canvas.concat(mViewBoxMatrix); } for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof VirtualView) { ((VirtualView) node).saveDefinition(); } } for (int i = 0; i < getChildCount(); i++) { View lNode = getChildAt(i); if (lNode instanceof VirtualView) { VirtualView node = (VirtualView) lNode; int count = node.saveAndSetupCanvas(canvas, mViewBoxMatrix); node.render(canvas, mPaint, 1f); node.restoreCanvas(canvas, count); if (node.isResponsible() && !mResponsible) { mResponsible = true; } } } } RectF getViewBox() { return new RectF( mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); } String toDataURL() { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); clearChildCache(); drawChildren(new Canvas(bitmap)); clearChildCache(); this.invalidate(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); bitmap.recycle(); byte[] bitmapBytes = stream.toByteArray(); return Base64.encodeToString(bitmapBytes, Base64.NO_WRAP); } String toDataURL(int width, int height) { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); clearChildCache(); drawChildren(new Canvas(bitmap)); clearChildCache(); this.invalidate(); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); bitmap.recycle(); byte[] bitmapBytes = stream.toByteArray(); return Base64.encodeToString(bitmapBytes, Base64.NO_WRAP); } void enableTouchEvents() { if (!mResponsible) { mResponsible = true; } } boolean isResponsible() { return mResponsible; } private int hitTest(float touchX, float touchY) { if (!mResponsible || !mInvertible) { return getId(); } float[] transformed = {touchX, touchY}; mInvViewBoxMatrix.mapPoints(transformed); int count = getChildCount(); int viewTag = -1; for (int i = count - 1; i >= 0; i--) { View child = getChildAt(i); if (child instanceof VirtualView) { viewTag = ((VirtualView) child).hitTest(transformed); } else if (child instanceof SvgView) { viewTag = ((SvgView) child).hitTest(touchX, touchY); } if (viewTag != -1) { break; } } return viewTag == -1 ? getId() : viewTag; } void defineClipPath(VirtualView clipPath, String clipPathRef) { mDefinedClipPaths.put(clipPathRef, clipPath); } VirtualView getDefinedClipPath(String clipPathRef) { return mDefinedClipPaths.get(clipPathRef); } void defineTemplate(VirtualView template, String templateRef) { mDefinedTemplates.put(templateRef, template); } VirtualView getDefinedTemplate(String templateRef) { return mDefinedTemplates.get(templateRef); } void defineBrush(Brush brush, String brushRef) { mDefinedBrushes.put(brushRef, brush); } Brush getDefinedBrush(String brushRef) { return mDefinedBrushes.get(brushRef); } void defineMask(VirtualView mask, String maskRef) { mDefinedMasks.put(maskRef, mask); } VirtualView getDefinedMask(String maskRef) { return mDefinedMasks.get(maskRef); } void defineFilter(VirtualView filter, String filterRef) { mDefinedFilters.put(filterRef, filter); } VirtualView getDefinedFilter(String filterRef) { return mDefinedFilters.get(filterRef); } void defineMarker(VirtualView marker, String markerRef) { mDefinedMarkers.put(markerRef, marker); } VirtualView getDefinedMarker(String markerRef) { return mDefinedMarkers.get(markerRef); } public Bitmap getCurrentBitmap() { return mCurrentBitmap; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SvgViewManager.java ================================================ /* * 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. */ package com.horcrux.svg; import android.graphics.Rect; import android.util.SparseArray; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.PixelUtil; 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.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; import java.lang.reflect.Method; import java.util.Locale; import javax.annotation.Nonnull; 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 RNSVGSvgViewAndroidManagerInterface { public static final String REACT_CLASS = "RNSVGSvgViewAndroid"; private static final SparseArray mTagToSvgView = new SparseArray<>(); private static final SparseArray mTagToRunnable = new SparseArray<>(); private final ViewManagerDelegate mDelegate; protected ViewManagerDelegate getDelegate() { return mDelegate; } public SvgViewManager() { mDelegate = new RNSVGSvgViewAndroidManagerDelegate(this); } static void setSvgView(int tag, SvgView svg) { mTagToSvgView.put(tag, svg); Runnable task = mTagToRunnable.get(tag); if (task != null) { task.run(); mTagToRunnable.delete(tag); } } static void runWhenViewIsAvailable(int tag, Runnable task) { mTagToRunnable.put(tag, task); } static @Nullable SvgView getSvgViewByTag(int tag) { return mTagToSvgView.get(tag); } @Nonnull @Override public String getName() { return REACT_CLASS; } @Nonnull @Override public ReactViewGroup createViewInstance(ThemedReactContext reactContext) { return new SvgView(reactContext); } @Override public void updateExtraData(ReactViewGroup root, Object extraData) { super.updateExtraData(root, extraData); root.invalidate(); } @Override public void onDropViewInstance(@Nonnull ReactViewGroup view) { super.onDropViewInstance(view); mTagToSvgView.remove(view.getId()); } @Override public boolean needsCustomLayoutForChildren() { return true; } @ReactProp(name = "color", customType = "Color") @Override public void setColor(SvgView node, Integer color) { node.setCurrentColor(color); } @ReactProp(name = "minX") @Override public void setMinX(SvgView node, float minX) { node.setMinX(minX); } @ReactProp(name = "minY") @Override public void setMinY(SvgView node, float minY) { node.setMinY(minY); } @ReactProp(name = "vbWidth") @Override public void setVbWidth(SvgView node, float vbWidth) { node.setVbWidth(vbWidth); } @ReactProp(name = "vbHeight") @Override public void setVbHeight(SvgView node, float vbHeight) { node.setVbHeight(vbHeight); } @ReactProp(name = "bbWidth") public void setBbWidth(SvgView node, Dynamic bbWidth) { node.setBbWidth(bbWidth); } @ReactProp(name = "bbHeight") public void setBbHeight(SvgView node, Dynamic bbHeight) { node.setBbHeight(bbHeight); } @ReactProp(name = "align") @Override public void setAlign(SvgView node, String align) { node.setAlign(align); } @ReactProp(name = "meetOrSlice") @Override public void setMeetOrSlice(SvgView node, int meetOrSlice) { node.setMeetOrSlice(meetOrSlice); } @ReactProp(name = ViewProps.POINTER_EVENTS) public void setPointerEvents(SvgView view, @Nullable String pointerEventsStr) { try { Class superclass = view.getClass().getSuperclass(); if (superclass != null) { Method method = superclass.getDeclaredMethod("setPointerEvents", PointerEvents.class); method.setAccessible(true); method.invoke( view, PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_"))); } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { e.printStackTrace(); } } @Override public void setHasTVPreferredFocus(SvgView view, boolean value) { super.setTVPreferredFocus(view, 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 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 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, Dynamic hitSlop) { // we don't call super here since its signature changed in RN 0.69 and we want backwards // compatibility switch (hitSlop.getType()) { case Map: ReadableMap hitSlopMap = hitSlop.asMap(); view.setHitSlopRect( new Rect( hitSlopMap.hasKey("left") ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("left")) : 0, hitSlopMap.hasKey("top") ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("top")) : 0, hitSlopMap.hasKey("right") ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("right")) : 0, hitSlopMap.hasKey("bottom") ? (int) PixelUtil.toPixelFromDIP(hitSlopMap.getDouble("bottom")) : 0)); break; case Number: int hitSlopValue = (int) PixelUtil.toPixelFromDIP(hitSlop.asDouble()); view.setHitSlopRect(new Rect(hitSlopValue, hitSlopValue, hitSlopValue, hitSlopValue)); break; default: FLog.w(ReactConstants.TAG, "Invalid type for 'hitSlop' value " + hitSlop.getType()); /* falls through */ case Null: view.setHitSlopRect(null); break; } } @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 setBorderBlockColor(SvgView view, @Nullable Integer value) { super.setBorderColor(view, 9, value); } @Override public void setBorderBlockEndColor(SvgView view, @Nullable Integer value) { super.setBorderColor(view, 10, value); } @Override public void setBorderBlockStartColor(SvgView view, @Nullable Integer value) { super.setBorderColor(view, 11, value); } @Override public void setBorderRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 0, rawBorderRadius); } @Override public void setBorderTopLeftRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 1, rawBorderRadius); } @Override public void setBorderTopRightRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 2, rawBorderRadius); } @Override public void setBorderBottomRightRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 3, rawBorderRadius); } @Override public void setBorderBottomLeftRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 4, rawBorderRadius); } @Override public void setBorderTopStartRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 5, rawBorderRadius); } @Override public void setBorderTopEndRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 6, rawBorderRadius); } @Override public void setBorderBottomStartRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 7, rawBorderRadius); } @Override public void setBorderBottomEndRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 8, rawBorderRadius); } @Override public void setBorderEndEndRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 9, rawBorderRadius); } @Override public void setBorderEndStartRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 10, rawBorderRadius); } @Override public void setBorderStartEndRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 11, rawBorderRadius); } @Override public void setBorderStartStartRadius(SvgView view, Dynamic rawBorderRadius) { super.setBorderRadius(view, 12, rawBorderRadius); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SvgViewModule.java ================================================ /* * 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. */ package com.horcrux.svg; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; 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 javax.annotation.Nonnull; @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 NAME; } private static void toDataURL( final int tag, final ReadableMap options, final Callback successCallback, final int attempt) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { SvgView svg = SvgViewManager.getSvgViewByTag(tag); if (svg == null) { SvgViewManager.runWhenViewIsAvailable( tag, new Runnable() { @Override public void run() { SvgView svg = SvgViewManager.getSvgViewByTag(tag); if (svg == null) { // Should never happen return; } svg.setToDataUrlTask( new Runnable() { @Override public void run() { toDataURL(tag, options, successCallback, attempt + 1); } }); } }); } else if (svg.notRendered()) { svg.setToDataUrlTask( new Runnable() { @Override public void run() { toDataURL(tag, options, successCallback, attempt + 1); } }); } else { if (options != null) { successCallback.invoke( svg.toDataURL(options.getInt("width"), options.getInt("height"))); } else { successCallback.invoke(svg.toDataURL()); } } } }); } @SuppressWarnings("unused") @ReactMethod @Override public void toDataURL(Double tag, ReadableMap options, Callback successCallback) { toDataURL(tag.intValue(), options, successCallback, 0); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/SymbolView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import com.facebook.react.bridge.ReactContext; @SuppressLint("ViewConstructor") class SymbolView extends GroupView { private float mMinX; private float mMinY; private float mVbWidth; private float mVbHeight; private String mAlign; private int mMeetOrSlice; public SymbolView(ReactContext reactContext) { super(reactContext); } public void setMinX(float minX) { mMinX = minX; invalidate(); } public void setMinY(float minY) { mMinY = minY; invalidate(); } public void setVbWidth(float vbWidth) { mVbWidth = vbWidth; invalidate(); } public void setVbHeight(float vbHeight) { mVbHeight = vbHeight; invalidate(); } public void setAlign(String align) { mAlign = align; invalidate(); } public void setMeetOrSlice(int meetOrSlice) { mMeetOrSlice = meetOrSlice; invalidate(); } @Override void draw(Canvas canvas, Paint paint, float opacity) { saveDefinition(); } void drawSymbol(Canvas canvas, Paint paint, float opacity, float width, float height) { if (mAlign != null) { RectF vbRect = new RectF( mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale); RectF eRect = new RectF(0, 0, width, height); Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice); canvas.concat(viewBoxMatrix); super.draw(canvas, paint, opacity); } } } ================================================ FILE: android/src/main/java/com/horcrux/svg/TSpanView.java ================================================ /* * 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. */ package com.horcrux.svg; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; import static android.graphics.PathMeasure.POSITION_MATRIX_FLAG; import static android.graphics.PathMeasure.TANGENT_MATRIX_FLAG; import static com.horcrux.svg.TextProperties.AlignmentBaseline; import static com.horcrux.svg.TextProperties.FontStyle; import static com.horcrux.svg.TextProperties.FontVariantLigatures; import static com.horcrux.svg.TextProperties.FontWeight; import static com.horcrux.svg.TextProperties.TextAnchor; import static com.horcrux.svg.TextProperties.TextPathMidLine; import static com.horcrux.svg.TextProperties.TextPathSide; import android.annotation.SuppressLint; import android.content.res.AssetManager; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.os.Build; import android.text.Layout; import android.text.SpannableString; import android.text.StaticLayout; import android.text.TextPaint; import android.view.View; import android.view.ViewParent; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.views.text.ReactFontManager; import java.text.Bidi; import java.util.ArrayList; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class TSpanView extends TextView { private static final double tau = 2 * Math.PI; private static final double radToDeg = 360 / tau; private static final String FONTS = "fonts/"; private static final String OTF = ".otf"; private static final String TTF = ".ttf"; private Path mCachedPath; @Nullable String mContent; private TextPathView textPath; private final ArrayList emoji = new ArrayList<>(); private final ArrayList emojiTransforms = new ArrayList<>(); private final AssetManager assets; public TSpanView(ReactContext reactContext) { super(reactContext); assets = mContext.getResources().getAssets(); } public void setContent(@Nullable String content) { mContent = content; invalidate(); } @Override public void invalidate() { mCachedPath = null; super.invalidate(); } void clearCache() { mCachedPath = null; super.clearCache(); } @Override void draw(Canvas canvas, Paint paint, float opacity) { if (mContent != null) { if (mInlineSize != null && mInlineSize.value != 0) { if (setupFillPaint(paint, opacity * fillOpacity)) { drawWrappedText(canvas, paint); } if (setupStrokePaint(paint, opacity * strokeOpacity)) { drawWrappedText(canvas, paint); } } else { int numEmoji = emoji.size(); if (numEmoji > 0) { GlyphContext gc = getTextRootGlyphContext(); FontData font = gc.getFont(); applyTextPropertiesToPaint(paint, font); for (int i = 0; i < numEmoji; i++) { String current = emoji.get(i); Matrix mid = emojiTransforms.get(i); canvas.save(); canvas.concat(mid); canvas.drawText(current, 0, 0, paint); canvas.restore(); } } drawPath(canvas, paint, opacity); } } else { clip(canvas, paint); drawGroup(canvas, paint, opacity); } } private void drawWrappedText(Canvas canvas, Paint paint) { GlyphContext gc = getTextRootGlyphContext(); pushGlyphContext(); FontData font = gc.getFont(); TextPaint tp = new TextPaint(paint); applyTextPropertiesToPaint(tp, font); applySpacingAndFeatures(tp, font); double fontSize = gc.getFontSize(); Layout.Alignment align; switch (font.textAnchor) { default: case start: align = Layout.Alignment.ALIGN_NORMAL; break; case middle: align = Layout.Alignment.ALIGN_CENTER; break; case end: align = Layout.Alignment.ALIGN_OPPOSITE; break; } boolean includeFontPadding = true; SpannableString text = new SpannableString(mContent); final double width = PropHelper.fromRelative(mInlineSize, canvas.getWidth(), 0, mScale, fontSize); StaticLayout layout = getStaticLayout(tp, align, includeFontPadding, text, (int) width); int lineAscent = layout.getLineAscent(0); float dx = (float) gc.nextX(0); float dy = (float) (gc.nextY() + lineAscent); popGlyphContext(); canvas.save(); canvas.translate(dx, dy); layout.draw(canvas); canvas.restore(); } @SuppressWarnings("deprecation") private StaticLayout getStaticLayout( TextPaint tp, Layout.Alignment align, boolean includeFontPadding, SpannableString text, int width) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return new StaticLayout(text, tp, width, align, 1.f, 0.f, includeFontPadding); } else { return StaticLayout.Builder.obtain(text, 0, text.length(), tp, width) .setAlignment(align) .setLineSpacing(0.f, 1.f) .setIncludePad(includeFontPadding) .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) .build(); } } /** * Implements visual to logical order converter. * * @author Nesterovsky bros * @param text an input text in visual order to convert. * @return a String value in logical order. */ public static String visualToLogical(String text) { if ((text == null) || (text.length() == 0)) { return text; } Bidi bidi = new Bidi(text, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); if (bidi.isLeftToRight()) { return text; } int count = bidi.getRunCount(); byte[] levels = new byte[count]; Integer[] runs = new Integer[count]; for (int i = 0; i < count; i++) { levels[i] = (byte) bidi.getRunLevel(i); runs[i] = i; } Bidi.reorderVisually(levels, 0, runs, 0, count); StringBuilder result = new StringBuilder(); for (int i = 0; i < count; i++) { int index = runs[i]; int start = bidi.getRunStart(index); int end = bidi.getRunLimit(index); int level = levels[index]; if ((level & 1) != 0) { for (; --end >= start; ) { result.append(text.charAt(end)); } } else { result.append(text, start, end); } } return result.toString(); } @Override Path getPath(Canvas canvas, Paint paint) { if (mCachedPath != null) { return mCachedPath; } if (mContent == null) { mCachedPath = getGroupPath(canvas, paint); return mCachedPath; } setupTextPath(); pushGlyphContext(); mCachedPath = getLinePath(visualToLogical(mContent), paint, canvas); popGlyphContext(); return mCachedPath; } double getSubtreeTextChunksTotalAdvance(Paint paint) { if (!Double.isNaN(cachedAdvance)) { return cachedAdvance; } double advance = 0; if (mContent == null) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof TextView) { TextView text = (TextView) child; advance += text.getSubtreeTextChunksTotalAdvance(paint); } } cachedAdvance = advance; return advance; } String line = mContent; final int length = line.length(); if (length == 0) { cachedAdvance = 0; return advance; } GlyphContext gc = getTextRootGlyphContext(); FontData font = gc.getFont(); applyTextPropertiesToPaint(paint, font); applySpacingAndFeatures(paint, font); cachedAdvance = paint.measureText(line); return cachedAdvance; } static final String requiredFontFeatures = "'rlig', 'liga', 'clig', 'calt', 'locl', 'ccmp', 'mark', 'mkmk',"; static final String disableDiscretionaryLigatures = "'liga' 0, 'clig' 0, 'dlig' 0, 'hlig' 0, 'cala' 0, "; static final String defaultFeatures = requiredFontFeatures + "'kern', "; static final String additionalLigatures = "'hlig', 'cala', "; static final String fontWeightTag = "'wght' "; private void applySpacingAndFeatures(Paint paint, FontData font) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { double letterSpacing = font.letterSpacing; paint.setLetterSpacing((float) (letterSpacing / (font.fontSize * mScale))); final boolean allowOptionalLigatures = letterSpacing == 0 && font.fontVariantLigatures == FontVariantLigatures.normal; if (allowOptionalLigatures) { paint.setFontFeatureSettings( defaultFeatures + additionalLigatures + font.fontFeatureSettings); } else { paint.setFontFeatureSettings( defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { paint.setFontVariationSettings( fontWeightTag + font.absoluteFontWeight + font.fontVariationSettings); } } } @SuppressWarnings("ConstantConditions") private Path getLinePath(String line, Paint paint, Canvas canvas) { final int length = line.length(); final Path path = new Path(); emoji.clear(); emojiTransforms.clear(); if (length == 0) { return path; } double pathLength = 0; PathMeasure pm = null; boolean isClosed = false; final boolean hasTextPath = textPath != null; if (hasTextPath) { pm = new PathMeasure(textPath.getTextPath(canvas, paint), false); pathLength = pm.getLength(); isClosed = pm.isClosed(); if (pathLength == 0) { return path; } } GlyphContext gc = getTextRootGlyphContext(); FontData font = gc.getFont(); applyTextPropertiesToPaint(paint, font); GlyphPathBag bag = new GlyphPathBag(paint); boolean[] ligature = new boolean[length]; final char[] chars = line.toCharArray(); /* * * Three properties affect the space between characters and words: * * ‘kerning’ indicates whether the user agent should adjust inter-glyph spacing * based on kerning tables that are included in the relevant font * (i.e., enable auto-kerning) or instead disable auto-kerning * and instead set inter-character spacing to a specific length (typically, zero). * * ‘letter-spacing’ indicates an amount of space that is to be added between text * characters supplemental to any spacing due to the ‘kerning’ property. * * ‘word-spacing’ indicates the spacing behavior between words. * * Letter-spacing is applied after bidi reordering and is in addition to any word-spacing. * Depending on the justification rules in effect, user agents may further increase * or decrease the space between typographic character units in order to justify text. * * */ double kerning = font.kerning; double wordSpacing = font.wordSpacing; double letterSpacing = font.letterSpacing; final boolean autoKerning = !font.manualKerning; /* 11.1.2. Fonts and glyphs A font consists of a collection of glyphs together with other information (collectively, the font tables) necessary to use those glyphs to present characters on some visual medium. The combination of the collection of glyphs and the font tables is called the font data. A font may supply substitution and positioning tables that can be used by a formatter (text shaper) to re-order, combine and position a sequence of glyphs to form one or more composite glyphs. The combining may be as simple as a ligature, or as complex as an indic syllable which combines, usually with some re-ordering, multiple consonants and vowel glyphs. The tables may be language dependent, allowing the use of language appropriate letter forms. When a glyph, simple or composite, represents an indivisible unit for typesetting purposes, it is know as a typographic character. Ligatures are an important feature of advance text layout. Some ligatures are discretionary while others (e.g. in Arabic) are required. The following explicit rules apply to ligature formation: Ligature formation should not be enabled when characters are in different DOM text nodes; thus, characters separated by markup should not use ligatures. Ligature formation should not be enabled when characters are in different text chunks. Discretionary ligatures should not be used when the spacing between two characters is not the same as the default space (e.g. when letter-spacing has a non-default value, or text-align has a value of justify and text-justify has a value of distribute). (See CSS Text Module Level 3, ([css-text-3]). SVG attributes such as ‘dx’, ‘textLength’, and ‘spacing’ (in ‘textPath’) that may reposition typographic characters do not break discretionary ligatures. If discretionary ligatures are not desired they can be turned off by using the font-variant-ligatures property. /* When the effective letter-spacing between two characters is not zero (due to either justification or non-zero computed ‘letter-spacing’), user agents should not apply optional ligatures. https://www.w3.org/TR/css-text-3/#letter-spacing-property */ final boolean allowOptionalLigatures = letterSpacing == 0 && font.fontVariantLigatures == FontVariantLigatures.normal; /* For OpenType fonts, discretionary ligatures include those enabled by the liga, clig, dlig, hlig, and cala features; required ligatures are found in the rlig feature. https://svgwg.org/svg2-draft/text.html#FontsGlyphs http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings https://www.microsoft.com/typography/otspec/featurelist.htm https://www.microsoft.com/typography/otspec/featuretags.htm https://www.microsoft.com/typography/otspec/features_pt.htm https://www.microsoft.com/typography/otfntdev/arabicot/features.aspx http://unifraktur.sourceforge.net/testcases/enable_opentype_features/ https://en.wikipedia.org/wiki/List_of_typographic_features http://ilovetypography.com/OpenType/opentype-features.html https://www.typotheque.com/articles/opentype_features_in_css https://practice.typekit.com/lesson/caring-about-opentype-features/ http://stateofwebtype.com/ 6.12. Low-level font feature settings control: the font-feature-settings property Name: font-feature-settings Value: normal | # Initial: normal Applies to: all elements Inherited: yes Percentages: N/A Media: visual Computed value: as specified Animatable: no https://drafts.csswg.org/css-fonts-3/#default-features 7.1. Default features For OpenType fonts, user agents must enable the default features defined in the OpenType documentation for a given script and writing mode. Required ligatures, common ligatures and contextual forms must be enabled by default (OpenType features: rlig, liga, clig, calt), along with localized forms (OpenType feature: locl), and features required for proper display of composed characters and marks (OpenType features: ccmp, mark, mkmk). These features must always be enabled, even when the value of the ‘font-variant’ and ‘font-feature-settings’ properties is ‘normal’. Individual features are only disabled when explicitly overridden by the author, as when ‘font-variant-ligatures’ is set to ‘no-common-ligatures’. TODO For handling complex scripts such as Arabic, Mongolian or Devanagari additional features are required. TODO For upright text within vertical text runs, vertical alternates (OpenType feature: vert) must be enabled. */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // String arabic = "'isol', 'fina', 'medi', 'init', 'rclt', 'mset', 'curs', "; if (allowOptionalLigatures) { paint.setFontFeatureSettings( defaultFeatures + additionalLigatures + font.fontFeatureSettings); } else { paint.setFontFeatureSettings( defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { paint.setFontVariationSettings( fontWeightTag + font.absoluteFontWeight + font.fontVariationSettings); } } // OpenType.js font data ReadableMap fontData = font.fontData; float[] advances = new float[length]; paint.getTextWidths(line, advances); /* This would give both advances and textMeasure in one call / looping over the text double textMeasure = paint.getTextRunAdvances(line, 0, length, 0, length, true, advances, 0); */ /* Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ and property text-anchor. For text-anchor:start, startpoint-on-the-path is the point on the path which represents the point on the path which is ‘startOffset’ distance along the path from the start of the path, calculated using the user agent's distance along the path algorithm. For text-anchor:middle, startpoint-on-the-path is the point on the path which represents the point on the path which is [ ‘startOffset’ minus half of the total advance values for all of the glyphs in the ‘textPath’ element ] distance along the path from the start of the path, calculated using the user agent's distance along the path algorithm. For text-anchor:end, startpoint-on-the-path is the point on the path which represents the point on the path which is [ ‘startOffset’ minus the total advance values for all of the glyphs in the ‘textPath’ element ]. Before rendering the first glyph, the horizontal component of the startpoint-on-the-path is adjusted to take into account various horizontal alignment text properties and attributes, such as a ‘dx’ attribute value on a ‘tspan’ element. */ final TextAnchor textAnchor = font.textAnchor; TextView anchorRoot = getTextAnchorRoot(); final double textMeasure = anchorRoot.getSubtreeTextChunksTotalAdvance(paint); double offset = getTextAnchorOffset(textAnchor, textMeasure); int side = 1; double startOfRendering = 0; double endOfRendering = pathLength; double fontSize = gc.getFontSize(); boolean sharpMidLine = false; if (hasTextPath) { sharpMidLine = textPath.getMidLine() == TextPathMidLine.sharp; /* Name side Value left | right initial value left Animatable yes Determines the side of the path the text is placed on (relative to the path direction). Specifying a value of right effectively reverses the path. Added in SVG 2 to allow text either inside or outside closed subpaths and basic shapes (e.g. rectangles, circles, and ellipses). Adding 'side' was resolved at the Sydney (2015) meeting. */ side = textPath.getSide() == TextPathSide.right ? -1 : 1; /* Name startOffset Value | | initial value 0 Animatable yes An offset from the start of the path for the initial current text position, calculated using the user agent's distance along the path algorithm, after converting the path to the ‘textPath’ element's coordinate system. If a other than a percentage is given, then the ‘startOffset’ represents a distance along the path measured in the current user coordinate system for the ‘textPath’ element. If a percentage is given, then the ‘startOffset’ represents a percentage distance along the entire path. Thus, startOffset="0%" indicates the start point of the path and startOffset="100%" indicates the end point of the path. Negative values and values larger than the path length (e.g. 150%) are allowed. Any typographic characters with mid-points that are not on the path are not rendered For paths consisting of a single closed subpath (including an equivalent path for a basic shape), typographic characters are rendered along one complete circuit of the path. The text is aligned as determined by the text-anchor property to a position along the path set by the ‘startOffset’ attribute. For the start (end) value, the text is rendered from the start (end) of the line until the initial position along the path is reached again. For the middle, the text is rendered from the middle point in both directions until a point on the path equal distance in both directions from the initial position on the path is reached. */ final double absoluteStartOffset = getAbsoluteStartOffset(textPath.getStartOffset(), pathLength, fontSize); offset += absoluteStartOffset; if (isClosed) { final double halfPathDistance = pathLength / 2; startOfRendering = absoluteStartOffset + (textAnchor == TextAnchor.middle ? -halfPathDistance : 0); endOfRendering = startOfRendering + pathLength; } /* TextPathSpacing spacing = textPath.getSpacing(); if (spacing == TextPathSpacing.auto) { // Hmm, what to do here? // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute } */ } /* Name method Value align | stretch initial value align Animatable yes Indicates the method by which text should be rendered along the path. A value of align indicates that the typographic character should be rendered using simple 2×3 matrix transformations such that there is no stretching/warping of the typographic characters. Typically, supplemental rotation, scaling and translation transformations are done for each typographic characters to be rendered. As a result, with align, in fonts where the typographic characters are designed to be connected (e.g., cursive fonts), the connections may not align properly when text is rendered along a path. A value of stretch indicates that the typographic character outlines will be converted into paths, and then all end points and control points will be adjusted to be along the perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. With this approach, connected typographic characters, such as in cursive scripts, will maintain their connections. (Non-vertical straight path segments should be converted to Bézier curves in such a way that horizontal straight paths have an (approximately) constant offset from the path along which the typographic characters are rendered.) TODO implement stretch */ /* Name Value Initial value Animatable textLength | | See below yes The author's computation of the total sum of all of the advance values that correspond to character data within this element, including the advance value on the glyph (horizontal or vertical), the effect of properties letter-spacing and word-spacing and adjustments due to attributes ‘dx’ and ‘dy’ on this ‘text’ or ‘tspan’ element or any descendants. This value is used to calibrate the user agent's own calculations with that of the author. The purpose of this attribute is to allow the author to achieve exact alignment, in visual rendering order after any bidirectional reordering, for the first and last rendered glyphs that correspond to this element; thus, for the last rendered character (in visual rendering order after any bidirectional reordering), any supplemental inter-character spacing beyond normal glyph advances are ignored (in most cases) when the user agent determines the appropriate amount to expand/compress the text string to fit within a length of ‘textLength’. If attribute ‘textLength’ is specified on a given element and also specified on an ancestor, the adjustments on all character data within this element are controlled by the value of ‘textLength’ on this element exclusively, with the possible side-effect that the adjustment ratio for the contents of this element might be different than the adjustment ratio used for other content that shares the same ancestor. The user agent must assume that the total advance values for the other content within that ancestor is the difference between the advance value on that ancestor and the advance value for this element. This attribute is not intended for use to obtain effects such as shrinking or expanding text. A negative value is an error (see Error processing). The ‘textLength’ attribute is only applied when the wrapping area is not defined by the TODO shape-inside or the inline-size properties. It is also not applied for any ‘text’ or TODO ‘tspan’ element that has forced line breaks (due to a white-space value of pre or pre-line). If the attribute is not specified anywhere within a ‘text’ element, the effect is as if the author's computation exactly matched the value calculated by the user agent; thus, no advance adjustments are made. */ double scaleSpacingAndGlyphs = 1; if (mTextLength != null) { final double author = PropHelper.fromRelative(mTextLength, canvas.getWidth(), 0, mScale, fontSize); if (author < 0) { throw new IllegalArgumentException("Negative textLength value"); } switch (mLengthAdjust) { default: case spacing: letterSpacing += (author - textMeasure) / (length - 1); break; case spacingAndGlyphs: scaleSpacingAndGlyphs = author / textMeasure; break; } } final double scaledDirection = scaleSpacingAndGlyphs * side; /* https://developer.mozilla.org/en/docs/Web/CSS/vertical-align https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html https://www.microsoft.com/typography/otspec/base.htm http://apike.ca/prog_svg_text_style.html https://www.w3schools.com/tags/canvas_textbaseline.asp http://vanseodesign.com/web-design/svg-text-baseline-alignment/ https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align https://tympanus.net/codrops/css_reference/vertical-align/ https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty 11.10.2.6. The ‘alignment-baseline’ property This property is defined in the CSS Line Layout Module 3 specification. See 'alignment-baseline'. [css-inline-3] https://drafts.csswg.org/css-inline/#propdef-alignment-baseline The vertical-align property shorthand should be preferred in new content. SVG 2 introduces some changes to the definition of this property. In particular: the values 'auto', 'before-edge', and 'after-edge' have been removed. For backwards compatibility, 'text-before-edge' should be mapped to 'text-top' and 'text-after-edge' should be mapped to 'text-bottom'. Neither 'text-before-edge' nor 'text-after-edge' should be used with the vertical-align property. */ final Paint.FontMetrics fm = paint.getFontMetrics(); final double descenderDepth = fm.descent; final double bottom = descenderDepth + fm.leading; final double ascenderHeight = -fm.ascent + fm.leading; final double top = -fm.top; final double totalHeight = top + bottom; double baselineShift = 0; String baselineShiftString = getBaselineShift(); AlignmentBaseline baseline = getAlignmentBaseline(); if (baseline != null) { // TODO alignment-baseline, test / verify behavior // TODO get per glyph baselines from font baseline table, for high-precision alignment switch (baseline) { // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling default: case baseline: // Use the dominant baseline choice of the parent. // Match the box’s corresponding baseline to that of its parent. baselineShift = 0; break; case textBottom: case afterEdge: case textAfterEdge: // Match the bottom of the box to the bottom of the parent’s content area. // text-after-edge = text-bottom // text-after-edge = descender depth baselineShift = -descenderDepth; break; case alphabetic: // Match the box’s alphabetic baseline to that of its parent. // alphabetic = 0 baselineShift = 0; break; case ideographic: // Match the box’s ideographic character face under-side baseline to that of its parent. // ideographic = descender depth baselineShift = -descenderDepth; break; case middle: // Align the vertical midpoint of the box with the baseline of the parent box plus half // the x-height of the parent. // middle = x height / 2 Rect bounds = new Rect(); // this will just retrieve the bounding rect for 'x' paint.getTextBounds("x", 0, 1, bounds); int xHeight = bounds.height(); baselineShift = xHeight / 2.0; break; case central: // Match the box’s central baseline to the central baseline of its parent. // central = (ascender height - descender depth) / 2 baselineShift = (ascenderHeight - descenderDepth) / 2; break; case mathematical: // Match the box’s mathematical baseline to that of its parent. // Hanging and mathematical baselines // There are no obvious formulas to calculate the position of these baselines. // At the time of writing FOP puts the hanging baseline at 80% of the ascender // height and the mathematical baseline at 50%. baselineShift = 0.5 * ascenderHeight; break; case hanging: baselineShift = 0.8 * ascenderHeight; break; case textTop: case beforeEdge: case textBeforeEdge: // Match the top of the box to the top of the parent’s content area. // text-before-edge = text-top // text-before-edge = ascender height baselineShift = ascenderHeight; break; case bottom: // Align the top of the aligned subtree with the top of the line box. baselineShift = bottom; break; case center: // Align the center of the aligned subtree with the center of the line box. baselineShift = totalHeight / 2; break; case top: // Align the bottom of the aligned subtree with the bottom of the line box. baselineShift = top; break; } } /* 2.2.2. Alignment Shift: baseline-shift longhand This property specifies by how much the box is shifted up from its alignment point. It does not apply when alignment-baseline is top or bottom. Authors should use the vertical-align shorthand instead of this property. Values have the following meanings: Raise (positive value) or lower (negative value) by the specified length. Raise (positive value) or lower (negative value) by the specified percentage of the line-height. TODO sub Lower by the offset appropriate for subscripts of the parent’s box. (The UA should use the parent’s font data to find this offset whenever possible.) TODO super Raise by the offset appropriate for superscripts of the parent’s box. (The UA should use the parent’s font data to find this offset whenever possible.) User agents may additionally support the keyword baseline as computing to 0 if is necessary for them to support legacy SVG content. Issue: We would prefer to remove this, and are looking for feedback from SVG user agents as to whether it’s necessary. https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift */ if (baselineShiftString != null && !baselineShiftString.isEmpty()) { switch (baseline) { case top: case bottom: break; default: switch (baselineShiftString) { case "sub": // TODO if (fontData != null && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { int unitsPerEm = fontData.getInt("unitsPerEm"); ReadableMap tables = fontData.getMap("tables"); if (tables.hasKey("os2")) { ReadableMap os2 = tables.getMap("os2"); if (os2.hasKey("ySubscriptYOffset")) { double subOffset = os2.getDouble("ySubscriptYOffset"); baselineShift += mScale * fontSize * subOffset / unitsPerEm; } } } break; case "super": // TODO if (fontData != null && fontData.hasKey("tables") && fontData.hasKey("unitsPerEm")) { int unitsPerEm = fontData.getInt("unitsPerEm"); ReadableMap tables = fontData.getMap("tables"); if (tables.hasKey("os2")) { ReadableMap os2 = tables.getMap("os2"); if (os2.hasKey("ySuperscriptYOffset")) { double superOffset = os2.getDouble("ySuperscriptYOffset"); baselineShift -= mScale * fontSize * superOffset / unitsPerEm; } } } break; case "baseline": break; default: baselineShift -= PropHelper.fromRelative(baselineShiftString, mScale * fontSize, mScale, fontSize); } break; } } final Matrix start = new Matrix(); final Matrix mid = new Matrix(); final Matrix end = new Matrix(); final float[] startPointMatrixData = new float[9]; final float[] endPointMatrixData = new float[9]; for (int index = 0; index < length; index++) { char currentChar = chars[index]; String current = String.valueOf(currentChar); boolean alreadyRenderedGraphemeCluster = ligature[index]; /* Determine the glyph's charwidth (i.e., the amount which the current text position advances horizontally when the glyph is drawn using horizontal text layout). */ boolean hasLigature = false; if (alreadyRenderedGraphemeCluster) { current = ""; } else { int nextIndex = index; while (++nextIndex < length) { float nextWidth = advances[nextIndex]; if (nextWidth > 0) { break; } String nextLigature = current + chars[nextIndex]; ligature[nextIndex] = true; current = nextLigature; hasLigature = true; } } double charWidth = paint.measureText(current) * scaleSpacingAndGlyphs; /* For each subsequent glyph, set a new startpoint-on-the-path as the previous endpoint-on-the-path, but with appropriate adjustments taking into account horizontal kerning tables in the font and current values of various attributes and properties, including spacing properties (e.g. letter-spacing and word-spacing) and ‘tspan’ elements with values provided for attributes ‘dx’ and ‘dy’. All adjustments are calculated as distance adjustments along the path, calculated using the user agent's distance along the path algorithm. */ if (autoKerning) { double kerned = advances[index] * scaleSpacingAndGlyphs; kerning = kerned - charWidth; } boolean isWordSeparator = currentChar == ' '; double wordSpace = isWordSeparator ? wordSpacing : 0; double spacing = wordSpace + letterSpacing; double advance = charWidth + spacing; double x = gc.nextX(alreadyRenderedGraphemeCluster ? 0 : kerning + advance); double y = gc.nextY(); double dx = gc.nextDeltaX(); double dy = gc.nextDeltaY(); double r = gc.nextRotation(); if (alreadyRenderedGraphemeCluster || isWordSeparator) { // Skip rendering other grapheme clusters of ligatures (already rendered), // But, make sure to increment index positions by making gc.next() calls. continue; } advance *= side; charWidth *= side; double cursor = offset + (x + dx) * side; double startPoint = cursor - advance; if (hasTextPath) { /* Determine the point on the curve which is charwidth distance along the path from the startpoint-on-the-path for this glyph, calculated using the user agent's distance along the path algorithm. This point is the endpoint-on-the-path for the glyph. */ double endPoint = startPoint + charWidth; /* Determine the midpoint-on-the-path, which is the point on the path which is "halfway" (user agents can choose either a distance calculation or a parametric calculation) between the startpoint-on-the-path and the endpoint-on-the-path. */ double halfWay = charWidth / 2; double midPoint = startPoint + halfWay; // Glyphs whose midpoint-on-the-path are off the path are not rendered. if (midPoint > endOfRendering) { continue; } else if (midPoint < startOfRendering) { continue; } /* Determine the glyph-midline, which is the vertical line in the glyph's coordinate system that goes through the glyph's x-axis midpoint. Position the glyph such that the glyph-midline passes through the midpoint-on-the-path and is perpendicular to the line through the startpoint-on-the-path and the endpoint-on-the-path. TODO suggest adding a compatibility mid-line rendering attribute to textPath, for a chrome/firefox/opera/safari compatible sharp text path rendering, which doesn't bend text smoothly along a right angle curve, (like Edge does) but keeps the mid-line orthogonal to the mid-point tangent at all times instead. https://github.com/w3c/svgwg/issues/337 */ final int posAndTanFlags = POSITION_MATRIX_FLAG | TANGENT_MATRIX_FLAG; if (sharpMidLine) { pm.getMatrix((float) midPoint, mid, posAndTanFlags); } else { /* In the calculation above, if either the startpoint-on-the-path or the endpoint-on-the-path is off the end of the path, then extend the path beyond its end points with a straight line that is parallel to the tangent at the path at its end point so that the midpoint-on-the-path can still be calculated. TODO suggest change in wording of svg spec: so that the midpoint-on-the-path can still be calculated. to so that the angle of the glyph-midline to the x-axis can still be calculated. or so that the line through the startpoint-on-the-path and the endpoint-on-the-path can still be calculated. https://github.com/w3c/svgwg/issues/337#issuecomment-318056199 */ if (startPoint < 0) { pm.getMatrix(0, start, posAndTanFlags); start.preTranslate((float) startPoint, 0); } else { pm.getMatrix((float) startPoint, start, POSITION_MATRIX_FLAG); } pm.getMatrix((float) midPoint, mid, POSITION_MATRIX_FLAG); if (endPoint > pathLength) { pm.getMatrix((float) pathLength, end, posAndTanFlags); end.preTranslate((float) (endPoint - pathLength), 0); } else { pm.getMatrix((float) endPoint, end, POSITION_MATRIX_FLAG); } start.getValues(startPointMatrixData); end.getValues(endPointMatrixData); double startX = startPointMatrixData[MTRANS_X]; double startY = startPointMatrixData[MTRANS_Y]; double endX = endPointMatrixData[MTRANS_X]; double endY = endPointMatrixData[MTRANS_Y]; // line through the startpoint-on-the-path and the endpoint-on-the-path double lineX = endX - startX; double lineY = endY - startY; double glyphMidlineAngle = Math.atan2(lineY, lineX); mid.preRotate((float) (glyphMidlineAngle * radToDeg * side)); } /* Align the glyph vertically relative to the midpoint-on-the-path based on property alignment-baseline and any specified values for attribute ‘dy’ on a ‘tspan’ element. */ mid.preTranslate((float) -halfWay, (float) (dy + baselineShift)); mid.preScale((float) scaledDirection, (float) side); mid.postTranslate(0, (float) y); } else { mid.setTranslate((float) startPoint, (float) (y + dy + baselineShift)); } mid.preRotate((float) r); Path glyph; if (hasLigature) { glyph = new Path(); paint.getTextPath(current, 0, current.length(), 0, 0, glyph); } else { glyph = bag.getOrCreateAndCache(currentChar, current); } RectF bounds = new RectF(); glyph.computeBounds(bounds, true); float width = bounds.width(); if (width == 0) { // Render unicode emoji canvas.save(); canvas.concat(mid); emoji.add(current); emojiTransforms.add(new Matrix(mid)); canvas.drawText(current, 0, 0, paint); canvas.restore(); } else { glyph.transform(mid); path.addPath(glyph); } } return path; } private double getAbsoluteStartOffset(SVGLength startOffset, double distance, double fontSize) { return PropHelper.fromRelative(startOffset, distance, 0, mScale, fontSize); } private double getTextAnchorOffset(TextAnchor textAnchor, double textMeasure) { switch (textAnchor) { default: case start: return 0; case middle: return -textMeasure / 2; case end: return -textMeasure; } } private void applyTextPropertiesToPaint(Paint paint, FontData font) { boolean isBold = font.fontWeight == FontWeight.Bold || font.absoluteFontWeight >= 550; boolean isItalic = font.fontStyle == FontStyle.italic; int style; if (isBold && isItalic) { style = Typeface.BOLD_ITALIC; } else if (isBold) { style = Typeface.BOLD; } else if (isItalic) { style = Typeface.ITALIC; } else { style = Typeface.NORMAL; } Typeface typeface = null; int weight = font.absoluteFontWeight; final String fontFamily = font.fontFamily; if (fontFamily != null && fontFamily.length() > 0) { String otfpath = FONTS + fontFamily + OTF; String ttfpath = FONTS + fontFamily + TTF; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Typeface.Builder builder = new Typeface.Builder(assets, otfpath); builder.setFontVariationSettings("'wght' " + weight + font.fontVariationSettings); builder.setWeight(weight); builder.setItalic(isItalic); typeface = builder.build(); if (typeface == null) { builder = new Typeface.Builder(assets, ttfpath); builder.setFontVariationSettings("'wght' " + weight + font.fontVariationSettings); builder.setWeight(weight); builder.setItalic(isItalic); typeface = builder.build(); } } else { try { typeface = Typeface.createFromAsset(assets, otfpath); typeface = Typeface.create(typeface, style); } catch (Exception ignored) { try { typeface = Typeface.createFromAsset(assets, ttfpath); typeface = Typeface.create(typeface, style); } catch (Exception ignored2) { } } } } if (typeface == null) { try { typeface = ReactFontManager.getInstance().getTypeface(fontFamily, style, assets); } catch (Exception ignored) { } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { typeface = Typeface.create(typeface, weight, isItalic); } paint.setLinearText(true); paint.setSubpixelText(true); paint.setTypeface(typeface); paint.setTextSize((float) (font.fontSize * mScale)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { paint.setLetterSpacing(0); } } private void setupTextPath() { ViewParent parent = getParent(); while (parent != null) { if (parent.getClass() == TextPathView.class) { textPath = (TextPathView) parent; break; } else if (!(parent instanceof TextView)) { break; } parent = parent.getParent(); } } @Override int hitTest(final float[] src) { if (mContent == null) { return super.hitTest(src); } if (mPath == null || !mInvertible) { return -1; } float[] dst = new float[2]; mInvMatrix.mapPoints(dst, src); int x = Math.round(dst[0]); int y = Math.round(dst[1]); initBounds(); if ((mRegion == null || !mRegion.contains(x, y)) && (mStrokeRegion == null || !mStrokeRegion.contains(x, y))) { return -1; } Path clipPath = getClipPath(); if (clipPath != null) { if (!mClipRegion.contains(x, y)) { return -1; } } return getId(); } } ================================================ FILE: android/src/main/java/com/horcrux/svg/TextLayoutAlgorithm.java ================================================ package com.horcrux.svg; // TODO implement https://www.w3.org/TR/SVG2/text.html#TextLayoutAlgorithm import static com.horcrux.svg.TextProperties.Direction; import static com.horcrux.svg.TextProperties.TextAnchor; import static com.horcrux.svg.TextProperties.TextPathSide; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.PointF; import android.view.View; import java.util.ArrayList; @SuppressWarnings("ALL") class TextLayoutAlgorithm { class CharacterInformation { int index; double x = 0; double y = 0; double advance; char character; double rotate = 0; TextView element; boolean hidden = false; boolean middle = false; boolean resolved = false; boolean xSpecified = false; boolean ySpecified = false; boolean addressable = true; boolean anchoredChunk = false; boolean rotateSpecified = false; boolean firstCharacterInResolvedDescendant = false; CharacterInformation(int index, char c) { this.index = index; this.character = c; } } class LayoutInput { TextView text; boolean horizontal; } private void getSubTreeTypographicCharacterPositions( ArrayList inTextPath, ArrayList subtree, StringBuilder line, View node, TextPathView textPath) { if (node instanceof TSpanView) { final TSpanView tSpanView = (TSpanView) node; String content = tSpanView.mContent; if (content == null) { for (int i = 0; i < tSpanView.getChildCount(); i++) { getSubTreeTypographicCharacterPositions( inTextPath, subtree, line, tSpanView.getChildAt(i), textPath); } } else { for (int i = 0; i < content.length(); i++) { subtree.add(tSpanView); inTextPath.add(textPath); } line.append(content); } } else { textPath = node instanceof TextPathView ? (TextPathView) node : textPath; for (int i = 0; i < textPath.getChildCount(); i++) { getSubTreeTypographicCharacterPositions( inTextPath, subtree, line, textPath.getChildAt(i), textPath); } } } CharacterInformation[] layoutText(LayoutInput layoutInput) { /* Setup Let root be the result of generating typographic character positions for the ‘text’ element and its subtree, laid out as if it were an absolutely positioned element. This will be a single line of text unless the white-space property causes line breaks. */ TextView text = layoutInput.text; StringBuilder line = new StringBuilder(); ArrayList subtree = new ArrayList<>(); ArrayList inTextPath = new ArrayList<>(); getSubTreeTypographicCharacterPositions(inTextPath, subtree, line, text, null); final char[] root = line.toString().toCharArray(); /* Let count be the number of DOM characters within the ‘text’ element's subtree. */ int count = root.length; /* Let result be an array of length count whose entries contain the per-character information described above. Each entry is initialized as follows: its global index number equal to its position in the array, its "x" coordinate set to "unspecified", its "y" coordinate set to "unspecified", its "rotate" coordinate set to "unspecified", its "hidden" flag is false, its "addressable" flag is true, its "middle" flag is false, its "anchored chunk" flag is false. */ final CharacterInformation[] result = new CharacterInformation[count]; for (int i = 0; i < count; i++) { result[i] = new CharacterInformation(i, root[i]); } /* If result is empty, then return result. */ if (count == 0) { return result; } /* Let CSS_positions be an array of length count whose entries will be filled with the x and y positions of the corresponding typographic character in root. The array entries are initialized to (0, 0). */ PointF[] CSS_positions = new PointF[count]; for (int i = 0; i < count; i++) { CSS_positions[i] = new PointF(0, 0); } /* Let "horizontal" be a flag, true if the writing mode of ‘text’ is horizontal, false otherwise. */ final boolean horizontal = true; /* Set flags and assign initial positions For each array element with index i in result: */ for (int i = 0; i < count; i++) { /* TODO Set addressable to false if the character at index i was: part of the text content of a non-rendered element discarded during layout due to being a collapsed white space character, a soft hyphen character, or a bidi control character; or discarded during layout due to being a collapsed segment break; or trimmed from the start or end of a line. Since there is collapsible white space not addressable by glyph positioning attributes in the following ‘text’ element (with a standard font), the "B" glyph will be placed at x=300. A B This is because the white space before the "A", and all but one white space character between the "A" and "B", is collapsed away or trimmed. */ result[i].addressable = true; /* Set middle to true if the character at index i TODO is the second or later character that corresponds to a typographic character. */ result[i].middle = false; /* TODO If the character at index i corresponds to a typographic character at the beginning of a line, then set the "anchored chunk" flag of result[i] to true. This ensures chunks shifted by text-anchor do not span multiple lines. */ result[i].anchoredChunk = i == 0; /* If addressable is true and middle is false then set CSS_positions[i] to the position of the TODO corresponding typographic character as determined by the CSS renderer. Otherwise, if i > 0, then set CSS_positions[i] = CSS_positions[i − 1] */ if (result[i].addressable && !result[i].middle) { CSS_positions[i].set(0, 0); } else if (i > 0) { CSS_positions[i].set(CSS_positions[i - 1]); } } /* Resolve character positioning Position adjustments (e.g values in a ‘x’ attribute) specified by a node apply to all characters in that node including characters in the node's descendants. Adjustments specified in descendant nodes, however, override adjustments from ancestor nodes. This section resolves which adjustments are to be applied to which characters. It also directly sets the rotate coordinate of result. Set up: Let resolve_x, resolve_y, resolve_dx, and resolve_dy be arrays of length count whose entries are all initialized to "unspecified". */ String[] resolve_x = new String[count]; String[] resolve_y = new String[count]; String[] resolve_dx = new String[count]; String[] resolve_dy = new String[count]; /* Set "in_text_path" flag false. This flag will allow ‘y’ (‘x’) attribute values to be ignored for horizontal (vertical) text inside ‘textPath’ elements. */ boolean in_text_path = false; /* Call the following procedure with the ‘text’ element node. Procedure: resolve character positioning: A recursive procedure that takes as input a node and whose steps are as follows: */ class CharacterPositioningResolver { private int global = 0; private boolean horizontal = true; private boolean in_text_path = false; private CharacterInformation[] result; private String[] resolve_x; private String[] resolve_y; private String[] resolve_dx; private String[] resolve_dy; private CharacterPositioningResolver( CharacterInformation[] result, String[] resolve_x, String[] resolve_y, String[] resolve_dx, String[] resolve_dy) { this.result = result; this.resolve_x = resolve_x; this.resolve_y = resolve_y; this.resolve_dx = resolve_dx; this.resolve_dy = resolve_dy; } private void resolveCharacterPositioning(TextView node) { /* If node is a ‘text’ or ‘tspan’ node: */ if (node.getClass() == TextView.class || node.getClass() == TSpanView.class) { /* Let index equal the "global index number" of the first character in the node. */ int index = global; /* Let x, y, dx, dy and rotate be the lists of values from the TODO corresponding attributes on node, or empty lists if the corresponding attribute was not specified or was invalid. */ // https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute String[] x = new String[] {}; // https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute String[] y = new String[] {}; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeLengths // https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute String[] dx = new String[] {}; // https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute String[] dy = new String[] {}; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeNumbers // https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute double[] rotate = new double[] {}; /* If "in_text_path" flag is false: Let new_chunk_count = max(length of x, length of y). */ int new_chunk_count; if (!in_text_path) { new_chunk_count = Math.max(x.length, y.length); /* Else: */ } else { /* If the "horizontal" flag is true: Let new_chunk_count = length of x. */ if (horizontal) { new_chunk_count = x.length; /* Else: Let new_chunk_count = length of y. */ } else { new_chunk_count = y.length; } } /* Let length be the number of DOM characters in the subtree rooted at node. */ String content = ((TSpanView) node).mContent; int length = content == null ? 0 : content.length(); /* Let i = 0 and j = 0. i is an index of addressable characters in the node; j is an index of all characters in the node. */ int i = 0; int j = 0; /* While j < length, do: */ while (j < length) { /* This loop applies the ‘x’, ‘y’, ‘dx’, ‘dy’ and ‘rotate’ attributes to the content inside node. If the "addressable" flag of result[index + j] is true, then: */ if (result[index + j].addressable) { /* If i < TODO new_check_count, then (typo) set the "anchored chunk" flag of result[index + j] to true. Else set the flag to false. Setting the flag to false ensures that ‘x’ and ‘y’ attributes set in a ‘text’ element don't create anchored chunk in a ‘textPath’ element when they should not. */ result[index + j].anchoredChunk = i < new_chunk_count; /* If i < length of x, then set resolve_x[index + j] to x[i]. */ if (i < x.length) { resolve_x[index + j] = x[i]; } /* If "in_text_path" flag is true and the "horizontal" flag is false, unset resolve_x[index]. The ‘x’ attribute is ignored for vertical text on a path. */ if (in_text_path && !horizontal) { resolve_x[index] = ""; } /* If i < length of y, then set resolve_y[index + j] to y[i]. */ if (i < y.length) { resolve_y[index + j] = y[i]; } /* If "in_text_path" flag is true and the "horizontal" flag is true, unset resolve_y[index]. The ‘y’ attribute is ignored for horizontal text on a path. */ if (in_text_path && horizontal) { resolve_y[index] = ""; } /* If i < length of dx, then set resolve_dx[index + j] to TODO dy[i]. (typo) */ if (i < dx.length) { resolve_dx[index + j] = dx[i]; } /* If i < length of dy, then set resolve_dy[index + j] to dy[i]. */ if (i < dy.length) { resolve_dy[index + j] = dy[i]; } /* If i < length of rotate, then set the angle value of result[index + j] to rotate[i]. Otherwise, if rotate is not empty, then set result[index + j] to result[index + j − 1]. */ if (i < rotate.length) { result[index + j].rotate = rotate[i]; } else if (rotate.length != 0) { result[index + j].rotate = result[index + j - 1].rotate; } /* Set i = i + 1. Set j = j + 1. */ } i++; j++; } /* If node is a ‘textPath’ node: Let index equal the global index number of the first character in the node (including descendant nodes). */ } else if (node.getClass() == TextPathView.class) { int index = global; /* Set the "anchored chunk" flag of result[index] to true. A ‘textPath’ element always creates an anchored chunk. */ result[index].anchoredChunk = true; /* Set in_text_path flag true. */ in_text_path = true; /* For each child node child of node: Resolve glyph positioning of child. */ for (int child = 0; child < node.getChildCount(); child++) { resolveCharacterPositioning((TextView) node.getChildAt(child)); } /* If node is a ‘textPath’ node: Set "in_text_path" flag false. */ if (node instanceof TextPathView) { in_text_path = false; } } } } CharacterPositioningResolver resolver = new CharacterPositioningResolver(result, resolve_x, resolve_y, resolve_dx, resolve_dy); /* Adjust positions: dx, dy The ‘dx’ and ‘dy’ adjustments are applied before adjustments due to the ‘textLength’ attribute while the ‘x’, ‘y’ and ‘rotate’ adjustments are applied after. Let shift be the cumulative x and y shifts due to ‘x’ and ‘y’ attributes, initialized to (0,0). */ PointF shift = new PointF(0, 0); /* For each array element with index i in result: */ for (int i = 0; i < count; i++) { /* If resolve_x[i] is unspecified, set it to 0. If resolve_y[i] is unspecified, set it to 0. */ if (resolve_x[i].equals("")) { resolve_x[i] = "0"; } if (resolve_y[i].equals("")) { resolve_y[i] = "0"; } /* Let shift.x = shift.x + resolve_x[i] and shift.y = shift.y + resolve_y[i]. */ shift.x = shift.x + Float.parseFloat(resolve_x[i]); shift.y = shift.y + Float.parseFloat(resolve_y[i]); /* Let result[i].x = CSS_positions[i].x + shift.x and result[i].y = CSS_positions[i].y + shift.y. */ result[i].x = CSS_positions[i].x + shift.x; result[i].y = CSS_positions[i].y + shift.y; } /* TODO Apply ‘textLength’ attribute Set up: Define resolved descendant node as a descendant of node with a valid ‘textLength’ attribute that is not itself a descendant node of a descendant node that has a valid ‘textLength’ attribute. Call the following procedure with the ‘text’ element node. Procedure: resolve text length: A recursive procedure that takes as input a node and whose steps are as follows: For each child node child of node: Resolve text length of child. Child nodes are adjusted before parent nodes. */ class TextLengthResolver { int global; private void resolveTextLength(TextView node) { /* If node is a ‘text’ or ‘tspan’ node and if the node has a valid ‘textLength’ attribute value: */ final Class nodeClass = node.getClass(); final boolean validTextLength = node.mTextLength != null; if ((nodeClass == TSpanView.class) && validTextLength) { /* Let a = +∞ and b = −∞. */ double a = Double.POSITIVE_INFINITY; double b = Double.NEGATIVE_INFINITY; /* Let i and j be the global index of the first character and last characters in node, respectively. */ String content = ((TSpanView) node).mContent; int i = global; int j = i + (content == null ? 0 : content.length()); /* For each index k in the range [i, j] where the "addressable" flag of result[k] is true: This loop finds the left-(top-) most and right-(bottom-) most extents of the typographic characters within the node and checks for forced line breaks. */ for (int k = i; k <= j; k++) { if (!result[i].addressable) { continue; } /* If the character at k is a linefeed or carriage return, return. No adjustments due to ‘textLength’ are made to a node with a forced line break. */ switch (result[i].character) { case '\n': case '\r': return; } /* Let pos = the x coordinate of the position in result[k], if the "horizontal" flag is true, and the y coordinate otherwise. */ double pos = horizontal ? result[k].x : result[k].y; /* Let advance = the advance of the typographic character corresponding to character k. [NOTE: This advance will be negative for RTL horizontal text.] */ double advance = result[k].advance; /* Set a = min(a, pos, pos + advance). Set b = max(b, pos, pos + advance). */ a = Math.min(a, Math.min(pos, pos + advance)); b = Math.max(b, Math.max(pos, pos + advance)); } /* If a ≠ +∞ then: */ if (a != Double.POSITIVE_INFINITY) { /* Find the distance delta = ‘textLength’ computed value − (b − a). */ double delta = node.mTextLength.value - (b - a); /* User agents are required to shift the last typographic character in the node by delta, in the positive x direction if the "horizontal" flag is true and if direction is lrt, in the negative x direction if the "horizontal" flag is true and direction is rtl, or in the positive y direction otherwise. User agents are free to adjust intermediate typographic characters for optimal typography. The next steps indicate one way to adjust typographic characters when the value of ‘lengthAdjust’ is spacing. Find n, the total number of typographic characters in this node TODO including any descendant nodes that are not resolved descendant nodes or within a resolved descendant node. */ int n = 0; int resolvedDescendantNodes = 0; for (int c = 0; c < node.getChildCount(); c++) { if (((TextPathView) node.getChildAt(c)).mTextLength == null) { String ccontent = ((TSpanView) node).mContent; n += ccontent == null ? 0 : ccontent.length(); } else { result[n].firstCharacterInResolvedDescendant = true; resolvedDescendantNodes++; } } /* Let n = n + number of resolved descendant nodes − 1. */ n += resolvedDescendantNodes - 1; /* Each resolved descendant node is treated as if it were a single typographic character in this context. Find the per-character adjustment δ = delta/n. Let shift = 0. */ double perCharacterAdjustment = delta / n; double shift = 0; /* For each index k in the range [i,j]: */ for (int k = i; k <= j; k++) { /* Add shift to the x coordinate of the position in result[k], if the "horizontal" flag is true, and to the y coordinate otherwise. */ if (horizontal) { result[k].x += shift; } else { result[k].y += shift; } /* If the "middle" flag for result[k] is not true and k is not a character in a resolved descendant node other than the first character then shift = shift + δ. */ if (!result[k].middle && (!result[k].resolved || result[k].firstCharacterInResolvedDescendant)) { shift += perCharacterAdjustment; } } } } } } TextLengthResolver lengthResolver = new TextLengthResolver(); lengthResolver.resolveTextLength(text); /* Adjust positions: x, y This loop applies ‘x’ and ‘y’ values, and ensures that text-anchor chunks do not start in the middle of a typographic character. Let shift be the current adjustment due to the ‘x’ and ‘y’ attributes, initialized to (0,0). Set index = 1. */ shift.set(0, 0); int index = 1; /* While index < count: */ while (index < count) { /* TODO If resolved_x[index] is set, then let (typo) shift.x = resolved_x[index] − result.x[index]. */ if (resolve_x[index] != null) { shift.x = (float) (Double.parseDouble(resolve_x[index]) - result[index].x); } /* TODO If resolved_y[index] is set, then let (typo) shift.y = resolved_y[index] − result.y[index]. */ if (resolve_y[index] != null) { shift.y = (float) (Double.parseDouble(resolve_y[index]) - result[index].y); } /* Let result.x[index] = result.x[index] + shift.x and result.y[index] = result.y[index] + shift.y. */ result[index].x += shift.x; result[index].y += shift.y; /* If the "middle" and "anchored chunk" flags of result[index] are both true, then: */ if (result[index].middle && result[index].anchoredChunk) { /* Set the "anchored chunk" flag of result[index] to false. */ result[index].anchoredChunk = false; } /* If index + 1 < count, then set the "anchored chunk" flag of result[index + 1] to true. */ if (index + 1 < count) { result[index + 1].anchoredChunk = true; } /* Set index to index + 1. */ index++; } /* Apply anchoring TODO For each slice result[i..j] (inclusive of both i and j), where: the "anchored chunk" flag of result[i] is true, the "anchored chunk" flags of result[k] where i < k ≤ j are false, and j = count − 1 or the "anchored chunk" flag of result[j + 1] is true; do: This loops over each anchored chunk. Let a = +∞ and b = −∞. For each index k in the range [i, j] where the "addressable" flag of result[k] is true: This loop finds the left-(top-) most and right-(bottom-) most extents of the typographic character within the anchored chunk. */ int i = 0; double a = Double.POSITIVE_INFINITY; double b = Double.NEGATIVE_INFINITY; double prevA = Double.POSITIVE_INFINITY; double prevB = Double.NEGATIVE_INFINITY; for (int k = 0; k < count; k++) { if (!result[k].addressable) { continue; } if (result[k].anchoredChunk) { prevA = a; prevB = b; a = Double.POSITIVE_INFINITY; b = Double.NEGATIVE_INFINITY; } /* Let pos = the x coordinate of the position in result[k], if the "horizontal" flag is true, and the y coordinate otherwise. Let advance = the advance of the typographic character corresponding to character k. [NOTE: This advance will be negative for RTL horizontal text.] Set a = min(a, pos, pos + advance). Set b = max(b, pos, pos + advance). */ double pos = horizontal ? result[k].x : result[k].y; double advance = result[k].advance; a = Math.min(a, Math.min(pos, pos + advance)); b = Math.max(b, Math.max(pos, pos + advance)); /* If a ≠ +∞, then: Here we perform the text anchoring. Let shift be the x coordinate of result[i], if the "horizontal" flag is true, and the y coordinate otherwise. TODO Adjust shift based on the value of text-anchor TODO and direction of the element the character at index i is in: (start, ltr) or (end, rtl) Set shift = shift − a. (start, rtl) or (end, ltr) Set shift = shift − b. (middle, ltr) or (middle, rtl) Set shift = shift − (a + b) / 2. */ if ((k > 0 && result[k].anchoredChunk && prevA != Double.POSITIVE_INFINITY) || k == count - 1) { TextAnchor anchor = TextAnchor.start; Direction direction = Direction.ltr; if (k == count - 1) { prevA = a; prevB = b; } double anchorShift = horizontal ? result[i].x : result[i].y; switch (anchor) { case start: if (direction == Direction.ltr) { anchorShift = anchorShift - prevA; } else { anchorShift = anchorShift - prevB; } break; case middle: if (direction == Direction.ltr) { anchorShift = anchorShift - (prevA + prevB) / 2; } else { anchorShift = anchorShift - (prevA + prevB) / 2; } break; case end: if (direction == Direction.ltr) { anchorShift = anchorShift - prevB; } else { anchorShift = anchorShift - prevA; } break; } /* For each index k in the range [i, j]: Add shift to the x coordinate of the position in result[k], if the "horizontal" flag is true, and to the y coordinate otherwise. */ int j = k == count - 1 ? k : k - 1; for (int r = i; r <= j; r++) { if (horizontal) { result[r].x += anchorShift; } else { result[r].y += anchorShift; } } i = k; } } /* Position on path Set index = 0. Set the "in path" flag to false. Set the "after path" flag to false. Let path_end be an offset for characters that follow a ‘textPath’ element. Set path_end to (0,0). While index < count: */ index = 0; boolean inPath = false; boolean afterPath = false; PointF path_end = new PointF(0, 0); Path textPath = null; PathMeasure pm = new PathMeasure(); while (index < count) { /* If the character at index i is within a ‘textPath’ element and corresponds to a typographic character, then: Set "in path" flag to true. */ final TextPathView textPathView = inTextPath.get(index); if (textPathView != null && result[index].addressable) { textPath = textPathView.getTextPath(null, null); inPath = true; /* If the "middle" flag of result[index] is false, then: */ if (!result[index].middle) { /* Here we apply ‘textPath’ positioning. Let path be the equivalent path of the basic shape element referenced by the ‘textPath’ element, or an empty path if the reference is invalid. If the ‘side’ attribute of the ‘textPath’ element is 'right', then TODO reverse path. */ Path path = textPath; if (textPathView.getSide() == TextPathSide.right) {} /* Let length be the length of path. */ pm.setPath(path, false); double length = pm.getLength(); /* Let offset be the value of the ‘textPath’ element's ‘startOffset’ attribute, adjusted due to any ‘pathLength’ attribute on the referenced element (if the referenced element is a ‘path’ element). */ double offset = textPathView.getStartOffset().value; /* Let advance = the advance of the typographic character corresponding to character TODO k. (typo) [NOTE: This advance will be negative for RTL horizontal text.] */ double advance = result[index].advance; /* Let (x, y) and angle be the position and angle in result[index]. */ double x = result[index].x; double y = result[index].y; double angle = result[index].rotate; /* Let mid be a coordinate value depending on the value of the "horizontal" flag: true mid is x + advance / 2 + offset false mid is y + advance / 2 + offset */ double mid = (horizontal ? x : y) + advance / 2 + offset; /* The user agent is free to make any additional adjustments to mid necessary to ensure high quality typesetting TODO due to a ‘spacing’ value of 'auto' or a ‘method’ value of 'stretch'. If path is not a closed subpath and mid < 0 or mid > length, set the "hidden" flag of result[index] to true. */ if (!pm.isClosed() && (mid < 0 || mid > length)) { result[index].hidden = true; } /* If path is a closed subpath depending on the values of text-anchor and direction of the element the character at index is in: */ if (pm.isClosed()) { /* This implements the special wrapping criteria for single closed subpaths. (start, ltr) or (end, rtl) If mid−offset < 0 or mid−offset > length, set the "hidden" flag of result[index] to true. (middle, ltr) or (middle, rtl) If If mid−offset < −length/2 or mid−offset > length/2, set the "hidden" flag of result[index] to true. (start, rtl) or (end, ltr) If mid−offset < −length or mid−offset > 0, set the "hidden" flag of result[index] to true. */ TextAnchor anchor = TextAnchor.start; Direction direction = Direction.ltr; double anchorShift = horizontal ? result[i].x : result[i].y; switch (anchor) { case start: if (direction == Direction.ltr) { if (mid < 0 || mid > length) { result[index].hidden = true; } } else { if (mid < -length || mid > 0) { result[index].hidden = true; } } break; case middle: if (mid < -length / 2 || mid > length / 2) { result[index].hidden = true; } break; case end: if (direction == Direction.ltr) { if (mid < -length || mid > 0) { result[index].hidden = true; } } else { if (mid < 0 || mid > length) { result[index].hidden = true; } } break; } } /* Set mid = mid mod length. */ mid %= length; /* If the hidden flag is false: */ if (!result[index].hidden) { /* Let point be the position and t be the unit vector tangent to the point mid distance along path. */ float[] point = new float[2]; float[] t = new float[2]; pm.getPosTan((float) mid, point, t); final double tau = 2 * Math.PI; final double radToDeg = 360 / tau; final double r = Math.atan2(t[1], t[0]) * radToDeg; /* If the "horizontal" flag is */ if (horizontal) { /* true Let n be the normal unit vector pointing in the direction t + 90°. */ double normAngle = r + 90; double[] n = new double[] {Math.cos(normAngle), Math.sin(normAngle)}; /* Let o be the horizontal distance from the TODO vertical center line of the glyph to the alignment point. */ double o = 0; /* Then set the position in result[index] to point - o×t + y×n. Let r be the angle from the positive x-axis to the tangent. Set the angle value in result[index] to angle + r. */ result[index].rotate += r; } else { /* false Let n be the normal unit vector pointing in the direction t - 90°. */ double normAngle = r - 90; double[] n = new double[] {Math.cos(normAngle), Math.sin(normAngle)}; /* Let o be the vertical distance from the TODO horizontal center line of the glyph to the alignment point. */ double o = 0; /* Then set the position in result[index] to point - o×t + x×n. Let r be the angle from the positive y-axis to the tangent. Set the angle value in result[index] to angle + r. */ result[index].rotate += r; } } /* Otherwise, the "middle" flag of result[index] is true: Set the position and angle values of result[index] to those in result[index − 1]. */ } else { result[index].x = result[index - 1].x; result[index].y = result[index - 1].y; result[index].rotate = result[index - 1].rotate; } } /* If the character at index i is not within a ‘textPath’ element and corresponds to a typographic character, then: This sets the starting point for rendering any characters that occur after a ‘textPath’ element to the end of the path. */ if (textPathView == null && result[index].addressable) { /* If the "in path" flag is true: Set the "in path" flag to false. Set the "after path" flag to true. Set path_end equal to the end point of the path referenced by ‘textPath’ − the position of result[index]. */ if (inPath) { inPath = false; afterPath = true; pm.setPath(textPath, false); float[] pos = new float[2]; pm.getPosTan(pm.getLength(), pos, null); path_end.set(pos[0], pos[1]); } /* If the "after path" is true. If anchored chunk of result[index] is true, set the "after path" flag to false. Else, let result.x[index] = result.x[index] + path_end.x and result.y[index] = result.y[index] + path_end.y. */ if (afterPath) { if (result[index].anchoredChunk) { afterPath = false; } else { result[index].x += path_end.x; result[index].y += path_end.y; } } } /* Set index = index + 1. */ index++; } /* Return result */ return result; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/TextPathView.java ================================================ /* * 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. */ package com.horcrux.svg; import static com.horcrux.svg.TextProperties.*; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class TextPathView extends TextView { private String mHref; private TextPathSide mSide; private TextPathMidLine mMidLine; private @Nullable SVGLength mStartOffset; private TextPathMethod mMethod = TextPathMethod.align; private TextPathSpacing mSpacing = TextPathSpacing.exact; public TextPathView(ReactContext reactContext) { super(reactContext); } public void setHref(String href) { mHref = href; invalidate(); } public void setStartOffset(Dynamic startOffset) { mStartOffset = SVGLength.from(startOffset); invalidate(); } public void setMethod(@Nullable String method) { mMethod = TextPathMethod.valueOf(method); invalidate(); } public void setSpacing(@Nullable String spacing) { mSpacing = TextPathSpacing.valueOf(spacing); invalidate(); } public void setSide(@Nullable String side) { mSide = TextPathSide.valueOf(side); invalidate(); } public void setSharp(@Nullable String midLine) { mMidLine = TextPathMidLine.valueOf(midLine); invalidate(); } @SuppressWarnings("unused") TextPathMethod getMethod() { return mMethod; } @SuppressWarnings("unused") TextPathSpacing getSpacing() { return mSpacing; } TextPathSide getSide() { return mSide; } TextPathMidLine getMidLine() { return mMidLine; } SVGLength getStartOffset() { return mStartOffset; } @Override void draw(Canvas canvas, Paint paint, float opacity) { drawGroup(canvas, paint, opacity); } Path getTextPath(Canvas canvas, Paint paint) { SvgView svg = getSvgView(); VirtualView template = svg.getDefinedTemplate(mHref); if (!(template instanceof RenderableView)) { // warning about this. return null; } RenderableView view = (RenderableView) template; return view.getPath(canvas, paint); } @Override Path getPath(Canvas canvas, Paint paint) { return getGroupPath(canvas, paint); } @Override void pushGlyphContext() { // do nothing } @Override void popGlyphContext() { // do nothing } } ================================================ FILE: android/src/main/java/com/horcrux/svg/TextProperties.java ================================================ package com.horcrux.svg; import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; class TextProperties { /* https://drafts.csswg.org/css-inline/#propdef-alignment-baseline 2.2.1. Alignment Point: alignment-baseline longhand Name: alignment-baseline Value: baseline | text-bottom | alphabetic | ideographic | middle | central | mathematical | text-top | bottom | center | top Initial: baseline Applies to: inline-level boxes, flex items, grid items, table cells Inherited: no Percentages: N/A Media: visual Computed value: as specified Canonical order: per grammar Animation type: discrete */ enum AlignmentBaseline { baseline("baseline"), textBottom("text-bottom"), alphabetic("alphabetic"), ideographic("ideographic"), middle("middle"), central("central"), mathematical("mathematical"), textTop("text-top"), bottom("bottom"), center("center"), top("top"), /* SVG implementations may support the following aliases in order to support legacy content: text-before-edge = text-top text-after-edge = text-bottom */ textBeforeEdge("text-before-edge"), textAfterEdge("text-after-edge"), // SVG 1.1 beforeEdge("before-edge"), afterEdge("after-edge"), hanging("hanging"), ; private final String alignment; AlignmentBaseline(String alignment) { this.alignment = alignment; } static AlignmentBaseline getEnum(String strVal) { if (!alignmentToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown String Value: " + strVal); } return alignmentToEnum.get(strVal); } private static final Map alignmentToEnum = new HashMap<>(); static { for (final AlignmentBaseline en : AlignmentBaseline.values()) { alignmentToEnum.put(en.alignment, en); } } @Nonnull @Override public String toString() { return alignment; } } // TODO implement rtl @SuppressWarnings("unused") enum Direction { ltr, rtl } enum FontVariantLigatures { normal, @SuppressWarnings("unused") none } enum FontStyle { normal, italic, @SuppressWarnings("unused") oblique } enum FontWeight { // Absolute Normal("normal"), Bold("bold"), w100("100"), w200("200"), w300("300"), w400("400"), w500("500"), w600("600"), w700("700"), w800("800"), w900("900"), // Relative Bolder("bolder"), Lighter("lighter"); private final String weight; FontWeight(String weight) { this.weight = weight; } static boolean hasEnum(String strVal) { return weightToEnum.containsKey(strVal); } static FontWeight get(String strVal) { return weightToEnum.get(strVal); } private static final Map weightToEnum = new HashMap<>(); static { for (final FontWeight en : FontWeight.values()) { weightToEnum.put(en.weight, en); } } @Nonnull @Override public String toString() { return weight; } } enum TextAnchor { start, middle, end } enum TextDecoration { None("none"), Underline("underline"), Overline("overline"), LineThrough("line-through"), Blink("blink"); private final String decoration; TextDecoration(String decoration) { this.decoration = decoration; } static TextDecoration getEnum(String strVal) { if (!decorationToEnum.containsKey(strVal)) { throw new IllegalArgumentException("Unknown String Value: " + strVal); } return decorationToEnum.get(strVal); } private static final Map decorationToEnum = new HashMap<>(); static { for (final TextDecoration en : TextDecoration.values()) { decorationToEnum.put(en.decoration, en); } } @Nonnull @Override public String toString() { return decoration; } } enum TextLengthAdjust { spacing, spacingAndGlyphs } enum TextPathMethod { align, @SuppressWarnings("unused") stretch } /* TODO suggest adding a compatibility mid-line rendering attribute to textPath, for a chrome/firefox/opera/safari compatible sharp text path rendering, which doesn't bend text smoothly along a right angle curve, (like Edge does) but keeps the mid-line orthogonal to the mid-point tangent at all times instead. */ enum TextPathMidLine { sharp, @SuppressWarnings("unused") smooth } enum TextPathSide { @SuppressWarnings("unused") left, right } enum TextPathSpacing { @SuppressWarnings("unused") auto, exact } } ================================================ FILE: android/src/main/java/com/horcrux/svg/TextView.java ================================================ /* * 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. */ package com.horcrux.svg; import static com.horcrux.svg.TextProperties.AlignmentBaseline; import static com.horcrux.svg.TextProperties.TextLengthAdjust; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Region; import android.view.View; import android.view.ViewParent; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import java.util.ArrayList; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") class TextView extends GroupView { SVGLength mInlineSize = null; SVGLength mTextLength = null; private String mBaselineShift = null; TextLengthAdjust mLengthAdjust = TextLengthAdjust.spacing; private AlignmentBaseline mAlignmentBaseline; @Nullable private ArrayList mPositionX; @Nullable private ArrayList mPositionY; @Nullable private ArrayList mRotate; @Nullable private ArrayList mDeltaX; @Nullable private ArrayList mDeltaY; double cachedAdvance = Double.NaN; public TextView(ReactContext reactContext) { super(reactContext); } @Override public void invalidate() { if (mPath == null) { return; } super.invalidate(); getTextContainer().clearChildCache(); } void clearCache() { cachedAdvance = Double.NaN; super.clearCache(); } public void setInlineSize(Dynamic inlineSize) { mInlineSize = SVGLength.from(inlineSize); invalidate(); } public void setTextLength(Dynamic length) { mTextLength = SVGLength.from(length); invalidate(); } public void setLengthAdjust(@Nullable String adjustment) { mLengthAdjust = TextLengthAdjust.valueOf(adjustment); invalidate(); } public void setMethod(@Nullable String alignment) { mAlignmentBaseline = AlignmentBaseline.getEnum(alignment); invalidate(); } public void setBaselineShift(Dynamic baselineShift) { mBaselineShift = SVGLength.toString(baselineShift); invalidate(); } public void setVerticalAlign(Dynamic dynamicVerticalAlign) { String verticalAlign = SVGLength.toString(dynamicVerticalAlign); if (verticalAlign != null) { verticalAlign = verticalAlign.trim(); int i = verticalAlign.lastIndexOf(' '); try { mAlignmentBaseline = AlignmentBaseline.getEnum(verticalAlign.substring(i)); } catch (IllegalArgumentException e) { mAlignmentBaseline = AlignmentBaseline.baseline; } try { mBaselineShift = verticalAlign.substring(0, i); } catch (IndexOutOfBoundsException e) { mBaselineShift = null; } } else { mAlignmentBaseline = AlignmentBaseline.baseline; mBaselineShift = null; } invalidate(); } public void setRotate(Dynamic rotate) { mRotate = SVGLength.arrayFrom(rotate); invalidate(); } public void setDeltaX(Dynamic deltaX) { mDeltaX = SVGLength.arrayFrom(deltaX); invalidate(); } public void setDeltaY(Dynamic deltaY) { mDeltaY = SVGLength.arrayFrom(deltaY); invalidate(); } public void setPositionX(Dynamic positionX) { mPositionX = SVGLength.arrayFrom(positionX); invalidate(); } public void setPositionY(Dynamic positionY) { mPositionY = SVGLength.arrayFrom(positionY); invalidate(); } @Override void draw(Canvas canvas, Paint paint, float opacity) { setupGlyphContext(canvas); clip(canvas, paint); getGroupPath(canvas, paint); pushGlyphContext(); drawGroup(canvas, paint, opacity); popGlyphContext(); } @Override Path getPath(Canvas canvas, Paint paint) { if (mPath != null) { return mPath; } setupGlyphContext(canvas); return getGroupPath(canvas, paint); } @Override Path getPath(Canvas canvas, Paint paint, Region.Op op) { return getPath(canvas, paint); } AlignmentBaseline getAlignmentBaseline() { if (mAlignmentBaseline == null) { ViewParent parent = this.getParent(); while (parent != null) { if (parent instanceof TextView) { TextView node = (TextView) parent; final AlignmentBaseline baseline = node.mAlignmentBaseline; if (baseline != null) { mAlignmentBaseline = baseline; return baseline; } } parent = parent.getParent(); } } if (mAlignmentBaseline == null) { mAlignmentBaseline = AlignmentBaseline.baseline; } return mAlignmentBaseline; } String getBaselineShift() { if (mBaselineShift == null) { ViewParent parent = this.getParent(); while (parent != null) { if (parent instanceof TextView) { TextView node = (TextView) parent; final String baselineShift = node.mBaselineShift; if (baselineShift != null) { mBaselineShift = baselineShift; return baselineShift; } } parent = parent.getParent(); } } return mBaselineShift; } Path getGroupPath(Canvas canvas, Paint paint) { if (mPath != null) { return mPath; } pushGlyphContext(); mPath = super.getPath(canvas, paint); popGlyphContext(); return mPath; } @Override void pushGlyphContext() { boolean isTextNode = !(this instanceof TextPathView) && !(this instanceof TSpanView); getTextRootGlyphContext() .pushContext(isTextNode, this, mFont, mPositionX, mPositionY, mDeltaX, mDeltaY, mRotate); } TextView getTextAnchorRoot() { GlyphContext gc = getTextRootGlyphContext(); ArrayList font = gc.mFontContext; TextView node = this; ViewParent parent = this.getParent(); for (int i = font.size() - 1; i >= 0; i--) { if (!(parent instanceof TextView) || font.get(i).textAnchor == TextProperties.TextAnchor.start || node.mPositionX != null) { return node; } node = (TextView) parent; parent = node.getParent(); } return node; } double getSubtreeTextChunksTotalAdvance(Paint paint) { if (!Double.isNaN(cachedAdvance)) { return cachedAdvance; } double advance = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof TextView) { TextView text = (TextView) child; advance += text.getSubtreeTextChunksTotalAdvance(paint); } } cachedAdvance = advance; return advance; } TextView getTextContainer() { TextView node = this; ViewParent parent = this.getParent(); while (parent instanceof TextView) { node = (TextView) parent; parent = node.getParent(); } return node; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/UseView.java ================================================ /* * 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. */ package com.horcrux.svg; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.ReactConstants; @SuppressLint("ViewConstructor") class UseView extends RenderableView { private String mHref; private SVGLength mX; private SVGLength mY; private SVGLength mW; private SVGLength mH; public UseView(ReactContext reactContext) { super(reactContext); } public void setHref(String href) { mHref = href; invalidate(); } public void setX(Dynamic x) { mX = SVGLength.from(x); invalidate(); } public void setY(Dynamic y) { mY = SVGLength.from(y); invalidate(); } public void setWidth(Dynamic width) { mW = SVGLength.from(width); invalidate(); } public void setHeight(Dynamic height) { mH = SVGLength.from(height); invalidate(); } @Override void draw(Canvas canvas, Paint paint, float opacity) { VirtualView template = getSvgView().getDefinedTemplate(mHref); if (template == null) { FLog.w( ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " + "template named: " + mHref + " is not defined."); return; } template.clearCache(); canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY)); if (template instanceof RenderableView) { ((RenderableView) template).mergeProperties(this); } int count = template.saveAndSetupCanvas(canvas, mCTM); clip(canvas, paint); if (template instanceof SymbolView) { SymbolView symbol = (SymbolView) template; symbol.drawSymbol( canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH)); } else { template.draw(canvas, paint, opacity * mOpacity); } // TODO: replace getMatrix with mCTM when it will be fixed RectF clientRect = new RectF(); this.getPath(canvas, paint).computeBounds(clientRect, true); canvas.getMatrix().mapRect(clientRect); this.setClientRect(clientRect); template.restoreCanvas(canvas, count); if (template instanceof RenderableView) { ((RenderableView) template).resetProperties(); } } @Override int hitTest(float[] src) { if (!mInvertible) { return -1; } float[] dst = new float[2]; mInvMatrix.mapPoints(dst, src); VirtualView template = getSvgView().getDefinedTemplate(mHref); if (template == null) { FLog.w( ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " + "template named: " + mHref + " is not defined."); return -1; } int hitChild = template.hitTest(dst); if (hitChild != -1) { return (template.isResponsible() || hitChild != template.getId()) ? hitChild : getId(); } return -1; } @Override Path getPath(Canvas canvas, Paint paint) { VirtualView template = getSvgView().getDefinedTemplate(mHref); if (template == null) { FLog.w( ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " + "template named: " + mHref + " is not defined."); return null; } Path path = template.getPath(canvas, paint); Path use = new Path(); Matrix m = new Matrix(); m.setTranslate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY)); path.transform(m, use); return use; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/ViewBox.java ================================================ /* * 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. */ package com.horcrux.svg; import android.graphics.Matrix; import android.graphics.RectF; class ViewBox { private static final int MOS_MEET = 0; private static final int MOS_SLICE = 1; private static final int MOS_NONE = 2; static Matrix getTransform(RectF vbRect, RectF eRect, String align, int meetOrSlice) { // based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform // Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the // viewBox attribute respectively. double vbX = vbRect.left; double vbY = vbRect.top; double vbWidth = vbRect.width(); double vbHeight = vbRect.height(); // Let e-x, e-y, e-width, e-height be the position and size of the element respectively. double eX = eRect.left; double eY = eRect.top; double eWidth = eRect.width(); double eHeight = eRect.height(); // Initialize scale-x to e-width/vb-width. double scaleX = eWidth / vbWidth; // Initialize scale-y to e-height/vb-height. double scaleY = eHeight / vbHeight; // Initialize translate-x to e-x - (vb-x * scale-x). // Initialize translate-y to e-y - (vb-y * scale-y). double translateX = eX - (vbX * scaleX); double translateY = eY - (vbY * scaleY); // If align is 'none' if (meetOrSlice == MOS_NONE) { // Let scale be set the smaller value of scale-x and scale-y. // Assign scale-x and scale-y to scale. double scale = scaleX = scaleY = Math.min(scaleX, scaleY); // If scale is greater than 1 if (scale > 1) { // Minus translateX by (eWidth / scale - vbWidth) / 2 // Minus translateY by (eHeight / scale - vbHeight) / 2 translateX -= (eWidth / scale - vbWidth) / 2; translateY -= (eHeight / scale - vbHeight) / 2; } else { translateX -= (eWidth - vbWidth * scale) / 2; translateY -= (eHeight - vbHeight * scale) / 2; } } else { // If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to // the smaller. // Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x // and scale-y to the larger. if (!align.equals("none") && meetOrSlice == MOS_MEET) { scaleX = scaleY = Math.min(scaleX, scaleY); } else if (!align.equals("none") && meetOrSlice == MOS_SLICE) { scaleX = scaleY = Math.max(scaleX, scaleY); } translateX = eX - (vbX * scaleX); translateY = eY - (vbY * scaleY); // If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x. if (align.contains("xMid")) { translateX += (eWidth - vbWidth * scaleX) / 2.0d; } // If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x. if (align.contains("xMax")) { translateX += (eWidth - vbWidth * scaleX); } // If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y. if (align.contains("YMid")) { translateY += (eHeight - vbHeight * scaleY) / 2.0d; } // If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y. if (align.contains("YMax")) { translateY += (eHeight - vbHeight * scaleY); } } // The transform applied to content contained by the element is given by // translate(translate-x, translate-y) scale(scale-x, scale-y). Matrix transform = new Matrix(); transform.postTranslate((float) translateX, (float) translateY); transform.preScale((float) scaleX, (float) scaleY); return transform; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/VirtualView.java ================================================ package com.horcrux.svg; import static com.horcrux.svg.FontData.DEFAULT_FONT_SIZE; import android.annotation.SuppressLint; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.view.View; import android.view.ViewParent; import android.view.accessibility.AccessibilityNodeInfo; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableType; import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.view.ReactViewGroup; import com.horcrux.svg.events.SvgOnLayoutEvent; import java.util.ArrayList; import javax.annotation.Nullable; @SuppressLint("ViewConstructor") public abstract class VirtualView extends ReactViewGroup { final ReactContext mContext; VirtualView(ReactContext reactContext) { super(reactContext); mContext = reactContext; mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; } /* N[1/Sqrt[2], 36] The inverse of the square root of 2. Provide enough digits for the 128-bit IEEE quad (36 significant digits). */ private static final double M_SQRT1_2l = 0.707106781186547524400844362104849039; private static final float[] sRawMatrix = new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; float mOpacity = 1f; Matrix mCTM = new Matrix(); Matrix mMatrix = new Matrix(); Matrix mInvCTM = new Matrix(); Matrix mInvMatrix = new Matrix(); boolean mInvertible = true; boolean mCTMInvertible = true; private RectF mClientRect; int mClipRule; private @Nullable String mClipPath; @Nullable String mMask; @Nullable String mMarkerStart; @Nullable String mMarkerMid; @Nullable String mMarkerEnd; private static final int CLIP_RULE_EVENODD = 0; static final int CLIP_RULE_NONZERO = 1; final float mScale; private boolean mResponsible; String mDisplay; String mName; private SvgView svgView; private Path mCachedClipPath; private GroupView mTextRoot; private double fontSize = -1; private double canvasDiagonal = -1; private float canvasHeight = -1; private float canvasWidth = -1; private GlyphContext glyphContext; Path mPath; Path mFillPath; Path mStrokePath; Path mMarkerPath; Path mClipRegionPath; RectF mBox; RectF mFillBounds; RectF mStrokeBounds; RectF mMarkerBounds; RectF mClipBounds; Region mRegion; Region mMarkerRegion; Region mStrokeRegion; Region mClipRegion; ArrayList elements; PointerEvents mPointerEvents; public void setPointerEvents(PointerEvents pointerEvents) { mPointerEvents = pointerEvents; } @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); if (mClientRect != null) { SvgView root = getSvgView(); int[] rootPositionOnScreen = new int[2]; getSvgView().getLocationOnScreen(rootPositionOnScreen); Rect infoBoundsInScreen = new Rect(); infoBoundsInScreen.left = rootPositionOnScreen[0] + (int) Math.floor(mClientRect.left); infoBoundsInScreen.top = rootPositionOnScreen[1] + (int) Math.floor(mClientRect.top); infoBoundsInScreen.right = infoBoundsInScreen.left + (int) Math.ceil(mClientRect.width()); infoBoundsInScreen.bottom = infoBoundsInScreen.top + (int) Math.ceil(mClientRect.height()); Rect rootVisibleRect = new Rect(); boolean isRootVisible = root.getGlobalVisibleRect(rootVisibleRect); boolean infoIsVisibleToUser = isRootVisible && infoBoundsInScreen.intersect(rootVisibleRect); String infoClassName = this.getClass().getCanonicalName(); info.setBoundsInScreen(infoBoundsInScreen); info.setClassName(infoClassName); info.setVisibleToUser(infoIsVisibleToUser); } } @Override public void invalidate() { if (this instanceof RenderableView && mPath == null) { return; } clearCache(); clearParentCache(); super.invalidate(); } void clearCache() { canvasDiagonal = -1; canvasHeight = -1; canvasWidth = -1; fontSize = -1; mStrokeRegion = null; mMarkerRegion = null; mRegion = null; mPath = null; } void clearChildCache() { clearCache(); for (int i = 0; i < getChildCount(); i++) { View node = getChildAt(i); if (node instanceof VirtualView) { ((VirtualView) node).clearChildCache(); } } } private void clearParentCache() { VirtualView node = this; while (true) { ViewParent parent = node.getParent(); if (!(parent instanceof VirtualView)) { return; } node = (VirtualView) parent; if (node.mPath == null) { return; } node.clearCache(); } } @Nullable GroupView getTextRoot() { VirtualView node = this; if (mTextRoot == null) { while (node != null) { if (node instanceof GroupView && ((GroupView) node).getGlyphContext() != null) { mTextRoot = (GroupView) node; break; } ViewParent parent = node.getParent(); if (!(parent instanceof VirtualView)) { node = null; } else { node = (VirtualView) parent; } } } return mTextRoot; } @Nullable GroupView getParentTextRoot() { ViewParent parent = this.getParent(); if (!(parent instanceof VirtualView)) { return null; } else { return ((VirtualView) parent).getTextRoot(); } } private double getFontSizeFromContext() { if (fontSize != -1) { return fontSize; } GroupView root = getTextRoot(); if (root == null) { return DEFAULT_FONT_SIZE; } if (glyphContext == null) { glyphContext = root.getGlyphContext(); } fontSize = glyphContext.getFontSize(); return fontSize; } abstract void draw(Canvas canvas, Paint paint, float opacity); void render(Canvas canvas, Paint paint, float opacity) { draw(canvas, paint, opacity); } /** * Sets up the transform matrix on the canvas before an element is drawn. * *

NB: for perf reasons this does not apply opacity, as that would mean creating a new canvas * layer (which allocates an offscreen bitmap) and having it composited afterwards. Instead, the * drawing code should apply opacity recursively. * * @param canvas the canvas to set up * @param ctm current transformation matrix */ int saveAndSetupCanvas(Canvas canvas, Matrix ctm) { int count = canvas.save(); mCTM.set(mMatrix); canvas.concat(mCTM); mCTM.preConcat(ctm); mCTMInvertible = mCTM.invert(mInvCTM); return count; } /** * Restore the canvas after an element was drawn. This is always called in mirror with {@link * #saveAndSetupCanvas}. * * @param canvas the canvas to restore */ void restoreCanvas(Canvas canvas, int count) { canvas.restoreToCount(count); } public void setName(String name) { mName = name; invalidate(); } public void setDisplay(String display) { mDisplay = display; invalidate(); } public void setMask(String mask) { mMask = mask; invalidate(); } public void setMarkerStart(String markerStart) { mMarkerStart = markerStart; invalidate(); } public void setMarkerMid(String markerMid) { mMarkerMid = markerMid; invalidate(); } public void setMarkerEnd(String markerEnd) { mMarkerEnd = markerEnd; invalidate(); } public void setClipPath(String clipPath) { mCachedClipPath = null; mClipPath = clipPath; invalidate(); } public void setClipRule(int clipRule) { mClipRule = clipRule; invalidate(); } public void setOpacity(float opacity) { mOpacity = opacity; invalidate(); } public void setMatrix(Dynamic matrixArray) { boolean isArrayType = !matrixArray.isNull() && matrixArray.getType().equals(ReadableType.Array); setMatrix(isArrayType ? matrixArray.asArray() : null); } public void setMatrix(@Nullable ReadableArray matrixArray) { if (matrixArray != null) { int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale); if (matrixSize == 6) { if (mMatrix == null) { mMatrix = new Matrix(); mInvMatrix = new Matrix(); } mMatrix.setValues(sRawMatrix); mInvertible = mMatrix.invert(mInvMatrix); } else if (matrixSize != -1) { FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6"); } } else { mMatrix.reset(); mInvMatrix.reset(); mInvertible = true; } super.invalidate(); clearParentCache(); } public void setResponsible(boolean responsible) { mResponsible = responsible; invalidate(); } @Nullable Path getClipPath() { return mCachedClipPath; } @Nullable Path getClipPath(Canvas canvas, Paint paint) { if (mClipPath != null) { ClipPathView mClipNode = (ClipPathView) getSvgView().getDefinedClipPath(mClipPath); if (mClipNode != null) { Path clipPath = mClipRule == CLIP_RULE_EVENODD ? mClipNode.getPath(canvas, paint) : mClipNode.getPath(canvas, paint, Region.Op.UNION); clipPath.transform(mClipNode.mMatrix); switch (mClipRule) { case CLIP_RULE_EVENODD: clipPath.setFillType(Path.FillType.EVEN_ODD); break; case CLIP_RULE_NONZERO: break; default: FLog.w(ReactConstants.TAG, "RNSVG: clipRule: " + mClipRule + " unrecognized"); } mCachedClipPath = clipPath; } else { FLog.w(ReactConstants.TAG, "RNSVG: Undefined clipPath: " + mClipPath); } } return getClipPath(); } void clip(Canvas canvas, Paint paint) { Path clip = getClipPath(canvas, paint); if (clip != null) { canvas.clipPath(clip); } } abstract int hitTest(final float[] point); boolean isResponsible() { return mResponsible; } abstract Path getPath(Canvas canvas, Paint paint); @Nullable public SvgView getSvgView() { if (svgView != null) { return svgView; } ViewParent parent = getParent(); if (parent == null) { return null; } else if (parent instanceof SvgView) { svgView = (SvgView) parent; } else if (parent instanceof VirtualView) { svgView = ((VirtualView) parent).getSvgView(); } else { FLog.e( ReactConstants.TAG, "RNSVG: " + getClass().getName() + " should be descendant of a SvgView."); } return svgView; } double relativeOnFraction(SVGLength length, float relative) { SVGLength.UnitType unit = length.unit; if (unit == SVGLength.UnitType.NUMBER) { return length.value * relative; } else if (unit == SVGLength.UnitType.PERCENTAGE) { return length.value / 100 * relative; } return fromRelativeFast(length); } double relativeOn(SVGLength length, float relative) { SVGLength.UnitType unit = length.unit; if (unit == SVGLength.UnitType.NUMBER) { return length.value * mScale; } else if (unit == SVGLength.UnitType.PERCENTAGE) { return length.value / 100 * relative; } return fromRelativeFast(length); } double relativeOnWidth(SVGLength length) { SvgView svg = getSvgView(); if (length.unit == SVGLength.UnitType.PERCENTAGE && svg != null && svg.getViewBox().width() != 0) { return relativeOn(length, svg.getViewBox().width()); } return relativeOn(length, getCanvasWidth()); } double relativeOnHeight(SVGLength length) { SvgView svg = getSvgView(); if (length.unit == SVGLength.UnitType.PERCENTAGE && svg != null && svg.getViewBox().height() != 0) { return relativeOn(length, svg.getViewBox().height()); } return relativeOn(length, getCanvasHeight()); } double relativeOnOther(SVGLength length) { return relativeOn(length, (float) getCanvasDiagonal()); } /** * Converts SVGLength into px / user units in the current user coordinate system * * @param length length string * @return value in the current user coordinate system */ private double fromRelativeFast(SVGLength length) { double unit; switch (length.unit) { case EMS: unit = getFontSizeFromContext(); break; case EXS: unit = getFontSizeFromContext() / 2; break; case CM: unit = 35.43307; break; case MM: unit = 3.543307; break; case IN: unit = 90; break; case PT: unit = 1.25; break; case PC: unit = 15; break; default: unit = 1; } return length.value * unit * mScale; } private float getCanvasWidth() { if (canvasWidth != -1) { return canvasWidth; } GroupView root = getTextRoot(); if (root == null) { canvasWidth = getSvgView().getCanvasBounds().width(); } else { canvasWidth = root.getGlyphContext().getWidth(); } return canvasWidth; } private float getCanvasHeight() { if (canvasHeight != -1) { return canvasHeight; } GroupView root = getTextRoot(); if (root == null) { canvasHeight = getSvgView().getCanvasBounds().height(); } else { canvasHeight = root.getGlyphContext().getHeight(); } return canvasHeight; } private double getCanvasDiagonal() { if (canvasDiagonal != -1) { return canvasDiagonal; } double powX = Math.pow((getCanvasWidth()), 2); double powY = Math.pow((getCanvasHeight()), 2); canvasDiagonal = Math.sqrt(powX + powY) * M_SQRT1_2l; return canvasDiagonal; } void saveDefinition() { if (mName != null) { getSvgView().defineTemplate(this, mName); } } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = mClientRect != null ? (int) Math.ceil(mClientRect.width()) : getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); int height = mClientRect != null ? (int) Math.ceil(mClientRect.height()) : getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); } /** * Called from layout when this view should assign a size and position to each of its children. * *

Derived classes with children should override this method and call layout on each of their * children. * * @param changed This is a new size or position for this view * @param pleft Left position, relative to parent * @param ptop Top position, relative to parent * @param pright Right position, relative to parent * @param pbottom Bottom position, relative to parent */ protected void onLayout(boolean changed, int pleft, int ptop, int pright, int pbottom) { if (mClientRect == null) { return; } if (!(this instanceof GroupView)) { int left = (int) Math.floor(mClientRect.left); int top = (int) Math.floor(mClientRect.top); int right = (int) Math.ceil(mClientRect.right); int bottom = (int) Math.ceil(mClientRect.bottom); setLeft(left); setTop(top); setRight(right); setBottom(bottom); } int width = (int) Math.ceil(mClientRect.width()); int height = (int) Math.ceil(mClientRect.height()); setMeasuredDimension(width, height); } void setClientRect(RectF rect) { if (mClientRect != null && mClientRect.equals(rect)) { return; } mClientRect = rect; if (mClientRect == null) { return; } int width = (int) Math.ceil(mClientRect.width()); int height = (int) Math.ceil(mClientRect.height()); int left = (int) Math.floor(mClientRect.left); int top = (int) Math.floor(mClientRect.top); int right = (int) Math.ceil(mClientRect.right); int bottom = (int) Math.ceil(mClientRect.bottom); setMeasuredDimension(width, height); if (!(this instanceof GroupView)) { SvgView root = this.getSvgView(); // Prevent going out of the root view bounds to properly handle touch events if (root != null) { setLeft(Math.max(left, 0)); setTop(Math.max(top, 0)); setRight(Math.min(right, root.getWidth())); setBottom(Math.min(bottom, root.getHeight())); } } EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(mContext, getId()); if (eventDispatcher != null) { eventDispatcher.dispatchEvent( new SvgOnLayoutEvent( UIManagerHelper.getSurfaceId(VirtualView.this), this.getId(), left, top, width, height)); } } RectF getClientRect() { return mClientRect; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/events/SvgLoadEvent.java ================================================ package com.horcrux.svg.events; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.events.Event; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.views.imagehelper.ImageSource; public class SvgLoadEvent extends Event { public static final String EVENT_NAME = "topLoad"; private final float width; private final float height; private final String uri; public SvgLoadEvent( int surfaceId, int viewId, ReactContext mContext, String uriString, float width, float height) { super(surfaceId, viewId); ImageSource imageSource = new ImageSource(mContext, uriString); this.uri = imageSource.getSource(); this.width = width; this.height = height; } @Override public String getEventName() { return EVENT_NAME; } @Override public short getCoalescingKey() { return 0; } @Override public void dispatch(RCTEventEmitter rctEventEmitter) { rctEventEmitter.receiveEvent(getViewTag(), getEventName(), getEventData()); } protected WritableMap getEventData() { WritableMap eventData = Arguments.createMap(); eventData.putDouble("width", width); eventData.putDouble("height", height); eventData.putString("uri", uri); WritableMap event = Arguments.createMap(); event.putMap("source", eventData); return event; } } ================================================ FILE: android/src/main/java/com/horcrux/svg/events/SvgOnLayoutEvent.java ================================================ package com.horcrux.svg.events; import androidx.core.util.Pools.SynchronizedPool; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.events.Event; public class SvgOnLayoutEvent extends Event { public static final String EVENT_NAME = "topSvgLayout"; public int x = 0; public int y = 0; public int width = 0; public int height = 0; public SvgOnLayoutEvent(int surfaceId, int viewId, int x, int y, int width, int height) { super(surfaceId, viewId); this.x = x; this.y = y; this.width = width; this.height = height; } @Override public String getEventName() { return EVENT_NAME; } @Override public short getCoalescingKey() { return 0; } @Override protected WritableMap getEventData() { WritableMap layout = Arguments.createMap(); layout.putDouble("x", (double) PixelUtil.toDIPFromPixel((float) x)); layout.putDouble("y", (double) PixelUtil.toDIPFromPixel((float) y)); layout.putDouble("width", (double) PixelUtil.toDIPFromPixel((float) width)); layout.putDouble("height", (double) PixelUtil.toDIPFromPixel((float) height)); WritableMap event = Arguments.createMap(); event.putMap("layout", layout); event.putInt("target", getViewTag()); return event; } } ================================================ FILE: android/src/main/jni/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.13) set(CMAKE_VERBOSE_MAKEFILE ON) set(RNSVG_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) set(RNSVG_COMMON_DIR ${RNSVG_ANDROID_DIR}/../common/cpp) set(RNSVG_GENERATED_DIR ${RNSVG_ANDROID_DIR}/build/generated) set(RNSVG_GENERATED_JNI_DIR ${RNSVG_GENERATED_DIR}/source/codegen/jni) set(RNSVG_GENERATED_REACT_DIR ${RNSVG_GENERATED_JNI_DIR}/react/renderer/components/rnsvg) file(GLOB rnsvg_SRCS CONFIGURE_DEPENDS *.cpp ${RNSVG_COMMON_DIR}/react/renderer/components/rnsvg/*.cpp) file(GLOB rnsvg_codegen_SRCS CONFIGURE_DEPENDS ${RNSVG_GENERATED_REACT_DIR}/*cpp) add_library( react_codegen_rnsvg SHARED ${rnsvg_SRCS} ${rnsvg_codegen_SRCS} ) target_include_directories( react_codegen_rnsvg PUBLIC . ${RNSVG_COMMON_DIR} ${RNSVG_GENERATED_JNI_DIR} ${RNSVG_GENERATED_REACT_DIR} ) # https://developer.android.com/guide/practices/page-sizes#cmake target_link_options(react_codegen_rnsvg PRIVATE "-Wl,-z,max-page-size=16384") find_package(ReactAndroid REQUIRED CONFIG) if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76) target_link_libraries( react_codegen_rnsvg ReactAndroid::reactnative ReactAndroid::jsi ) else() target_link_libraries( react_codegen_rnsvg 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_image react_render_componentregistry rrc_view turbomodulejsijni yoga react_render_imagemanager react_utils ) endif() target_link_libraries( react_codegen_rnsvg fbjni ) target_include_directories( react_codegen_rnsvg PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80) target_compile_reactnative_options(react_codegen_rnsvg PUBLIC) else() target_compile_options( react_codegen_rnsvg PRIVATE -fexceptions -frtti -std=c++20 -Wall ) endif() target_compile_options( react_codegen_rnsvg PRIVATE -Wpedantic -Wno-gnu-zero-variadic-macro-arguments -Wno-dollar-in-identifier-extension ) target_compile_definitions( react_codegen_rnsvg PRIVATE REACT_NATIVE_MINOR_VERSION=${ReactAndroid_VERSION_MINOR} ) ================================================ FILE: android/src/main/jni/rnsvg.cpp ================================================ /** * 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(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(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(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(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(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(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(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(turboModule).invokeJavaMethod(rt, PromiseKind, "getRawResource", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); } NativeSvgRenderableModuleSpecJSI::NativeSvgRenderableModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) : 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(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 ¶ms) : JavaTurboModule(params) { methodMap_["toDataURL"] = MethodMetadata {3, __hostFunction_NativeSvgViewModuleSpecJSI_toDataURL}; } std::shared_ptr rnsvg_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { if (moduleName == "RNSVGRenderableModule") { return std::make_shared(params); } if (moduleName == "RNSVGSvgViewModule") { return std::make_shared(params); } return nullptr; } } // namespace react } // namespace facebook ================================================ FILE: android/src/main/jni/rnsvg.h ================================================ #pragma once #include #include #include #include #include namespace facebook { namespace react { /** * JNI C++ class for module 'NativeSvgRenderableModule' */ class JSI_EXPORT NativeSvgRenderableModuleSpecJSI : public JavaTurboModule { public: NativeSvgRenderableModuleSpecJSI(const JavaTurboModule::InitParams ¶ms); }; /** * JNI C++ class for module 'NativeSvgViewModule' */ class JSI_EXPORT NativeSvgViewModuleSpecJSI : public JavaTurboModule { public: NativeSvgViewModuleSpecJSI(const JavaTurboModule::InitParams ¶ms); }; JSI_EXPORT std::shared_ptr rnsvg_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); } // namespace react } // namespace facebook ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGCircleManagerDelegate & RNSVGCircleManagerInterface> extends BaseViewManagerDelegate { public RNSVGCircleManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "cx": mViewManager.setCx(view, new DynamicFromObject(value)); break; case "cy": mViewManager.setCy(view, new DynamicFromObject(value)); break; case "r": mViewManager.setR(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGCircleManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGCircleManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setCx(T view, Dynamic value); void setCy(T view, Dynamic value); void setR(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGClipPathManagerDelegate & RNSVGClipPathManagerInterface> extends BaseViewManagerDelegate { public RNSVGClipPathManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGClipPathManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGClipPathManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGDefsManagerDelegate.java ================================================ /** * 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.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGDefsManagerDelegate & RNSVGDefsManagerInterface> extends BaseViewManagerDelegate { public RNSVGDefsManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGDefsManagerInterface.java ================================================ /** * 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.ReadableArray; public interface RNSVGDefsManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGEllipseManagerDelegate & RNSVGEllipseManagerInterface> extends BaseViewManagerDelegate { public RNSVGEllipseManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "cx": mViewManager.setCx(view, new DynamicFromObject(value)); break; case "cy": mViewManager.setCy(view, new DynamicFromObject(value)); break; case "rx": mViewManager.setRx(view, new DynamicFromObject(value)); break; case "ry": mViewManager.setRy(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGEllipseManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGEllipseManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setCx(T view, Dynamic value); void setCy(T view, Dynamic value); void setRx(T view, Dynamic value); void setRy(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeBlendManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeBlendManagerDelegate & RNSVGFeBlendManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeBlendManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "in1": mViewManager.setIn1(view, value == null ? null : (String) value); break; case "in2": mViewManager.setIn2(view, value == null ? null : (String) value); break; case "mode": mViewManager.setMode(view, (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeBlendManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFeBlendManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setIn1(T view, @Nullable String value); void setIn2(T view, @Nullable String value); void setMode(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeColorMatrixManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeColorMatrixManagerDelegate & RNSVGFeColorMatrixManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeColorMatrixManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "in1": mViewManager.setIn1(view, value == null ? null : (String) value); break; case "type": mViewManager.setType(view, (String) value); break; case "values": mViewManager.setValues(view, (ReadableArray) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeColorMatrixManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGFeColorMatrixManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setIn1(T view, @Nullable String value); void setType(T view, @Nullable String value); void setValues(T view, @Nullable ReadableArray value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeCompositeManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeCompositeManagerDelegate & RNSVGFeCompositeManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeCompositeManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "in1": mViewManager.setIn1(view, value == null ? null : (String) value); break; case "in2": mViewManager.setIn2(view, value == null ? null : (String) value); break; case "operator1": mViewManager.setOperator1(view, (String) value); break; case "k1": mViewManager.setK1(view, value == null ? 0f : ((Double) value).floatValue()); break; case "k2": mViewManager.setK2(view, value == null ? 0f : ((Double) value).floatValue()); break; case "k3": mViewManager.setK3(view, value == null ? 0f : ((Double) value).floatValue()); break; case "k4": mViewManager.setK4(view, value == null ? 0f : ((Double) value).floatValue()); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeCompositeManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFeCompositeManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setIn1(T view, @Nullable String value); void setIn2(T view, @Nullable String value); void setOperator1(T view, @Nullable String value); void setK1(T view, float value); void setK2(T view, float value); void setK3(T view, float value); void setK4(T view, float value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeFloodManagerDelegate & RNSVGFeFloodManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeFloodManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "floodColor": mViewManager.setFloodColor(view, new DynamicFromObject(value)); break; case "floodOpacity": mViewManager.setFloodOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeFloodManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFeFloodManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setFloodColor(T view, Dynamic value); void setFloodOpacity(T view, float value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeGaussianBlurManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeGaussianBlurManagerDelegate & RNSVGFeGaussianBlurManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeGaussianBlurManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "in1": mViewManager.setIn1(view, value == null ? null : (String) value); break; case "stdDeviationX": mViewManager.setStdDeviationX(view, value == null ? 0f : ((Double) value).floatValue()); break; case "stdDeviationY": mViewManager.setStdDeviationY(view, value == null ? 0f : ((Double) value).floatValue()); break; case "edgeMode": mViewManager.setEdgeMode(view, (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeGaussianBlurManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFeGaussianBlurManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setIn1(T view, @Nullable String value); void setStdDeviationX(T view, float value); void setStdDeviationY(T view, float value); void setEdgeMode(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeMergeManagerDelegate & RNSVGFeMergeManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeMergeManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "nodes": mViewManager.setNodes(view, (ReadableArray) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGFeMergeManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setNodes(T view, @Nullable ReadableArray value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeOffsetManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFeOffsetManagerDelegate & RNSVGFeOffsetManagerInterface> extends BaseViewManagerDelegate { public RNSVGFeOffsetManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "result": mViewManager.setResult(view, value == null ? null : (String) value); break; case "in1": mViewManager.setIn1(view, value == null ? null : (String) value); break; case "dx": mViewManager.setDx(view, new DynamicFromObject(value)); break; case "dy": mViewManager.setDy(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeOffsetManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFeOffsetManagerInterface { void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setResult(T view, @Nullable String value); void setIn1(T view, @Nullable String value); void setDx(T view, Dynamic value); void setDy(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFilterManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGFilterManagerDelegate & RNSVGFilterManagerInterface> extends BaseViewManagerDelegate { public RNSVGFilterManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "filterUnits": mViewManager.setFilterUnits(view, (String) value); break; case "primitiveUnits": mViewManager.setPrimitiveUnits(view, (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFilterManagerInterface.java ================================================ /** * 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.Dynamic; public interface RNSVGFilterManagerInterface { void setName(T view, @Nullable String value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); void setFilterUnits(T view, @Nullable String value); void setPrimitiveUnits(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGForeignObjectManagerDelegate & RNSVGForeignObjectManagerInterface> extends BaseViewManagerDelegate { public RNSVGForeignObjectManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGForeignObjectManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGForeignObjectManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGGroupManagerDelegate & RNSVGGroupManagerInterface> extends BaseViewManagerDelegate { public RNSVGGroupManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGGroupManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGGroupManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGImageManagerDelegate & RNSVGImageManagerInterface> extends BaseViewManagerDelegate { public RNSVGImageManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "src": mViewManager.setSrc(view, (ReadableMap) value); break; case "align": mViewManager.setAlign(view, value == null ? null : (String) value); break; case "meetOrSlice": mViewManager.setMeetOrSlice(view, value == null ? 0 : ((Double) value).intValue()); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGImageManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; public interface RNSVGImageManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setWidth(T view, Dynamic value); void setHeight(T view, Dynamic value); void setSrc(T view, @Nullable ReadableMap value); void setAlign(T view, @Nullable String value); void setMeetOrSlice(T view, int value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGLineManagerDelegate & RNSVGLineManagerInterface> extends BaseViewManagerDelegate { public RNSVGLineManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "x1": mViewManager.setX1(view, new DynamicFromObject(value)); break; case "y1": mViewManager.setY1(view, new DynamicFromObject(value)); break; case "x2": mViewManager.setX2(view, new DynamicFromObject(value)); break; case "y2": mViewManager.setY2(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLineManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGLineManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setX1(T view, Dynamic value); void setY1(T view, Dynamic value); void setX2(T view, Dynamic value); void setY2(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGLinearGradientManagerDelegate & RNSVGLinearGradientManagerInterface> extends BaseViewManagerDelegate { public RNSVGLinearGradientManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "x1": mViewManager.setX1(view, new DynamicFromObject(value)); break; case "y1": mViewManager.setY1(view, new DynamicFromObject(value)); break; case "x2": mViewManager.setX2(view, new DynamicFromObject(value)); break; case "y2": mViewManager.setY2(view, new DynamicFromObject(value)); break; case "gradient": mViewManager.setGradient(view, (ReadableArray) value); break; case "gradientUnits": mViewManager.setGradientUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "gradientTransform": mViewManager.setGradientTransform(view, (ReadableArray) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGLinearGradientManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGLinearGradientManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setX1(T view, Dynamic value); void setY1(T view, Dynamic value); void setX2(T view, Dynamic value); void setY2(T view, Dynamic value); void setGradient(T view, @Nullable ReadableArray value); void setGradientUnits(T view, int value); void setGradientTransform(T view, @Nullable ReadableArray value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGMarkerManagerDelegate & RNSVGMarkerManagerInterface> extends BaseViewManagerDelegate { public RNSVGMarkerManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "refX": mViewManager.setRefX(view, new DynamicFromObject(value)); break; case "refY": mViewManager.setRefY(view, new DynamicFromObject(value)); break; case "markerHeight": mViewManager.setMarkerHeight(view, new DynamicFromObject(value)); break; case "markerWidth": mViewManager.setMarkerWidth(view, new DynamicFromObject(value)); break; case "markerUnits": mViewManager.setMarkerUnits(view, value == null ? null : (String) value); break; case "orient": mViewManager.setOrient(view, value == null ? null : (String) value); break; case "minX": mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); break; case "minY": mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbWidth": mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbHeight": mViewManager.setVbHeight(view, value == null ? 0f : ((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; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMarkerManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGMarkerManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setRefX(T view, Dynamic value); void setRefY(T view, Dynamic value); void setMarkerHeight(T view, Dynamic value); void setMarkerWidth(T view, Dynamic value); void setMarkerUnits(T view, @Nullable String value); void setOrient(T view, @Nullable String 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); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGMaskManagerDelegate & RNSVGMaskManagerInterface> extends BaseViewManagerDelegate { public RNSVGMaskManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "maskUnits": mViewManager.setMaskUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "maskContentUnits": mViewManager.setMaskContentUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "maskType": mViewManager.setMaskType(view, value == null ? 0 : ((Double) value).intValue()); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGMaskManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGMaskManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); void setMaskUnits(T view, int value); void setMaskContentUnits(T view, int value); void setMaskType(T view, int value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGPathManagerDelegate & RNSVGPathManagerInterface> extends BaseViewManagerDelegate { public RNSVGPathManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "d": mViewManager.setD(view, value == null ? null : (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPathManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGPathManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setD(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGPatternManagerDelegate & RNSVGPatternManagerInterface> extends BaseViewManagerDelegate { public RNSVGPatternManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "patternUnits": mViewManager.setPatternUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "patternContentUnits": mViewManager.setPatternContentUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "patternTransform": mViewManager.setPatternTransform(view, (ReadableArray) value); break; case "minX": mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); break; case "minY": mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbWidth": mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbHeight": mViewManager.setVbHeight(view, value == null ? 0f : ((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; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGPatternManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGPatternManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); void setPatternUnits(T view, int value); void setPatternContentUnits(T view, int value); void setPatternTransform(T view, @Nullable ReadableArray 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); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGRadialGradientManagerDelegate & RNSVGRadialGradientManagerInterface> extends BaseViewManagerDelegate { public RNSVGRadialGradientManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "fx": mViewManager.setFx(view, new DynamicFromObject(value)); break; case "fy": mViewManager.setFy(view, new DynamicFromObject(value)); break; case "cx": mViewManager.setCx(view, new DynamicFromObject(value)); break; case "cy": mViewManager.setCy(view, new DynamicFromObject(value)); break; case "rx": mViewManager.setRx(view, new DynamicFromObject(value)); break; case "ry": mViewManager.setRy(view, new DynamicFromObject(value)); break; case "gradient": mViewManager.setGradient(view, (ReadableArray) value); break; case "gradientUnits": mViewManager.setGradientUnits(view, value == null ? 0 : ((Double) value).intValue()); break; case "gradientTransform": mViewManager.setGradientTransform(view, (ReadableArray) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRadialGradientManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGRadialGradientManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setFx(T view, Dynamic value); void setFy(T view, Dynamic value); void setCx(T view, Dynamic value); void setCy(T view, Dynamic value); void setRx(T view, Dynamic value); void setRy(T view, Dynamic value); void setGradient(T view, @Nullable ReadableArray value); void setGradientUnits(T view, int value); void setGradientTransform(T view, @Nullable ReadableArray value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGRectManagerDelegate & RNSVGRectManagerInterface> extends BaseViewManagerDelegate { public RNSVGRectManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; case "rx": mViewManager.setRx(view, new DynamicFromObject(value)); break; case "ry": mViewManager.setRy(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGRectManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGRectManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); void setRx(T view, Dynamic value); void setRy(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGSvgViewAndroidManagerDelegate & RNSVGSvgViewAndroidManagerInterface> extends BaseViewManagerDelegate { public RNSVGSvgViewAndroidManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "bbWidth": mViewManager.setBbWidth(view, new DynamicFromObject(value)); break; case "bbHeight": mViewManager.setBbHeight(view, new DynamicFromObject(value)); break; case "minX": mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); break; case "minY": mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbWidth": mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbHeight": mViewManager.setVbHeight(view, value == null ? 0f : ((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 "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 "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 "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 "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, new DynamicFromObject(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 "borderBlockColor": mViewManager.setBorderBlockColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "borderBlockEndColor": mViewManager.setBorderBlockEndColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "borderBlockStartColor": mViewManager.setBorderBlockStartColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "borderRadius": mViewManager.setBorderRadius(view, new DynamicFromObject(value)); break; case "borderTopLeftRadius": mViewManager.setBorderTopLeftRadius(view, new DynamicFromObject(value)); break; case "borderTopRightRadius": mViewManager.setBorderTopRightRadius(view, new DynamicFromObject(value)); break; case "borderBottomRightRadius": mViewManager.setBorderBottomRightRadius(view, new DynamicFromObject(value)); break; case "borderBottomLeftRadius": mViewManager.setBorderBottomLeftRadius(view, new DynamicFromObject(value)); break; case "borderTopStartRadius": mViewManager.setBorderTopStartRadius(view, new DynamicFromObject(value)); break; case "borderTopEndRadius": mViewManager.setBorderTopEndRadius(view, new DynamicFromObject(value)); break; case "borderBottomStartRadius": mViewManager.setBorderBottomStartRadius(view, new DynamicFromObject(value)); break; case "borderBottomEndRadius": mViewManager.setBorderBottomEndRadius(view, new DynamicFromObject(value)); break; case "borderEndEndRadius": mViewManager.setBorderEndEndRadius(view, new DynamicFromObject(value)); break; case "borderEndStartRadius": mViewManager.setBorderEndStartRadius(view, new DynamicFromObject(value)); break; case "borderStartEndRadius": mViewManager.setBorderStartEndRadius(view, new DynamicFromObject(value)); break; case "borderStartStartRadius": mViewManager.setBorderStartStartRadius(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSvgViewAndroidManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableMap; public interface RNSVGSvgViewAndroidManagerInterface { void setBbWidth(T view, Dynamic value); void setBbHeight(T view, Dynamic 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 setColor(T view, @Nullable Integer value); void setPointerEvents(T view, @Nullable String value); void setHasTVPreferredFocus(T view, boolean 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 setBorderEndColor(T view, @Nullable Integer value); void setFocusable(T view, boolean value); void setNativeBackgroundAndroid(T view, @Nullable ReadableMap 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, Dynamic value); void setBorderTopColor(T view, @Nullable Integer value); void setNextFocusLeft(T view, int value); void setBorderBlockColor(T view, @Nullable Integer value); void setBorderBlockEndColor(T view, @Nullable Integer value); void setBorderBlockStartColor(T view, @Nullable Integer value); void setBorderRadius(T view, Dynamic value); void setBorderTopLeftRadius(T view, Dynamic value); void setBorderTopRightRadius(T view, Dynamic value); void setBorderBottomRightRadius(T view, Dynamic value); void setBorderBottomLeftRadius(T view, Dynamic value); void setBorderTopStartRadius(T view, Dynamic value); void setBorderTopEndRadius(T view, Dynamic value); void setBorderBottomStartRadius(T view, Dynamic value); void setBorderBottomEndRadius(T view, Dynamic value); void setBorderEndEndRadius(T view, Dynamic value); void setBorderEndStartRadius(T view, Dynamic value); void setBorderStartEndRadius(T view, Dynamic value); void setBorderStartStartRadius(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGSymbolManagerDelegate & RNSVGSymbolManagerInterface> extends BaseViewManagerDelegate { public RNSVGSymbolManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "minX": mViewManager.setMinX(view, value == null ? 0f : ((Double) value).floatValue()); break; case "minY": mViewManager.setMinY(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbWidth": mViewManager.setVbWidth(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vbHeight": mViewManager.setVbHeight(view, value == null ? 0f : ((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; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGSymbolManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGSymbolManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic 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); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGTSpanManagerDelegate & RNSVGTSpanManagerInterface> extends BaseViewManagerDelegate { public RNSVGTSpanManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "dx": mViewManager.setDx(view, new DynamicFromObject(value)); break; case "dy": mViewManager.setDy(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "rotate": mViewManager.setRotate(view, new DynamicFromObject(value)); break; case "inlineSize": mViewManager.setInlineSize(view, new DynamicFromObject(value)); break; case "textLength": mViewManager.setTextLength(view, new DynamicFromObject(value)); break; case "baselineShift": mViewManager.setBaselineShift(view, new DynamicFromObject(value)); break; case "lengthAdjust": mViewManager.setLengthAdjust(view, value == null ? null : (String) value); break; case "alignmentBaseline": mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); break; case "verticalAlign": mViewManager.setVerticalAlign(view, new DynamicFromObject(value)); break; case "content": mViewManager.setContent(view, value == null ? null : (String) value); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTSpanManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGTSpanManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setDx(T view, Dynamic value); void setDy(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setRotate(T view, Dynamic value); void setInlineSize(T view, Dynamic value); void setTextLength(T view, Dynamic value); void setBaselineShift(T view, Dynamic value); void setLengthAdjust(T view, @Nullable String value); void setAlignmentBaseline(T view, @Nullable String value); void setVerticalAlign(T view, Dynamic value); void setContent(T view, @Nullable String value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGTextManagerDelegate & RNSVGTextManagerInterface> extends BaseViewManagerDelegate { public RNSVGTextManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "dx": mViewManager.setDx(view, new DynamicFromObject(value)); break; case "dy": mViewManager.setDy(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "rotate": mViewManager.setRotate(view, new DynamicFromObject(value)); break; case "inlineSize": mViewManager.setInlineSize(view, new DynamicFromObject(value)); break; case "textLength": mViewManager.setTextLength(view, new DynamicFromObject(value)); break; case "baselineShift": mViewManager.setBaselineShift(view, new DynamicFromObject(value)); break; case "lengthAdjust": mViewManager.setLengthAdjust(view, value == null ? null : (String) value); break; case "alignmentBaseline": mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); break; case "verticalAlign": mViewManager.setVerticalAlign(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGTextManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setDx(T view, Dynamic value); void setDy(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setRotate(T view, Dynamic value); void setInlineSize(T view, Dynamic value); void setTextLength(T view, Dynamic value); void setBaselineShift(T view, Dynamic value); void setLengthAdjust(T view, @Nullable String value); void setAlignmentBaseline(T view, @Nullable String value); void setVerticalAlign(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGTextPathManagerDelegate & RNSVGTextPathManagerInterface> extends BaseViewManagerDelegate { public RNSVGTextPathManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "fontSize": mViewManager.setFontSize(view, new DynamicFromObject(value)); break; case "fontWeight": mViewManager.setFontWeight(view, new DynamicFromObject(value)); break; case "font": mViewManager.setFont(view, new DynamicFromObject(value)); break; case "dx": mViewManager.setDx(view, new DynamicFromObject(value)); break; case "dy": mViewManager.setDy(view, new DynamicFromObject(value)); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "rotate": mViewManager.setRotate(view, new DynamicFromObject(value)); break; case "inlineSize": mViewManager.setInlineSize(view, new DynamicFromObject(value)); break; case "textLength": mViewManager.setTextLength(view, new DynamicFromObject(value)); break; case "baselineShift": mViewManager.setBaselineShift(view, new DynamicFromObject(value)); break; case "lengthAdjust": mViewManager.setLengthAdjust(view, value == null ? null : (String) value); break; case "alignmentBaseline": mViewManager.setAlignmentBaseline(view, value == null ? null : (String) value); break; case "verticalAlign": mViewManager.setVerticalAlign(view, new DynamicFromObject(value)); break; case "href": mViewManager.setHref(view, value == null ? null : (String) value); break; case "side": mViewManager.setSide(view, value == null ? null : (String) value); break; case "method": mViewManager.setMethod(view, value == null ? null : (String) value); break; case "midLine": mViewManager.setMidLine(view, value == null ? null : (String) value); break; case "spacing": mViewManager.setSpacing(view, value == null ? null : (String) value); break; case "startOffset": mViewManager.setStartOffset(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGTextPathManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGTextPathManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setFontSize(T view, Dynamic value); void setFontWeight(T view, Dynamic value); void setFont(T view, Dynamic value); void setDx(T view, Dynamic value); void setDy(T view, Dynamic value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setRotate(T view, Dynamic value); void setInlineSize(T view, Dynamic value); void setTextLength(T view, Dynamic value); void setBaselineShift(T view, Dynamic value); void setLengthAdjust(T view, @Nullable String value); void setAlignmentBaseline(T view, @Nullable String value); void setVerticalAlign(T view, Dynamic value); void setHref(T view, @Nullable String value); void setSide(T view, @Nullable String value); void setMethod(T view, @Nullable String value); void setMidLine(T view, @Nullable String value); void setSpacing(T view, @Nullable String value); void setStartOffset(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerDelegate.java ================================================ /** * 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.DynamicFromObject; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; public class RNSVGUseManagerDelegate & RNSVGUseManagerInterface> extends BaseViewManagerDelegate { public RNSVGUseManagerDelegate(U viewManager) { super(viewManager); } @Override public void setProperty(T view, String propName, @Nullable Object value) { switch (propName) { case "name": mViewManager.setName(view, value == null ? null : (String) value); break; case "opacity": mViewManager.setOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "matrix": mViewManager.setMatrix(view, (ReadableArray) value); break; case "mask": mViewManager.setMask(view, value == null ? null : (String) value); break; case "markerStart": mViewManager.setMarkerStart(view, value == null ? null : (String) value); break; case "markerMid": mViewManager.setMarkerMid(view, value == null ? null : (String) value); break; case "markerEnd": mViewManager.setMarkerEnd(view, value == null ? null : (String) value); break; case "clipPath": mViewManager.setClipPath(view, value == null ? null : (String) value); break; case "clipRule": mViewManager.setClipRule(view, value == null ? 0 : ((Double) value).intValue()); break; case "responsible": mViewManager.setResponsible(view, value == null ? false : (boolean) value); break; case "display": mViewManager.setDisplay(view, value == null ? null : (String) value); break; case "pointerEvents": mViewManager.setPointerEvents(view, value == null ? null : (String) value); break; case "color": mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); break; case "fill": mViewManager.setFill(view, new DynamicFromObject(value)); break; case "fillOpacity": mViewManager.setFillOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "fillRule": mViewManager.setFillRule(view, value == null ? 1 : ((Double) value).intValue()); break; case "stroke": mViewManager.setStroke(view, new DynamicFromObject(value)); break; case "strokeOpacity": mViewManager.setStrokeOpacity(view, value == null ? 1f : ((Double) value).floatValue()); break; case "strokeWidth": mViewManager.setStrokeWidth(view, new DynamicFromObject(value)); break; case "strokeLinecap": mViewManager.setStrokeLinecap(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeLinejoin": mViewManager.setStrokeLinejoin(view, value == null ? 0 : ((Double) value).intValue()); break; case "strokeDasharray": mViewManager.setStrokeDasharray(view, new DynamicFromObject(value)); break; case "strokeDashoffset": mViewManager.setStrokeDashoffset(view, value == null ? 0f : ((Double) value).floatValue()); break; case "strokeMiterlimit": mViewManager.setStrokeMiterlimit(view, value == null ? 0f : ((Double) value).floatValue()); break; case "vectorEffect": mViewManager.setVectorEffect(view, value == null ? 0 : ((Double) value).intValue()); break; case "propList": mViewManager.setPropList(view, (ReadableArray) value); break; case "filter": mViewManager.setFilter(view, value == null ? null : (String) value); break; case "href": mViewManager.setHref(view, value == null ? null : (String) value); break; case "x": mViewManager.setX(view, new DynamicFromObject(value)); break; case "y": mViewManager.setY(view, new DynamicFromObject(value)); break; case "height": mViewManager.setHeight(view, new DynamicFromObject(value)); break; case "width": mViewManager.setWidth(view, new DynamicFromObject(value)); break; default: super.setProperty(view, propName, value); } } } ================================================ FILE: android/src/paper/java/com/facebook/react/viewmanagers/RNSVGUseManagerInterface.java ================================================ /** * 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.Dynamic; import com.facebook.react.bridge.ReadableArray; public interface RNSVGUseManagerInterface { void setName(T view, @Nullable String value); void setOpacity(T view, float value); void setMatrix(T view, @Nullable ReadableArray value); void setMask(T view, @Nullable String value); void setMarkerStart(T view, @Nullable String value); void setMarkerMid(T view, @Nullable String value); void setMarkerEnd(T view, @Nullable String value); void setClipPath(T view, @Nullable String value); void setClipRule(T view, int value); void setResponsible(T view, boolean value); void setDisplay(T view, @Nullable String value); void setPointerEvents(T view, @Nullable String value); void setColor(T view, @Nullable Integer value); void setFill(T view, Dynamic value); void setFillOpacity(T view, float value); void setFillRule(T view, int value); void setStroke(T view, Dynamic value); void setStrokeOpacity(T view, float value); void setStrokeWidth(T view, Dynamic value); void setStrokeLinecap(T view, int value); void setStrokeLinejoin(T view, int value); void setStrokeDasharray(T view, Dynamic value); void setStrokeDashoffset(T view, float value); void setStrokeMiterlimit(T view, float value); void setVectorEffect(T view, int value); void setPropList(T view, @Nullable ReadableArray value); void setFilter(T view, @Nullable String value); void setHref(T view, @Nullable String value); void setX(T view, Dynamic value); void setY(T view, Dynamic value); void setHeight(T view, Dynamic value); void setWidth(T view, Dynamic value); } ================================================ FILE: android/src/paper/java/com/horcrux/svg/NativeSvgRenderableModuleSpec.java ================================================ /** * 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: GenerateModuleJavaSpec.js * * @nolint */ package com.horcrux.svg; 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.ReactModuleWithSpec; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.turbomodule.core.interfaces.TurboModule; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class NativeSvgRenderableModuleSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule { public static final String NAME = "RNSVGRenderableModule"; public NativeSvgRenderableModuleSpec(ReactApplicationContext reactContext) { super(reactContext); } @Override public @Nonnull String getName() { return NAME; } @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract boolean isPointInFill(@Nullable Double tag, @Nullable ReadableMap options); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract boolean isPointInStroke(@Nullable Double tag, @Nullable ReadableMap options); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract double getTotalLength(@Nullable Double tag); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract WritableMap getPointAtLength(@Nullable Double tag, @Nullable ReadableMap options); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract WritableMap getBBox(@Nullable Double tag, @Nullable ReadableMap options); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract WritableMap getCTM(@Nullable Double tag); @ReactMethod(isBlockingSynchronousMethod = true) @DoNotStrip public abstract WritableMap getScreenCTM(@Nullable Double tag); @ReactMethod @DoNotStrip public abstract void getRawResource(String name, Promise promise); } ================================================ FILE: android/src/paper/java/com/horcrux/svg/NativeSvgViewModuleSpec.java ================================================ /** * 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: GenerateModuleJavaSpec.js * * @nolint */ package com.horcrux.svg; 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.ReactModuleWithSpec; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.turbomodule.core.interfaces.TurboModule; import javax.annotation.Nonnull; import javax.annotation.Nullable; public abstract class NativeSvgViewModuleSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule { public static final String NAME = "RNSVGSvgViewModule"; public NativeSvgViewModuleSpec(ReactApplicationContext reactContext) { super(reactContext); } @Override public @Nonnull String getName() { return NAME; } @ReactMethod @DoNotStrip public abstract void toDataURL(@Nullable Double tag, @Nullable ReadableMap options, @Nullable Callback callback); } ================================================ FILE: apple/.npmignore ================================================ */project.xcworkspace/ */xcuserdata/ .DS_Store .npmignore Pods/ build/ ================================================ FILE: apple/Brushes/RNSVGBrush.h ================================================ /** * 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 #import #import "RNSVGPainter.h" @interface RNSVGBrush : NSObject @property (nonatomic, strong) NSString *brushRef; /* @abstract */ - (instancetype)initWithArray:(NSArray *)data; /** * @abstract * For certain brushes we can fast path a combined fill and stroke. * For those brushes we override applyFillColor which sets the fill * color to be used by those batch paints. Those return YES. * We can't batch gradient painting in CoreGraphics, so those will * return NO and paint gets called instead. */ - (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity; - (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity; - (CGColorRef)getColorWithOpacity:(CGFloat)opacity; /** * @abstract * paint fills the context with a brush. The context is assumed to * be clipped. */ - (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds; @end ================================================ FILE: apple/Brushes/RNSVGBrush.mm ================================================ /** * 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 "RNSVGBrush.h" #import @implementation RNSVGBrush - (instancetype)initWithArray:(NSArray *)data { return [super init]; } - (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds { } - (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity { return NO; } - (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity { return NO; } - (CGColorRef)getColorWithOpacity:(CGFloat)opacity { return nil; } - (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter { // abstract } @end ================================================ FILE: apple/Brushes/RNSVGBrushType.h ================================================ /** * 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. */ typedef enum { kRNSVGUndefinedType, kRNSVGLinearGradient, kRNSVGRadialGradient, kRNSVGPattern } RNSVGBrushType; ================================================ FILE: apple/Brushes/RNSVGContextBrush.h ================================================ /** * Copyright (c) 2015-present, react-native-community. * 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 "RNSVGBrush.h" @interface RNSVGContextBrush : RNSVGBrush - (instancetype)initFill; - (instancetype)initStroke; @end ================================================ FILE: apple/Brushes/RNSVGContextBrush.mm ================================================ /** * Copyright (c) 2015-present, react-native-community. * 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 "RNSVGContextBrush.h" #import "RNSVGNode.h" #import "RNSVGRenderable.h" #import #import "RCTConvert+RNSVG.h" @implementation RNSVGContextBrush { BOOL _isStroke; } - (instancetype)initFill { if ((self = [super initWithArray:nil])) { _isStroke = NO; } return self; } - (instancetype)initStroke { if ((self = [super initWithArray:nil])) { _isStroke = YES; } return self; } - (void)dealloc { } - (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity { RNSVGRenderable *element = RNSVGRenderable.contextElement; if (!element) { return NO; } RNSVGBrush *brush = _isStroke ? element.stroke : element.fill; BOOL fillColor; if (brush.class == RNSVGBrush.class) { CGContextSetFillColorWithColor(context, [element getCurrentColor]); fillColor = YES; } else { fillColor = [brush applyFillColor:context opacity:opacity]; } return fillColor; } - (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity { RNSVGRenderable *element = RNSVGRenderable.contextElement; if (!element) { return NO; } RNSVGBrush *brush = _isStroke ? element.stroke : element.fill; BOOL strokeColor; if (brush.class == RNSVGBrush.class) { CGContextSetStrokeColorWithColor(context, [element getCurrentColor]); strokeColor = YES; } else { strokeColor = [brush applyStrokeColor:context opacity:opacity]; } return YES; } @end ================================================ FILE: apple/Brushes/RNSVGPainter.h ================================================ /** * 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 "RCTConvert+RNSVG.h" #import "RNSVGBrushType.h" #import "RNSVGLength.h" #import "RNSVGUnits.h" @class RNSVGPattern; @interface RNSVGPainter : NSObject @property (nonatomic, assign) RNSVGPattern *pattern; @property (nonatomic, assign) CGRect paintBounds; @property (nonatomic, assign) bool useObjectBoundingBoxForContentUnits; @property (nonatomic, assign) CGRect bounds; - (instancetype)initWithPointsArray:(NSArray *)pointsArray NS_DESIGNATED_INITIALIZER; - (void)paint:(CGContextRef)context bounds:(CGRect)bounds; - (void)setUnits:(RNSVGUnits)unit; - (void)setContentUnits:(RNSVGUnits)unit; - (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox; - (void)setTransform:(CGAffineTransform)transform; - (void)setLinearGradientColors:(NSArray *)colors; - (void)setRadialGradientColors:(NSArray *)colors; @end ================================================ FILE: apple/Brushes/RNSVGPainter.mm ================================================ /** * 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 "RNSVGPainter.h" #import "RNSVGPattern.h" #import "RNSVGViewBox.h" @implementation RNSVGPainter { NSArray *_points; NSArray *_colors; RNSVGBrushType _type; BOOL _useObjectBoundingBox; BOOL _useContentObjectBoundingBox; CGAffineTransform _transform; CGRect _userSpaceBoundingBox; } - (instancetype)initWithPointsArray:(NSArray *)pointsArray { if ((self = [super init])) { _points = pointsArray; } return self; } RCT_NOT_IMPLEMENTED(-(instancetype)init) - (void)setUnits:(RNSVGUnits)unit { _useObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox; } - (void)setContentUnits:(RNSVGUnits)unit { _useContentObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox; } - (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox { _userSpaceBoundingBox = userSpaceBoundingBox; } - (void)setTransform:(CGAffineTransform)transform { _transform = transform; } - (void)setPattern:(RNSVGPattern *)pattern { if (_type != kRNSVGUndefinedType) { // todo: throw error return; } _type = kRNSVGPattern; _pattern = pattern; } - (void)setLinearGradientColors:(NSArray *)colors { if (_type != kRNSVGUndefinedType) { // todo: throw error return; } _type = kRNSVGLinearGradient; _colors = colors; } - (void)setRadialGradientColors:(NSArray *)colors { if (_type != kRNSVGUndefinedType) { // todo: throw error return; } _type = kRNSVGRadialGradient; _colors = colors; } - (void)paint:(CGContextRef)context bounds:(CGRect)bounds { if (_type == kRNSVGLinearGradient) { [self paintLinearGradient:context bounds:bounds]; } else if (_type == kRNSVGRadialGradient) { [self paintRadialGradient:context bounds:bounds]; } else if (_type == kRNSVGPattern) { [self paintPattern:context bounds:bounds]; } } - (CGRect)getPaintRect:(CGContextRef)context bounds:(CGRect)bounds { CGRect rect = _useObjectBoundingBox ? bounds : _userSpaceBoundingBox; CGFloat height = CGRectGetHeight(rect); CGFloat width = CGRectGetWidth(rect); CGFloat x = 0.0; CGFloat y = 0.0; if (_useObjectBoundingBox) { x = CGRectGetMinX(rect); y = CGRectGetMinY(rect); } return CGRectMake(x, y, width, height); } void PatternFunction(void *info, CGContextRef context) { RNSVGPainter *_painter = (__bridge RNSVGPainter *)info; RNSVGPattern *_pattern = [_painter pattern]; CGRect rect = _painter.paintBounds; CGFloat minX = _pattern.minX; CGFloat minY = _pattern.minY; CGFloat vbWidth = _pattern.vbWidth; CGFloat vbHeight = _pattern.vbHeight; if (vbWidth > 0 && vbHeight > 0) { CGRect vbRect = CGRectMake(minX, minY, vbWidth, vbHeight); CGAffineTransform _viewBoxTransform = [RNSVGViewBox getTransform:vbRect eRect:rect align:_pattern.align meetOrSlice:_pattern.meetOrSlice]; CGContextConcatCTM(context, _viewBoxTransform); } if (_painter.useObjectBoundingBoxForContentUnits) { CGRect bounds = _painter.bounds; CGContextConcatCTM(context, CGAffineTransformMakeScale(bounds.size.width, bounds.size.height)); } [_pattern renderTo:context rect:rect]; } - (CGFloat)getVal:(RNSVGLength *)length relative:(CGFloat)relative { RNSVGLengthUnitType unit = [length unit]; CGFloat val = [RNSVGPropHelper fromRelative:length relative:relative]; return _useObjectBoundingBox && unit == SVG_LENGTHTYPE_NUMBER ? val * relative : val; } - (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds { CGRect rect = [self getPaintRect:context bounds:bounds]; CGFloat height = CGRectGetHeight(rect); CGFloat width = CGRectGetWidth(rect); CGFloat x = [self getVal:[_points objectAtIndex:0] relative:width]; CGFloat y = [self getVal:[_points objectAtIndex:1] relative:height]; CGFloat w = [self getVal:[_points objectAtIndex:2] relative:width]; CGFloat h = [self getVal:[_points objectAtIndex:3] relative:height]; CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform]; #if TARGET_OS_OSX // This is needed because macOS and iOS have different conventions for where the origin is. // For macOS, it's in the bottom-left corner. For iOS, it's in the top-left corner. viewbox = CGAffineTransformScale(viewbox, 1, -1); #endif // TARGET_OS_OSX CGRect newBounds = CGRectMake(x, y, w, h); CGSize size = newBounds.size; self.useObjectBoundingBoxForContentUnits = _useContentObjectBoundingBox; self.paintBounds = newBounds; self.bounds = rect; const CGPatternCallbacks callbacks = {0, &PatternFunction, NULL}; CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); CGContextSetFillColorSpace(context, patternSpace); CGColorSpaceRelease(patternSpace); CGPatternRef pattern = CGPatternCreate( #if TARGET_OS_OSX (__bridge_retained void *_Nullable)(self), #else (__bridge void *_Nullable)(self), #endif newBounds, viewbox, size.width, size.height, kCGPatternTilingConstantSpacing, true, &callbacks); CGFloat alpha = 1.0; CGContextSetFillPattern(context, pattern, &alpha); CGPatternRelease(pattern); CGContextFillRect(context, bounds); } - (void)paintLinearGradient:(CGContextRef)context bounds:(CGRect)bounds { if ([_colors count] == 0) { RCTLogWarn(@"No stops in gradient"); return; } CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]); CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; CGRect rect = [self getPaintRect:context bounds:bounds]; CGFloat height = CGRectGetHeight(rect); CGFloat width = CGRectGetWidth(rect); CGFloat offsetX = CGRectGetMinX(rect); CGFloat offsetY = CGRectGetMinY(rect); CGFloat x1 = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX; CGFloat y1 = [self getVal:[_points objectAtIndex:1] relative:height] + offsetY; CGFloat x2 = [self getVal:[_points objectAtIndex:2] relative:width] + offsetX; CGFloat y2 = [self getVal:[_points objectAtIndex:3] relative:height] + offsetY; CGContextConcatCTM(context, _transform); CGContextDrawLinearGradient(context, gradient, CGPointMake(x1, y1), CGPointMake(x2, y2), extendOptions); CGGradientRelease(gradient); } - (void)paintRadialGradient:(CGContextRef)context bounds:(CGRect)bounds { if ([_colors count] == 0) { RCTLogWarn(@"No stops in gradient"); return; } CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]); CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; CGRect rect = [self getPaintRect:context bounds:bounds]; CGFloat width = CGRectGetWidth(rect); CGFloat height = CGRectGetHeight(rect); CGFloat offsetX = CGRectGetMinX(rect); CGFloat offsetY = CGRectGetMinY(rect); CGFloat rx = [self getVal:[_points objectAtIndex:2] relative:width]; CGFloat ry = [self getVal:[_points objectAtIndex:3] relative:height]; if (rx <= 0 || ry <= 0) { // Gradient with radius = 0 should be rendered as solid color of the last stop rx = width; ry = height; CGGradientRelease(gradient); NSArray *gradientArray = @[ _colors.firstObject, _colors.lastObject, _colors[_colors.count - 2], _colors.lastObject ]; gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:gradientArray]); } double ratio = ry / rx; CGFloat fx = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX; CGFloat fy = ([self getVal:[_points objectAtIndex:1] relative:height] + offsetY) / ratio; CGFloat cx = [self getVal:[_points objectAtIndex:4] relative:width] + offsetX; CGFloat cy = ([self getVal:[_points objectAtIndex:5] relative:height] + offsetY) / ratio; CGAffineTransform transform = CGAffineTransformMakeScale(1, ratio); CGContextConcatCTM(context, transform); CGContextConcatCTM(context, _transform); CGContextDrawRadialGradient(context, gradient, CGPointMake(fx, fy), 0, CGPointMake(cx, cy), rx, extendOptions); CGGradientRelease(gradient); } @end ================================================ FILE: apple/Brushes/RNSVGPainterBrush.h ================================================ /** * 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 "RNSVGBrush.h" @interface RNSVGPainterBrush : RNSVGBrush @end ================================================ FILE: apple/Brushes/RNSVGPainterBrush.mm ================================================ /** * 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 "RNSVGPainterBrush.h" #import #import "RCTConvert+RNSVG.h" #import "RNSVGPainter.h" @implementation RNSVGPainterBrush - (instancetype)initWithArray:(NSArray *)array { if ((self = [super initWithArray:array])) { if (array.count != 2) { RCTLogError(@"-[%@ %@] expects 2 elements, received %@", self.class, NSStringFromSelector(_cmd), array); return nil; } self.brushRef = [array objectAtIndex:1]; } return self; } - (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds { BOOL transparency = opacity < 1; if (transparency) { CGContextSetAlpha(context, opacity); CGContextBeginTransparencyLayer(context, NULL); } [painter paint:context bounds:bounds]; if (transparency) { CGContextEndTransparencyLayer(context); } } @end ================================================ FILE: apple/Brushes/RNSVGSolidColorBrush.h ================================================ /** * 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 "RNSVGBrush.h" @interface RNSVGSolidColorBrush : RNSVGBrush - (instancetype)initWithNumber:(NSNumber *)number; - (instancetype)initWithColor:(RNSVGColor *)color; @end ================================================ FILE: apple/Brushes/RNSVGSolidColorBrush.mm ================================================ /** * 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 "RNSVGSolidColorBrush.h" #import "RNSVGUIKit.h" #import #import "RCTConvert+RNSVG.h" @implementation RNSVGSolidColorBrush { RNSVGColor *_color; } - (instancetype)initWithArray:(NSArray *)array { if ((self = [super initWithArray:array])) { _color = [RCTConvert RNSVGColor:array offset:1]; } return self; } - (instancetype)initWithNumber:(NSNumber *)number { if ((self = [super init])) { _color = [RCTConvert RNSVGColor:number]; } return self; } - (instancetype)initWithColor:(RNSVGColor *)color { if ((self = [super init])) { _color = color; } return self; } - (void)dealloc { _color = nil; } - (CGColorRef)getColorWithOpacity:(CGFloat)opacity { CGColorRef baseColor = _color.CGColor; CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor)); return color; } - (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity { CGColorRef color = [self getColorWithOpacity:opacity]; CGContextSetFillColorWithColor(context, color); CGColorRelease(color); return YES; } - (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity { CGColorRef color = [self getColorWithOpacity:opacity]; CGContextSetStrokeColorWithColor(context, color); CGColorRelease(color); return YES; } @end ================================================ FILE: apple/Elements/RNSVGClipPath.h ================================================ /** * 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 #import "RNSVGContainer.h" #import "RNSVGGroup.h" #import "RNSVGSvgView.h" @interface RNSVGClipPath : RNSVGGroup - (BOOL)isSimpleClipPath; @end ================================================ FILE: apple/Elements/RNSVGClipPath.mm ================================================ /** * 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 "RNSVGClipPath.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGClipPath #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); setCommonNodeProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; } #endif // RCT_NEW_ARCH_ENABLED - (void)parseReference { self.dirty = false; [self.svgView defineClipPath:self clipPathName:self.name]; } - (BOOL)isSimpleClipPath { NSArray *children = self.subviews; if (children.count == 1) { RNSVGPlatformView *child = children[0]; if ([child class] != [RNSVGGroup class]) { return true; } } return false; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGClipPathCls(void) { return RNSVGClipPath.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGDefs.h ================================================ /** * 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 "RNSVGNode.h" /** * RNSVG defination are implemented as abstract views for all elements inside Defs. */ @interface RNSVGDefs : RNSVGNode @end ================================================ FILE: apple/Elements/RNSVGDefs.mm ================================================ /** * 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 "RNSVGDefs.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGDefs #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } #endif // RCT_NEW_ARCH_ENABLED - (void)renderTo:(CGContextRef)context { // Defs do not render } - (void)parseReference { self.dirty = false; [self traverseSubviews:^(RNSVGNode *node) { if ([node isKindOfClass:[RNSVGNode class]]) { [node parseReference]; } return YES; }]; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGDefsCls(void) { return RNSVGDefs.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGForeignObject.h ================================================ #import "RNSVGGroup.h" #import "RNSVGLength.h" @interface RNSVGForeignObject : RNSVGGroup @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *foreignObjectwidth; @property (nonatomic, strong) RNSVGLength *foreignObjectheight; @end ================================================ FILE: apple/Elements/RNSVGForeignObject.mm ================================================ /** * 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 "RNSVGForeignObject.h" #import "RNSVGClipPath.h" #import "RNSVGMask.h" #import "RNSVGNode.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGForeignObject #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id height = RNSVGConvertFollyDynamicToId(newProps.height); if (height != nil) { self.foreignObjectheight = [RCTConvert RNSVGLength:height]; } id width = RNSVGConvertFollyDynamicToId(newProps.width); if (width != nil) { self.foreignObjectwidth = [RCTConvert RNSVGLength:width]; } setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x = nil; _y = nil; _foreignObjectheight = nil; _foreignObjectwidth = nil; } - (void)layoutSubviews { [super layoutSubviews]; // We know layout is done, but the async text rendering is not. // We schedule the SVG redraw for the next runloop cycle. // This gives the text layout system time to finish its work. dispatch_async(dispatch_get_main_queue(), ^{ [self invalidate]; }); } #endif // RCT_NEW_ARCH_ENABLED - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { [self clip:context]; CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]); CGRect clip = CGRectMake( 0, 0, [self relativeOnWidth:self.foreignObjectwidth], [self relativeOnHeight:self.foreignObjectheight]); CGContextClipToRect(context, clip); [super renderLayerTo:context rect:rect]; } - (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect { [self pushGlyphContext]; __block CGRect bounds = CGRectNull; [self traverseSubviews:^(RNSVGView *node) { if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) { // no-op } else if ([node isKindOfClass:[RNSVGNode class]]) { RNSVGNode *svgNode = (RNSVGNode *)node; if (svgNode.display && [@"none" isEqualToString:svgNode.display]) { return YES; } if (svgNode.responsible && !self.svgView.responsible) { self.svgView.responsible = YES; } if ([node isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)node mergeProperties:self]; } [svgNode renderTo:context rect:rect]; CGRect nodeRect = svgNode.clientRect; if (!CGRectIsEmpty(nodeRect)) { bounds = CGRectUnion(bounds, nodeRect); } if ([node isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)node resetProperties]; } } else if ([node isKindOfClass:[RNSVGSvgView class]]) { RNSVGSvgView *svgView = (RNSVGSvgView *)node; CGFloat width = [self relativeOnWidth:svgView.bbWidth]; CGFloat height = [self relativeOnHeight:svgView.bbHeight]; CGRect svgViewRect = CGRectMake(0, 0, width, height); CGContextClipToRect(context, svgViewRect); [svgView drawToContext:context withRect:svgViewRect]; } else { CGContextSaveGState(context); CGRect bounds = node.layer.bounds; CGPoint position = node.layer.position; CATransform3D transform = node.layer.transform; CGContextTranslateCTM(context, position.x, position.y); if (!CATransform3DIsIdentity(transform)) { CGAffineTransform affine = CATransform3DGetAffineTransform(transform); CGContextConcatCTM(context, affine); } // This moves the origin from that center point to the object's top-left corner, // which is where drawing operations will begin. CGContextTranslateCTM(context, -bounds.size.width / 2, -bounds.size.height / 2); node.hidden = NO; [node.layer renderInContext:context]; node.hidden = YES; CGContextRestoreGState(context); } return YES; }]; CGPathRef path = [self getPath:context]; [self setHitArea:path]; if (!CGRectEqualToRect(bounds, CGRectNull)) { self.clientRect = bounds; self.fillBounds = CGPathGetPathBoundingBox(path); self.strokeBounds = CGPathGetPathBoundingBox(self.strokePath); self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds); CGAffineTransform current = CGContextGetCTM(context); CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM); self.ctm = svgToClientTransform; self.screenCTM = current; CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); CGPoint center = CGPointApplyAffineTransform(mid, self.matrix); self.bounds = bounds; if (!isnan(center.x) && !isnan(center.y)) { self.center = center; } self.frame = bounds; } [self popGlyphContext]; } #ifdef RCT_NEW_ARCH_ENABLED - (void) willRemoveSubview:(RNSVGPlatformView *) subview { if ([subview isKindOfClass:[RCTViewComponentView class]]) { subview.hidden = NO; } } #endif - (void)drawRect:(CGRect)rect { [self invalidate]; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } _x = x; [self invalidate]; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } _y = y; [self invalidate]; } - (void)setForeignObjectwidth:(RNSVGLength *)foreignObjectwidth { if ([foreignObjectwidth isEqualTo:_foreignObjectwidth]) { return; } _foreignObjectwidth = foreignObjectwidth; [self invalidate]; } - (void)setForeignObjectheight:(RNSVGLength *)foreignObjectheight { if ([foreignObjectheight isEqualTo:_foreignObjectheight]) { return; } _foreignObjectheight = foreignObjectheight; [self invalidate]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGForeignObjectCls(void) { return RNSVGForeignObject.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGGroup.h ================================================ /** * 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 #import "RNSVGUIKit.h" #import "RNSVGCGFCRule.h" #import "RNSVGContainer.h" #import "RNSVGGlyphContext.h" #import "RNSVGPath.h" #import "RNSVGSvgView.h" @interface RNSVGGroup : RNSVGPath @property (nonatomic, strong) NSDictionary *font; - (void)renderPathTo:(CGContextRef)context rect:(CGRect)rect; - (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect; - (RNSVGGlyphContext *)getGlyphContext; - (void)pushGlyphContext; - (void)popGlyphContext; @end ================================================ FILE: apple/Elements/RNSVGGroup.mm ================================================ /** * 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 "RNSVGGroup.h" #import "RNSVGClipPath.h" #import "RNSVGMask.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGGroup { RNSVGGlyphContext *_glyphContext; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _font = nil; _glyphContext = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setFont:(NSDictionary *)font { if (font == _font) { return; } [self invalidate]; _font = font; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { [self clip:context]; [self setupGlyphContext:context]; [self renderGroupTo:context rect:rect]; } - (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect { [self pushGlyphContext]; __block CGRect bounds = CGRectNull; [self traverseSubviews:^(RNSVGView *node) { if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) { [(RNSVGRenderable *)node mergeProperties:self]; } else if ([node isKindOfClass:[RNSVGNode class]]) { RNSVGNode *svgNode = (RNSVGNode *)node; if (svgNode.display && [@"none" isEqualToString:svgNode.display]) { return YES; } if (svgNode.responsible && !self.svgView.responsible) { self.svgView.responsible = YES; } if ([node isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)node mergeProperties:self]; } [svgNode renderTo:context rect:rect]; CGRect nodeRect = svgNode.clientRect; if (!CGRectIsEmpty(nodeRect)) { bounds = CGRectUnion(bounds, nodeRect); } if ([node isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)node resetProperties]; } } else if ([node isKindOfClass:[RNSVGSvgView class]]) { RNSVGSvgView *svgView = (RNSVGSvgView *)node; // Merge properties with inner Svg element. if (svgView.subviews.count > 0) { RNSVGView *viewNode = svgView.subviews[0]; if ([viewNode isKindOfClass:[RNSVGGroup class]]) { RNSVGGroup *group = (RNSVGGroup *)viewNode; [group mergeProperties:self]; } } CGFloat width = [self relativeOnWidth:svgView.bbWidth]; CGFloat height = [self relativeOnHeight:svgView.bbHeight]; CGRect svgViewRect = CGRectMake(0, 0, width, height); CGContextClipToRect(context, svgViewRect); [svgView drawToContext:context withRect:svgViewRect]; } else { [node drawRect:rect]; } return YES; }]; CGPathRef path = [self getPath:context]; [self setHitArea:path]; if (!CGRectEqualToRect(bounds, CGRectNull)) { self.clientRect = bounds; self.fillBounds = CGPathGetPathBoundingBox(path); self.strokeBounds = CGPathGetPathBoundingBox(self.strokePath); self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds); CGAffineTransform current = CGContextGetCTM(context); CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM); self.ctm = svgToClientTransform; self.screenCTM = current; CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); CGPoint center = CGPointApplyAffineTransform(mid, self.matrix); self.bounds = bounds; if (!isnan(center.x) && !isnan(center.y)) { self.center = center; } self.frame = bounds; } [self popGlyphContext]; } - (void)setupGlyphContext:(CGContextRef)context { CGRect clipBounds = CGContextGetClipBoundingBox(context); #if TARGET_OS_OSX // [macOS RNSVGSvgView *svgView = [self svgView]; if (svgView != nil && (clipBounds.origin.x < 0 || clipBounds.origin.y < 0)) { clipBounds = CGRectApplyAffineTransform([svgView boundingBox], [svgView getInvViewBoxTransform]); } #endif // macOS] clipBounds = CGRectApplyAffineTransform(clipBounds, self.matrix); CGFloat width = CGRectGetWidth(clipBounds); CGFloat height = CGRectGetHeight(clipBounds); _glyphContext = [[RNSVGGlyphContext alloc] initWithWidth:width height:height]; } - (RNSVGGlyphContext *)getGlyphContext { return _glyphContext; } - (void)pushGlyphContext { __typeof__(self) __weak weakSelf = self; [[self.textRoot getGlyphContext] pushContext:weakSelf font:self.font]; } - (void)popGlyphContext { [[self.textRoot getGlyphContext] popContext]; } - (void)renderPathTo:(CGContextRef)context rect:(CGRect)rect { [super renderLayerTo:context rect:rect]; } - (CGPathRef)getPath:(CGContextRef)context { CGPathRef cached = self.path; if (cached) { return cached; } CGMutablePathRef __block path = CGPathCreateMutable(); [self traverseSubviews:^(RNSVGNode *node) { if ([node isKindOfClass:[RNSVGNode class]] && ![node isKindOfClass:[RNSVGMask class]]) { CGAffineTransform transform = node.matrix; CGPathAddPath(path, &transform, [node getPath:context]); CGPathAddPath(path, &transform, [node markerPath]); node.dirty = false; } return YES; }]; cached = CGPathRetain((CGPathRef)CFAutorelease(path)); self.path = cached; return cached; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); if (!CGRectContainsPoint(self.pathBounds, transformed)) { return nil; } if (self.clipPath) { RNSVGClipPath *clipNode = (RNSVGClipPath *)[self.svgView getDefinedClipPath:self.clipPath]; if ([clipNode isSimpleClipPath]) { CGPathRef clipPath = [self getClipPath]; if (clipPath && !CGPathContainsPoint(clipPath, nil, transformed, clipNode.clipRule == kRNSVGCGFCRuleEvenodd)) { return nil; } } else { RNSVGRenderable *clipGroup = (RNSVGRenderable *)clipNode; if (![clipGroup hitTest:transformed withEvent:event]) { return nil; } } } if (!event) { NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@ AND active == TRUE", [RNSVGNode class]]; NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive]; if ([filtered count] != 0) { return [filtered.lastObject hitTest:transformed withEvent:event]; } } for (RNSVGView *node in [self.subviews reverseObjectEnumerator]) { if ([node isKindOfClass:[RNSVGNode class]]) { if ([node isKindOfClass:[RNSVGMask class]]) { continue; } RNSVGNode *svgNode = (RNSVGNode *)node; if (event) { svgNode.active = NO; } RNSVGPlatformView *hitChild = [svgNode hitTest:transformed withEvent:event]; if (hitChild) { svgNode.active = YES; return (svgNode.responsible || (svgNode != hitChild)) ? hitChild : self; } } else if ([node isKindOfClass:[RNSVGSvgView class]]) { RNSVGSvgView *svgView = (RNSVGSvgView *)node; RNSVGPlatformView *hitChild = [svgView hitTest:transformed withEvent:event]; if (hitChild) { return hitChild; } } } RNSVGPlatformView *hitSelf = [super hitTest:transformed withEvent:event]; if (hitSelf) { return hitSelf; } return nil; } - (void)parseReference { self.dirty = false; if (self.name) { __typeof__(self) __weak weakSelf = self; [self.svgView defineTemplate:weakSelf templateName:self.name]; } [self traverseSubviews:^(RNSVGNode *node) { if ([node isKindOfClass:[RNSVGNode class]]) { [node parseReference]; } return YES; }]; } - (void)resetProperties { [self traverseSubviews:^(__kindof RNSVGNode *node) { if ([node isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)node resetProperties]; } return YES; }]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGGroupCls(void) { return RNSVGGroup.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGImage.h ================================================ /** * 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 #import #import "RNSVGLength.h" #import "RNSVGRenderable.h" #import "RNSVGVBMOS.h" #import #ifdef RCT_NEW_ARCH_ENABLED #import #endif @interface RNSVGImage : RNSVGRenderable #ifdef RCT_NEW_ARCH_ENABLED #endif @property (nonatomic, weak) RCTBridge *bridge; @property (nonatomic, assign) RCTImageSource *src; @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *imagewidth; @property (nonatomic, strong) RNSVGLength *imageheight; @property (nonatomic, strong) NSString *align; @property (nonatomic, assign) RNSVGVBMOS meetOrSlice; @property (nonatomic, copy) RCTDirectEventBlock onLoad; @end ================================================ FILE: apple/Elements/RNSVGImage.mm ================================================ /** * 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 "RNSVGImage.h" #import "RCTConvert+RNSVG.h" #if __has_include() #import #else #import #import #import #import #endif // RCT_NEW_ARCH_ENABLED #import #import #import "RNSVGViewBox.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import #import #import #import "RNSVGFabricConversions.h" using namespace facebook::react; #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGImage { CGImageRef _image; CGSize _imageSize; RCTImageLoaderCancellationBlock _reloadImageCancellationBlock; #ifdef RCT_NEW_ARCH_ENABLED RNSVGImageShadowNode::ConcreteState::Shared _state; std::shared_ptr _imageResponseObserverProxy; #endif // RCT_NEW_ARCH_ENABLED } #ifdef RCT_NEW_ARCH_ENABLED // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; _imageResponseObserverProxy = std::make_shared(self); } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id height = RNSVGConvertFollyDynamicToId(newProps.height); if (height != nil) { self.imageheight = [RCTConvert RNSVGLength:height]; } id width = RNSVGConvertFollyDynamicToId(newProps.width); if (width != nil) { self.imagewidth = [RCTConvert RNSVGLength:width]; } self.align = RCTNSStringFromStringNilIfEmpty(newProps.align); self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice); setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); [super updateProps:props oldProps:oldProps]; } - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { RCTAssert(state, @"`state` must not be null."); RCTAssert( std::dynamic_pointer_cast(state), @"`state` must be a pointer to `RNSVGImageShadowNode::ConcreteState`."); auto oldImageState = std::static_pointer_cast(_state); auto newImageState = std::static_pointer_cast(state); [self _setStateAndResubscribeImageResponseObserver:newImageState]; } - (void)_setStateAndResubscribeImageResponseObserver:(RNSVGImageShadowNode::ConcreteState::Shared const &)state { if (_state) { auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator(); #if REACT_NATIVE_MINOR_VERSION > 84 observerCoordinator.removeObserver(_imageResponseObserverProxy); #else observerCoordinator.removeObserver(*_imageResponseObserverProxy); #endif } _state = state; if (_state) { auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator(); #if REACT_NATIVE_MINOR_VERSION > 84 observerCoordinator.addObserver(_imageResponseObserverProxy); #else observerCoordinator.addObserver(*_imageResponseObserverProxy); #endif } } #pragma mark - RCTImageResponseDelegate #if !TARGET_OS_OSX // [macOS] - (void)didReceiveImage:(UIImage *)image metadata:(id)metadata fromObserver:(void const *)observer #else // [macOS - (void)didReceiveImage:(NSImage *)image metadata:(id)metadata fromObserver:(void const *)observer #endif // macOS] { 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; } auto imageSource = _state->getData().getImageSource(); imageSource.size = {image.size.width, image.size.height}; if (_eventEmitter != nullptr) { static_cast(*_eventEmitter) .onLoad( {.source = { .width = imageSource.size.width * imageSource.scale, .height = imageSource.size.height * imageSource.scale, .uri = imageSource.uri, }}); } dispatch_async(dispatch_get_main_queue(), ^{ self->_image = CGImageRetain(image.CGImage); self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image)); [self invalidate]; }); } - (void)didReceiveFailure:(nonnull NSError *)error fromObserver:(nonnull const void *)observer { if (_image) { CGImageRelease(_image); } _image = nil; } - (void)didReceiveProgress:(float)progress loaded:(int64_t)loaded total:(int64_t)total fromObserver:(nonnull const void *)observer { } #pragma mark - RCTImageResponseDelegate - < RN 0.75 - (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; _imagewidth = nil; _src = nil; _align = nil; _meetOrSlice = kRNSVGVBMOSMeet; if (_image) { CGImageRelease(_image); } _image = nil; _imageSize = CGSizeZero; _reloadImageCancellationBlock = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setSrc:(RCTImageSource *)src { #ifdef RCT_NEW_ARCH_ENABLED #else if (src == _src) { return; } _src = src; CGImageRelease(_image); _image = nil; if (src.size.width != 0 && src.size.height != 0) { _imageSize = src.size; } else { _imageSize = CGSizeMake(0, 0); } RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock; if (previousCancellationBlock) { previousCancellationBlock(); _reloadImageCancellationBlock = nil; } _reloadImageCancellationBlock = [[self.bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:src.request #if !TARGET_OS_OSX // [macOS] callback:^(__unused NSError *error, UIImage *image) { #else // [macOS callback:^(__unused NSError *error, NSImage *image) { #endif // macOS] dispatch_async(dispatch_get_main_queue(), ^{ self->_image = CGImageRetain(image.CGImage); self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image)); if (self->_onLoad) { RCTImageSource *sourceLoaded; #if TARGET_OS_OSX // [macOS] sourceLoaded = [src imageSourceWithSize:image.size scale:1]; #else sourceLoaded = [src imageSourceWithSize:image.size scale:image.scale]; #endif NSDictionary *dict = @{ @"uri" : sourceLoaded.request.URL.absoluteString, @"width" : @(sourceLoaded.size.width), @"height" : @(sourceLoaded.size.height), }; self->_onLoad(@{@"source" : dict}); } [self invalidate]; }); }]; #endif // RCT_NEW_ARCH_ENABLED } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } [self invalidate]; _x = x; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } [self invalidate]; _y = y; } - (void)setImagewidth:(RNSVGLength *)width { if ([width isEqualTo:_imagewidth]) { return; } [self invalidate]; _imagewidth = width; } - (void)setImageheight:(RNSVGLength *)height { if ([height isEqualTo:_imageheight]) { return; } [self invalidate]; _imageheight = height; } - (void)setAlign:(NSString *)align { if ([align isEqualToString:_align]) { return; } [self invalidate]; _align = align; } - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice { if (meetOrSlice == _meetOrSlice) { return; } [self invalidate]; _meetOrSlice = meetOrSlice; } - (void)dealloc { CGImageRelease(_image); } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { if (CGSizeEqualToSize(CGSizeZero, _imageSize)) { return; } CGContextSaveGState(context); // add hit area CGRect hitArea = [self getHitArea]; CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil); [self setHitArea:hitAreaPath]; CGPathRelease(hitAreaPath); self.pathBounds = hitArea; self.fillBounds = hitArea; self.strokeBounds = hitArea; // apply viewBox transform on Image render. CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height); CGAffineTransform viewbox = [RNSVGViewBox getTransform:imageBounds eRect:hitArea align:self.align meetOrSlice:self.meetOrSlice]; [self clip:context]; CGContextClipToRect(context, hitArea); CGContextConcatCTM(context, viewbox); CGContextTranslateCTM(context, 0, imageBounds.size.height); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, imageBounds, _image); CGContextRestoreGState(context); CGRect bounds = hitArea; self.clientRect = bounds; CGAffineTransform current = CGContextGetCTM(context); CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM); self.ctm = svgToClientTransform; self.screenCTM = current; CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); CGPoint center = CGPointApplyAffineTransform(mid, self.matrix); self.bounds = bounds; if (!isnan(center.x) && !isnan(center.y)) { self.center = center; } self.frame = bounds; } - (CGRect)getHitArea { CGFloat x = [self relativeOnWidth:self.x]; CGFloat y = [self relativeOnHeight:self.y]; CGFloat width = [self relativeOnWidth:self.imagewidth]; CGFloat height = [self relativeOnHeight:self.imageheight]; if (width == 0) { width = _imageSize.width; } if (height == 0) { height = _imageSize.height; } return CGRectMake(x, y, width, height); } - (CGPathRef)getPath:(CGContextRef)context { return (CGPathRef)CFAutorelease(CGPathCreateWithRect([self getHitArea], nil)); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGImageCls(void) { return RNSVGImage.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGLinearGradient.h ================================================ /** * 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 "RNSVGLength.h" #import "RNSVGNode.h" @interface RNSVGLinearGradient : RNSVGNode @property (nonatomic, strong) RNSVGLength *x1; @property (nonatomic, strong) RNSVGLength *y1; @property (nonatomic, strong) RNSVGLength *x2; @property (nonatomic, strong) RNSVGLength *y2; @property (nonatomic, copy) NSArray *gradient; @property (nonatomic, assign) RNSVGUnits gradientUnits; @property (nonatomic, assign) CGAffineTransform gradientTransform; @end ================================================ FILE: apple/Elements/RNSVGLinearGradient.mm ================================================ /** * 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 "RNSVGLinearGradient.h" #import "RNSVGBrushType.h" #import "RNSVGPainter.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGLinearGradient #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x1 = RNSVGConvertFollyDynamicToId(newProps.x1); if (x1 != nil) { self.x1 = [RCTConvert RNSVGLength:x1]; } id y1 = RNSVGConvertFollyDynamicToId(newProps.y1); if (y1 != nil) { self.y1 = [RCTConvert RNSVGLength:y1]; } id x2 = RNSVGConvertFollyDynamicToId(newProps.x2); if (x2 != nil) { self.x2 = [RCTConvert RNSVGLength:x2]; } id y2 = RNSVGConvertFollyDynamicToId(newProps.y2); if (y2 != nil) { self.y2 = [RCTConvert RNSVGLength:y2]; } if (newProps.gradient.size() > 0) { NSMutableArray *gradientArray = [NSMutableArray new]; for (auto number : newProps.gradient) { [gradientArray addObject:[NSNumber numberWithDouble:number]]; } self.gradient = gradientArray; } self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; if (newProps.gradientTransform.size() == 6) { self.gradientTransform = CGAffineTransformMake( newProps.gradientTransform.at(0), newProps.gradientTransform.at(1), newProps.gradientTransform.at(2), newProps.gradientTransform.at(3), newProps.gradientTransform.at(4), newProps.gradientTransform.at(5)); } setCommonNodeProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x1 = nil; _y1 = nil; _x2 = nil; _y2 = nil; _gradient = nil; _gradientUnits = kRNSVGUnitsObjectBoundingBox; _gradientTransform = CGAffineTransformIdentity; } #endif // RCT_NEW_ARCH_ENABLED - (instancetype)init { if (self = [super init]) { _gradientTransform = CGAffineTransformIdentity; } return self; } - (void)setX1:(RNSVGLength *)x1 { if ([x1 isEqualTo:_x1]) { return; } _x1 = x1; [self invalidate]; } - (void)setY1:(RNSVGLength *)y1 { if ([y1 isEqualTo:_y1]) { return; } _y1 = y1; [self invalidate]; } - (void)setX2:(RNSVGLength *)x2 { if ([x2 isEqualTo:_x2]) { return; } _x2 = x2; [self invalidate]; } - (void)setY2:(RNSVGLength *)y2 { if ([y2 isEqualTo:_y2]) { return; } _y2 = y2; [self invalidate]; } - (void)setGradient:(NSArray *)gradient { if (gradient == _gradient) { return; } _gradient = gradient; [self invalidate]; } - (void)setGradientUnits:(RNSVGUnits)gradientUnits { if (gradientUnits == _gradientUnits) { return; } _gradientUnits = gradientUnits; [self invalidate]; } - (void)setGradientTransform:(CGAffineTransform)gradientTransform { _gradientTransform = gradientTransform; [self invalidate]; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; NSArray *points = @[ self.x1, self.y1, self.x2, self.y2 ]; RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points]; [painter setUnits:self.gradientUnits]; [painter setTransform:self.gradientTransform]; [painter setLinearGradientColors:self.gradient]; if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) { [painter setUserSpaceBoundingBox:[self.svgView getContextBounds]]; } [self.svgView definePainter:painter painterName:self.name]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGLinearGradientCls(void) { return RNSVGLinearGradient.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGMarker.h ================================================ #import "RNSVGGroup.h" #import "RNSVGLength.h" #import "RNSVGMarkerPosition.h" @interface RNSVGMarker : RNSVGGroup @property (nonatomic, strong) RNSVGLength *refX; @property (nonatomic, strong) RNSVGLength *refY; @property (nonatomic, strong) RNSVGLength *markerWidth; @property (nonatomic, strong) RNSVGLength *markerHeight; @property (nonatomic, strong) NSString *markerUnits; @property (nonatomic, strong) NSString *orient; @property (nonatomic, assign) CGFloat minX; @property (nonatomic, assign) CGFloat minY; @property (nonatomic, assign) CGFloat vbWidth; @property (nonatomic, assign) CGFloat vbHeight; @property (nonatomic, strong) NSString *align; @property (nonatomic, assign) RNSVGVBMOS meetOrSlice; - (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition *)position strokeWidth:(CGFloat)strokeWidth; @end ================================================ FILE: apple/Elements/RNSVGMarker.mm ================================================ /** * 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 "RNSVGMarker.h" #import "RNSVGBrushType.h" #import "RNSVGNode.h" #import "RNSVGPainter.h" #import "RNSVGViewBox.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGMarker #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id refX = RNSVGConvertFollyDynamicToId(newProps.refX); if (refX != nil) { self.refX = [RCTConvert RNSVGLength:refX]; } id refY = RNSVGConvertFollyDynamicToId(newProps.refY); if (refY != nil) { self.refY = [RCTConvert RNSVGLength:refY]; } id markerHeight = RNSVGConvertFollyDynamicToId(newProps.markerHeight); if (markerHeight != nil) { self.markerHeight = [RCTConvert RNSVGLength:markerHeight]; } id markerWidth = RNSVGConvertFollyDynamicToId(newProps.markerWidth); if (markerWidth != nil) { self.markerWidth = [RCTConvert RNSVGLength:markerWidth]; } self.markerUnits = RCTNSStringFromStringNilIfEmpty(newProps.markerUnits); self.orient = RCTNSStringFromStringNilIfEmpty(newProps.orient); self.minX = newProps.minX; self.minY = newProps.minY; self.vbWidth = newProps.vbWidth; self.vbHeight = newProps.vbHeight; self.align = RCTNSStringFromStringNilIfEmpty(newProps.align); self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice); setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _refX = nil; _refY = nil; _markerHeight = nil; _markerWidth = nil; _markerUnits = nil; _orient = nil; _minX = 0; _minY = 0; _vbWidth = 0; _vbHeight = 0; _align = nil; _meetOrSlice = kRNSVGVBMOSMeet; } #endif // RCT_NEW_ARCH_ENABLED - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; [self.svgView defineMarker:self markerName:self.name]; [self traverseSubviews:^(RNSVGNode *node) { if ([node isKindOfClass:[RNSVGNode class]]) { [node parseReference]; } return YES; }]; } - (void)setX:(RNSVGLength *)refX { if ([refX isEqualTo:_refX]) { return; } _refX = refX; [self invalidate]; } - (void)setY:(RNSVGLength *)refY { if ([refY isEqualTo:_refY]) { return; } _refY = refY; [self invalidate]; } - (void)setMarkerWidth:(RNSVGLength *)markerWidth { if ([markerWidth isEqualTo:_markerWidth]) { return; } _markerWidth = markerWidth; [self invalidate]; } - (void)setMarkerHeight:(RNSVGLength *)markerHeight { if ([markerHeight isEqualTo:_markerHeight]) { return; } _markerHeight = markerHeight; [self invalidate]; } - (void)setMarkerUnits:(NSString *)markerUnits { if ([_markerUnits isEqualToString:markerUnits]) { return; } _markerUnits = markerUnits; [self invalidate]; } - (void)setOrient:(NSString *)orient { if ([orient isEqualToString:_orient]) { return; } [self invalidate]; _orient = orient; } - (void)setMinX:(CGFloat)minX { if (minX == _minX) { return; } [self invalidate]; _minX = minX; } - (void)setMinY:(CGFloat)minY { if (minY == _minY) { return; } [self invalidate]; _minY = minY; } - (void)setVbWidth:(CGFloat)vbWidth { if (vbWidth == _vbWidth) { return; } [self invalidate]; _vbWidth = vbWidth; } - (void)setVbHeight:(CGFloat)vbHeight { if (_vbHeight == vbHeight) { return; } [self invalidate]; _vbHeight = vbHeight; } - (void)setAlign:(NSString *)align { if ([align isEqualToString:_align]) { return; } [self invalidate]; _align = align; } - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice { if (meetOrSlice == _meetOrSlice) { return; } [self invalidate]; _meetOrSlice = meetOrSlice; } static CGFloat RNSVG_degToRad = (CGFloat)M_PI / 180; double deg2rad(CGFloat deg) { return deg * RNSVG_degToRad; } - (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition *)position strokeWidth:(CGFloat)strokeWidth { CGContextSaveGState(context); CGPoint origin = [position origin]; CGAffineTransform transform = CGAffineTransformMakeTranslation(origin.x, origin.y); float markerAngle = [@"auto" isEqualToString:_orient] ? -1 : [_orient doubleValue]; float angle = 180 + (markerAngle == -1 ? [position angle] : markerAngle); float rad = deg2rad(angle); transform = CGAffineTransformRotate(transform, rad); bool useStrokeWidth = [@"strokeWidth" isEqualToString:_markerUnits]; if (useStrokeWidth) { transform = CGAffineTransformScale(transform, strokeWidth, strokeWidth); } CGFloat width = [self relativeOnWidth:self.markerWidth]; CGFloat height = [self relativeOnHeight:self.markerHeight]; CGRect eRect = CGRectMake(0, 0, width, height); if (self.align) { CGAffineTransform viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight) eRect:eRect align:self.align meetOrSlice:self.meetOrSlice]; transform = CGAffineTransformScale(transform, viewBoxTransform.a, viewBoxTransform.d); } CGFloat x = [self relativeOnWidth:self.refX]; CGFloat y = [self relativeOnHeight:self.refY]; transform = CGAffineTransformTranslate(transform, -x, -y); self.transform = transform; CGContextConcatCTM(context, transform); [self renderGroupTo:context rect:eRect]; CGContextRestoreGState(context); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGMarkerCls(void) { return RNSVGMarker.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGMask.h ================================================ #import "RNSVGGroup.h" #import "RNSVGLength.h" @interface RNSVGMask : RNSVGGroup @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *maskwidth; @property (nonatomic, strong) RNSVGLength *maskheight; @property (nonatomic, assign) RNSVGUnits maskUnits; @property (nonatomic, assign) RNSVGUnits maskContentUnits; @property (nonatomic, assign) RNSVGMaskType maskType; @end ================================================ FILE: apple/Elements/RNSVGMask.mm ================================================ /** * 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 "RNSVGMask.h" #import "RNSVGBrushType.h" #import "RNSVGNode.h" #import "RNSVGPainter.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGMask #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id maskheight = RNSVGConvertFollyDynamicToId(newProps.height); if (maskheight != nil) { self.maskheight = [RCTConvert RNSVGLength:maskheight]; } id maskwidth = RNSVGConvertFollyDynamicToId(newProps.width); if (maskwidth != nil) { self.maskwidth = [RCTConvert RNSVGLength:maskwidth]; } self.maskUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; self.maskContentUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; self.maskType = newProps.maskType == 0 ? kRNSVGMaskTypeLuminance : kRNSVGMaskTypeAlpha; setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x = nil; _y = nil; _maskheight = nil; _maskwidth = nil; _maskUnits = kRNSVGUnitsObjectBoundingBox; _maskContentUnits = kRNSVGUnitsObjectBoundingBox; _maskType = kRNSVGMaskTypeLuminance; } #endif // RCT_NEW_ARCH_ENABLED - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; [self.svgView defineMask:self maskName:self.name]; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } _x = x; [self invalidate]; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } _y = y; [self invalidate]; } - (void)setMaskwidth:(RNSVGLength *)maskwidth { if ([maskwidth isEqualTo:_maskwidth]) { return; } _maskwidth = maskwidth; [self invalidate]; } - (void)setMaskheight:(RNSVGLength *)maskheight { if ([maskheight isEqualTo:_maskheight]) { return; } _maskheight = maskheight; [self invalidate]; } - (void)setMaskUnits:(RNSVGUnits)maskUnits { if (maskUnits == _maskUnits) { return; } _maskUnits = maskUnits; [self invalidate]; } - (void)setMaskContentUnits:(RNSVGUnits)maskContentUnits { if (maskContentUnits == _maskContentUnits) { return; } _maskContentUnits = maskContentUnits; [self invalidate]; } - (void)setMaskType:(RNSVGMaskType)maskType { if (maskType == _maskType) { return; } _maskType = maskType; [self invalidate]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGMaskCls(void) { return RNSVGMask.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGPath.h ================================================ /** * 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 #import "RNSVGPathParser.h" #import "RNSVGRenderable.h" @interface RNSVGPath : RNSVGRenderable @property (nonatomic, strong) RNSVGPathParser *d; @end ================================================ FILE: apple/Elements/RNSVGPath.mm ================================================ /** * 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 "RNSVGPath.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGPath { CGPathRef _path; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.d = [[RNSVGPathParser alloc] initWithPathString:RCTNSStringFromString(newProps.d)]; setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; if (_path) { CGPathRelease(_path); } _path = nil; _d = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setD:(RNSVGPathParser *)d { if (d == _d) { return; } [self invalidate]; _d = d; CGPathRelease(_path); _path = CGPathRetain([d getPath]); } - (CGPathRef)getPath:(CGContextRef)context { return _path; } - (void)dealloc { CGPathRelease(_path); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGPathCls(void) { return RNSVGPath.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGPattern.h ================================================ #import "RNSVGGroup.h" #import "RNSVGLength.h" @interface RNSVGPattern : RNSVGGroup @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *patternwidth; @property (nonatomic, strong) RNSVGLength *patternheight; @property (nonatomic, assign) RNSVGUnits patternUnits; @property (nonatomic, assign) RNSVGUnits patternContentUnits; @property (nonatomic, assign) CGAffineTransform patternTransform; @property (nonatomic, assign) CGFloat minX; @property (nonatomic, assign) CGFloat minY; @property (nonatomic, assign) CGFloat vbWidth; @property (nonatomic, assign) CGFloat vbHeight; @property (nonatomic, strong) NSString *align; @property (nonatomic, assign) RNSVGVBMOS meetOrSlice; @end ================================================ FILE: apple/Elements/RNSVGPattern.mm ================================================ /** * 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 "RNSVGPattern.h" #import "RNSVGBrushType.h" #import "RNSVGNode.h" #import "RNSVGPainter.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGPattern #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id patternheight = RNSVGConvertFollyDynamicToId(newProps.height); if (patternheight != nil) { self.patternheight = [RCTConvert RNSVGLength:patternheight]; } id patternwidth = RNSVGConvertFollyDynamicToId(newProps.width); if (patternwidth != nil) { self.patternwidth = [RCTConvert RNSVGLength:patternwidth]; } self.patternUnits = newProps.patternUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; self.patternContentUnits = newProps.patternContentUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; if (newProps.patternTransform.size() == 6) { self.patternTransform = CGAffineTransformMake( newProps.patternTransform.at(0), newProps.patternTransform.at(1), newProps.patternTransform.at(2), newProps.patternTransform.at(3), newProps.patternTransform.at(4), newProps.patternTransform.at(5)); } self.minX = newProps.minX; self.minY = newProps.minY; self.vbWidth = newProps.vbWidth; self.vbHeight = newProps.vbHeight; self.align = RCTNSStringFromStringNilIfEmpty(newProps.align); self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice); setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x = nil; _y = nil; _patternheight = nil; _patternwidth = nil; _patternUnits = kRNSVGUnitsObjectBoundingBox; _patternContentUnits = kRNSVGUnitsObjectBoundingBox; _patternTransform = CGAffineTransformIdentity; _minX = 0; _minY = 0; _vbWidth = 0; _vbHeight = 0; _align = nil; _meetOrSlice = kRNSVGVBMOSMeet; } #endif // RCT_NEW_ARCH_ENABLED - (instancetype)init { if (self = [super init]) { _patternTransform = CGAffineTransformIdentity; } return self; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; NSArray *points = @[ self.x, self.y, self.patternwidth, self.patternheight ]; RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points]; [painter setUnits:self.patternUnits]; [painter setContentUnits:self.patternContentUnits]; [painter setTransform:self.patternTransform]; [painter setPattern:self]; if (self.patternUnits == kRNSVGUnitsUserSpaceOnUse || self.patternContentUnits == kRNSVGUnitsUserSpaceOnUse) { [painter setUserSpaceBoundingBox:[self.svgView getContextBounds]]; } [self.svgView definePainter:painter painterName:self.name]; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } _x = x; [self invalidate]; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } _y = y; [self invalidate]; } - (void)setPatternwidth:(RNSVGLength *)patternwidth { if ([patternwidth isEqualTo:_patternwidth]) { return; } _patternwidth = patternwidth; [self invalidate]; } - (void)setPatternheight:(RNSVGLength *)patternheight { if ([patternheight isEqualTo:_patternheight]) { return; } _patternheight = patternheight; [self invalidate]; } - (void)setPatternUnits:(RNSVGUnits)patternUnits { if (patternUnits == _patternUnits) { return; } _patternUnits = patternUnits; [self invalidate]; } - (void)setPatternContentUnits:(RNSVGUnits)patternContentUnits { if (patternContentUnits == _patternContentUnits) { return; } _patternContentUnits = patternContentUnits; [self invalidate]; } - (void)setPatternTransform:(CGAffineTransform)patternTransform { _patternTransform = patternTransform; [self invalidate]; } - (void)setMinX:(CGFloat)minX { if (minX == _minX) { return; } [self invalidate]; _minX = minX; } - (void)setMinY:(CGFloat)minY { if (minY == _minY) { return; } [self invalidate]; _minY = minY; } - (void)setVbWidth:(CGFloat)vbWidth { if (vbWidth == _vbWidth) { return; } [self invalidate]; _vbWidth = vbWidth; } - (void)setVbHeight:(CGFloat)vbHeight { if (_vbHeight == vbHeight) { return; } [self invalidate]; _vbHeight = vbHeight; } - (void)setAlign:(NSString *)align { if ([align isEqualToString:_align]) { return; } [self invalidate]; _align = align; } - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice { if (meetOrSlice == _meetOrSlice) { return; } [self invalidate]; _meetOrSlice = meetOrSlice; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGPatternCls(void) { return RNSVGPattern.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGRadialGradient.h ================================================ /** * 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 "RNSVGLength.h" #import "RNSVGNode.h" @interface RNSVGRadialGradient : RNSVGNode @property (nonatomic, strong) RNSVGLength *fx; @property (nonatomic, strong) RNSVGLength *fy; @property (nonatomic, strong) RNSVGLength *rx; @property (nonatomic, strong) RNSVGLength *ry; @property (nonatomic, strong) RNSVGLength *cx; @property (nonatomic, strong) RNSVGLength *cy; @property (nonatomic, copy) NSArray *gradient; @property (nonatomic, assign) RNSVGUnits gradientUnits; @property (nonatomic, assign) CGAffineTransform gradientTransform; @end ================================================ FILE: apple/Elements/RNSVGRadialGradient.mm ================================================ /** * 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 "RNSVGRadialGradient.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGRadialGradient #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id fx = RNSVGConvertFollyDynamicToId(newProps.fx); if (fx != nil) { self.fx = [RCTConvert RNSVGLength:fx]; } id fy = RNSVGConvertFollyDynamicToId(newProps.fy); if (fy != nil) { self.fy = [RCTConvert RNSVGLength:fy]; } id cx = RNSVGConvertFollyDynamicToId(newProps.cx); if (cx != nil) { self.cx = [RCTConvert RNSVGLength:cx]; } id cy = RNSVGConvertFollyDynamicToId(newProps.cy); if (cy != nil) { self.cy = [RCTConvert RNSVGLength:cy]; } id rx = RNSVGConvertFollyDynamicToId(newProps.rx); if (rx != nil) { self.rx = [RCTConvert RNSVGLength:rx]; } id ry = RNSVGConvertFollyDynamicToId(newProps.ry); if (ry != nil) { self.ry = [RCTConvert RNSVGLength:ry]; } if (newProps.gradient.size() > 0) { NSMutableArray *gradientArray = [NSMutableArray new]; for (auto number : newProps.gradient) { [gradientArray addObject:[NSNumber numberWithDouble:number]]; } self.gradient = gradientArray; } self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse; if (newProps.gradientTransform.size() == 6) { self.gradientTransform = CGAffineTransformMake( newProps.gradientTransform.at(0), newProps.gradientTransform.at(1), newProps.gradientTransform.at(2), newProps.gradientTransform.at(3), newProps.gradientTransform.at(4), newProps.gradientTransform.at(5)); } setCommonNodeProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _fx = nil; _fy = nil; _cx = nil; _cy = nil; _rx = nil; _ry = nil; _gradient = nil; _gradientUnits = kRNSVGUnitsObjectBoundingBox; _gradientTransform = CGAffineTransformIdentity; } #endif // RCT_NEW_ARCH_ENABLED - (instancetype)init { if (self = [super init]) { _gradientTransform = CGAffineTransformIdentity; } return self; } - (void)setFx:(RNSVGLength *)fx { if ([fx isEqualTo:_fx]) { return; } _fx = fx; [self invalidate]; } - (void)setFy:(RNSVGLength *)fy { if ([fy isEqualTo:_fy]) { return; } _fy = fy; [self invalidate]; } - (void)setRx:(RNSVGLength *)rx { if ([rx isEqualTo:_rx]) { return; } _rx = rx; [self invalidate]; } - (void)setRy:(RNSVGLength *)ry { if ([ry isEqualTo:_ry]) { return; } _ry = ry; [self invalidate]; } - (void)setCx:(RNSVGLength *)cx { if ([cx isEqualTo:_cx]) { return; } _cx = cx; [self invalidate]; } - (void)setCy:(RNSVGLength *)cy { if ([cy isEqualTo:_cy]) { return; } _cy = cy; [self invalidate]; } - (void)setGradient:(NSArray *)gradient { if (gradient == _gradient) { return; } _gradient = gradient; [self invalidate]; } - (void)setGradientUnits:(RNSVGUnits)gradientUnits { if (gradientUnits == _gradientUnits) { return; } _gradientUnits = gradientUnits; [self invalidate]; } - (void)setGradientTransform:(CGAffineTransform)gradientTransform { _gradientTransform = gradientTransform; [self invalidate]; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { self.dirty = false; NSArray *points = @[ self.fx, self.fy, self.rx, self.ry, self.cx, self.cy ]; RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points]; [painter setUnits:self.gradientUnits]; [painter setTransform:self.gradientTransform]; [painter setRadialGradientColors:self.gradient]; if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) { [painter setUserSpaceBoundingBox:[self.svgView getContextBounds]]; } [self.svgView definePainter:painter painterName:self.name]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGRadialGradientCls(void) { return RNSVGRadialGradient.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGSvgView.h ================================================ /** * 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 "RNSVGUIKit.h" #import "RNSVGContainer.h" #import "RNSVGPainter.h" #import "RNSVGVBMOS.h" @class RNSVGNode; @class RNSVGMarker; @class RNSVGMask; @class RNSVGFilter; @interface RNSVGSvgView : RNSVGView @property (nonatomic, strong) RNSVGColor *color; @property (nonatomic, strong) RNSVGLength *bbWidth; @property (nonatomic, strong) RNSVGLength *bbHeight; @property (nonatomic, assign) CGFloat minX; @property (nonatomic, assign) CGFloat minY; @property (nonatomic, assign) CGFloat vbWidth; @property (nonatomic, assign) CGFloat vbHeight; @property (nonatomic, strong) NSString *align; @property (nonatomic, assign) RNSVGVBMOS meetOrSlice; @property (nonatomic, assign) BOOL responsible; @property (nonatomic, assign) BOOL active; @property (nonatomic, assign) CGRect boundingBox; @property (nonatomic, assign) CGAffineTransform initialCTM; @property (nonatomic, assign) CGAffineTransform invInitialCTM; @property (nonatomic, assign) CGAffineTransform viewBoxTransform; @property (nonatomic, assign) UIEdgeInsets hitTestEdgeInsets; /** * define content as clipPath template. */ - (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathName:(NSString *)clipPathName; - (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathName; - (void)defineTemplate:(__kindof RNSVGNode *)definedTemplate templateName:(NSString *)templateName; - (RNSVGNode *)getDefinedTemplate:(NSString *)templateName; - (void)definePainter:(RNSVGPainter *)painter painterName:(NSString *)painterName; - (RNSVGPainter *)getDefinedPainter:(NSString *)painterName; - (void)defineMarker:(RNSVGMarker *)marker markerName:(NSString *)markerName; - (RNSVGMarker *)getDefinedMarker:(NSString *)markerName; - (void)defineMask:(RNSVGMask *)mask maskName:(NSString *)maskName; - (RNSVGMask *)getDefinedMask:(NSString *)maskName; - (void)defineFilter:(RNSVGFilter *)filter filterName:(NSString *)filterName; - (RNSVGFilter *)getDefinedFilter:(NSString *)filterName; - (NSString *)getDataURLWithBounds:(CGRect)bounds; - (CGRect)getContextBounds; - (void)drawRect:(CGRect)rect; - (void)drawToContext:(CGContextRef)context withRect:(CGRect)rect; - (CGAffineTransform)getViewBoxTransform; - (CGAffineTransform)getInvViewBoxTransform; @end ================================================ FILE: apple/Elements/RNSVGSvgView.mm ================================================ /** * 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 "RNSVGSvgView.h" #import #import "RNSVGNode.h" #import "RNSVGViewBox.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED #if TARGET_OS_OSX // [macOS #import "RNSVGUIKit.h" #endif // macOS] @implementation RNSVGSvgView { NSMutableDictionary *_clipPaths; NSMutableDictionary *_templates; NSMutableDictionary *_painters; NSMutableDictionary *_markers; NSMutableDictionary *_masks; NSMutableDictionary *_filters; CGAffineTransform _invViewBoxTransform; bool rendered; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; #endif // RCT_NEW_ARCH_ENABLED // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { #if !TARGET_OS_OSX // Not available on macOS // This is necessary to ensure that [self setNeedsDisplay] actually triggers // a redraw when our parent transitions between hidden and visible. self.contentMode = UIViewContentModeRedraw; #endif // TARGET_OS_OSX rendered = false; #ifdef RCT_NEW_ARCH_ENABLED static const auto defaultProps = std::make_shared(); _props = defaultProps; #if !TARGET_OS_OSX // On macOS, views are transparent by default // TODO: think if we can do it better self.opaque = NO; #endif // TARGET_OS_OSX #endif // RCT_NEW_ARCH_ENABLED } return self; } #ifdef RCT_NEW_ARCH_ENABLED #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.minX = newProps.minX; self.minY = newProps.minY; self.vbWidth = newProps.vbWidth; self.vbHeight = newProps.vbHeight; id bbWidth = RNSVGConvertFollyDynamicToId(newProps.bbWidth); if (bbWidth != nil) { self.bbWidth = [RCTConvert RNSVGLength:bbWidth]; } id bbHeight = RNSVGConvertFollyDynamicToId(newProps.bbHeight); if (bbHeight != nil) { self.bbHeight = [RCTConvert RNSVGLength:bbHeight]; } self.align = RCTNSStringFromStringNilIfEmpty(newProps.align); self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice); if (RCTUIColorFromSharedColor(newProps.color)) { self.color = RCTUIColorFromSharedColor(newProps.color); } [super updateProps:props oldProps:oldProps]; } - (void)prepareForRecycle { [super prepareForRecycle]; _minX = 0; _minY = 0; _vbWidth = 0; _vbHeight = 0; _bbWidth = 0; _bbHeight = 0; _align = nil; _meetOrSlice = kRNSVGVBMOSMeet; _responsible = NO; _active = NO; _boundingBox = CGRectZero; _initialCTM = CGAffineTransformIdentity; _invInitialCTM = CGAffineTransformIdentity; _viewBoxTransform = CGAffineTransformIdentity; _clipPaths = nil; _templates = nil; _painters = nil; _markers = nil; _masks = nil; _filters = nil; _invViewBoxTransform = CGAffineTransformIdentity; rendered = NO; } - (void)mountChildComponentView:(RNSVGView *)childComponentView index:(NSInteger)index { [super mountChildComponentView:childComponentView index:index]; [self invalidate]; } - (void)unmountChildComponentView:(RNSVGView *)childComponentView index:(NSInteger)index { [super unmountChildComponentView:childComponentView index:index]; [self invalidate]; } #endif // RCT_NEW_ARCH_ENABLED - (void)insertReactSubview:(RNSVGPlatformView *)subview atIndex:(NSInteger)atIndex { [super insertReactSubview:subview atIndex:atIndex]; [self insertSubview:subview atIndex:atIndex]; [self invalidate]; } - (void)removeReactSubview:(RNSVGPlatformView *)subview { [super removeReactSubview:subview]; [self invalidate]; } - (void)didUpdateReactSubviews { // Do nothing, as subviews are inserted by insertReactSubview: } - (void)clearChildCache { if (!rendered) { return; } rendered = false; for (__kindof RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { [node clearChildCache]; } } } - (void)invalidate { RNSVGPlatformView *parent = self.superview; if ([parent isKindOfClass:[RNSVGNode class]]) { if (!rendered) { return; } RNSVGNode *svgNode = (RNSVGNode *)parent; [svgNode invalidate]; rendered = false; return; } [self setNeedsDisplay]; } - (void)setColor:(RNSVGColor *)color { if (color == _color) { return; } [self invalidate]; _color = color; } - (void)setMinX:(CGFloat)minX { if (minX == _minX) { return; } [self invalidate]; [self clearChildCache]; _minX = minX; } - (void)setMinY:(CGFloat)minY { if (minY == _minY) { return; } [self invalidate]; [self clearChildCache]; _minY = minY; } - (void)setVbWidth:(CGFloat)vbWidth { if (vbWidth == _vbWidth) { return; } [self invalidate]; [self clearChildCache]; _vbWidth = vbWidth; } - (void)setVbHeight:(CGFloat)vbHeight { if (_vbHeight == vbHeight) { return; } [self invalidate]; [self clearChildCache]; _vbHeight = vbHeight; } - (void)setBbWidth:(RNSVGLength *)bbWidth { if ([bbWidth isEqualTo:_bbWidth]) { return; } [self invalidate]; [self clearChildCache]; _bbWidth = bbWidth; } - (void)setBbHeight:(RNSVGLength *)bbHeight { if ([bbHeight isEqualTo:_bbHeight]) { return; } [self invalidate]; [self clearChildCache]; _bbHeight = bbHeight; } - (void)setAlign:(NSString *)align { if ([align isEqualToString:_align]) { return; } [self invalidate]; [self clearChildCache]; _align = align; } - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice { if (meetOrSlice == _meetOrSlice) { return; } [self invalidate]; [self clearChildCache]; _meetOrSlice = meetOrSlice; } - (void)drawToContext:(CGContextRef)context withRect:(CGRect)rect { rendered = true; _clipPaths = nil; _templates = nil; _painters = nil; self.initialCTM = CGContextGetCTM(context); self.invInitialCTM = CGAffineTransformInvert(self.initialCTM); if (self.align) { CGRect tRect = CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight); _viewBoxTransform = [RNSVGViewBox getTransform:tRect eRect:rect align:self.align meetOrSlice:self.meetOrSlice]; _invViewBoxTransform = CGAffineTransformInvert(_viewBoxTransform); CGContextConcatCTM(context, _viewBoxTransform); } else { _viewBoxTransform = CGAffineTransformIdentity; _invViewBoxTransform = CGAffineTransformIdentity; } for (RNSVGPlatformView *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { RNSVGNode *svg = (RNSVGNode *)node; if (svg.responsible && !self.responsible) { self.responsible = YES; } [svg parseReference]; [svg renderTo:context rect:rect]; } else { [node drawRect:rect]; } } } - (void)drawRect:(CGRect)rect { RNSVGPlatformView *parent = self.superview; if ([parent isKindOfClass:[RNSVGNode class]]) { return; } #if TARGET_OS_OSX // [macOS _boundingBox = [self bounds]; #else // macOS] _boundingBox = rect; #endif CGContextRef context = UIGraphicsGetCurrentContext(); [self drawToContext:context withRect:[self bounds]]; } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero)) { return [super pointInside:point withEvent:event]; } CGRect hitFrame = UIEdgeInsetsInsetRect(self.bounds, self.hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point); } #ifdef RCT_NEW_ARCH_ENABLED - (RNSVGPlatformView *)betterHitTest:(CGPoint)point withEvent:(UIEvent *)event #else - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event #endif { if (point.x < 0 || point.y < 0 || point.x > self.bounds.size.width || point.y > self.bounds.size.height) { return nil; } CGPoint transformed = point; if (self.align) { transformed = CGPointApplyAffineTransform(transformed, _invViewBoxTransform); } for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) { if (![node isKindOfClass:[RNSVGNode class]]) { continue; } if (event) { node.active = NO; } RNSVGPlatformView *hitChild = [node hitTest:transformed withEvent:event]; if (hitChild) { node.active = YES; return (node.responsible || (node != hitChild)) ? hitChild : self; } } BOOL isPointInside = [self pointInside:point withEvent:event]; return isPointInside ? self : nil; } - (NSString *)getDataURLWithBounds:(CGRect)bounds { #if !TARGET_OS_OSX // [macOS] UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:bounds.size]; UIImage *image = [renderer imageWithActions:^(__unused UIGraphicsImageRendererContext *_Nonnull rendererContext) { #else // [macOS RNSVGUIGraphicsBeginImageContextWithOptions(bounds.size, NO, 1); #endif // macOS] [self clearChildCache]; [self drawRect:bounds]; [self clearChildCache]; [self invalidate]; #if !TARGET_OS_OSX // [macOS] }]; #endif #if !TARGET_OS_OSX // [macOS] NSData *imageData = UIImagePNGRepresentation(image); NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; #else // [macOS NSData *imageData = UIImagePNGRepresentation(RNSVGUIGraphicsGetImageFromCurrentImageContext()); NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; RNSVGUIGraphicsEndImageContext(); #endif // macOS] return base64; } - (void)reactSetInheritedBackgroundColor:(RNSVGColor *)inheritedBackgroundColor { self.backgroundColor = inheritedBackgroundColor; } - (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathName:(NSString *)clipPathName { if (!clipPathName) { return; } if (!_clipPaths) { _clipPaths = [[NSMutableDictionary alloc] init]; } [_clipPaths setObject:clipPath forKey:clipPathName]; } - (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathName { return _clipPaths ? [_clipPaths objectForKey:clipPathName] : nil; } - (void)defineTemplate:(RNSVGNode *)definedTemplate templateName:(NSString *)templateName { if (!templateName) { return; } if (!_templates) { _templates = [[NSMutableDictionary alloc] init]; } [_templates setObject:definedTemplate forKey:templateName]; } - (RNSVGNode *)getDefinedTemplate:(NSString *)templateName { return _templates ? [_templates objectForKey:templateName] : nil; } - (void)definePainter:(RNSVGPainter *)painter painterName:(NSString *)painterName { if (!painterName) { return; } if (!_painters) { _painters = [[NSMutableDictionary alloc] init]; } [_painters setObject:painter forKey:painterName]; } - (RNSVGPainter *)getDefinedPainter:(NSString *)painterName { return _painters ? [_painters objectForKey:painterName] : nil; } - (void)defineMarker:(RNSVGMarker *)marker markerName:(NSString *)markerName { if (!markerName) { return; } if (!_markers) { _markers = [[NSMutableDictionary alloc] init]; } [_markers setObject:marker forKey:markerName]; } - (RNSVGMarker *)getDefinedMarker:(NSString *)markerName { return _markers ? [_markers objectForKey:markerName] : nil; } - (void)defineMask:(RNSVGMask *)mask maskName:(NSString *)maskName { if (!maskName) { return; } if (!_masks) { _masks = [[NSMutableDictionary alloc] init]; } [_masks setObject:mask forKey:maskName]; } - (RNSVGMask *)getDefinedMask:(NSString *)maskName { return _masks ? [_masks objectForKey:maskName] : nil; } - (void)defineFilter:(RNSVGFilter *)filter filterName:(NSString *)filterName { if (!filterName) { return; } if (!_filters) { _filters = [[NSMutableDictionary alloc] init]; } [_filters setObject:filter forKey:filterName]; } - (RNSVGFilter *)getDefinedFilter:(NSString *)filterName { return _filters ? [_filters objectForKey:filterName] : nil; } - (CGRect)getContextBounds { return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext()); } - (CGAffineTransform)getViewBoxTransform { return _viewBoxTransform; } - (CGAffineTransform)getInvViewBoxTransform { return _invViewBoxTransform; } #if !RCT_NEW_ARCH_ENABLED && TARGET_OS_OSX // [macOS - (void)updateReactTransformInternal:(CATransform3D)transform { [self setTransform:CATransform3DGetAffineTransform(transform)]; } #endif // macOS] @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGSvgViewCls(void) { return RNSVGSvgView.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGSymbol.h ================================================ /** * 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 "RNSVGGroup.h" /** * RNSVG defination are implemented as abstract UIViews for all elements inside Defs. */ @interface RNSVGSymbol : RNSVGGroup @property (nonatomic, assign) CGFloat minX; @property (nonatomic, assign) CGFloat minY; @property (nonatomic, assign) CGFloat vbWidth; @property (nonatomic, assign) CGFloat vbHeight; @property (nonatomic, strong) NSString *align; @property (nonatomic, assign) RNSVGVBMOS meetOrSlice; - (void)renderSymbolTo:(CGContextRef)context width:(CGFloat)width height:(CGFloat)height; @end ================================================ FILE: apple/Elements/RNSVGSymbol.mm ================================================ /** * 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 "RNSVGSymbol.h" #import "RNSVGViewBox.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGSymbol #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.minX = newProps.minX; self.minY = newProps.minY; self.vbWidth = newProps.vbWidth; self.vbHeight = newProps.vbHeight; self.align = RCTNSStringFromStringNilIfEmpty(newProps.align); self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice); setCommonGroupProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _minX = 0; _minY = 0; _vbWidth = 0; _vbHeight = 0; _align = nil; _meetOrSlice = kRNSVGVBMOSMeet; } #endif // RCT_NEW_ARCH_ENABLED - (void)setMinX:(CGFloat)minX { if (minX == _minX) { return; } [self invalidate]; _minX = minX; } - (void)setMinY:(CGFloat)minY { if (minY == _minY) { return; } [self invalidate]; _minY = minY; } - (void)setVbWidth:(CGFloat)vbWidth { if (vbWidth == _vbWidth) { return; } [self invalidate]; _vbWidth = vbWidth; } - (void)setVbHeight:(CGFloat)vbHeight { if (_vbHeight == vbHeight) { return; } [self invalidate]; _vbHeight = vbHeight; } - (void)setAlign:(NSString *)align { if ([align isEqualToString:_align]) { return; } [self invalidate]; _align = align; } - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice { if (meetOrSlice == _meetOrSlice) { return; } [self invalidate]; _meetOrSlice = meetOrSlice; } - (void)renderTo:(CGContextRef)context rect:(CGRect)rect { self.dirty = false; // Do not render Symbol } - (void)renderSymbolTo:(CGContextRef)context width:(CGFloat)width height:(CGFloat)height { CGRect eRect = CGRectMake(0, 0, width, height); if (self.align) { CGAffineTransform viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight) eRect:eRect align:self.align meetOrSlice:self.meetOrSlice]; CGContextConcatCTM(context, viewBoxTransform); } [self renderGroupTo:context rect:eRect]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGSymbolCls(void) { return RNSVGSymbol.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Elements/RNSVGUse.h ================================================ /** * 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 "RNSVGLength.h" #import "RNSVGRenderable.h" /** * RNSVG defination are implemented as abstract UIViews for all elements inside Defs. */ @interface RNSVGUse : RNSVGRenderable @property (nonatomic, strong) NSString *href; @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *usewidth; @property (nonatomic, strong) RNSVGLength *useheight; @end ================================================ FILE: apple/Elements/RNSVGUse.mm ================================================ /** * 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 "RNSVGUse.h" #import #import "RNSVGSymbol.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGUse #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id useheight = RNSVGConvertFollyDynamicToId(newProps.height); if (useheight != nil) { self.useheight = [RCTConvert RNSVGLength:useheight]; } id usewidth = RNSVGConvertFollyDynamicToId(newProps.width); if (usewidth != nil) { self.usewidth = [RCTConvert RNSVGLength:usewidth]; } self.href = RCTNSStringFromStringNilIfEmpty(newProps.href); setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x = nil; _y = nil; _useheight = nil; _usewidth = nil; _href = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setHref:(NSString *)href { if ([href isEqualToString:_href]) { return; } [self invalidate]; _href = href; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } [self invalidate]; _x = x; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } [self invalidate]; _y = y; } - (void)setUsewidth:(RNSVGLength *)usewidth { if ([usewidth isEqualTo:_usewidth]) { return; } [self invalidate]; _usewidth = usewidth; } - (void)setUseheight:(RNSVGLength *)useheight { if ([useheight isEqualTo:_useheight]) { return; } [self invalidate]; _useheight = useheight; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]); RNSVGNode *definedTemplate = [self.svgView getDefinedTemplate:self.href]; if (definedTemplate) { [self beginTransparencyLayer:context]; [self clip:context]; if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)definedTemplate mergeProperties:self]; } if ([definedTemplate class] == [RNSVGSymbol class]) { RNSVGSymbol *symbol = (RNSVGSymbol *)definedTemplate; [symbol renderSymbolTo:context width:[self relativeOnWidth:self.usewidth] height:[self relativeOnHeight:self.useheight]]; } else { [definedTemplate renderTo:context rect:rect]; } if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) { [(RNSVGRenderable *)definedTemplate resetProperties]; } [self endTransparencyLayer:context]; } else if (self.href) { // TODO: calling yellow box here RCTLogWarn( @"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href); return; } else { return; } CGRect bounds = definedTemplate.clientRect; self.clientRect = bounds; self.pathBounds = definedTemplate.pathBounds; CGAffineTransform current = CGContextGetCTM(context); CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM); self.ctm = svgToClientTransform; self.screenCTM = current; CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); CGPoint center = CGPointApplyAffineTransform(mid, self.matrix); self.bounds = bounds; if (!isnan(center.x) && !isnan(center.y)) { self.center = center; } self.frame = bounds; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); RNSVGNode const *definedTemplate = [self.svgView getDefinedTemplate:self.href]; if (event) { self.active = NO; } else if (self.active) { return self; } RNSVGPlatformView const *hitChild = [definedTemplate hitTest:transformed withEvent:event]; if (hitChild) { self.active = YES; return self; } return nil; } - (CGPathRef)getPath:(CGContextRef)context { CGAffineTransform transform = CGAffineTransformMakeTranslation([self relativeOnWidth:self.x], [self relativeOnHeight:self.y]); RNSVGNode const *definedTemplate = [self.svgView getDefinedTemplate:self.href]; if (!definedTemplate) { return nil; } CGPathRef path = [definedTemplate getPath:context]; return (CGPathRef)CFAutorelease(CGPathCreateCopyByTransformingPath(path, &transform)); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGUseCls(void) { return RNSVGUse.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Filters/MetalCI/RNSVGArithmeticFilter.h ================================================ #import "RNSVGCustomFilter.h" @interface RNSVGArithmeticFilter : RNSVGCustomFilter { CIImage *inputImage2; NSNumber *inputK1; NSNumber *inputK2; NSNumber *inputK3; NSNumber *inputK4; } @end ================================================ FILE: apple/Filters/MetalCI/RNSVGArithmeticFilter.metal ================================================ #include using namespace metal; #include extern "C" float4 RNSVGArithmeticFilter(coreimage::sample_t in1, coreimage::sample_t in2, float k1, float k2, float k3, float k4) { float4 arithmeticResult; arithmeticResult.rgb = k1 * in1.rgb * in2.rgb + k2 * in1.rgb + k3 * in2.rgb + k4; arithmeticResult.a = k1 * in1.a * in2.a + k2 * in1.a + k3 * in2.a + k4; arithmeticResult.rgb = clamp(arithmeticResult.rgb, 0.0, 1.0); arithmeticResult.a = clamp(arithmeticResult.a, 0.0, 1.0); return arithmeticResult; } ================================================ FILE: apple/Filters/MetalCI/RNSVGArithmeticFilter.mm ================================================ #import "RNSVGArithmeticFilter.h" static CIColorKernel *arithmeticFilter = nil; @implementation RNSVGArithmeticFilter - (id)init { if (arithmeticFilter == nil) { arithmeticFilter = [super getWithName:@"RNSVGArithmeticFilter"]; } return [super init]; } - (NSDictionary *)customAttributes { return @{ @"inputImage1" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"CIImage", kCIAttributeDisplayName : @"in1", kCIAttributeType : kCIAttributeTypeImage }, @"inputImage2" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"CIImage", kCIAttributeDisplayName : @"in2", kCIAttributeType : kCIAttributeTypeImage }, @"inputK1" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"NSNumber", kCIAttributeDisplayName : @"k1", kCIAttributeType : kCIAttributeTypeScalar }, @"inputK2" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"NSNumber", kCIAttributeDisplayName : @"k2", kCIAttributeType : kCIAttributeTypeScalar }, @"inputK3" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"NSNumber", kCIAttributeDisplayName : @"k3", kCIAttributeType : kCIAttributeTypeScalar }, @"inputK4" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"NSNumber", kCIAttributeDisplayName : @"k4", kCIAttributeType : kCIAttributeTypeScalar }, }; } - (CIImage *)outputImage { CISampler *in1 = [CISampler samplerWithImage:inputImage1]; CISampler *in2 = [CISampler samplerWithImage:inputImage2]; return [arithmeticFilter applyWithExtent:inputImage1.extent arguments:@[ in1, in2, inputK1, inputK2, inputK3, inputK4 ]]; } @end ================================================ FILE: apple/Filters/MetalCI/RNSVGCompositeXor.h ================================================ #import "RNSVGCustomFilter.h" @interface RNSVGCompositeXor : RNSVGCustomFilter { CIImage *inputImage2; } @end ================================================ FILE: apple/Filters/MetalCI/RNSVGCompositeXor.metal ================================================ #include using namespace metal; #include extern "C" float4 RNSVGCompositeXor(coreimage::sample_t in1, coreimage::sample_t in2) { float4 result; result.rgb = in1.rgb * (1.0 - in2.a) + in2.rgb * (1.0 - in1.a); result.a = in1.a + in2.a - 2.0 * in1.a * in2.a; return result; } ================================================ FILE: apple/Filters/MetalCI/RNSVGCompositeXor.mm ================================================ #import "RNSVGCompositeXor.h" static CIColorKernel *compositeXor = nil; @implementation RNSVGCompositeXor - (id)init { if (compositeXor == nil) { compositeXor = [super getWithName:@"RNSVGCompositeXor"]; } return [super init]; } - (NSDictionary *)customAttributes { return @{ @"inputImage1" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"CIImage", kCIAttributeDisplayName : @"in1", kCIAttributeType : kCIAttributeTypeImage }, @"inputImage2" : @{ kCIAttributeIdentity : @0, kCIAttributeClass : @"CIImage", kCIAttributeDisplayName : @"in2", kCIAttributeType : kCIAttributeTypeImage }, }; } - (CIImage *)outputImage { CISampler *in1 = [CISampler samplerWithImage:inputImage1]; CISampler *in2 = [CISampler samplerWithImage:inputImage2]; return [compositeXor applyWithExtent:inputImage1.extent arguments:@[ in1, in2 ]]; } @end ================================================ FILE: apple/Filters/MetalCI/RNSVGCustomFilter.h ================================================ #import @interface RNSVGCustomFilter : CIFilter { CIImage *inputImage1; } - (CIColorKernel *)getWithName:(NSString *)name; @end ================================================ FILE: apple/Filters/MetalCI/RNSVGCustomFilter.mm ================================================ #import "RNSVGCustomFilter.h" #if TARGET_OS_OSX #define extension @"macosx.metallib" #elif TARGET_OS_IOS #define extension @"iphoneos.metallib" #elif TARGET_OS_TV #define extension @"tvos.metallib" #elif TARGET_OS_VISION #define extension @"xros.metallib" #endif @implementation RNSVGCustomFilter - (CIColorKernel *)getWithName:(NSString *)name { NSBundle *frameworkBundle = [NSBundle bundleForClass:[self class]]; NSURL *bundleUrl = [frameworkBundle.resourceURL URLByAppendingPathComponent:@"RNSVGFilters.bundle"]; NSBundle *bundle = [NSBundle bundleWithURL:bundleUrl]; NSURL *url = [bundle URLForResource:name withExtension:extension]; if (url != nil) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error]; @try { return [CIColorKernel kernelWithFunctionName:name fromMetalLibraryData:data error:&error]; } @catch (NSException *exception) { NSLog(@"RNSVG CustomFilter exception: %@", exception); } } return nil; } @end ================================================ FILE: apple/Filters/RNSVGBlendMode.h ================================================ typedef CF_ENUM(int32_t, RNSVGBlendMode) { SVG_FEBLEND_MODE_UNKNOWN, SVG_FEBLEND_MODE_NORMAL, SVG_FEBLEND_MODE_MULTIPLY, SVG_FEBLEND_MODE_SCREEN, SVG_FEBLEND_MODE_DARKEN, SVG_FEBLEND_MODE_LIGHTEN, }; ================================================ FILE: apple/Filters/RNSVGColorMatrixType.h ================================================ #import typedef NS_ENUM(NSInteger, RNSVGColorMatrixType) { SVG_FECOLORMATRIX_TYPE_UNKNOWN, SVG_FECOLORMATRIX_TYPE_MATRIX, SVG_FECOLORMATRIX_TYPE_SATURATE, SVG_FECOLORMATRIX_TYPE_HUEROTATE, SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA }; ================================================ FILE: apple/Filters/RNSVGCompositeOperator.h ================================================ typedef CF_ENUM(int32_t, RNSVGCompositeOperator) { SVG_FECOMPOSITE_OPERATOR_UNKNOWN, SVG_FECOMPOSITE_OPERATOR_OVER, SVG_FECOMPOSITE_OPERATOR_IN, SVG_FECOMPOSITE_OPERATOR_OUT, SVG_FECOMPOSITE_OPERATOR_ATOP, SVG_FECOMPOSITE_OPERATOR_XOR, SVG_FECOMPOSITE_OPERATOR_ARITHMETIC }; ================================================ FILE: apple/Filters/RNSVGEdgeMode.h ================================================ #import typedef NS_ENUM(NSInteger, RNSVGEdgeMode) { SVG_EDGEMODE_UNKNOWN, SVG_EDGEMODE_DUPLICATE, SVG_EDGEMODE_WRAP, SVG_EDGEMODE_NONE }; ================================================ FILE: apple/Filters/RNSVGFeBlend.h ================================================ #import "RNSVGBlendMode.h" #import "RNSVGFilterPrimitive.h" @interface RNSVGFeBlend : RNSVGFilterPrimitive @property (nonatomic, strong) NSString *in1; @property (nonatomic, strong) NSString *in2; @property (nonatomic, assign) RNSVGBlendMode mode; @end ================================================ FILE: apple/Filters/RNSVGFeBlend.mm ================================================ #import "RNSVGFeBlend.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeBlend #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1); self.in2 = RCTNSStringFromStringNilIfEmpty(newProps.in2); self.mode = [RNSVGConvert RNSVGBlendModeFromCppEquivalent:newProps.mode]; setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _in1 = nil; _in2 = nil; _mode = RNSVGBlendMode::SVG_FEBLEND_MODE_NORMAL; } #endif // RCT_NEW_ARCH_ENABLED - (void)setIn1:(NSString *)in1 { if ([in1 isEqualToString:_in1]) { return; } _in1 = in1; [self invalidate]; } - (void)setIn2:(NSString *)in2 { if ([in2 isEqualToString:_in2]) { return; } _in2 = in2; [self invalidate]; } - (void)setMode:(RNSVGBlendMode)mode { if (mode == _mode) { return; } _mode = mode; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { CIImage *inResults1 = self.in1 ? [results objectForKey:self.in1] : nil; CIImage *inResults2 = self.in2 ? [results objectForKey:self.in2] : nil; CIImage *inputImage1 = inResults1 ? inResults1 : previous; CIImage *inputImage2 = inResults2 ? inResults2 : previous; CIFilter *filter = nil; switch (self.mode) { case SVG_FEBLEND_MODE_NORMAL: filter = [CIFilter filterWithName:@"CISourceOverCompositing"]; break; case SVG_FEBLEND_MODE_MULTIPLY: filter = [CIFilter filterWithName:@"CIMultiplyBlendMode"]; break; case SVG_FEBLEND_MODE_SCREEN: filter = [CIFilter filterWithName:@"CIScreenBlendMode"]; break; case SVG_FEBLEND_MODE_DARKEN: filter = [CIFilter filterWithName:@"CIDarkenBlendMode"]; break; case SVG_FEBLEND_MODE_LIGHTEN: filter = [CIFilter filterWithName:@"CILightenBlendMode"]; break; default: return nil; } [filter setDefaults]; [filter setValue:inputImage1 forKey:@"inputImage"]; [filter setValue:inputImage2 forKey:@"inputBackgroundImage"]; return [filter valueForKey:@"outputImage"]; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeBlendCls(void) { return RNSVGFeBlend.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeColorMatrix.h ================================================ #import "RNSVGColorMatrixType.h" #import "RNSVGFilterPrimitive.h" @interface RNSVGFeColorMatrix : RNSVGFilterPrimitive @property (nonatomic, strong) NSString *in1; @property (nonatomic, assign) RNSVGColorMatrixType type; @property (nonatomic, strong) NSArray *values; @end ================================================ FILE: apple/Filters/RNSVGFeColorMatrix.mm ================================================ #import "RNSVGFeColorMatrix.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeColorMatrix #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1); if (newProps.values.size() > 0) { NSMutableArray *valuesArray = [NSMutableArray new]; for (auto number : newProps.values) { [valuesArray addObject:[NSNumber numberWithFloat:number]]; } self.values = valuesArray; } self.type = [RNSVGConvert RNSVGColorMatrixTypeFromCppEquivalent:newProps.type]; setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _in1 = nil; _values = nil; _type = RNSVGColorMatrixType::SVG_FECOLORMATRIX_TYPE_MATRIX; } #endif // RCT_NEW_ARCH_ENABLED - (void)setIn1:(NSString *)in1 { if ([in1 isEqualToString:_in1]) { return; } _in1 = in1; [self invalidate]; } - (void)setValues:(NSArray *)values { if (values == _values) { return; } _values = values; [self invalidate]; } - (void)setType:(RNSVGColorMatrixType)type { if (type == _type) { return; } _type = type; [self invalidate]; } #define deg2rad(degrees) ((M_PI * degrees) / 180) - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { CIImage *inResults = self.in1 ? [results objectForKey:self.in1] : nil; CIImage *inputImage = inResults ? inResults : previous; CIFilter *filter = nil; NSArray *array = self.values; NSUInteger count = [array count]; switch (self.type) { case SVG_FECOLORMATRIX_TYPE_UNKNOWN: return nil; case SVG_FECOLORMATRIX_TYPE_MATRIX: { if (count != 20) { return nil; } CGFloat v[20] = {0}; for (NSUInteger i = 0; i < count; i++) { v[i] = (CGFloat)[array[i] doubleValue]; } filter = [CIFilter filterWithName:@"CIColorMatrix"]; [filter setDefaults]; [filter setValue:[CIVector vectorWithX:v[0] Y:v[1] Z:v[2] W:v[3]] forKey:@"inputRVector"]; [filter setValue:[CIVector vectorWithX:v[5] Y:v[6] Z:v[7] W:v[8]] forKey:@"inputGVector"]; [filter setValue:[CIVector vectorWithX:v[10] Y:v[11] Z:v[12] W:v[13]] forKey:@"inputBVector"]; [filter setValue:[CIVector vectorWithX:v[15] Y:v[16] Z:v[17] W:v[18]] forKey:@"inputAVector"]; [filter setValue:[CIVector vectorWithX:v[4] Y:v[9] Z:v[14] W:v[19]] forKey:@"inputBiasVector"]; break; } case SVG_FECOLORMATRIX_TYPE_SATURATE: { if (count != 1) { return nil; } float saturation = [array[0] floatValue]; filter = [CIFilter filterWithName:@"CIColorControls"]; [filter setDefaults]; [filter setValue:[NSNumber numberWithFloat:saturation] forKey:@"inputSaturation"]; break; } case SVG_FECOLORMATRIX_TYPE_HUEROTATE: { if (count != 1) { return nil; } double deg = [array[0] doubleValue]; filter = [CIFilter filterWithName:@"CIHueAdjust"]; [filter setDefaults]; float radians = (float)deg2rad(deg); [filter setValue:[NSNumber numberWithFloat:radians] forKey:@"inputAngle"]; break; } case SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA: { if (count != 0) { return nil; } filter = [CIFilter filterWithName:@"CIColorMatrix"]; [filter setDefaults]; CGFloat zero[4] = {0, 0, 0, 0}; CGFloat alpha[4] = {0.2125, 0.7154, 0.0721, 0}; [filter setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputRVector"]; [filter setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputGVector"]; [filter setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBVector"]; [filter setValue:[CIVector vectorWithValues:alpha count:4] forKey:@"inputAVector"]; [filter setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBiasVector"]; break; } default: return nil; } [filter setValue:inputImage forKey:@"inputImage"]; return [filter valueForKey:@"outputImage"]; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeColorMatrixCls(void) { return RNSVGFeColorMatrix.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeComposite.h ================================================ #import "RNSVGArithmeticFilter.h" #import "RNSVGCompositeOperator.h" #import "RNSVGCompositeXor.h" #import "RNSVGFilterPrimitive.h" @interface RNSVGFeComposite : RNSVGFilterPrimitive @property (nonatomic, strong) NSString *in1; @property (nonatomic, strong) NSString *in2; @property (nonatomic, assign) RNSVGCompositeOperator operator1; @property (nonatomic, strong) NSNumber *k1; @property (nonatomic, strong) NSNumber *k2; @property (nonatomic, strong) NSNumber *k3; @property (nonatomic, strong) NSNumber *k4; @end ================================================ FILE: apple/Filters/RNSVGFeComposite.mm ================================================ #import "RNSVGFeComposite.h" #import "RNSVGArithmeticFilter.h" #import "RNSVGCompositeXor.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED static CIColorKernel *thresholdKernel; @implementation RNSVGFeComposite #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1); self.in2 = RCTNSStringFromStringNilIfEmpty(newProps.in2); self.k1 = [NSNumber numberWithFloat:newProps.k1]; self.k2 = [NSNumber numberWithFloat:newProps.k2]; self.k3 = [NSNumber numberWithFloat:newProps.k3]; self.k4 = [NSNumber numberWithFloat:newProps.k4]; self.operator1 = [RNSVGConvert RNSVGRNSVGCompositeOperatorFromCppEquivalent:newProps.operator1]; setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _in1 = nil; _in2 = nil; _k1 = nil; _k2 = nil; _k3 = nil; _k4 = nil; _operator1 = RNSVGCompositeOperator::SVG_FECOMPOSITE_OPERATOR_UNKNOWN; } #endif // RCT_NEW_ARCH_ENABLED - (void)setIn1:(NSString *)in1 { if ([in1 isEqualToString:_in1]) { return; } _in1 = in1; [self invalidate]; } - (void)setIn2:(NSString *)in2 { if ([in2 isEqualToString:_in2]) { return; } _in2 = in2; [self invalidate]; } - (void)setK1:(NSNumber *)k1 { if (k1 == _k1) { return; } _k1 = k1; [self invalidate]; } - (void)setK2:(NSNumber *)k2 { if (k2 == _k2) { return; } _k2 = k2; [self invalidate]; } - (void)setK3:(NSNumber *)k3 { if (k3 == _k3) { return; } _k3 = k3; [self invalidate]; } - (void)setK4:(NSNumber *)k4 { if (k4 == _k4) { return; } _k4 = k4; [self invalidate]; } - (void)setOperator1:(RNSVGCompositeOperator)operator1 { if (operator1 == _operator1) { return; } _operator1 = operator1; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { CIImage *inResults1 = self.in1 ? [results objectForKey:self.in1] : nil; CIImage *inResults2 = self.in2 ? [results objectForKey:self.in2] : nil; CIImage *inputImage1 = inResults1 ? inResults1 : previous; CIImage *inputImage2 = inResults2 ? inResults2 : previous; CIFilter *filter = nil; switch (self.operator1) { case SVG_FECOMPOSITE_OPERATOR_OVER: filter = [CIFilter filterWithName:@"CISourceOverCompositing"]; break; case SVG_FECOMPOSITE_OPERATOR_IN: filter = [CIFilter filterWithName:@"CISourceInCompositing"]; break; case SVG_FECOMPOSITE_OPERATOR_OUT: filter = [CIFilter filterWithName:@"CISourceOutCompositing"]; break; case SVG_FECOMPOSITE_OPERATOR_ATOP: filter = [CIFilter filterWithName:@"CISourceAtopCompositing"]; break; case SVG_FECOMPOSITE_OPERATOR_XOR: filter = [[RNSVGCompositeXor alloc] init]; break; case SVG_FECOMPOSITE_OPERATOR_ARITHMETIC: filter = [[RNSVGArithmeticFilter alloc] init]; break; default: return nil; } [filter setDefaults]; if (self.operator1 == SVG_FECOMPOSITE_OPERATOR_XOR) { [filter setValue:inputImage1 forKey:@"inputImage1"]; [filter setValue:inputImage2 forKey:@"inputImage2"]; } else if (self.operator1 == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) { [filter setValue:inputImage1 forKey:@"inputImage1"]; [filter setValue:inputImage2 forKey:@"inputImage2"]; [filter setValue:(self.k1 != nil ? self.k1 : @0) forKey:@"inputK1"]; [filter setValue:(self.k2 != nil ? self.k2 : @0) forKey:@"inputK2"]; [filter setValue:(self.k3 != nil ? self.k3 : @0) forKey:@"inputK3"]; [filter setValue:(self.k4 != nil ? self.k4 : @0) forKey:@"inputK4"]; } else { [filter setValue:inputImage1 forKey:@"inputImage"]; [filter setValue:inputImage2 forKey:@"inputBackgroundImage"]; } return [filter valueForKey:@"outputImage"]; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeCompositeCls(void) { return RNSVGFeComposite.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeFlood.h ================================================ #import "RNSVGBrush.h" #import "RNSVGFilterPrimitive.h" @interface RNSVGFeFlood : RNSVGFilterPrimitive @property (nonatomic, strong) RNSVGBrush *floodColor; @property (nonatomic, assign) CGFloat floodOpacity; @end ================================================ FILE: apple/Filters/RNSVGFeFlood.mm ================================================ #import "RNSVGFeFlood.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeFlood #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id floodColor = RNSVGConvertFollyDynamicToId(newProps.floodColor); if (floodColor != nil) { self.floodColor = [RCTConvert RNSVGBrush:floodColor]; } self.floodOpacity = newProps.floodOpacity; setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _floodColor = nil; _floodOpacity = 1; } #endif // RCT_NEW_ARCH_ENABLED - (void)setFloodColor:(RNSVGBrush *)floodColor { if (floodColor == _floodColor) { return; } _floodColor = floodColor; [self invalidate]; } - (void)setFloodOpacity:(CGFloat)floodOpacity { if (floodOpacity == _floodOpacity) { return; } _floodOpacity = floodOpacity; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { CGColorRef color = [self.floodColor getColorWithOpacity:self.floodOpacity]; CIImage *image = [CIImage imageWithColor:[CIColor colorWithCGColor:color]]; CGColorRelease(color); return image; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeFloodCls(void) { return RNSVGFeFlood.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeGaussianBlur.h ================================================ #import "RNSVGEdgeMode.h" #import "RNSVGFilterPrimitive.h" @interface RNSVGFeGaussianBlur : RNSVGFilterPrimitive @property (nonatomic, strong) NSString *in1; @property (nonatomic, strong) NSNumber *stdDeviationX; @property (nonatomic, strong) NSNumber *stdDeviationY; @property (nonatomic, assign) RNSVGEdgeMode edgeMode; @end ================================================ FILE: apple/Filters/RNSVGFeGaussianBlur.mm ================================================ #import "RNSVGFeGaussianBlur.h" #import "RNSVGRenderUtils.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeGaussianBlur #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1); self.stdDeviationX = [NSNumber numberWithFloat:newProps.stdDeviationX]; self.stdDeviationY = [NSNumber numberWithFloat:newProps.stdDeviationY]; self.edgeMode = [RNSVGConvert RNSVGEdgeModeFromCppEquivalent:newProps.edgeMode]; setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _in1 = nil; _stdDeviationX = nil; _stdDeviationY = nil; _edgeMode = SVG_EDGEMODE_UNKNOWN; } #endif // RCT_NEW_ARCH_ENABLED - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { CIImage *inResults = self.in1 ? [results objectForKey:self.in1] : nil; CIImage *inputImage = inResults ? inResults : previous; if (!inputImage) { return nil; } // We need to multiply stdDeviation by screenScale to achive the same results as on web CGFloat screenScale = [RNSVGRenderUtils getScreenScale]; CIFilter *filter = [CIFilter filterWithName:(_stdDeviationX == _stdDeviationY ? @"CIGaussianBlur" : @"CIMotionBlur")]; [filter setDefaults]; [filter setValue:inputImage forKey:@"inputImage"]; [filter setValue:@([_stdDeviationX floatValue] * screenScale) forKey:@"inputRadius"]; if (_stdDeviationX != _stdDeviationY) { // X axis [filter setValue:[NSNumber numberWithFloat:0] forKey:@"inputAngle"]; // Y axis [filter setValue:[filter valueForKey:@"outputImage"] forKey:@"inputImage"]; [filter setValue:@([_stdDeviationY floatValue] * screenScale) forKey:@"inputRadius"]; [filter setValue:[NSNumber numberWithFloat:M_PI_2] forKey:@"inputAngle"]; } return [filter valueForKey:@"outputImage"]; } - (void)setIn1:(NSString *)in1 { if ([in1 isEqualToString:_in1]) { return; } _in1 = in1; [self invalidate]; } - (void)setStdDeviationX:(NSNumber *)stdDeviationX { if (stdDeviationX == _stdDeviationX) { return; } _stdDeviationX = stdDeviationX; [self invalidate]; } - (void)setStdDeviationY:(NSNumber *)stdDeviationY { if (stdDeviationY == _stdDeviationY) { return; } _stdDeviationY = stdDeviationY; [self invalidate]; } - (void)setEdgeMode:(RNSVGEdgeMode)edgeMode { if (edgeMode == _edgeMode) { return; } _edgeMode = edgeMode; [self invalidate]; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeGaussianBlurCls(void) { return RNSVGFeGaussianBlur.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeMerge.h ================================================ #import "RNSVGFilterPrimitive.h" @interface RNSVGFeMerge : RNSVGFilterPrimitive @property (nonatomic, copy) NSArray *nodes; @end ================================================ FILE: apple/Filters/RNSVGFeMerge.mm ================================================ #import "RNSVGFeMerge.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeMerge #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); if (newProps.nodes.size() > 0) { NSMutableArray *nodesArray = [NSMutableArray new]; for (auto node : newProps.nodes) { [nodesArray addObject:[NSString stringWithCString:node.c_str() encoding:NSUTF8StringEncoding]]; } self.nodes = nodesArray; } setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _nodes = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setNodes:(NSArray *)nodes { if (nodes == _nodes) { return; } _nodes = nodes; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous ctm:(CGAffineTransform)ctm { CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"]; [filter setDefaults]; CIImage *result; for (int i = 0; i < (int)[self.nodes count]; i++) { NSString *nodeKey = [self.nodes objectAtIndex:i]; CIImage *inputImage = [nodeKey isEqual:@""] ? previous : [results objectForKey:nodeKey]; if (inputImage == nil) { continue; } if (result == nil) { result = inputImage; continue; } [filter setValue:result forKey:@"inputBackgroundImage"]; [filter setValue:inputImage forKey:@"inputImage"]; result = [filter valueForKey:@"outputImage"]; } return result; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeMergeCls(void) { return RNSVGFeMerge.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFeOffset.h ================================================ #import "RNSVGFilterPrimitive.h" @interface RNSVGFeOffset : RNSVGFilterPrimitive @property (nonatomic, strong) NSString *in1; @property (nonatomic, strong) RNSVGLength *dx; @property (nonatomic, strong) RNSVGLength *dy; @end ================================================ FILE: apple/Filters/RNSVGFeOffset.mm ================================================ #import "RNSVGFeOffset.h" #if TARGET_OS_OSX #import "RNSVGRenderUtils.h" #endif #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFeOffset #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1); id dx = RNSVGConvertFollyDynamicToId(newProps.dx); if (dx != nil) { self.dx = [RCTConvert RNSVGLength:dx]; } id dy = RNSVGConvertFollyDynamicToId(newProps.dy); if (dy != nil) { self.dy = [RCTConvert RNSVGLength:dy]; } setCommonFilterProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _in1 = nil; _dx = nil; _dy = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setIn1:(NSString *)in1 { if ([in1 isEqualToString:_in1]) { return; } _in1 = in1; [self invalidate]; } - (void)setDx:(RNSVGLength *)dx { if ([dx isEqualTo:_dx]) { return; } _dx = dx; [self invalidate]; } - (void)setDy:(RNSVGLength *)dy { if ([dy isEqualTo:_dy]) { return; } _dy = dy; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous ctm:(CGAffineTransform)ctm { CIImage *inResults = self.in1 ? [results objectForKey:self.in1] : nil; CIImage *inputImage = inResults ? inResults : previous; if (!inputImage) { return nil; } CIFilter *filter = [CIFilter filterWithName:@"CIAffineTransform"]; [filter setDefaults]; [filter setValue:inputImage forKey:@"inputImage"]; CGFloat dx = [self relativeOnWidth:self.dx]; CGFloat dy = [self relativeOnWidth:self.dy]; // reset ctm translation CGAffineTransform contextTransform = CGAffineTransformConcat(ctm, CGAffineTransformMakeTranslation(-ctm.tx, -ctm.ty)); #if !TARGET_OS_OSX // [macOS] CGPoint translate = CGPointMake(dx, dy); #else // [macOS CGPoint translate = CGPointMake(dx, dy); CGFloat scale = [RNSVGRenderUtils getScreenScale]; CGAffineTransform screenScaleCTM = CGAffineTransformMake(scale, 0, 0, scale, 0, 0); translate = CGPointApplyAffineTransform(translate, screenScaleCTM); #endif // macOS] translate = CGPointApplyAffineTransform(translate, contextTransform); CGAffineTransform transform = CGAffineTransformMakeTranslation(translate.x, translate.y); [filter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:@"inputTransform"]; return [filter valueForKey:@"outputImage"]; } #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFeOffsetCls(void) { return RNSVGFeOffset.class; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/Filters/RNSVGFilter.h ================================================ #import "RNSVGFilterRegion.h" #import "RNSVGNode.h" @interface RNSVGFilter : RNSVGNode @property (nonatomic, assign) RNSVGUnits filterUnits; @property (nonatomic, assign) RNSVGUnits primitiveUnits; @property (nonatomic, strong) RNSVGFilterRegion *filterRegion; - (CIImage *)applyFilter:(CIImage *)img backgroundImg:(CIImage *)backgroundImg renderableBounds:(CGRect)renderableBounds canvasBounds:(CGRect)canvasBounds ctm:(CGAffineTransform)ctm; - (CGContext *)openContext:(CGSize)size; - (void)endContext:(CGContext *)context; - (CIImage *)getMaskFromRect:(CGContext *)context rect:(CGRect)rect ctm:(CGAffineTransform)ctm; - (void)setX:(RNSVGLength *)x; - (void)setY:(RNSVGLength *)y; - (void)setWidth:(RNSVGLength *)width; - (void)setHeight:(RNSVGLength *)height; @end ================================================ FILE: apple/Filters/RNSVGFilter.mm ================================================ #import "RNSVGFilter.h" #import "RNSVGFilterPrimitive.h" #import "RNSVGRenderUtils.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import "RNSVGConvert.h" #import "RNSVGFabricConversions.h" #import "rnsvg/RNSVGComponentDescriptors.h" #endif // RCT_NEW_ARCH_ENABLED #if TARGET_OS_OSX // [macOS #import "RNSVGUIKit.h" #endif // macOS] @implementation RNSVGFilter { NSMutableDictionary *resultsMap; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.name = RCTNSStringFromStringNilIfEmpty(newProps.name); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id height = RNSVGConvertFollyDynamicToId(newProps.height); if (height != nil) { self.height = [RCTConvert RNSVGLength:height]; } id width = RNSVGConvertFollyDynamicToId(newProps.width); if (width != nil) { self.width = [RCTConvert RNSVGLength:width]; } self.filterUnits = [RNSVGConvert RNSVGUnitsFromFilterUnitsCppEquivalent:newProps.filterUnits]; self.primitiveUnits = [RNSVGConvert RNSVGUnitsFromPrimitiveUnitsCppEquivalent:newProps.primitiveUnits]; _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _filterUnits = kRNSVGUnitsObjectBoundingBox; _primitiveUnits = kRNSVGUnitsUserSpaceOnUse; _filterRegion = [[RNSVGFilterRegion alloc] init]; } #endif // RCT_NEW_ARCH_ENABLED - (id)init { if (self = [super init]) { resultsMap = [NSMutableDictionary dictionary]; _filterRegion = [[RNSVGFilterRegion alloc] init]; } return self; } - (CIImage *)applyFilter:(CIImage *)img backgroundImg:(CIImage *)backgroundImg renderableBounds:(CGRect)renderableBounds canvasBounds:(CGRect)canvasBounds ctm:(CGAffineTransform)ctm { [resultsMap removeAllObjects]; [resultsMap setObject:img forKey:@"SourceGraphic"]; [resultsMap setObject:applySourceAlphaFilter(img) forKey:@"SourceAlpha"]; [resultsMap setObject:backgroundImg forKey:@"BackgroundImage"]; [resultsMap setObject:applySourceAlphaFilter(backgroundImg) forKey:@"BackgroundAlpha"]; // Setup crop filter CGRect cropRect; CIFilter *cropFilter = [CIFilter filterWithName:@"CIBlendWithMask"]; [cropFilter setDefaults]; [cropFilter setValue:nil forKey:@"inputBackgroundImage"]; CGContext *cropContext = [self openContext:canvasBounds.size]; CIImage *mask; CGRect filterRegionRect = [self.filterRegion getCropRect:self units:self.filterUnits bounds:renderableBounds]; CIImage *result = img; RNSVGFilterPrimitive *currentFilter; for (RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGFilterPrimitive class]]) { currentFilter = (RNSVGFilterPrimitive *)node; cropRect = [currentFilter.filterSubregion getCropRect:currentFilter units:self.primitiveUnits bounds:self.primitiveUnits == kRNSVGUnitsUserSpaceOnUse ? filterRegionRect : renderableBounds]; mask = [self getMaskFromRect:cropContext rect:cropRect ctm:ctm]; [cropFilter setValue:[currentFilter applyFilter:resultsMap previousFilterResult:result ctm:ctm] forKey:@"inputImage"]; [cropFilter setValue:mask forKey:@"inputMaskImage"]; CGContextClearRect(cropContext, canvasBounds); CGImageRef cgResult = [[RNSVGRenderUtils sharedCIContext] createCGImage:[cropFilter valueForKey:@"outputImage"] fromRect:[result extent]]; result = [CIImage imageWithCGImage:cgResult]; CGImageRelease(cgResult); if (result != nil && currentFilter.result) { [resultsMap setObject:result forKey:currentFilter.result]; } } else { RCTLogError(@"Invalid `Filter` subview: Filter children can only be `Fe...` components"); } } mask = [self getMaskFromRect:cropContext rect:filterRegionRect ctm:ctm]; [cropFilter setValue:result forKey:@"inputImage"]; [cropFilter setValue:mask forKey:@"inputMaskImage"]; [self endContext:cropContext]; return [cropFilter valueForKey:@"outputImage"]; } - (CGContext *)openContext:(CGSize)size { RNSVGUIGraphicsBeginImageContextWithOptions(size, NO, 1.0); CGContextRef cropContext = UIGraphicsGetCurrentContext(); #if TARGET_OS_OSX CGFloat scale = [RNSVGRenderUtils getScreenScale]; CGContextScaleCTM(cropContext, scale, scale); #else CGContextTranslateCTM(cropContext, 0, size.height); CGContextScaleCTM(cropContext, 1, -1); #endif return cropContext; } - (void)endContext:(CGContext *)context { RNSVGUIGraphicsEndImageContext(); } - (CIImage *)getMaskFromRect:(CGContext *)context rect:(CGRect)rect ctm:(CGAffineTransform)ctm { CGPathRef path = CGPathCreateWithRect(rect, nil); CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(path, &ctm); CGPathRelease(path); CGContextSetRGBFillColor(context, 255, 255, 255, 255); CGContextAddPath(context, transformedPath); CGContextFillPath(context); CGPathRelease(transformedPath); CGImage *maskImage = CGBitmapContextCreateImage(context); CIImage *ciMaskImage = [CIImage imageWithCGImage:maskImage]; CGImageRelease(maskImage); return ciMaskImage; } static CIFilter *sourceAlphaFilter() { CIFilter *sourceAlpha = [CIFilter filterWithName:@"CIColorMatrix"]; CGFloat zero[4] = {0, 0, 0, 0}; [sourceAlpha setDefaults]; [sourceAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputRVector"]; [sourceAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputGVector"]; [sourceAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBVector"]; [sourceAlpha setValue:[CIVector vectorWithX:0.0 Y:0.0 Z:0.0 W:1.0] forKey:@"inputAVector"]; [sourceAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBiasVector"]; return sourceAlpha; } static CIImage *applySourceAlphaFilter(CIImage *inputImage) { CIFilter *sourceAlpha = sourceAlphaFilter(); [sourceAlpha setValue:inputImage forKey:@"inputImage"]; return [sourceAlpha valueForKey:@"outputImage"]; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { [self.svgView defineFilter:self filterName:self.name]; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_filterRegion.x]) { return; } [_filterRegion setX:x]; [self invalidate]; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_filterRegion.y]) { return; } [_filterRegion setY:y]; [self invalidate]; } - (void)setWidth:(RNSVGLength *)width { if ([width isEqualTo:_filterRegion.width]) { return; } [_filterRegion setWidth:width]; [self invalidate]; } - (void)setHeight:(RNSVGLength *)height { if ([height isEqualTo:_filterRegion.height]) { return; } [_filterRegion setHeight:height]; [self invalidate]; } - (void)setFilterUnits:(RNSVGUnits)filterUnits { if (filterUnits == _filterUnits) { return; } _filterUnits = filterUnits; [self invalidate]; } - (void)setPrimitiveUnits:(RNSVGUnits)primitiveUnits { if (primitiveUnits == _primitiveUnits) { return; } _primitiveUnits = primitiveUnits; [self invalidate]; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGFilterCls(void) { return RNSVGFilter.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Filters/RNSVGFilterPrimitive.h ================================================ #import "RNSVGFilterRegion.h" #import "RNSVGNode.h" @interface RNSVGFilterPrimitive : RNSVGNode @property (nonatomic, strong) NSString *result; @property (nonatomic, strong) RNSVGFilterRegion *filterSubregion; - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous; - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous ctm:(CGAffineTransform)ctm; - (void)setX:(RNSVGLength *)x; - (void)setY:(RNSVGLength *)y; - (void)setWidth:(RNSVGLength *)width; - (void)setHeight:(RNSVGLength *)height; @end ================================================ FILE: apple/Filters/RNSVGFilterPrimitive.mm ================================================ #import "RNSVGFilterPrimitive.h" #import "RNSVGFilter.h" #import "RNSVGNode.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGFilterPrimitive #ifdef RCT_NEW_ARCH_ENABLED - (void)prepareForRecycle { [super prepareForRecycle]; _filterSubregion = [[RNSVGFilterRegion alloc] init]; _result = nil; } #endif // RCT_NEW_ARCH_ENABLED - (instancetype)init { self = [super init]; if (self) { _filterSubregion = [[RNSVGFilterRegion alloc] init]; } return self; } - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } - (void)parseReference { } - (void)invalidate { self.dirty = false; [super invalidate]; } - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_filterSubregion.x]) { return; } [_filterSubregion setX:x]; [self invalidate]; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_filterSubregion.y]) { return; } [_filterSubregion setY:y]; [self invalidate]; } - (void)setWidth:(RNSVGLength *)width { if ([width isEqualTo:_filterSubregion.width]) { return; } [_filterSubregion setWidth:width]; [self invalidate]; } - (void)setHeight:(RNSVGLength *)height { if ([height isEqualTo:_filterSubregion.height]) { return; } [_filterSubregion setHeight:height]; [self invalidate]; } - (void)setResult:(NSString *)result { if ([result isEqualToString:_result]) { return; } _result = result; [self invalidate]; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous { return previous; } - (CIImage *)applyFilter:(NSMutableDictionary *)results previousFilterResult:(CIImage *)previous ctm:(CGAffineTransform)ctm { return [self applyFilter:results previousFilterResult:previous]; } @end ================================================ FILE: apple/Filters/RNSVGFilterRegion.h ================================================ #import "RNSVGNode.h" #import "RNSVGUnits.h" #ifndef RNSVGFilterRegion_h #define RNSVGFilterRegion_h @interface RNSVGFilterRegion : NSObject @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *width; @property (nonatomic, strong) RNSVGLength *height; + (instancetype)regionWithX:(RNSVGLength *)x y:(RNSVGLength *)y width:(RNSVGLength *)width height:(RNSVGLength *)height; - (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units bounds:(CGRect)bounds; @end #endif /* RNSVGFilterRegion_h */ ================================================ FILE: apple/Filters/RNSVGFilterRegion.mm ================================================ #import @implementation RNSVGFilterRegion - (instancetype)init { self = [super init]; return self; } + (instancetype)regionWithX:(RNSVGLength *)x y:(RNSVGLength *)y width:(RNSVGLength *)width height:(RNSVGLength *)height { RNSVGFilterRegion *filterRegion = [[self alloc] init]; filterRegion.x = x; filterRegion.y = y; filterRegion.width = width; filterRegion.height = height; return filterRegion; } - (void)setX:(RNSVGLength *)x { _x = x; } - (void)setY:(RNSVGLength *)y { _y = y; } - (void)setWidth:(RNSVGLength *)width { _width = width; } - (void)setHeight:(RNSVGLength *)height { _height = height; } + (CGFloat)getRelativeOrDefault:(RNSVGNode *)node value:(RNSVGLength *)value relativeOn:(CGFloat)relativeOn defaultValue:(CGFloat)defaultValue { if (value == nil || value.unit == SVG_LENGTHTYPE_UNKNOWN) { return defaultValue; } return [node relativeOn:value relative:relativeOn]; } - (CGRect)getCropRect:(RNSVGNode *)node units:(RNSVGUnits)units bounds:(CGRect)bounds { CGFloat x, y, width, height; if (units == kRNSVGUnitsObjectBoundingBox) { x = [node relativeOnFraction:self.x relative:bounds.size.width]; y = [node relativeOnFraction:self.y relative:bounds.size.height]; width = [node relativeOnFraction:self.width relative:bounds.size.width]; height = [node relativeOnFraction:self.height relative:bounds.size.height]; return CGRectMake(bounds.origin.x + x, bounds.origin.y + y, width, height); } else { // kRNSVGUnitsUserSpaceOnUse x = [RNSVGFilterRegion getRelativeOrDefault:node value:self.x relativeOn:[node getCanvasWidth] defaultValue:bounds.origin.x]; y = [RNSVGFilterRegion getRelativeOrDefault:node value:self.y relativeOn:[node getCanvasHeight] defaultValue:bounds.origin.y]; width = [RNSVGFilterRegion getRelativeOrDefault:node value:self.width relativeOn:[node getCanvasWidth] defaultValue:bounds.size.width]; height = [RNSVGFilterRegion getRelativeOrDefault:node value:self.height relativeOn:[node getCanvasHeight] defaultValue:bounds.size.height]; return CGRectMake(x, y, width, height); } } @end ================================================ FILE: apple/RNSVG.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */; }; 0CF68B0B1AF0549300FF9E5C /* RNSVGBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* RNSVGBrush.m */; }; 0CF68B0F1AF0549300FF9E5C /* RNSVGSolidColorBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* RNSVGSolidColorBrush.m */; }; 1023B48D1D3DDCCE0051496D /* RNSVGDefsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48C1D3DDCCE0051496D /* RNSVGDefsManager.m */; }; 1023B4901D3DF4C40051496D /* RNSVGDefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48F1D3DF4C40051496D /* RNSVGDefs.m */; }; 1023B4931D3DF5060051496D /* RNSVGUse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4921D3DF5060051496D /* RNSVGUse.m */; }; 1023B4961D3DF57D0051496D /* RNSVGUseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */; }; 1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */; }; 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; }; 1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; }; 1039D28C1CE71EB7001E90A8 /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */; }; 1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2901CE71EC2001E90A8 /* RNSVGText.m */; }; 1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */; }; 10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */; }; 10BA0D351CE74E3100887C2B /* RNSVGEllipseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D1F1CE74E3100887C2B /* RNSVGEllipseManager.m */; }; 10BA0D361CE74E3100887C2B /* RNSVGGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D211CE74E3100887C2B /* RNSVGGroupManager.m */; }; 10BA0D371CE74E3100887C2B /* RNSVGImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D231CE74E3100887C2B /* RNSVGImageManager.m */; }; 10BA0D381CE74E3100887C2B /* RNSVGLineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D251CE74E3100887C2B /* RNSVGLineManager.m */; }; 10BA0D391CE74E3100887C2B /* RNSVGNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D271CE74E3100887C2B /* RNSVGNodeManager.m */; }; 10BA0D3A1CE74E3100887C2B /* RNSVGPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D291CE74E3100887C2B /* RNSVGPathManager.m */; }; 10BA0D3B1CE74E3100887C2B /* RNSVGRectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D2B1CE74E3100887C2B /* RNSVGRectManager.m */; }; 10BA0D3C1CE74E3100887C2B /* RNSVGRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D2D1CE74E3100887C2B /* RNSVGRenderableManager.m */; }; 10BA0D3E1CE74E3100887C2B /* RNSVGSvgViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D311CE74E3100887C2B /* RNSVGSvgViewManager.m */; }; 10BA0D3F1CE74E3100887C2B /* RNSVGTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D331CE74E3100887C2B /* RNSVGTextManager.m */; }; 10BA0D481CE74E3D00887C2B /* RNSVGCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D411CE74E3D00887C2B /* RNSVGCircle.m */; }; 10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */; }; 10BA0D4A1CE74E3D00887C2B /* RNSVGLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D451CE74E3D00887C2B /* RNSVGLine.m */; }; 10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */; }; 10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */; }; 10BEC1BD1D3F66F500FDCB19 /* RNSVGRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */; }; 10BEC1C21D3F680F00FDCB19 /* RNSVGLinearGradientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1BF1D3F680F00FDCB19 /* RNSVGLinearGradientManager.m */; }; 10BEC1C31D3F680F00FDCB19 /* RNSVGRadialGradientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1C11D3F680F00FDCB19 /* RNSVGRadialGradientManager.m */; }; 10BEC1C61D3F7BD300FDCB19 /* RNSVGPainter.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1C51D3F7BD300FDCB19 /* RNSVGPainter.m */; }; 10ED4A9B1CF065260078BC02 /* RNSVGClipPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */; }; 10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */; }; 10ED4AA21CF078830078BC02 /* RNSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4AA11CF078830078BC02 /* RNSVGNode.m */; }; 10FDEEB21D3FB60500A5C46C /* RNSVGPainterBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 10FDEEB11D3FB60500A5C46C /* RNSVGPainterBrush.m */; }; 167AF4572087C26F0035AA75 /* RNSVGBezierElement.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895A820352B35004DBF1E /* RNSVGBezierElement.m */; }; 167AF4582087C2910035AA75 /* RNSVGFontData.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895B020352B9B004DBF1E /* RNSVGFontData.m */; }; 167AF4592087C2950035AA75 /* RNSVGGlyphContext.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895AF20352B9B004DBF1E /* RNSVGGlyphContext.m */; }; 167AF45A2087C2990035AA75 /* RNSVGPropHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895AB20352B9B004DBF1E /* RNSVGPropHelper.m */; }; 167AF45B2087C2A10035AA75 /* RNSVGTextProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895A62035274F004DBF1E /* RNSVGTextProperties.m */; }; 1687FE772422B4B800741CCB /* RNSVGForeignObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 1687FE762422B4B800741CCB /* RNSVGForeignObject.m */; }; 1691FD1A2422B74500C5277B /* RNSVGForeignObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1691FD192422B74500C5277B /* RNSVGForeignObjectManager.m */; }; 7F08CE9A1E23476900650F83 /* RNSVGTextPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE971E23476900650F83 /* RNSVGTextPathManager.m */; }; 7F08CE9B1E23476900650F83 /* RNSVGTSpanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */; }; 7F08CEA01E23479700650F83 /* RNSVGTextPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */; }; 7F08CEA11E23479700650F83 /* RNSVGTSpan.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */; }; 7F9CDAFA1E1F809C00E0C805 /* RNSVGPathParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */; }; 7FC260CE1E3499BC00A39833 /* RNSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */; }; 7FC260D11E34A12000A39833 /* RNSVGSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */; }; 7FC260D41E34A12A00A39833 /* RNSVGSymbolManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */; }; 94241666213B0D4500088E93 /* RNSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 94241665213B0D4500088E93 /* RNSVGPattern.m */; }; 94241667213B0D4500088E93 /* RNSVGPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 94241665213B0D4500088E93 /* RNSVGPattern.m */; }; 9424166D213B302600088E93 /* RNSVGPatternManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9424166C213B302600088E93 /* RNSVGPatternManager.m */; }; 9424166E213B302600088E93 /* RNSVGPatternManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9424166C213B302600088E93 /* RNSVGPatternManager.m */; }; 947F380B214810DC00677F2A /* RNSVGMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380A214810DC00677F2A /* RNSVGMask.m */; }; 947F380C214810DC00677F2A /* RNSVGMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380A214810DC00677F2A /* RNSVGMask.m */; }; 947F380F2148119A00677F2A /* RNSVGMaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380E2148119A00677F2A /* RNSVGMaskManager.m */; }; 947F38102148119A00677F2A /* RNSVGMaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 947F380E2148119A00677F2A /* RNSVGMaskManager.m */; }; 9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */; }; 9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */; }; 9482DF02234680A200FC486E /* RNSVGPathMeasure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */; }; 9482DF03234680A200FC486E /* RNSVGPathMeasure.m in Sources */ = {isa = PBXBuildFile; fileRef = 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */; }; 9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */; }; 9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4D91F473BCB00D5BCFD /* CoreText.framework */; }; 9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */; }; 9494C4DE1F473BDD00D5BCFD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DD1F473BDD00D5BCFD /* UIKit.framework */; }; 9494C4E01F473BED00D5BCFD /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4DF1F473BED00D5BCFD /* Accelerate.framework */; }; 9494C4E21F473BF500D5BCFD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9494C4E11F473BF500D5BCFD /* Foundation.framework */; }; 94A178F72344094E00693CB3 /* RNSVGMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178F52344094D00693CB3 /* RNSVGMarker.m */; }; 94A178F82344094E00693CB3 /* RNSVGMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178F52344094D00693CB3 /* RNSVGMarker.m */; }; 94A178FB2344095C00693CB3 /* RNSVGMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178F92344095C00693CB3 /* RNSVGMarkerManager.m */; }; 94A178FC2344095C00693CB3 /* RNSVGMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178F92344095C00693CB3 /* RNSVGMarkerManager.m */; }; 94A178FF2344097B00693CB3 /* RNSVGMarkerPosition.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178FE2344097B00693CB3 /* RNSVGMarkerPosition.m */; }; 94A179002344097B00693CB3 /* RNSVGMarkerPosition.m in Sources */ = {isa = PBXBuildFile; fileRef = 94A178FE2344097B00693CB3 /* RNSVGMarkerPosition.m */; }; 94F00C5621780D2E00384EA4 /* RNSVGLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 94F00C5521780D2E00384EA4 /* RNSVGLength.m */; }; 94F00C5721780D2E00384EA4 /* RNSVGLength.m in Sources */ = {isa = PBXBuildFile; fileRef = 94F00C5521780D2E00384EA4 /* RNSVGLength.m */; }; A361E76E1EB0C33D00646005 /* RNSVGTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D331CE74E3100887C2B /* RNSVGTextManager.m */; }; A361E76F1EB0C33D00646005 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; }; A361E7701EB0C33D00646005 /* RNSVGRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */; }; A361E7711EB0C33D00646005 /* RNSVGCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */; }; A361E7721EB0C33D00646005 /* RNSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */; }; A361E7751EB0C33D00646005 /* RNSVGEllipse.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */; }; A361E7761EB0C33D00646005 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; }; A361E7771EB0C33D00646005 /* RNSVGTextPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */; }; A361E7781EB0C33D00646005 /* RNSVGUse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4921D3DF5060051496D /* RNSVGUse.m */; }; A361E7791EB0C33D00646005 /* RNSVGLinearGradientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1BF1D3F680F00FDCB19 /* RNSVGLinearGradientManager.m */; }; A361E77A1EB0C33D00646005 /* RNSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2901CE71EC2001E90A8 /* RNSVGText.m */; }; A361E77B1EB0C33D00646005 /* RNSVGRectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D2B1CE74E3100887C2B /* RNSVGRectManager.m */; }; A361E77C1EB0C33D00646005 /* RNSVGRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */; }; A361E77D1EB0C33D00646005 /* RNSVGGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */; }; A361E77E1EB0C33D00646005 /* RNSVGClipPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */; }; A361E77F1EB0C33D00646005 /* RNSVGPainter.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1C51D3F7BD300FDCB19 /* RNSVGPainter.m */; }; A361E7801EB0C33D00646005 /* RNSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4AA11CF078830078BC02 /* RNSVGNode.m */; }; A361E7811EB0C33D00646005 /* RNSVGClipPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */; }; A361E7821EB0C33D00646005 /* RNSVGSvgViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D311CE74E3100887C2B /* RNSVGSvgViewManager.m */; }; A361E7831EB0C33D00646005 /* RNSVGSolidColorBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* RNSVGSolidColorBrush.m */; }; A361E7841EB0C33D00646005 /* RNSVGPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D291CE74E3100887C2B /* RNSVGPathManager.m */; }; A361E7861EB0C33D00646005 /* RNSVGRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D2D1CE74E3100887C2B /* RNSVGRenderableManager.m */; }; A361E7871EB0C33D00646005 /* RNSVGRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */; }; A361E7881EB0C33D00646005 /* RNSVGRadialGradientManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BEC1C11D3F680F00FDCB19 /* RNSVGRadialGradientManager.m */; }; A361E7891EB0C33D00646005 /* RNSVGImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D231CE74E3100887C2B /* RNSVGImageManager.m */; }; A361E78A1EB0C33D00646005 /* RNSVGNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D271CE74E3100887C2B /* RNSVGNodeManager.m */; }; A361E78B1EB0C33D00646005 /* RNSVGSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */; }; A361E78C1EB0C33D00646005 /* RNSVGDefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48F1D3DF4C40051496D /* RNSVGDefs.m */; }; A361E78D1EB0C33D00646005 /* RNSVGLineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D251CE74E3100887C2B /* RNSVGLineManager.m */; }; A361E78E1EB0C33D00646005 /* RNSVGCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D411CE74E3D00887C2B /* RNSVGCircle.m */; }; A361E78F1EB0C33D00646005 /* RNSVGEllipseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D1F1CE74E3100887C2B /* RNSVGEllipseManager.m */; }; A361E7901EB0C33D00646005 /* RCTConvert+RNSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */; }; A361E7911EB0C33D00646005 /* RNSVGBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* RNSVGBrush.m */; }; A361E7921EB0C33D00646005 /* RNSVGSymbolManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */; }; A361E7931EB0C33D00646005 /* RNSVGPathParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */; }; A361E7941EB0C33D00646005 /* RNSVGGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D211CE74E3100887C2B /* RNSVGGroupManager.m */; }; A361E7951EB0C33D00646005 /* RNSVGTextPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE971E23476900650F83 /* RNSVGTextPathManager.m */; }; A361E7961EB0C33D00646005 /* RNSVGTSpanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */; }; A361E7971EB0C33D00646005 /* RNSVGViewBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */; }; A361E7981EB0C33D00646005 /* RNSVGTSpan.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */; }; A361E7991EB0C33D00646005 /* RNSVGLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D451CE74E3D00887C2B /* RNSVGLine.m */; }; A361E79A1EB0C33D00646005 /* RNSVGPainterBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 10FDEEB11D3FB60500A5C46C /* RNSVGPainterBrush.m */; }; A361E79B1EB0C33D00646005 /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */; }; A361E79C1EB0C33D00646005 /* RNSVGUseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */; }; A361E79D1EB0C33D00646005 /* RNSVGDefsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1023B48C1D3DDCCE0051496D /* RNSVGDefsManager.m */; }; B56895A720352750004DBF1E /* RNSVGTextProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895A62035274F004DBF1E /* RNSVGTextProperties.m */; }; B56895AA20352B36004DBF1E /* RNSVGBezierElement.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895A820352B35004DBF1E /* RNSVGBezierElement.m */; }; B56895B120352B9C004DBF1E /* RNSVGPropHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895AB20352B9B004DBF1E /* RNSVGPropHelper.m */; }; B56895B220352B9C004DBF1E /* RNSVGGlyphContext.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895AF20352B9B004DBF1E /* RNSVGGlyphContext.m */; }; B56895B320352B9C004DBF1E /* RNSVGFontData.m in Sources */ = {isa = PBXBuildFile; fileRef = B56895B020352B9B004DBF1E /* RNSVGFontData.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 0CF68ABF1AF0540F00FF9E5C /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; A361E79F1EB0C33D00646005 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0CF68AC11AF0540F00FF9E5C /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNSVG.a; sourceTree = BUILT_PRODUCTS_DIR; }; 0CF68AE11AF0549300FF9E5C /* RNSVGRenderable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGRenderable.h; sourceTree = ""; }; 0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGRenderable.m; sourceTree = ""; }; 0CF68AEB1AF0549300FF9E5C /* RNSVGBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGBrush.h; sourceTree = ""; }; 0CF68AEC1AF0549300FF9E5C /* RNSVGBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGBrush.m; sourceTree = ""; }; 0CF68AF31AF0549300FF9E5C /* RNSVGSolidColorBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSolidColorBrush.h; sourceTree = ""; }; 0CF68AF41AF0549300FF9E5C /* RNSVGSolidColorBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSolidColorBrush.m; sourceTree = ""; }; 1023B48B1D3DDCCE0051496D /* RNSVGDefsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGDefsManager.h; sourceTree = ""; }; 1023B48C1D3DDCCE0051496D /* RNSVGDefsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGDefsManager.m; sourceTree = ""; }; 1023B48E1D3DF4C40051496D /* RNSVGDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGDefs.h; path = Elements/RNSVGDefs.h; sourceTree = ""; }; 1023B48F1D3DF4C40051496D /* RNSVGDefs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGDefs.m; path = Elements/RNSVGDefs.m; sourceTree = ""; }; 1023B4911D3DF5060051496D /* RNSVGUse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGUse.h; path = Elements/RNSVGUse.h; sourceTree = ""; }; 1023B4921D3DF5060051496D /* RNSVGUse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGUse.m; path = Elements/RNSVGUse.m; sourceTree = ""; }; 1023B4941D3DF57D0051496D /* RNSVGUseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGUseManager.h; sourceTree = ""; }; 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGUseManager.m; sourceTree = ""; }; 1039D2811CE71EB7001E90A8 /* RNSVGGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGGroup.h; path = Elements/RNSVGGroup.h; sourceTree = ""; }; 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGGroup.m; path = Elements/RNSVGGroup.m; sourceTree = ""; }; 1039D2831CE71EB7001E90A8 /* RNSVGImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGImage.h; path = Elements/RNSVGImage.h; sourceTree = ""; }; 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGImage.m; path = Elements/RNSVGImage.m; sourceTree = ""; }; 1039D2851CE71EB7001E90A8 /* RNSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPath.h; path = Elements/RNSVGPath.h; sourceTree = ""; }; 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPath.m; path = Elements/RNSVGPath.m; sourceTree = ""; }; 1039D2871CE71EB7001E90A8 /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGSvgView.h; path = Elements/RNSVGSvgView.h; sourceTree = ""; }; 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSvgView.m; path = Elements/RNSVGSvgView.m; sourceTree = ""; }; 1039D28F1CE71EC2001E90A8 /* RNSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGText.h; path = Text/RNSVGText.h; sourceTree = ""; }; 1039D2901CE71EC2001E90A8 /* RNSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGText.m; path = Text/RNSVGText.m; sourceTree = ""; }; 1039D29B1CE72177001E90A8 /* RCTConvert+RNSVG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "RCTConvert+RNSVG.h"; path = "Utils/RCTConvert+RNSVG.h"; sourceTree = ""; }; 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+RNSVG.m"; path = "Utils/RCTConvert+RNSVG.m"; sourceTree = ""; }; 1039D2A11CE721A7001E90A8 /* RNSVGContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGContainer.h; sourceTree = ""; }; 10ABC7371D439779006CCF6E /* RNSVGCGFCRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGCGFCRule.h; path = Utils/RNSVGCGFCRule.h; sourceTree = ""; }; 10ABC7381D43982B006CCF6E /* RNSVGVBMOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGVBMOS.h; path = Utils/RNSVGVBMOS.h; sourceTree = ""; }; 10BA0D1C1CE74E3100887C2B /* RNSVGCircleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGCircleManager.h; sourceTree = ""; }; 10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGCircleManager.m; sourceTree = ""; }; 10BA0D1E1CE74E3100887C2B /* RNSVGEllipseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGEllipseManager.h; sourceTree = ""; }; 10BA0D1F1CE74E3100887C2B /* RNSVGEllipseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGEllipseManager.m; sourceTree = ""; }; 10BA0D201CE74E3100887C2B /* RNSVGGroupManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGGroupManager.h; sourceTree = ""; }; 10BA0D211CE74E3100887C2B /* RNSVGGroupManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGGroupManager.m; sourceTree = ""; }; 10BA0D221CE74E3100887C2B /* RNSVGImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGImageManager.h; sourceTree = ""; }; 10BA0D231CE74E3100887C2B /* RNSVGImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGImageManager.m; sourceTree = ""; }; 10BA0D241CE74E3100887C2B /* RNSVGLineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGLineManager.h; sourceTree = ""; }; 10BA0D251CE74E3100887C2B /* RNSVGLineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGLineManager.m; sourceTree = ""; }; 10BA0D261CE74E3100887C2B /* RNSVGNodeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGNodeManager.h; sourceTree = ""; }; 10BA0D271CE74E3100887C2B /* RNSVGNodeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGNodeManager.m; sourceTree = ""; }; 10BA0D281CE74E3100887C2B /* RNSVGPathManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGPathManager.h; sourceTree = ""; }; 10BA0D291CE74E3100887C2B /* RNSVGPathManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGPathManager.m; sourceTree = ""; }; 10BA0D2A1CE74E3100887C2B /* RNSVGRectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGRectManager.h; sourceTree = ""; }; 10BA0D2B1CE74E3100887C2B /* RNSVGRectManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGRectManager.m; sourceTree = ""; }; 10BA0D2C1CE74E3100887C2B /* RNSVGRenderableManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGRenderableManager.h; sourceTree = ""; }; 10BA0D2D1CE74E3100887C2B /* RNSVGRenderableManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGRenderableManager.m; sourceTree = ""; }; 10BA0D301CE74E3100887C2B /* RNSVGSvgViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSvgViewManager.h; sourceTree = ""; }; 10BA0D311CE74E3100887C2B /* RNSVGSvgViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSvgViewManager.m; sourceTree = ""; }; 10BA0D321CE74E3100887C2B /* RNSVGTextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGTextManager.h; sourceTree = ""; }; 10BA0D331CE74E3100887C2B /* RNSVGTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGTextManager.m; sourceTree = ""; }; 10BA0D401CE74E3D00887C2B /* RNSVGCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGCircle.h; path = Shapes/RNSVGCircle.h; sourceTree = ""; }; 10BA0D411CE74E3D00887C2B /* RNSVGCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGCircle.m; path = Shapes/RNSVGCircle.m; sourceTree = ""; }; 10BA0D421CE74E3D00887C2B /* RNSVGEllipse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGEllipse.h; path = Shapes/RNSVGEllipse.h; sourceTree = ""; }; 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGEllipse.m; path = Shapes/RNSVGEllipse.m; sourceTree = ""; }; 10BA0D441CE74E3D00887C2B /* RNSVGLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGLine.h; path = Shapes/RNSVGLine.h; sourceTree = ""; }; 10BA0D451CE74E3D00887C2B /* RNSVGLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGLine.m; path = Shapes/RNSVGLine.m; sourceTree = ""; }; 10BA0D461CE74E3D00887C2B /* RNSVGRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGRect.h; path = Shapes/RNSVGRect.h; sourceTree = ""; }; 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGRect.m; path = Shapes/RNSVGRect.m; sourceTree = ""; }; 10BEC1B81D3F66F500FDCB19 /* RNSVGLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGLinearGradient.h; path = Elements/RNSVGLinearGradient.h; sourceTree = ""; }; 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGLinearGradient.m; path = Elements/RNSVGLinearGradient.m; sourceTree = ""; }; 10BEC1BA1D3F66F500FDCB19 /* RNSVGRadialGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGRadialGradient.h; path = Elements/RNSVGRadialGradient.h; sourceTree = ""; }; 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGRadialGradient.m; path = Elements/RNSVGRadialGradient.m; sourceTree = ""; }; 10BEC1BE1D3F680F00FDCB19 /* RNSVGLinearGradientManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGLinearGradientManager.h; sourceTree = ""; }; 10BEC1BF1D3F680F00FDCB19 /* RNSVGLinearGradientManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGLinearGradientManager.m; sourceTree = ""; }; 10BEC1C01D3F680F00FDCB19 /* RNSVGRadialGradientManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGRadialGradientManager.h; sourceTree = ""; }; 10BEC1C11D3F680F00FDCB19 /* RNSVGRadialGradientManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGRadialGradientManager.m; sourceTree = ""; }; 10BEC1C41D3F793100FDCB19 /* RNSVGPainter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPainter.h; sourceTree = ""; }; 10BEC1C51D3F7BD300FDCB19 /* RNSVGPainter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGPainter.m; sourceTree = ""; }; 10ED4A991CF065260078BC02 /* RNSVGClipPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGClipPath.h; path = Elements/RNSVGClipPath.h; sourceTree = ""; }; 10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGClipPath.m; path = Elements/RNSVGClipPath.m; sourceTree = ""; }; 10ED4A9C1CF0656A0078BC02 /* RNSVGClipPathManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGClipPathManager.h; sourceTree = ""; }; 10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGClipPathManager.m; sourceTree = ""; }; 10ED4AA01CF078830078BC02 /* RNSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGNode.h; sourceTree = ""; }; 10ED4AA11CF078830078BC02 /* RNSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGNode.m; sourceTree = ""; }; 10FDEEB01D3FB60500A5C46C /* RNSVGPainterBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGPainterBrush.h; sourceTree = ""; }; 10FDEEB11D3FB60500A5C46C /* RNSVGPainterBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGPainterBrush.m; sourceTree = ""; }; 10FDEEB31D3FBED400A5C46C /* RNSVGBrushType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGBrushType.h; sourceTree = ""; }; 1687FE752422B47400741CCB /* RNSVGForeignObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGForeignObject.h; path = Elements/RNSVGForeignObject.h; sourceTree = ""; }; 1687FE762422B4B800741CCB /* RNSVGForeignObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGForeignObject.m; path = Elements/RNSVGForeignObject.m; sourceTree = ""; }; 1691FD182422B6F400C5277B /* RNSVGForeignObjectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGForeignObjectManager.h; sourceTree = ""; }; 1691FD192422B74500C5277B /* RNSVGForeignObjectManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGForeignObjectManager.m; sourceTree = ""; }; 7F08CE961E23476900650F83 /* RNSVGTextPathManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGTextPathManager.h; sourceTree = ""; }; 7F08CE971E23476900650F83 /* RNSVGTextPathManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGTextPathManager.m; sourceTree = ""; }; 7F08CE981E23476900650F83 /* RNSVGTSpanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGTSpanManager.h; sourceTree = ""; }; 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGTSpanManager.m; sourceTree = ""; }; 7F08CE9C1E23479700650F83 /* RNSVGTextPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextPath.h; path = Text/RNSVGTextPath.h; sourceTree = ""; }; 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGTextPath.m; path = Text/RNSVGTextPath.m; sourceTree = ""; }; 7F08CE9E1E23479700650F83 /* RNSVGTSpan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTSpan.h; path = Text/RNSVGTSpan.h; sourceTree = ""; }; 7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGTSpan.m; path = Text/RNSVGTSpan.m; sourceTree = ""; }; 7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGUnits.h; path = Utils/RNSVGUnits.h; sourceTree = ""; }; 7F9CDAF81E1F809C00E0C805 /* RNSVGPathParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPathParser.h; path = Utils/RNSVGPathParser.h; sourceTree = ""; }; 7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPathParser.m; path = Utils/RNSVGPathParser.m; sourceTree = ""; }; 7FC260CC1E3499BC00A39833 /* RNSVGViewBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGViewBox.h; path = Utils/RNSVGViewBox.h; sourceTree = ""; }; 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGViewBox.m; path = Utils/RNSVGViewBox.m; sourceTree = ""; }; 7FC260CF1E34A12000A39833 /* RNSVGSymbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGSymbol.h; path = Elements/RNSVGSymbol.h; sourceTree = ""; }; 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSymbol.m; path = Elements/RNSVGSymbol.m; sourceTree = ""; }; 7FC260D21E34A12A00A39833 /* RNSVGSymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSymbolManager.h; sourceTree = ""; }; 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSymbolManager.m; sourceTree = ""; }; 94241665213B0D4500088E93 /* RNSVGPattern.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNSVGPattern.m; path = Elements/RNSVGPattern.m; sourceTree = ""; }; 9424166A213B2FF100088E93 /* RNSVGPatternManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSVGPatternManager.h; sourceTree = ""; }; 9424166C213B302600088E93 /* RNSVGPatternManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSVGPatternManager.m; sourceTree = ""; }; 94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGVectorEffect.h; path = Utils/RNSVGVectorEffect.h; sourceTree = ""; }; 947F3809214810B800677F2A /* RNSVGMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMask.h; path = Elements/RNSVGMask.h; sourceTree = ""; }; 947F380A214810DC00677F2A /* RNSVGMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMask.m; path = Elements/RNSVGMask.m; sourceTree = ""; }; 947F380D2148118300677F2A /* RNSVGMaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMaskManager.h; sourceTree = ""; }; 947F380E2148119A00677F2A /* RNSVGMaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGMaskManager.m; sourceTree = ""; }; 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGContextBrush.m; sourceTree = ""; }; 9482DEF923460EC800FC486E /* RNSVGContextBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGContextBrush.h; sourceTree = ""; }; 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPathMeasure.m; path = Utils/RNSVGPathMeasure.m; sourceTree = ""; }; 9482DF01234680A200FC486E /* RNSVGPathMeasure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPathMeasure.h; path = Utils/RNSVGPathMeasure.h; sourceTree = ""; }; 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 9494C4D91F473BCB00D5BCFD /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 9494C4DD1F473BDD00D5BCFD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 9494C4DF1F473BED00D5BCFD /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 9494C4E11F473BF500D5BCFD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 94A178F42344094D00693CB3 /* RNSVGPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPattern.h; path = Elements/RNSVGPattern.h; sourceTree = ""; }; 94A178F52344094D00693CB3 /* RNSVGMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMarker.m; path = Elements/RNSVGMarker.m; sourceTree = ""; }; 94A178F62344094D00693CB3 /* RNSVGMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMarker.h; path = Elements/RNSVGMarker.h; sourceTree = ""; }; 94A178F92344095C00693CB3 /* RNSVGMarkerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGMarkerManager.m; sourceTree = ""; }; 94A178FA2344095C00693CB3 /* RNSVGMarkerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGMarkerManager.h; sourceTree = ""; }; 94A178FD2344097B00693CB3 /* RNSVGMarkerPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGMarkerPosition.h; path = Utils/RNSVGMarkerPosition.h; sourceTree = ""; }; 94A178FE2344097B00693CB3 /* RNSVGMarkerPosition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGMarkerPosition.m; path = Utils/RNSVGMarkerPosition.m; sourceTree = ""; }; 94DDAC5C1F3D024300EED511 /* libRNSVG-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRNSVG-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 94F00C5421780CEE00384EA4 /* RNSVGLength.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSVGLength.h; path = Utils/RNSVGLength.h; sourceTree = ""; }; 94F00C5521780D2E00384EA4 /* RNSVGLength.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNSVGLength.m; path = Utils/RNSVGLength.m; sourceTree = ""; }; B56895A52035274F004DBF1E /* RNSVGTextProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextProperties.h; path = Text/RNSVGTextProperties.h; sourceTree = ""; }; B56895A62035274F004DBF1E /* RNSVGTextProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGTextProperties.m; path = Text/RNSVGTextProperties.m; sourceTree = ""; }; B56895A820352B35004DBF1E /* RNSVGBezierElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGBezierElement.m; path = Utils/RNSVGBezierElement.m; sourceTree = ""; }; B56895A920352B36004DBF1E /* RNSVGBezierElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGBezierElement.h; path = Utils/RNSVGBezierElement.h; sourceTree = ""; }; B56895AB20352B9B004DBF1E /* RNSVGPropHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPropHelper.m; path = Text/RNSVGPropHelper.m; sourceTree = ""; }; B56895AC20352B9B004DBF1E /* RNSVGFontData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGFontData.h; path = Text/RNSVGFontData.h; sourceTree = ""; }; B56895AD20352B9B004DBF1E /* RNSVGGlyphContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGGlyphContext.h; path = Text/RNSVGGlyphContext.h; sourceTree = ""; }; B56895AE20352B9B004DBF1E /* RNSVGPropHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGPropHelper.h; path = Text/RNSVGPropHelper.h; sourceTree = ""; }; B56895AF20352B9B004DBF1E /* RNSVGGlyphContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGGlyphContext.m; path = Text/RNSVGGlyphContext.m; sourceTree = ""; }; B56895B020352B9B004DBF1E /* RNSVGFontData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGFontData.m; path = Text/RNSVGFontData.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0CF68ABE1AF0540F00FF9E5C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 9494C4E01F473BED00D5BCFD /* Accelerate.framework in Frameworks */, 9494C4D81F473BA700D5BCFD /* QuartzCore.framework in Frameworks */, 9494C4DA1F473BCB00D5BCFD /* CoreText.framework in Frameworks */, 9494C4DC1F473BD900D5BCFD /* CoreGraphics.framework in Frameworks */, 9494C4DE1F473BDD00D5BCFD /* UIKit.framework in Frameworks */, 9494C4E21F473BF500D5BCFD /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; A361E79E1EB0C33D00646005 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0CF68AB81AF0540F00FF9E5C = { isa = PBXGroup; children = ( 1039D29A1CE7212C001E90A8 /* Utils */, 1039D2801CE71DCF001E90A8 /* Elements */, 1039D27F1CE71D9B001E90A8 /* Text */, 1039D27E1CE71C70001E90A8 /* Shapes */, 0CF68AEA1AF0549300FF9E5C /* Brushes */, 0CF68AF81AF0549300FF9E5C /* ViewManagers */, 1039D2A11CE721A7001E90A8 /* RNSVGContainer.h */, 10ED4AA01CF078830078BC02 /* RNSVGNode.h */, 10ED4AA11CF078830078BC02 /* RNSVGNode.m */, 0CF68AE11AF0549300FF9E5C /* RNSVGRenderable.h */, 0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */, 0CF68AC21AF0540F00FF9E5C /* Products */, 9494C2B31F46139600D5BCFD /* Frameworks */, ); sourceTree = ""; }; 0CF68AC21AF0540F00FF9E5C /* Products */ = { isa = PBXGroup; children = ( 0CF68AC11AF0540F00FF9E5C /* libRNSVG.a */, 94DDAC5C1F3D024300EED511 /* libRNSVG-tvOS.a */, ); name = Products; sourceTree = ""; }; 0CF68AEA1AF0549300FF9E5C /* Brushes */ = { isa = PBXGroup; children = ( 9482DEF923460EC800FC486E /* RNSVGContextBrush.h */, 9482DEF823460EC700FC486E /* RNSVGContextBrush.m */, 10FDEEB31D3FBED400A5C46C /* RNSVGBrushType.h */, 10FDEEB01D3FB60500A5C46C /* RNSVGPainterBrush.h */, 10FDEEB11D3FB60500A5C46C /* RNSVGPainterBrush.m */, 0CF68AEB1AF0549300FF9E5C /* RNSVGBrush.h */, 0CF68AEC1AF0549300FF9E5C /* RNSVGBrush.m */, 0CF68AF31AF0549300FF9E5C /* RNSVGSolidColorBrush.h */, 0CF68AF41AF0549300FF9E5C /* RNSVGSolidColorBrush.m */, 10BEC1C41D3F793100FDCB19 /* RNSVGPainter.h */, 10BEC1C51D3F7BD300FDCB19 /* RNSVGPainter.m */, ); path = Brushes; sourceTree = ""; }; 0CF68AF81AF0549300FF9E5C /* ViewManagers */ = { isa = PBXGroup; children = ( 94A178FA2344095C00693CB3 /* RNSVGMarkerManager.h */, 1691FD182422B6F400C5277B /* RNSVGForeignObjectManager.h */, 1691FD192422B74500C5277B /* RNSVGForeignObjectManager.m */, 94A178F92344095C00693CB3 /* RNSVGMarkerManager.m */, 7FC260D21E34A12A00A39833 /* RNSVGSymbolManager.h */, 7FC260D31E34A12A00A39833 /* RNSVGSymbolManager.m */, 7F08CE961E23476900650F83 /* RNSVGTextPathManager.h */, 7F08CE971E23476900650F83 /* RNSVGTextPathManager.m */, 7F08CE981E23476900650F83 /* RNSVGTSpanManager.h */, 7F08CE991E23476900650F83 /* RNSVGTSpanManager.m */, 9424166A213B2FF100088E93 /* RNSVGPatternManager.h */, 9424166C213B302600088E93 /* RNSVGPatternManager.m */, 947F380D2148118300677F2A /* RNSVGMaskManager.h */, 947F380E2148119A00677F2A /* RNSVGMaskManager.m */, 10BEC1BE1D3F680F00FDCB19 /* RNSVGLinearGradientManager.h */, 10BEC1BF1D3F680F00FDCB19 /* RNSVGLinearGradientManager.m */, 10BEC1C01D3F680F00FDCB19 /* RNSVGRadialGradientManager.h */, 10BEC1C11D3F680F00FDCB19 /* RNSVGRadialGradientManager.m */, 1023B4941D3DF57D0051496D /* RNSVGUseManager.h */, 1023B4951D3DF57D0051496D /* RNSVGUseManager.m */, 1023B48B1D3DDCCE0051496D /* RNSVGDefsManager.h */, 1023B48C1D3DDCCE0051496D /* RNSVGDefsManager.m */, 10ED4A9C1CF0656A0078BC02 /* RNSVGClipPathManager.h */, 10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */, 10BA0D1C1CE74E3100887C2B /* RNSVGCircleManager.h */, 10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */, 10BA0D1E1CE74E3100887C2B /* RNSVGEllipseManager.h */, 10BA0D1F1CE74E3100887C2B /* RNSVGEllipseManager.m */, 10BA0D201CE74E3100887C2B /* RNSVGGroupManager.h */, 10BA0D211CE74E3100887C2B /* RNSVGGroupManager.m */, 10BA0D221CE74E3100887C2B /* RNSVGImageManager.h */, 10BA0D231CE74E3100887C2B /* RNSVGImageManager.m */, 10BA0D241CE74E3100887C2B /* RNSVGLineManager.h */, 10BA0D251CE74E3100887C2B /* RNSVGLineManager.m */, 10BA0D261CE74E3100887C2B /* RNSVGNodeManager.h */, 10BA0D271CE74E3100887C2B /* RNSVGNodeManager.m */, 10BA0D281CE74E3100887C2B /* RNSVGPathManager.h */, 10BA0D291CE74E3100887C2B /* RNSVGPathManager.m */, 10BA0D2A1CE74E3100887C2B /* RNSVGRectManager.h */, 10BA0D2B1CE74E3100887C2B /* RNSVGRectManager.m */, 10BA0D2C1CE74E3100887C2B /* RNSVGRenderableManager.h */, 10BA0D2D1CE74E3100887C2B /* RNSVGRenderableManager.m */, 10BA0D301CE74E3100887C2B /* RNSVGSvgViewManager.h */, 10BA0D311CE74E3100887C2B /* RNSVGSvgViewManager.m */, 10BA0D321CE74E3100887C2B /* RNSVGTextManager.h */, 10BA0D331CE74E3100887C2B /* RNSVGTextManager.m */, ); path = ViewManagers; sourceTree = ""; }; 1039D27E1CE71C70001E90A8 /* Shapes */ = { isa = PBXGroup; children = ( 10BA0D401CE74E3D00887C2B /* RNSVGCircle.h */, 10BA0D411CE74E3D00887C2B /* RNSVGCircle.m */, 10BA0D421CE74E3D00887C2B /* RNSVGEllipse.h */, 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */, 10BA0D441CE74E3D00887C2B /* RNSVGLine.h */, 10BA0D451CE74E3D00887C2B /* RNSVGLine.m */, 10BA0D461CE74E3D00887C2B /* RNSVGRect.h */, 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */, ); name = Shapes; sourceTree = ""; }; 1039D27F1CE71D9B001E90A8 /* Text */ = { isa = PBXGroup; children = ( B56895AC20352B9B004DBF1E /* RNSVGFontData.h */, B56895B020352B9B004DBF1E /* RNSVGFontData.m */, B56895AD20352B9B004DBF1E /* RNSVGGlyphContext.h */, B56895AF20352B9B004DBF1E /* RNSVGGlyphContext.m */, B56895AE20352B9B004DBF1E /* RNSVGPropHelper.h */, B56895AB20352B9B004DBF1E /* RNSVGPropHelper.m */, 1039D28F1CE71EC2001E90A8 /* RNSVGText.h */, 1039D2901CE71EC2001E90A8 /* RNSVGText.m */, 7F08CE9C1E23479700650F83 /* RNSVGTextPath.h */, 7F08CE9D1E23479700650F83 /* RNSVGTextPath.m */, B56895A52035274F004DBF1E /* RNSVGTextProperties.h */, B56895A62035274F004DBF1E /* RNSVGTextProperties.m */, 7F08CE9E1E23479700650F83 /* RNSVGTSpan.h */, 7F08CE9F1E23479700650F83 /* RNSVGTSpan.m */, ); name = Text; sourceTree = ""; }; 1039D2801CE71DCF001E90A8 /* Elements */ = { isa = PBXGroup; children = ( 1687FE762422B4B800741CCB /* RNSVGForeignObject.m */, 1687FE752422B47400741CCB /* RNSVGForeignObject.h */, 94A178F62344094D00693CB3 /* RNSVGMarker.h */, 94A178F52344094D00693CB3 /* RNSVGMarker.m */, 94A178F42344094D00693CB3 /* RNSVGPattern.h */, 7FC260CF1E34A12000A39833 /* RNSVGSymbol.h */, 7FC260D01E34A12000A39833 /* RNSVGSymbol.m */, 10BEC1B81D3F66F500FDCB19 /* RNSVGLinearGradient.h */, 10BEC1B91D3F66F500FDCB19 /* RNSVGLinearGradient.m */, 94241665213B0D4500088E93 /* RNSVGPattern.m */, 947F3809214810B800677F2A /* RNSVGMask.h */, 947F380A214810DC00677F2A /* RNSVGMask.m */, 10BEC1BA1D3F66F500FDCB19 /* RNSVGRadialGradient.h */, 10BEC1BB1D3F66F500FDCB19 /* RNSVGRadialGradient.m */, 1023B4911D3DF5060051496D /* RNSVGUse.h */, 1023B4921D3DF5060051496D /* RNSVGUse.m */, 1023B48E1D3DF4C40051496D /* RNSVGDefs.h */, 1023B48F1D3DF4C40051496D /* RNSVGDefs.m */, 10ED4A991CF065260078BC02 /* RNSVGClipPath.h */, 10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */, 1039D2811CE71EB7001E90A8 /* RNSVGGroup.h */, 1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */, 1039D2831CE71EB7001E90A8 /* RNSVGImage.h */, 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */, 1039D2851CE71EB7001E90A8 /* RNSVGPath.h */, 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */, 1039D2871CE71EB7001E90A8 /* RNSVGSvgView.h */, 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */, ); name = Elements; sourceTree = ""; }; 1039D29A1CE7212C001E90A8 /* Utils */ = { isa = PBXGroup; children = ( 9482DF01234680A200FC486E /* RNSVGPathMeasure.h */, 9482DF00234680A200FC486E /* RNSVGPathMeasure.m */, 94A178FD2344097B00693CB3 /* RNSVGMarkerPosition.h */, 94A178FE2344097B00693CB3 /* RNSVGMarkerPosition.m */, 94696EE92235A7F200C1D558 /* RNSVGVectorEffect.h */, B56895A920352B36004DBF1E /* RNSVGBezierElement.h */, B56895A820352B35004DBF1E /* RNSVGBezierElement.m */, 7F69160D1E3703D800DA6EDC /* RNSVGUnits.h */, 10ABC7381D43982B006CCF6E /* RNSVGVBMOS.h */, 10ABC7371D439779006CCF6E /* RNSVGCGFCRule.h */, 7FC260CC1E3499BC00A39833 /* RNSVGViewBox.h */, 7FC260CD1E3499BC00A39833 /* RNSVGViewBox.m */, 7F9CDAF81E1F809C00E0C805 /* RNSVGPathParser.h */, 7F9CDAF91E1F809C00E0C805 /* RNSVGPathParser.m */, 1039D29B1CE72177001E90A8 /* RCTConvert+RNSVG.h */, 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */, 94F00C5421780CEE00384EA4 /* RNSVGLength.h */, 94F00C5521780D2E00384EA4 /* RNSVGLength.m */, ); name = Utils; sourceTree = ""; }; 9494C2B31F46139600D5BCFD /* Frameworks */ = { isa = PBXGroup; children = ( 9494C4E11F473BF500D5BCFD /* Foundation.framework */, 9494C4DF1F473BED00D5BCFD /* Accelerate.framework */, 9494C4DD1F473BDD00D5BCFD /* UIKit.framework */, 9494C4DB1F473BD900D5BCFD /* CoreGraphics.framework */, 9494C4D91F473BCB00D5BCFD /* CoreText.framework */, 9494C4D71F473BA700D5BCFD /* QuartzCore.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0CF68AC01AF0540F00FF9E5C /* RNSVG */ = { isa = PBXNativeTarget; buildConfigurationList = 0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "RNSVG" */; buildPhases = ( 0CF68ABD1AF0540F00FF9E5C /* Sources */, 0CF68ABE1AF0540F00FF9E5C /* Frameworks */, 0CF68ABF1AF0540F00FF9E5C /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = RNSVG; productName = RNSVG; productReference = 0CF68AC11AF0540F00FF9E5C /* libRNSVG.a */; productType = "com.apple.product-type.library.static"; }; A361E76C1EB0C33D00646005 /* RNSVG-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = A361E7A01EB0C33D00646005 /* Build configuration list for PBXNativeTarget "RNSVG-tvOS" */; buildPhases = ( A361E76D1EB0C33D00646005 /* Sources */, A361E79E1EB0C33D00646005 /* Frameworks */, A361E79F1EB0C33D00646005 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = "RNSVG-tvOS"; productName = RNSVG; productReference = 94DDAC5C1F3D024300EED511 /* libRNSVG-tvOS.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0CF68AB91AF0540F00FF9E5C /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0940; TargetAttributes = { 0CF68AC01AF0540F00FF9E5C = { CreatedOnToolsVersion = 6.2; }; }; }; buildConfigurationList = 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "RNSVG" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 0CF68AB81AF0540F00FF9E5C; productRefGroup = 0CF68AC21AF0540F00FF9E5C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0CF68AC01AF0540F00FF9E5C /* RNSVG */, A361E76C1EB0C33D00646005 /* RNSVG-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ 0CF68ABD1AF0540F00FF9E5C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B56895AA20352B36004DBF1E /* RNSVGBezierElement.m in Sources */, 10BA0D3F1CE74E3100887C2B /* RNSVGTextManager.m in Sources */, 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */, 94241666213B0D4500088E93 /* RNSVGPattern.m in Sources */, 10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */, 10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */, 94A178FB2344095C00693CB3 /* RNSVGMarkerManager.m in Sources */, 947F380B214810DC00677F2A /* RNSVGMask.m in Sources */, 10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */, 10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */, 1691FD1A2422B74500C5277B /* RNSVGForeignObjectManager.m in Sources */, 1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */, 94A178F72344094E00693CB3 /* RNSVGMarker.m in Sources */, 7F08CEA01E23479700650F83 /* RNSVGTextPath.m in Sources */, 1023B4931D3DF5060051496D /* RNSVGUse.m in Sources */, 10BEC1C21D3F680F00FDCB19 /* RNSVGLinearGradientManager.m in Sources */, 1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */, 10BA0D3B1CE74E3100887C2B /* RNSVGRectManager.m in Sources */, 9482DEFA23460EC800FC486E /* RNSVGContextBrush.m in Sources */, 0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */, 1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */, 9482DF02234680A200FC486E /* RNSVGPathMeasure.m in Sources */, 10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */, 10BEC1C61D3F7BD300FDCB19 /* RNSVGPainter.m in Sources */, 10ED4AA21CF078830078BC02 /* RNSVGNode.m in Sources */, 10ED4A9B1CF065260078BC02 /* RNSVGClipPath.m in Sources */, 10BA0D3E1CE74E3100887C2B /* RNSVGSvgViewManager.m in Sources */, 0CF68B0F1AF0549300FF9E5C /* RNSVGSolidColorBrush.m in Sources */, 10BA0D3A1CE74E3100887C2B /* RNSVGPathManager.m in Sources */, B56895B220352B9C004DBF1E /* RNSVGGlyphContext.m in Sources */, 10BA0D3C1CE74E3100887C2B /* RNSVGRenderableManager.m in Sources */, 10BEC1BD1D3F66F500FDCB19 /* RNSVGRadialGradient.m in Sources */, 10BEC1C31D3F680F00FDCB19 /* RNSVGRadialGradientManager.m in Sources */, 10BA0D371CE74E3100887C2B /* RNSVGImageManager.m in Sources */, 10BA0D391CE74E3100887C2B /* RNSVGNodeManager.m in Sources */, 7FC260D11E34A12000A39833 /* RNSVGSymbol.m in Sources */, 1023B4901D3DF4C40051496D /* RNSVGDefs.m in Sources */, 10BA0D381CE74E3100887C2B /* RNSVGLineManager.m in Sources */, 10BA0D481CE74E3D00887C2B /* RNSVGCircle.m in Sources */, 10BA0D351CE74E3100887C2B /* RNSVGEllipseManager.m in Sources */, 1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */, 0CF68B0B1AF0549300FF9E5C /* RNSVGBrush.m in Sources */, B56895A720352750004DBF1E /* RNSVGTextProperties.m in Sources */, 7FC260D41E34A12A00A39833 /* RNSVGSymbolManager.m in Sources */, 7F9CDAFA1E1F809C00E0C805 /* RNSVGPathParser.m in Sources */, 10BA0D361CE74E3100887C2B /* RNSVGGroupManager.m in Sources */, 94F00C5621780D2E00384EA4 /* RNSVGLength.m in Sources */, 9424166D213B302600088E93 /* RNSVGPatternManager.m in Sources */, 7F08CE9A1E23476900650F83 /* RNSVGTextPathManager.m in Sources */, 7F08CE9B1E23476900650F83 /* RNSVGTSpanManager.m in Sources */, B56895B120352B9C004DBF1E /* RNSVGPropHelper.m in Sources */, 7FC260CE1E3499BC00A39833 /* RNSVGViewBox.m in Sources */, 7F08CEA11E23479700650F83 /* RNSVGTSpan.m in Sources */, 947F380F2148119A00677F2A /* RNSVGMaskManager.m in Sources */, 10BA0D4A1CE74E3D00887C2B /* RNSVGLine.m in Sources */, 10FDEEB21D3FB60500A5C46C /* RNSVGPainterBrush.m in Sources */, 1039D28C1CE71EB7001E90A8 /* RNSVGSvgView.m in Sources */, 1023B4961D3DF57D0051496D /* RNSVGUseManager.m in Sources */, 1687FE772422B4B800741CCB /* RNSVGForeignObject.m in Sources */, B56895B320352B9C004DBF1E /* RNSVGFontData.m in Sources */, 1023B48D1D3DDCCE0051496D /* RNSVGDefsManager.m in Sources */, 94A178FF2344097B00693CB3 /* RNSVGMarkerPosition.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; A361E76D1EB0C33D00646005 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A361E76E1EB0C33D00646005 /* RNSVGTextManager.m in Sources */, A361E76F1EB0C33D00646005 /* RNSVGImage.m in Sources */, A361E7701EB0C33D00646005 /* RNSVGRect.m in Sources */, 94241667213B0D4500088E93 /* RNSVGPattern.m in Sources */, A361E7711EB0C33D00646005 /* RNSVGCircleManager.m in Sources */, A361E7721EB0C33D00646005 /* RNSVGLinearGradient.m in Sources */, 94A178FC2344095C00693CB3 /* RNSVGMarkerManager.m in Sources */, 947F380C214810DC00677F2A /* RNSVGMask.m in Sources */, A361E7751EB0C33D00646005 /* RNSVGEllipse.m in Sources */, A361E7761EB0C33D00646005 /* RNSVGPath.m in Sources */, A361E7771EB0C33D00646005 /* RNSVGTextPath.m in Sources */, 94A178F82344094E00693CB3 /* RNSVGMarker.m in Sources */, A361E7781EB0C33D00646005 /* RNSVGUse.m in Sources */, A361E7791EB0C33D00646005 /* RNSVGLinearGradientManager.m in Sources */, A361E77A1EB0C33D00646005 /* RNSVGText.m in Sources */, A361E77B1EB0C33D00646005 /* RNSVGRectManager.m in Sources */, A361E77C1EB0C33D00646005 /* RNSVGRenderable.m in Sources */, 9482DEFB23460EC800FC486E /* RNSVGContextBrush.m in Sources */, A361E77D1EB0C33D00646005 /* RNSVGGroup.m in Sources */, A361E77E1EB0C33D00646005 /* RNSVGClipPathManager.m in Sources */, 9482DF03234680A200FC486E /* RNSVGPathMeasure.m in Sources */, A361E77F1EB0C33D00646005 /* RNSVGPainter.m in Sources */, A361E7801EB0C33D00646005 /* RNSVGNode.m in Sources */, A361E7811EB0C33D00646005 /* RNSVGClipPath.m in Sources */, A361E7821EB0C33D00646005 /* RNSVGSvgViewManager.m in Sources */, A361E7831EB0C33D00646005 /* RNSVGSolidColorBrush.m in Sources */, 167AF45A2087C2990035AA75 /* RNSVGPropHelper.m in Sources */, A361E7841EB0C33D00646005 /* RNSVGPathManager.m in Sources */, 167AF4572087C26F0035AA75 /* RNSVGBezierElement.m in Sources */, A361E7861EB0C33D00646005 /* RNSVGRenderableManager.m in Sources */, A361E7871EB0C33D00646005 /* RNSVGRadialGradient.m in Sources */, A361E7881EB0C33D00646005 /* RNSVGRadialGradientManager.m in Sources */, A361E7891EB0C33D00646005 /* RNSVGImageManager.m in Sources */, A361E78A1EB0C33D00646005 /* RNSVGNodeManager.m in Sources */, A361E78B1EB0C33D00646005 /* RNSVGSymbol.m in Sources */, A361E78C1EB0C33D00646005 /* RNSVGDefs.m in Sources */, A361E78D1EB0C33D00646005 /* RNSVGLineManager.m in Sources */, 167AF4592087C2950035AA75 /* RNSVGGlyphContext.m in Sources */, A361E78E1EB0C33D00646005 /* RNSVGCircle.m in Sources */, A361E78F1EB0C33D00646005 /* RNSVGEllipseManager.m in Sources */, A361E7901EB0C33D00646005 /* RCTConvert+RNSVG.m in Sources */, A361E7911EB0C33D00646005 /* RNSVGBrush.m in Sources */, A361E7921EB0C33D00646005 /* RNSVGSymbolManager.m in Sources */, A361E7931EB0C33D00646005 /* RNSVGPathParser.m in Sources */, A361E7941EB0C33D00646005 /* RNSVGGroupManager.m in Sources */, 94F00C5721780D2E00384EA4 /* RNSVGLength.m in Sources */, 9424166E213B302600088E93 /* RNSVGPatternManager.m in Sources */, A361E7951EB0C33D00646005 /* RNSVGTextPathManager.m in Sources */, 167AF45B2087C2A10035AA75 /* RNSVGTextProperties.m in Sources */, A361E7961EB0C33D00646005 /* RNSVGTSpanManager.m in Sources */, A361E7971EB0C33D00646005 /* RNSVGViewBox.m in Sources */, A361E7981EB0C33D00646005 /* RNSVGTSpan.m in Sources */, 947F38102148119A00677F2A /* RNSVGMaskManager.m in Sources */, A361E7991EB0C33D00646005 /* RNSVGLine.m in Sources */, 167AF4582087C2910035AA75 /* RNSVGFontData.m in Sources */, A361E79A1EB0C33D00646005 /* RNSVGPainterBrush.m in Sources */, A361E79B1EB0C33D00646005 /* RNSVGSvgView.m in Sources */, A361E79C1EB0C33D00646005 /* RNSVGUseManager.m in Sources */, A361E79D1EB0C33D00646005 /* RNSVGDefsManager.m in Sources */, 94A179002344097B00693CB3 /* RNSVGMarkerPosition.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 0CF68AD31AF0540F00FF9E5C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES; CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_FLOAT_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 0CF68AD41AF0540F00FF9E5C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES; CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_FLOAT_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 0CF68AD61AF0540F00FF9E5C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULE_DEBUGGING = YES; PRODUCT_NAME = RNSVG; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/; SKIP_INSTALL = YES; }; name = Debug; }; 0CF68AD71AF0540F00FF9E5C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULE_DEBUGGING = YES; PRODUCT_NAME = RNSVG; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/; SKIP_INSTALL = YES; }; name = Release; }; A361E7A11EB0C33D00646005 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/; SDKROOT = appletvos; SKIP_INSTALL = YES; }; name = Debug; }; A361E7A21EB0C33D00646005 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/; SDKROOT = appletvos; SKIP_INSTALL = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "RNSVG" */ = { isa = XCConfigurationList; buildConfigurations = ( 0CF68AD31AF0540F00FF9E5C /* Debug */, 0CF68AD41AF0540F00FF9E5C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "RNSVG" */ = { isa = XCConfigurationList; buildConfigurations = ( 0CF68AD61AF0540F00FF9E5C /* Debug */, 0CF68AD71AF0540F00FF9E5C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; A361E7A01EB0C33D00646005 /* Build configuration list for PBXNativeTarget "RNSVG-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( A361E7A11EB0C33D00646005 /* Debug */, A361E7A21EB0C33D00646005 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0CF68AB91AF0540F00FF9E5C /* Project object */; } ================================================ FILE: apple/RNSVGContainer.h ================================================ /** * 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 @protocol RNSVGContainer // This is used as a hook for child to mark it's parent as dirty. // This bubbles up to the root which gets marked as dirty. - (void)invalidate; @end ================================================ FILE: apple/RNSVGNode.h ================================================ /** * 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 "RNSVGCGFCRule.h" #import "RNSVGSvgView.h" #import "RNSVGUIKit.h" #import #import @class RNSVGGroup; /** * RNSVG nodes are implemented as base NSViews/UIViews. They should be implementation for all basic *interfaces for all non-definition nodes. */ @interface RNSVGNode : RNSVGView /* N[1/Sqrt[2], 36] The inverse of the square root of 2. Provide enough digits for the 128-bit IEEE quad (36 significant digits). */ extern CGFloat const RNSVG_M_SQRT1_2l; extern CGFloat const RNSVG_DEFAULT_FONT_SIZE; @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *display; @property (nonatomic, assign) CGFloat opacity; @property (nonatomic, assign) RNSVGCGFCRule clipRule; @property (nonatomic, strong) NSString *clipPath; @property (nonatomic, strong) NSString *mask; @property (nonatomic, strong) NSString *markerStart; @property (nonatomic, strong) NSString *markerMid; @property (nonatomic, strong) NSString *markerEnd; @property (nonatomic, strong) RNSVGPlatformView *parentComponentView; /** * Used to control how touch events are processed. */ @property (nonatomic, assign) RCTPointerEvents pointerEvents; @property (nonatomic, assign) BOOL responsible; @property (nonatomic, assign) CGAffineTransform ctm; @property (nonatomic, assign) CGAffineTransform screenCTM; @property (nonatomic, assign) CGAffineTransform matrix; @property (nonatomic, assign) CGAffineTransform invmatrix; @property (nonatomic, assign) BOOL active; @property (nonatomic, assign) BOOL dirty; @property (nonatomic, assign) BOOL merging; @property (nonatomic, assign) BOOL skip; @property (nonatomic, assign) CGPathRef path; @property (nonatomic, assign) CGPathRef strokePath; @property (nonatomic, assign) CGPathRef markerPath; @property (nonatomic, assign) CGRect clientRect; @property (nonatomic, assign) CGRect pathBounds; @property (nonatomic, assign) CGRect fillBounds; @property (nonatomic, assign) CGRect strokeBounds; @property (nonatomic, assign) CGRect markerBounds; @property (nonatomic, copy) RCTDirectEventBlock onSvgLayout; /** * RNSVGSvgView which ownes current RNSVGNode */ @property (nonatomic, readonly, weak) RNSVGSvgView *svgView; @property (nonatomic, readonly, weak) RNSVGGroup *textRoot; - (void)invalidate; - (RNSVGGroup *)getParentTextRoot; - (void)renderTo:(CGContextRef)context rect:(CGRect)rect; /** * @abstract * renderTo will take opacity into account and draw renderLayerTo off-screen if there is opacity * specified, then composite that onto the context. renderLayerTo always draws at opacity=1. */ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect; /** * get clipPath from cache */ - (CGPathRef)getClipPath; /** * get clipPath through context */ - (CGPathRef)getClipPath:(CGContextRef)context; /** * clip node by clipPath */ - (void)clip:(CGContextRef)context; /** * getPath will return the path inside node as a ClipPath. */ - (CGPathRef)getPath:(CGContextRef)context; - (CGFloat)relativeOnWidthString:(NSString *)length; - (CGFloat)relativeOnHeightString:(NSString *)length; - (CGFloat)relativeOnOtherString:(NSString *)length; - (CGFloat)relativeOn:(RNSVGLength *)length relative:(CGFloat)relative; - (CGFloat)relativeOnFraction:(RNSVGLength *)length relative:(CGFloat)relative; - (CGFloat)relativeOnWidth:(RNSVGLength *)length; - (CGFloat)relativeOnHeight:(RNSVGLength *)length; - (CGFloat)relativeOnOther:(RNSVGLength *)length; - (CGFloat)getFontSizeFromContext; - (CGFloat)getContextWidth; - (CGFloat)getContextHeight; /** * save element`s reference into svg element. */ - (void)parseReference; - (void)beginTransparencyLayer:(CGContextRef)context; - (void)endTransparencyLayer:(CGContextRef)context; - (void)traverseSubviews:(BOOL (^)(__kindof RNSVGView *node))block; - (void)clearChildCache; - (void)clearPath; /** * get canvas dimensions */ - (CGFloat)getCanvasWidth; - (CGFloat)getCanvasHeight; - (void)setTransforms:(CGAffineTransform)transforms; @end ================================================ FILE: apple/RNSVGNode.mm ================================================ /** * 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 "RNSVGNode.h" #import "RNSVGClipPath.h" #import "RNSVGContainer.h" #import "RNSVGGlyphContext.h" #import "RNSVGGroup.h" #ifdef RCT_NEW_ARCH_ENABLED #import using namespace facebook::react; #endif // RCT_NEW_ARCH_ENABLED @interface RNSVGNode () @property (nonatomic, readwrite, weak) RNSVGSvgView *svgView; @property (nonatomic, readwrite, weak) RNSVGGroup *textRoot; @end @implementation RNSVGNode { RNSVGGlyphContext *glyphContext; BOOL _transparent; RNSVGClipPath *_clipNode; CGPathRef _cachedClipPath; CGFloat canvasWidth; CGFloat canvasHeight; CGFloat canvasDiagonal; } CGFloat const RNSVG_M_SQRT1_2l = (CGFloat)0.707106781186547524400844362104849039; CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12; - (instancetype)init { if (self = [super init]) { #if !TARGET_OS_OSX // On macOS, views are transparent by default self.opaque = false; #endif _matrix = CGAffineTransformIdentity; _invmatrix = CGAffineTransformIdentity; _opacity = 1; _merging = false; _dirty = false; } return self; } - (void)insertReactSubview:(RNSVGPlatformView *)subview atIndex:(NSInteger)atIndex { [super insertReactSubview:subview atIndex:atIndex]; [self insertSubview:subview atIndex:atIndex]; [self invalidate]; } - (void)removeReactSubview:(RNSVGPlatformView *)subview { [super removeReactSubview:subview]; [self invalidate]; } #ifdef RCT_NEW_ARCH_ENABLED - (void)mountChildComponentView:(RNSVGView *)childComponentView index:(NSInteger)index { [super mountChildComponentView:childComponentView index:index]; [self invalidate]; } - (void)unmountChildComponentView:(RNSVGView *)childComponentView index:(NSInteger)index { [super unmountChildComponentView:childComponentView index:index]; [self invalidate]; } #endif - (void)didUpdateReactSubviews { // Do nothing, as subviews are inserted by insertReactSubview: } - (void)invalidate { if (_dirty || _merging) { return; } _dirty = true; RNSVGPlatformView *container = self.superview; // on Fabric, when the child components are added to hierarchy and their props are set, // their superview is not set yet. if (container != nil) { [(id)container invalidate]; } [self clearPath]; canvasWidth = -1; canvasHeight = -1; canvasDiagonal = -1; } - (void)clearPath { CGPathRelease(_path); self.path = nil; } - (void)clearChildCache { [self clearPath]; for (__kindof RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { [node clearChildCache]; } } } - (void)clearParentCache { RNSVGNode *node = self; while (node != nil) { RNSVGPlatformView *parent = [node superview]; if (![parent isKindOfClass:[RNSVGNode class]]) { return; } node = (RNSVGNode *)parent; if (!node.path) { return; } [node clearPath]; } } - (RNSVGGroup *)textRoot { if (_textRoot) { return _textRoot; } RNSVGNode *node = self; while (node != nil) { if ([node isKindOfClass:[RNSVGGroup class]] && [((RNSVGGroup *)node) getGlyphContext] != nil) { _textRoot = (RNSVGGroup *)node; break; } RNSVGPlatformView *parent = [node superview]; if (![node isKindOfClass:[RNSVGNode class]]) { node = nil; } else { node = (RNSVGNode *)parent; } } return _textRoot; } - (RNSVGGroup *)getParentTextRoot { RNSVGNode *parent = (RNSVGGroup *)[self superview]; if (![parent isKindOfClass:[RNSVGGroup class]]) { return nil; } else { return parent.textRoot; } } - (CGFloat)getFontSizeFromContext { RNSVGGroup *root = self.textRoot; if (root == nil) { return RNSVG_DEFAULT_FONT_SIZE; } if (glyphContext == nil) { glyphContext = [root getGlyphContext]; } return [glyphContext getFontSize]; } - (void)reactSetInheritedBackgroundColor:(RNSVGColor *)inheritedBackgroundColor { self.backgroundColor = inheritedBackgroundColor; } - (void)setPointerEvents:(RCTPointerEvents)pointerEvents { _pointerEvents = pointerEvents; self.userInteractionEnabled = (pointerEvents != RCTPointerEventsNone); if (pointerEvents == RCTPointerEventsBoxNone) { #if TARGET_OS_OSX self.accessibilityModal = NO; #else self.accessibilityViewIsModal = NO; #endif // TARGET_OS_OSX } } - (void)setName:(NSString *)name { if ([name isEqualToString:_name]) { return; } [self invalidate]; _name = name; } - (void)setDisplay:(NSString *)display { if ([display isEqualToString:_display]) { return; } [self invalidate]; _display = display; } - (void)setOpacity:(CGFloat)opacity { if (opacity == _opacity) { return; } if (opacity <= 0) { opacity = 0; } else if (opacity > 1) { opacity = 1; } [self invalidate]; _transparent = opacity < 1; _opacity = opacity; } - (void)setMarkerPath:(CGPathRef)markerPath { if (_markerPath == markerPath) { return; } CGPathRelease(_markerPath); _markerPath = markerPath; [self invalidate]; } - (void)setMatrix:(CGAffineTransform)matrix { if (CGAffineTransformEqualToTransform(matrix, _matrix)) { return; } _matrix = matrix; _invmatrix = CGAffineTransformInvert(matrix); RNSVGPlatformView *container = self.superview; // on Fabric, when the child components are added to hierarchy and their props are set, // their superview is still their componentView, we change it in `mountChildComponentView` method. if ([container conformsToProtocol:@protocol(RNSVGContainer)]) { [(id)container invalidate]; } } - (void)setTransforms:(CGAffineTransform)transforms { self.matrix = transforms; } - (void)setClientRect:(CGRect)clientRect { if (CGRectEqualToRect(_clientRect, clientRect)) { return; } _clientRect = clientRect; #ifdef RCT_NEW_ARCH_ENABLED if (_eventEmitter != nullptr) { static_cast(*_eventEmitter) .onSvgLayout( {.layout = { .x = static_cast(_clientRect.origin.x), .y = static_cast(_clientRect.origin.y), .width = static_cast(_clientRect.size.width), .height = static_cast(_clientRect.size.height) }}); } #else if (self.onSvgLayout) { self.onSvgLayout(@{ @"layout" : @{ @"x" : @(_clientRect.origin.x), @"y" : @(_clientRect.origin.y), @"width" : @(_clientRect.size.width), @"height" : @(_clientRect.size.height), } }); } #endif } - (void)setClipPath:(NSString *)clipPath { if ([_clipPath isEqualToString:clipPath]) { return; } CGPathRelease(_cachedClipPath); _cachedClipPath = nil; _clipPath = clipPath; [self invalidate]; } - (void)setClipRule:(RNSVGCGFCRule)clipRule { if (_clipRule == clipRule) { return; } CGPathRelease(_cachedClipPath); _cachedClipPath = nil; _clipRule = clipRule; [self invalidate]; } - (void)setMask:(NSString *)mask { if ([_mask isEqualToString:mask]) { return; } _mask = mask; [self invalidate]; } - (void)setMarkerStart:(NSString *)markerStart { if ([_markerStart isEqualToString:markerStart]) { return; } _markerStart = markerStart; [self invalidate]; } - (void)setMarkerMid:(NSString *)markerMid { if ([_markerMid isEqualToString:markerMid]) { return; } _markerMid = markerMid; [self invalidate]; } - (void)setMarkerEnd:(NSString *)markerEnd { if ([_markerEnd isEqualToString:markerEnd]) { return; } _markerEnd = markerEnd; [self invalidate]; } - (void)beginTransparencyLayer:(CGContextRef)context { if (_transparent) { CGContextBeginTransparencyLayer(context, NULL); } } - (void)endTransparencyLayer:(CGContextRef)context { if (_transparent) { CGContextEndTransparencyLayer(context); } } - (void)renderTo:(CGContextRef)context rect:(CGRect)rect { self.dirty = false; // abstract } - (CGPathRef)getClipPath { return _cachedClipPath; } - (CGPathRef)getClipPath:(CGContextRef)context { if (self.clipPath) { _clipNode = (RNSVGClipPath *)[self.svgView getDefinedClipPath:self.clipPath]; if (_cachedClipPath) { CGPathRelease(_cachedClipPath); } CGAffineTransform transform = _clipNode.matrix; _cachedClipPath = CGPathCreateCopyByTransformingPath([_clipNode getPath:context], &transform); } return _cachedClipPath; } - (void)clip:(CGContextRef)context { CGPathRef clipPath = [self getClipPath:context]; if (clipPath) { CGContextAddPath(context, clipPath); if (_clipRule == kRNSVGCGFCRuleEvenodd) { CGContextEOClip(context); } else { CGContextClip(context); } } } - (CGPathRef)getPath:(CGContextRef)context { // abstract return nil; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { // abstract } // hitTest delagate - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // abstract return nil; } - (RNSVGSvgView *)svgView { if (_svgView) { return _svgView; } __kindof RNSVGPlatformView *parent = self.superview; if ([parent class] == [RNSVGSvgView class]) { _svgView = parent; } else if ([parent isKindOfClass:[RNSVGNode class]]) { _svgView = ((RNSVGNode *)parent).svgView; } else { RCTLogError(@"RNSVG: %@ should be descendant of a SvgViewShadow.", NSStringFromClass(self.class)); } return _svgView; } - (CGFloat)relativeOnWidthString:(NSString *)length { return [RNSVGPropHelper fromRelativeWithNSString:length relative:[self getCanvasWidth] fontSize:[self getFontSizeFromContext]]; } - (CGFloat)relativeOnHeightString:(NSString *)length { return [RNSVGPropHelper fromRelativeWithNSString:length relative:[self getCanvasHeight] fontSize:[self getFontSizeFromContext]]; } - (CGFloat)relativeOnOtherString:(NSString *)length { return [RNSVGPropHelper fromRelativeWithNSString:length relative:[self getCanvasDiagonal] fontSize:[self getFontSizeFromContext]]; } - (CGFloat)relativeOnFraction:(RNSVGLength *)length relative:(CGFloat)relative { RNSVGLengthUnitType unit = length.unit; if (unit == SVG_LENGTHTYPE_NUMBER) { return relative * length.value; } else if (unit == SVG_LENGTHTYPE_PERCENTAGE) { return length.value / 100 * relative; } return [self fromRelative:length]; } - (CGFloat)relativeOn:(RNSVGLength *)length relative:(CGFloat)relative { RNSVGLengthUnitType unit = length.unit; if (unit == SVG_LENGTHTYPE_NUMBER) { return length.value; } else if (unit == SVG_LENGTHTYPE_PERCENTAGE) { return length.value / 100 * relative; } return [self fromRelative:length]; } - (CGFloat)relativeOnWidth:(RNSVGLength *)length { if (length.unit == SVG_LENGTHTYPE_PERCENTAGE && self.svgView.vbWidth != 0) { return [self relativeOn:length relative:self.svgView.vbWidth]; } return [self relativeOn:length relative:[self getCanvasWidth]]; } - (CGFloat)relativeOnHeight:(RNSVGLength *)length { if (length.unit == SVG_LENGTHTYPE_PERCENTAGE && self.svgView.vbHeight != 0) { return [self relativeOn:length relative:self.svgView.vbHeight]; } return [self relativeOn:length relative:[self getCanvasHeight]]; } - (CGFloat)relativeOnOther:(RNSVGLength *)length { return [self relativeOn:length relative:[self getCanvasDiagonal]]; } - (CGFloat)fromRelative:(RNSVGLength *)length { CGFloat unit; switch (length.unit) { case SVG_LENGTHTYPE_EMS: unit = [self getFontSizeFromContext]; break; case SVG_LENGTHTYPE_EXS: unit = [self getFontSizeFromContext] / 2; break; case SVG_LENGTHTYPE_CM: unit = (CGFloat)35.43307; break; case SVG_LENGTHTYPE_MM: unit = (CGFloat)3.543307; break; case SVG_LENGTHTYPE_IN: unit = 90; break; case SVG_LENGTHTYPE_PT: unit = 1.25; break; case SVG_LENGTHTYPE_PC: unit = 15; break; default: unit = 1; } return length.value * unit; } - (CGRect)getContextBounds { return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext()); } - (CGFloat)getContextWidth { return CGRectGetWidth([self getContextBounds]); } - (CGFloat)getContextHeight { return CGRectGetHeight([self getContextBounds]); } - (CGFloat)getContextDiagonal { CGRect bounds = [self getContextBounds]; CGFloat width = CGRectGetWidth(bounds); CGFloat height = CGRectGetHeight(bounds); CGFloat powX = width * width; CGFloat powY = height * height; CGFloat r = sqrt(powX + powY) * RNSVG_M_SQRT1_2l; return r; } - (CGFloat)getCanvasWidth { if (canvasWidth != -1) { return canvasWidth; } RNSVGGroup *root = [self textRoot]; if (root == nil) { canvasWidth = [self getContextWidth]; } else { canvasWidth = [[root getGlyphContext] getWidth]; } return canvasWidth; } - (CGFloat)getCanvasHeight { if (canvasHeight != -1) { return canvasHeight; } RNSVGGroup *root = [self textRoot]; if (root == nil) { canvasHeight = [self getContextHeight]; } else { canvasHeight = [[root getGlyphContext] getHeight]; } return canvasHeight; } - (CGFloat)getCanvasDiagonal { if (canvasDiagonal != -1) { return canvasDiagonal; } CGFloat width = [self getCanvasWidth]; CGFloat height = [self getCanvasHeight]; CGFloat powX = width * width; CGFloat powY = height * height; canvasDiagonal = sqrt(powX + powY) * RNSVG_M_SQRT1_2l; return canvasDiagonal; } - (void)parseReference { self.dirty = false; if (self.name) { __typeof__(self) __weak weakSelf = self; [self.svgView defineTemplate:weakSelf templateName:self.name]; } } - (void)traverseSubviews:(BOOL (^)(__kindof RNSVGView *node))block { for (RNSVGView *node in self.subviews) { if (!block(node)) { break; } } } - (void)dealloc { CGPathRelease(_cachedClipPath); CGPathRelease(_strokePath); CGPathRelease(_path); CGPathRelease(_markerPath); } #ifdef RCT_NEW_ARCH_ENABLED - (void)prepareForRecycle { [super prepareForRecycle]; #if !TARGET_OS_OSX // On macOS, views are transparent by default self.opaque = false; #endif _merging = false; _dirty = false; _name = nil; _display = nil; _opacity = 1; _clipRule = kRNSVGCGFCRuleEvenodd; _clipPath = nil; _mask = nil; _markerStart = nil; _markerMid = nil; _markerEnd = nil; _parentComponentView = nil; _pointerEvents = RCTPointerEventsUnspecified; _responsible = NO; _ctm = CGAffineTransformIdentity; _screenCTM = CGAffineTransformIdentity; _matrix = CGAffineTransformIdentity; _invmatrix = CGAffineTransformIdentity; _active = NO; _skip = NO; if (_markerPath) { CGPathRelease(_markerPath); } _markerPath = nil; _clientRect = CGRectZero; _pathBounds = CGRectZero; _fillBounds = CGRectZero; _strokeBounds = CGRectZero; _markerBounds = CGRectZero; _onSvgLayout = nil; _svgView = nil; _textRoot = nil; glyphContext = nil; _transparent = NO; _clipNode = nil; canvasWidth = 0; canvasHeight = 0; canvasDiagonal = 0; CGPathRelease(_cachedClipPath); _cachedClipPath = nil; CGPathRelease(_strokePath); _strokePath = nil; CGPathRelease(_path); _path = nil; } #endif // RCT_NEW_ARCH_ENABLED @end ================================================ FILE: apple/RNSVGRenderable.h ================================================ /** * 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 #import "RNSVGUIKit.h" #import "RNSVGBrush.h" #import "RNSVGCGFCRule.h" #import "RNSVGLength.h" #import "RNSVGNode.h" #import "RNSVGVectorEffect.h" @interface RNSVGRenderable : RNSVGNode @property (class) RNSVGRenderable *contextElement; @property (nonatomic, strong) RNSVGColor *color; @property (nonatomic, strong) RNSVGBrush *fill; @property (nonatomic, assign) CGFloat fillOpacity; @property (nonatomic, assign) RNSVGCGFCRule fillRule; @property (nonatomic, strong) RNSVGBrush *stroke; @property (nonatomic, assign) CGFloat strokeOpacity; @property (nonatomic, strong) RNSVGLength *strokeWidth; @property (nonatomic, assign) CGLineCap strokeLinecap; @property (nonatomic, assign) CGLineJoin strokeLinejoin; @property (nonatomic, assign) CGFloat strokeMiterlimit; @property (nonatomic, strong) NSArray *strokeDasharray; @property (nonatomic, assign) CGFloat strokeDashoffset; @property (nonatomic, assign) RNSVGVectorEffect vectorEffect; @property (nonatomic, copy) NSArray *propList; @property (nonatomic, assign) CGPathRef hitArea; @property (nonatomic, strong) NSString *filter; - (void)setColor:(RNSVGColor *)color; - (void)setHitArea:(CGPathRef)path; - (NSArray *)getAttributeList; - (void)mergeProperties:(__kindof RNSVGRenderable *)target; - (void)resetProperties; - (CGColor *)getCurrentColor; @end ================================================ FILE: apple/RNSVGRenderable.mm ================================================ /** * 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 "RNSVGRenderable.h" #import #import "RNSVGBezierElement.h" #import "RNSVGClipPath.h" #import "RNSVGFilter.h" #import "RNSVGMarker.h" #import "RNSVGMarkerPosition.h" #import "RNSVGMask.h" #import "RNSVGRenderUtils.h" #import "RNSVGVectorEffect.h" #import "RNSVGViewBox.h" @implementation RNSVGRenderable { NSMutableDictionary *_originProperties; NSArray *_lastMergedList; NSArray *_attributeList; NSArray *_sourceStrokeDashArray; CGFloat *_strokeDashArrayData; CGPathRef _srcHitPath; RNSVGRenderable *_caller; } static RNSVGRenderable *_contextElement; + (RNSVGRenderable *)contextElement { return _contextElement; } + (void)setContextElement:(RNSVGRenderable *)contextElement { _contextElement = contextElement; } - (id)init { if (self = [super init]) { _fillOpacity = 1; _strokeOpacity = 1; _strokeWidth = [RNSVGLength lengthWithNumber:1]; _fillRule = kRNSVGCGFCRuleNonzero; } return self; } - (void)invalidate { _sourceStrokeDashArray = nil; if (self.dirty || self.merging) { return; } _srcHitPath = nil; [super invalidate]; self.dirty = true; } - (void)setColor:(RNSVGColor *)color { if (color == _color) { return; } [self invalidate]; _color = color; } - (void)setFill:(RNSVGBrush *)fill { if (fill == _fill) { return; } [self invalidate]; _fill = fill; } - (void)setFillOpacity:(CGFloat)fillOpacity { if (fillOpacity == _fillOpacity) { return; } [self invalidate]; _fillOpacity = fillOpacity; } - (void)setFillRule:(RNSVGCGFCRule)fillRule { if (fillRule == _fillRule) { return; } [self invalidate]; _fillRule = fillRule; } - (void)setStroke:(RNSVGBrush *)stroke { if (stroke == _stroke) { return; } [self invalidate]; _stroke = stroke; } - (void)setStrokeOpacity:(CGFloat)strokeOpacity { if (strokeOpacity == _strokeOpacity) { return; } [self invalidate]; _strokeOpacity = strokeOpacity; } - (void)setStrokeWidth:(RNSVGLength *)strokeWidth { if ([strokeWidth isEqualTo:_strokeWidth]) { return; } [self invalidate]; _strokeWidth = strokeWidth; } - (void)setStrokeLinecap:(CGLineCap)strokeLinecap { if (strokeLinecap == _strokeLinecap) { return; } [self invalidate]; _strokeLinecap = strokeLinecap; } - (void)setStrokeJoin:(CGLineJoin)strokeLinejoin { if (strokeLinejoin == _strokeLinejoin) { return; } [self invalidate]; _strokeLinejoin = strokeLinejoin; } - (void)setStrokeMiterlimit:(CGFloat)strokeMiterlimit { if (strokeMiterlimit == _strokeMiterlimit) { return; } [self invalidate]; _strokeMiterlimit = strokeMiterlimit; } - (void)setStrokeDasharray:(NSArray *)strokeDasharray { if (strokeDasharray == _strokeDasharray) { return; } [self invalidate]; _strokeDasharray = strokeDasharray; } - (void)setStrokeDashoffset:(CGFloat)strokeDashoffset { if (strokeDashoffset == _strokeDashoffset) { return; } [self invalidate]; _strokeDashoffset = strokeDashoffset; } - (void)setVectorEffect:(RNSVGVectorEffect)vectorEffect { if (vectorEffect == _vectorEffect) { return; } [self invalidate]; _vectorEffect = vectorEffect; } - (void)setPropList:(NSArray *)propList { if (propList == _propList) { return; } _propList = _attributeList = propList; [self invalidate]; } - (void)setFilter:(NSString *)filter { if ([_filter isEqualToString:filter]) { return; } _filter = filter; [self invalidate]; } - (void)dealloc { CGPathRelease(_hitArea); _sourceStrokeDashArray = nil; if (_strokeDashArrayData) { free(_strokeDashArrayData); } _strokeDashArrayData = nil; } #ifdef RCT_NEW_ARCH_ENABLED - (void)prepareForRecycle { [super prepareForRecycle]; _fillOpacity = 1; _strokeOpacity = 1; _strokeWidth = [RNSVGLength lengthWithNumber:1]; _fillRule = kRNSVGCGFCRuleNonzero; _originProperties = nil; _lastMergedList = nil; _attributeList = nil; _sourceStrokeDashArray = nil; _srcHitPath = nil; CGPathRelease(_hitArea); _hitArea = nil; _sourceStrokeDashArray = nil; if (_strokeDashArrayData) { free(_strokeDashArrayData); } _strokeDashArrayData = nil; _contextElement = nil; _color = nil; _fill = nil; _stroke = nil; _strokeLinecap = kCGLineCapButt; _strokeLinejoin = kCGLineJoinMiter; _strokeMiterlimit = 0; _strokeDasharray = nil; _strokeDashoffset = 0; _vectorEffect = kRNSVGVectorEffectDefault; _propList = nil; _filter = nil; _caller = nil; } #endif // RCT_NEW_ARCH_ENABLED UInt32 saturate(CGFloat value) { return value <= 0 ? 0 : value >= 255 ? 255 : (UInt32)value; } - (void)renderTo:(CGContextRef)context rect:(CGRect)rect { self.dirty = false; // This needs to be painted on a layer before being composited. CGContextSaveGState(context); CGContextConcatCTM(context, self.matrix); CGContextSetAlpha(context, self.opacity); [self beginTransparencyLayer:context]; RNSVGFilter *filterNode = self.filter ? [self.svgView getDefinedFilter:self.filter] : nil; RNSVGMask *maskNode = self.mask ? [self.svgView getDefinedMask:self.mask] : nil; if (maskNode || filterNode) { CGRect bounds = CGContextGetClipBoundingBox(context); // Get current context transformations for offscreenContext CGAffineTransform currentCTM = CGContextGetCTM(context); CGFloat height = rect.size.height; CGFloat width = rect.size.width; CGFloat scale = [RNSVGRenderUtils getScreenScale]; NSUInteger iheight = (NSUInteger)height; NSUInteger iwidth = (NSUInteger)width; NSUInteger iscale = (NSUInteger)scale; NSUInteger scaledHeight = iheight * iscale; NSUInteger scaledWidth = iwidth * iscale; NSUInteger npixels = scaledHeight * scaledWidth; CGAffineTransform screenScaleCTM = CGAffineTransformMake(scale, 0, 0, scale, 0, 0); CGRect scaledRect = CGRectApplyAffineTransform(rect, screenScaleCTM); #if TARGET_OS_OSX CGImage *contentImage = [RNSVGRenderUtils renderToImage:self ctm:currentCTM rect:scaledRect clip:nil]; #else CGImage *contentImage = [RNSVGRenderUtils renderToImage:self ctm:currentCTM rect:rect clip:nil]; #endif if (filterNode) { // https://www.w3.org/TR/SVG11/filters.html#FilterElement CIImage *content = [CIImage imageWithCGImage:contentImage]; CGImage *backgroundImage = CGBitmapContextCreateImage(context); CIImage *background = (backgroundImage != nil) ? [CIImage imageWithCGImage:backgroundImage] : [CIImage emptyImage]; content = [filterNode applyFilter:content backgroundImg:background renderableBounds:self.pathBounds canvasBounds:scaledRect ctm:currentCTM]; CGImageRelease(contentImage); contentImage = [[RNSVGRenderUtils sharedCIContext] createCGImage:content fromRect:scaledRect]; if (!maskNode) { CGContextConcatCTM(context, CGAffineTransformInvert(currentCTM)); #if TARGET_OS_OSX CGContextDrawImage(context, rect, contentImage); #else CGContextDrawImage(context, scaledRect, contentImage); #endif CGContextConcatCTM(context, currentCTM); } CGImageRelease(backgroundImage); } if (maskNode) { // https://www.w3.org/TR/SVG11/masking.html#MaskElement // Allocate pixel buffer and bitmap context for mask NSUInteger bytesPerPixel = 4; NSUInteger bitsPerComponent = 8; NSUInteger bytesPerRow = bytesPerPixel * scaledWidth; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); UInt32 *pixels = (UInt32 *)calloc(npixels, sizeof(UInt32)); CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big; CGContextRef bcontext = CGBitmapContextCreate( pixels, scaledWidth, scaledHeight, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); #if TARGET_OS_OSX // [macOS] // on macOS currentCTM is not scaled properly with screen scale so we need to scale it manually CGContextConcatCTM(bcontext, screenScaleCTM); #endif // [macOS] CGContextConcatCTM(bcontext, currentCTM); // Clip to mask bounds and render the mask CGRect maskBounds; if ([maskNode maskUnits] == RNSVGUnits::kRNSVGUnitsUserSpaceOnUse) { CGFloat x = [self relativeOn:[maskNode x] relative:width]; CGFloat y = [self relativeOn:[maskNode y] relative:height]; CGFloat w = [self relativeOn:[maskNode maskwidth] relative:width]; CGFloat h = [self relativeOn:[maskNode maskheight] relative:height]; maskBounds = CGRectMake(x, y, w, h); } else { CGSize currentBoundsSize = self.pathBounds.size; CGFloat x = [self relativeOnFraction:[maskNode x] relative:currentBoundsSize.width]; CGFloat y = [self relativeOnFraction:[maskNode y] relative:currentBoundsSize.height]; CGFloat w = [self relativeOnFraction:[maskNode maskwidth] relative:currentBoundsSize.width]; CGFloat h = [self relativeOnFraction:[maskNode maskheight] relative:currentBoundsSize.height]; maskBounds = CGRectMake(self.pathBounds.origin.x + x, self.pathBounds.origin.y + y, w, h); } CGContextClipToRect(bcontext, maskBounds); [maskNode renderLayerTo:bcontext rect:bounds]; // Apply luminanceToAlpha filter primitive // https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement UInt32 *currentPixel = pixels; if (maskNode.maskType == kRNSVGMaskTypeLuminance) { for (NSUInteger i = 0; i < npixels; i++) { UInt32 color = *currentPixel; UInt32 r = color & 0xFF; UInt32 g = (color >> 8) & 0xFF; UInt32 b = (color >> 16) & 0xFF; CGFloat luma = (CGFloat)(0.299 * r + 0.587 * g + 0.144 * b); *currentPixel = saturate(luma) << 24; currentPixel++; } } // Create mask image and release memory CGImageRef maskImage = CGBitmapContextCreateImage(bcontext); CGColorSpaceRelease(colorSpace); CGContextRelease(bcontext); free(pixels); #if !TARGET_OS_OSX // [macOS] UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:rect.size format:format]; // Blend current element and mask UIImage *blendedImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { CGContextConcatCTM( rendererContext.CGContext, CGAffineTransformInvert(CGContextGetCTM(rendererContext.CGContext))); CGContextConcatCTM(rendererContext.CGContext, screenScaleCTM); CGContextSetBlendMode(rendererContext.CGContext, kCGBlendModeCopy); CGContextDrawImage(rendererContext.CGContext, rect, maskImage); CGContextSetBlendMode(rendererContext.CGContext, kCGBlendModeSourceIn); CGContextDrawImage(rendererContext.CGContext, rect, contentImage); }]; // Invert the CTM and apply transformations to draw image in 1:1 CGContextConcatCTM(context, CGAffineTransformInvert(currentCTM)); CGContextTranslateCTM(context, 0.0, scaledRect.size.height); CGContextScaleCTM(context, 1.0, -1.0); // Render blended result into current render context [blendedImage drawInRect:scaledRect]; #else // [macOS // Blend current element and mask RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, scale); CGContextRef newContext = UIGraphicsGetCurrentContext(); CGContextSetBlendMode(newContext, kCGBlendModeCopy); CGContextDrawImage(newContext, rect, maskImage); CGContextSetBlendMode(newContext, kCGBlendModeSourceIn); CGContextDrawImage(newContext, rect, contentImage); CGImageRef blendedImage = CGBitmapContextCreateImage(newContext); RNSVGUIGraphicsEndImageContext(); // Invert the CTM and apply transformations to draw image in 1:1 CGContextConcatCTM(context, CGAffineTransformInvert(currentCTM)); CGContextTranslateCTM(context, 0.0, rect.size.height); CGContextScaleCTM(context, 1.0, -1.0); // Render blended result into current render context CGContextDrawImage(context, rect, blendedImage); CGImageRelease(blendedImage); #endif // macOS] CGImageRelease(maskImage); } CGImageRelease(contentImage); } else { [self renderLayerTo:context rect:rect]; } [self endTransparencyLayer:context]; CGContextRestoreGState(context); [self renderMarkers:context path:self.path rect:&rect]; } - (void)prepareStrokeDash:(NSUInteger)count strokeDasharray:(NSArray *)strokeDasharray { if (strokeDasharray != _sourceStrokeDashArray) { CGFloat *dash = _strokeDashArrayData; _strokeDashArrayData = (CGFloat *)realloc(dash, sizeof(CGFloat) * count); if (!_strokeDashArrayData) { free(dash); return; } _sourceStrokeDashArray = strokeDasharray; for (NSUInteger i = 0; i < count; i++) { _strokeDashArrayData[i] = (CGFloat)[self relativeOnOther:strokeDasharray[i]]; } } } - (void)renderMarkers:(CGContextRef)context path:(CGPathRef)path rect:(const CGRect *)rect { RNSVGMarker *markerStart = (RNSVGMarker *)[self.svgView getDefinedMarker:self.markerStart]; RNSVGMarker *markerMid = (RNSVGMarker *)[self.svgView getDefinedMarker:self.markerMid]; RNSVGMarker *markerEnd = (RNSVGMarker *)[self.svgView getDefinedMarker:self.markerEnd]; if (markerStart || markerMid || markerEnd) { _contextElement = self; NSArray *positions = [RNSVGMarkerPosition fromCGPath:path]; CGFloat width = self.strokeWidth ? [self relativeOnOther:self.strokeWidth] : 1; __block CGRect bounds = CGRectNull; CGMutablePathRef markerPath = CGPathCreateMutable(); for (RNSVGMarkerPosition *position in positions) { RNSVGMarkerType type = [position type]; RNSVGMarker *marker; switch (type) { case kStartMarker: marker = markerStart; break; case kMidMarker: marker = markerMid; break; case kEndMarker: marker = markerEnd; break; } if (!marker) { continue; } [marker renderMarker:context rect:*rect position:position strokeWidth:width]; CGAffineTransform transform = marker.transform; CGPathRef hitArea = marker.hitArea; CGPathAddPath(markerPath, &transform, hitArea); CGRect nodeRect = marker.pathBounds; if (!CGRectIsEmpty(nodeRect)) { bounds = CGRectUnion(bounds, CGRectApplyAffineTransform(nodeRect, transform)); } } self.markerBounds = bounds; self.markerPath = markerPath; _contextElement = nil; } } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { CGPathRef path = self.path; if (!path) { path = [self getPath:context]; if (!self.path) { self.path = CGPathRetain(path); } [self setHitArea:path]; self.fillBounds = CGPathGetPathBoundingBox(path); self.strokeBounds = CGPathGetPathBoundingBox(self.strokePath); self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds); } const CGRect pathBounds = self.pathBounds; CGAffineTransform current = CGContextGetCTM(context); CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM); CGRect clientRect = CGRectApplyAffineTransform(pathBounds, svgToClientTransform); self.ctm = svgToClientTransform; self.clientRect = clientRect; self.screenCTM = current; if (_vectorEffect == kRNSVGVectorEffectNonScalingStroke) { path = CGPathCreateCopyByTransformingPath(path, &svgToClientTransform); CGContextConcatCTM(context, CGAffineTransformInvert(svgToClientTransform)); } CGAffineTransform vbmatrix = self.svgView.getViewBoxTransform; CGAffineTransform matrix = CGAffineTransformConcat(self.matrix, vbmatrix); CGRect bounds = CGRectMake(0, 0, CGRectGetWidth(clientRect), CGRectGetHeight(clientRect)); CGPoint mid = CGPointMake(CGRectGetMidX(pathBounds), CGRectGetMidY(pathBounds)); CGPoint center = CGPointApplyAffineTransform(mid, matrix); if (!isnan(bounds.size.width) && !isnan(bounds.size.height)) { self.bounds = bounds; } if (!isnan(center.x) && !isnan(center.y)) { self.center = center; } self.frame = clientRect; if (self.skip || self.opacity == 0) { return; } if (!self.fill && !self.stroke) { return; } CGPathDrawingMode mode = kCGPathStroke; BOOL fillColor = NO; [self clip:context]; BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd; if (self.fill) { if (self.fill.class == RNSVGBrush.class) { CGContextSetFillColorWithColor(context, [self getCurrentColor]); fillColor = YES; } else { fillColor = [self.fill applyFillColor:context opacity:self.fillOpacity]; } if (fillColor) { mode = evenodd ? kCGPathEOFill : kCGPathFill; } else { CGContextSaveGState(context); CGContextAddPath(context, path); evenodd ? CGContextEOClip(context) : CGContextClip(context); [self.fill paint:context opacity:self.fillOpacity painter:[self.svgView getDefinedPainter:self.fill.brushRef] bounds:pathBounds]; CGContextRestoreGState(context); if (!self.stroke) { return; } } } if (self.stroke) { CGFloat width = self.strokeWidth ? [self relativeOnOther:self.strokeWidth] : 1; CGContextSetLineWidth(context, width); CGContextSetLineCap(context, self.strokeLinecap); CGContextSetLineJoin(context, self.strokeLinejoin); NSArray *strokeDasharray = self.strokeDasharray; NSUInteger count = strokeDasharray.count; if (count) { [self prepareStrokeDash:count strokeDasharray:strokeDasharray]; if (_strokeDashArrayData) { CGContextSetLineDash(context, self.strokeDashoffset, _strokeDashArrayData, count); } } if (!fillColor) { CGContextAddPath(context, path); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); } BOOL strokeColor; if (self.stroke.class == RNSVGBrush.class) { CGContextSetStrokeColorWithColor(context, [self getCurrentColor]); strokeColor = YES; } else { strokeColor = [self.stroke applyStrokeColor:context opacity:self.strokeOpacity]; } if (strokeColor && fillColor) { mode = evenodd ? kCGPathEOFillStroke : kCGPathFillStroke; } else if (!strokeColor) { // draw fill if (fillColor) { CGContextAddPath(context, path); CGContextDrawPath(context, mode); } // draw stroke CGContextAddPath(context, path); CGContextReplacePathWithStrokedPath(context); evenodd ? CGContextEOClip(context) : CGContextClip(context); [self.stroke paint:context opacity:self.strokeOpacity painter:[self.svgView getDefinedPainter:self.stroke.brushRef] bounds:pathBounds]; return; } } CGContextAddPath(context, path); CGContextDrawPath(context, mode); } - (void)setHitArea:(CGPathRef)path { if (_srcHitPath == path) { return; } _srcHitPath = path; CGPathRelease(_hitArea); CGPathRelease(self.strokePath); _hitArea = CGPathCreateCopy(path); self.strokePath = nil; if (self.stroke && self.strokeWidth) { // Add stroke to hitArea CGFloat width = [self relativeOnOther:self.strokeWidth]; self.strokePath = CGPathRetain((CGPathRef)CFAutorelease(CGPathCreateCopyByStrokingPath( path, nil, width, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit))); // TODO add dashing // CGPathCreateCopyByDashingPath(CGPathRef _Nullable path, const CGAffineTransform * _Nullable transform, CGFloat // phase, const CGFloat * _Nullable lengths, size_t count) } } - (BOOL)isUserInteractionEnabled { return NO; } // hitTest delegate - (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (!_hitArea) { return nil; } BOOL canReceiveTouchEvents = (self.pointerEvents != RCTPointerEventsNone && ![self isHidden]); if (!canReceiveTouchEvents) { return nil; } if (self.active) { if (!event) { self.active = NO; } return self; } CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); if (!CGRectContainsPoint(self.pathBounds, transformed) && !CGRectContainsPoint(self.markerBounds, transformed)) { return nil; } BOOL evenodd = self.fillRule == kRNSVGCGFCRuleEvenodd; if (!CGPathContainsPoint(_hitArea, nil, transformed, evenodd) && !CGPathContainsPoint(self.strokePath, nil, transformed, NO) && !CGPathContainsPoint(self.markerPath, nil, transformed, NO)) { return nil; } if (self.clipPath) { RNSVGClipPath *clipNode = (RNSVGClipPath *)[self.svgView getDefinedClipPath:self.clipPath]; if ([clipNode isSimpleClipPath]) { CGPathRef clipPath = [self getClipPath]; if (clipPath && !CGPathContainsPoint(clipPath, nil, transformed, clipNode.clipRule == kRNSVGCGFCRuleEvenodd)) { return nil; } } else { RNSVGRenderable *clipGroup = (RNSVGRenderable *)clipNode; if (![clipGroup hitTest:transformed withEvent:event]) { return nil; } } } return self; } - (NSArray *)getAttributeList { return _attributeList; } - (void)mergeProperties:(__kindof RNSVGRenderable *)target { _caller = target; NSArray *targetAttributeList = [target getAttributeList]; if (targetAttributeList.count == 0) { return; } self.merging = true; NSMutableArray *attributeList = self.propList ? [self.propList mutableCopy] : [[NSMutableArray alloc] init]; _originProperties = [[NSMutableDictionary alloc] init]; for (NSString *key in targetAttributeList) { [_originProperties setValue:[self valueForKey:key] forKey:key]; if (![attributeList containsObject:key]) { [attributeList addObject:key]; [self setValue:[target valueForKey:key] forKey:key]; } } _lastMergedList = targetAttributeList; _attributeList = [attributeList copy]; self.merging = false; } - (void)resetProperties { self.merging = true; for (NSString *key in _lastMergedList) { [self setValue:[_originProperties valueForKey:key] forKey:key]; } _caller = nil; _lastMergedList = nil; _attributeList = _propList; self.merging = false; } - (CGColor *)getCurrentColor { if (self.color != nil) { return [self.color CGColor]; } if (_caller != nil) { return [_caller getCurrentColor]; } RNSVGPlatformView *parentView = [self superview]; if ([parentView isKindOfClass:[RNSVGRenderable class]]) { return [(RNSVGRenderable *)parentView getCurrentColor]; } else if ([parentView isKindOfClass:[RNSVGSvgView class]]) { return [[(RNSVGSvgView *)parentView color] CGColor]; } return nil; } @end ================================================ FILE: apple/RNSVGRenderableModule.h ================================================ /** * 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 RCT_NEW_ARCH_ENABLED #import #else #import #endif @interface RNSVGRenderableModule : NSObject #ifdef RCT_NEW_ARCH_ENABLED #else #endif @end ================================================ FILE: apple/RNSVGRenderableModule.mm ================================================ /** * 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 #import #import #import "RNSVGPathMeasure.h" #import "RNSVGRenderable.h" #import "RCTConvert+RNSVG.h" #import "RNSVGCGFCRule.h" @implementation RNSVGRenderableModule RCT_EXPORT_MODULE() #ifdef RCT_NEW_ARCH_ENABLED @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED; #endif // RCT_NEW_ARCH_ENABLED @synthesize bridge = _bridge; 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 = CGRectNull; if (fill && !CGRectIsEmpty(svg.fillBounds)) { bounds = CGRectUnion(bounds, svg.fillBounds); } if (stroke && !CGRectIsEmpty(svg.strokeBounds)) { bounds = CGRectUnion(bounds, svg.strokeBounds); } if (markers && !CGRectIsEmpty(svg.markerBounds)) { bounds = CGRectUnion(bounds, svg.markerBounds); } if (clipped) { CGPathRef clipPath = [svg getClipPath]; CGRect clipBounds = CGPathGetPathBoundingBox(clipPath); if (clipPath && !CGRectIsEmpty(clipBounds)) { bounds = CGRectIntersection(bounds, clipBounds); } } if (CGRectIsNull(bounds)) { bounds = CGRectZero; } 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; #ifdef RCT_NEW_ARCH_ENABLED dispatch_sync(dispatch_get_main_queue(), ^{ view = [self.viewRegistry_DEPRECATED viewForReactTag:reactTag]; }); #else dispatch_sync(dispatch_get_main_queue(), ^{ view = [self.bridge.uiManager viewForReactTag:reactTag]; }); #endif // RCT_NEW_ARCH_ENABLED return view; } #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } #endif @end ================================================ FILE: apple/RNSVGSvgViewModule.h ================================================ /** * 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 RCT_NEW_ARCH_ENABLED #import #else #import #endif @interface RNSVGSvgViewModule : NSObject #ifdef RCT_NEW_ARCH_ENABLED #else #endif @end ================================================ FILE: apple/RNSVGSvgViewModule.mm ================================================ /** * 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 #import #import #import "RNSVGSvgView.h" @implementation RNSVGSvgViewModule RCT_EXPORT_MODULE() #ifdef RCT_NEW_ARCH_ENABLED @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED; #endif // RCT_NEW_ARCH_ENABLED @synthesize bridge = _bridge; - (void)toDataURL:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback attempt:(int)attempt { #ifdef RCT_NEW_ARCH_ENABLED [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { __kindof RNSVGPlatformView *view = [viewRegistry viewForReactTag:reactTag]; #else [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, __unused NSDictionary *viewRegistry) { __kindof RNSVGPlatformView *view = [uiManager viewForReactTag:reactTag]; #endif // RCT_NEW_ARCH_ENABLED NSString *b64; if ([view isKindOfClass:[RNSVGSvgView class]]) { RNSVGSvgView *svg = view; if (options == nil) { b64 = [svg getDataURLWithBounds:svg.boundingBox]; } 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(@[]); } }]; }; RCT_EXPORT_METHOD(toDataURL : (nonnull NSNumber *)reactTag options : (NSDictionary *)options callback : (RCTResponseSenderBlock)callback) { [self toDataURL:reactTag options:options callback:callback attempt:0]; } #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } #endif - (dispatch_queue_t)methodQueue { if (self.bridge) { return RCTGetUIManagerQueue(); } else { return dispatch_get_main_queue(); } } @end ================================================ FILE: apple/RNSVGUIKit.h ================================================ // Most (if not all) of this file could probably go away once react-native-macos's version of RCTUIKit.h makes its way // upstream. https://github.com/microsoft/react-native-macos/issues/242 #ifdef RCT_NEW_ARCH_ENABLED #import #endif // RCT_NEW_ARCH_ENABLED #import #if !TARGET_OS_OSX #import #define RNSVGColor UIColor #define RNSVGPlatformView UIView #define RNSVGTextView UILabel #ifdef RCT_NEW_ARCH_ENABLED #define RNSVGView RCTViewComponentView #else #define RNSVGView UIView #endif // RCT_NEW_ARCH_ENABLED #define RNSVGUIGraphicsBeginImageContextWithOptions UIGraphicsBeginImageContextWithOptions #define RNSVGUIGraphicsEndImageContext UIGraphicsEndImageContext #define RNSVGUIGraphicsGetImageFromCurrentImageContext UIGraphicsGetImageFromCurrentImageContext #else // TARGET_OS_OSX [ // Due to name mangling, calling c-style functions from .mm files will fail, therefore we need to wrap them with extern // "C" so they are handled correctly. We also need to have imports positioned in a correct way, so that this extern "C" // wrapper is used before the functions from RCTUIKit are used. #ifdef __cplusplus extern "C" { #endif #import #ifdef __cplusplus } #endif #define RNSVGColor NSColor #define RNSVGPlatformView NSView #define RNSVGTextView NSTextView @interface RNSVGColor (CGColor) - (NSColor *)CGColor; @end @interface RNSVGView : #ifdef RCT_NEW_ARCH_ENABLED RCTViewComponentView #else RCTUIView #endif // RCT_NEW_ARCH_ENABLED @property CGPoint center; @property (nonatomic, strong) RNSVGColor *tintColor; @end // TODO: These could probably be a part of react-native-macos // See https://github.com/microsoft/react-native-macos/issues/658 and // https://github.com/microsoft/react-native-macos/issues/659 @interface NSImage (RNSVGMacOSExtensions) @property (readonly) CGImageRef CGImage; @end @interface NSValue (RNSVGMacOSExtensions) + (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform; + (NSValue *)valueWithCGPoint:(CGPoint)point; @property (readonly) CGAffineTransform CGAffineTransformValue; @property (readonly) CGPoint CGPointValue; @end // These functions are copied from react-native-macos to enable compatibility with react-native-macos@0.76+ // https://github.com/microsoft/react-native-macos/blob/7361b165ef633d3d95dbdb69da58ff6119f07369/packages/react-native/React/Base/macOS/RCTUIKit.m // See https://github.com/software-mansion/react-native-svg/issues/2528 void RNSVGUIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale); void RNSVGUIGraphicsEndImageContext(void); NSImage *RNSVGUIGraphicsGetImageFromCurrentImageContext(void); #endif // ] TARGET_OS_OSX ================================================ FILE: apple/RNSVGUIKit.macos.mm ================================================ #import "RNSVGUIKit.h" #import #if TARGET_OS_OSX @implementation RNSVGView { } - (CGPoint)center { NSRect frameRect = self.frame; CGFloat xCenter = frameRect.origin.x + frameRect.size.width / 2; CGFloat yCenter = frameRect.origin.y + frameRect.size.height / 2; return CGPointMake(xCenter, yCenter); } - (void)setCenter:(CGPoint)point { NSRect frameRect = self.frame; CGFloat xOrigin = frameRect.origin.x - frameRect.size.width / 2; CGFloat yOrigin = frameRect.origin.y - frameRect.size.height / 2; self.frame = CGRectMake(xOrigin, yOrigin, frameRect.size.width, frameRect.size.height); } @end @implementation NSImage (RNSVGMacOSExtensions) - (CGImageRef)CGImage { return [self CGImageForProposedRect:NULL context:NULL hints:NULL]; } @end @implementation NSValue (RNSVGMacOSExtensions) + (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform { return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)]; } + (NSValue *)valueWithCGPoint:(CGPoint)point { return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)]; } - (CGAffineTransform)CGAffineTransformValue { CGAffineTransform value; [self getValue:&value]; return value; } - (CGPoint)CGPointValue { CGPoint value; [self getValue:&value]; return value; } @end static char RCTGraphicsContextSizeKey; void RNSVGUIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale) { if (scale == 0.0) { // TODO: Assert. We can't assume a display scale on macOS scale = 1.0; } size_t width = ceilf(size.width * scale); size_t height = ceilf(size.height * scale); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef ctx = CGBitmapContextCreate( NULL, width, height, 8 /*bitsPerComponent*/, width * 4 /*bytesPerRow*/, colorSpace, kCGImageAlphaPremultipliedFirst); CGColorSpaceRelease(colorSpace); if (ctx != NULL) { // flip the context (top left at 0, 0) and scale it CGContextTranslateCTM(ctx, 0.0, height); CGContextScaleCTM(ctx, scale, -scale); NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES]; objc_setAssociatedObject( graphicsContext, &RCTGraphicsContextSizeKey, [NSValue valueWithSize:size], OBJC_ASSOCIATION_COPY_NONATOMIC); [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:graphicsContext]; CFRelease(ctx); } } void RNSVGUIGraphicsEndImageContext(void) { RCTAssert( objc_getAssociatedObject([NSGraphicsContext currentContext], &RCTGraphicsContextSizeKey), @"The current graphics context is not a React image context!"); [NSGraphicsContext restoreGraphicsState]; } NSImage *RNSVGUIGraphicsGetImageFromCurrentImageContext(void) { NSImage *image = nil; NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; NSValue *sizeValue = objc_getAssociatedObject(graphicsContext, &RCTGraphicsContextSizeKey); if (sizeValue != nil) { CGImageRef cgImage = CGBitmapContextCreateImage([graphicsContext CGContext]); if (cgImage != NULL) { NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; image = [[NSImage alloc] initWithSize:[sizeValue sizeValue]]; [image addRepresentation:imageRep]; CFRelease(cgImage); } } return image; } #endif // TARGET_OS_OSX ================================================ FILE: apple/Shapes/RNSVGCircle.h ================================================ /** * 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 #import "RNSVGPath.h" @interface RNSVGCircle : RNSVGRenderable @property (nonatomic, strong) RNSVGLength *cx; @property (nonatomic, strong) RNSVGLength *cy; @property (nonatomic, strong) RNSVGLength *r; @end ================================================ FILE: apple/Shapes/RNSVGCircle.mm ================================================ /** * 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 "RNSVGCircle.h" #import #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGCircle #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id cx = RNSVGConvertFollyDynamicToId(newProps.cx); if (cx != nil) { self.cx = [RCTConvert RNSVGLength:cx]; } id cy = RNSVGConvertFollyDynamicToId(newProps.cy); if (cy != nil) { self.cy = [RCTConvert RNSVGLength:cy]; } id r = RNSVGConvertFollyDynamicToId(newProps.r); if (r != nil) { self.r = [RCTConvert RNSVGLength:r]; } setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _cx = nil; _cy = nil; _r = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setCx:(RNSVGLength *)cx { if ([cx isEqualTo:_cx]) { return; } [self invalidate]; _cx = cx; } - (void)setCy:(RNSVGLength *)cy { if ([cy isEqualTo:_cy]) { return; } [self invalidate]; _cy = cy; } - (void)setR:(RNSVGLength *)r { if ([r isEqualTo:_r]) { return; } [self invalidate]; _r = r; } - (CGPathRef)getPath:(CGContextRef)context { CGMutablePathRef path = CGPathCreateMutable(); CGFloat cx = [self relativeOnWidth:self.cx]; CGFloat cy = [self relativeOnHeight:self.cy]; CGFloat r = [self relativeOnOther:self.r]; CGPathAddArc(path, nil, cx, cy, r, 0, 2 * (CGFloat)M_PI, NO); return (CGPathRef)CFAutorelease(path); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGCircleCls(void) { return RNSVGCircle.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Shapes/RNSVGEllipse.h ================================================ /** * 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 #import "RNSVGPath.h" @interface RNSVGEllipse : RNSVGRenderable @property (nonatomic, strong) RNSVGLength *cx; @property (nonatomic, strong) RNSVGLength *cy; @property (nonatomic, strong) RNSVGLength *rx; @property (nonatomic, strong) RNSVGLength *ry; @end ================================================ FILE: apple/Shapes/RNSVGEllipse.mm ================================================ /** * 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 "RNSVGEllipse.h" #import #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGEllipse #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id cx = RNSVGConvertFollyDynamicToId(newProps.cx); if (cx != nil) { self.cx = [RCTConvert RNSVGLength:cx]; } id cy = RNSVGConvertFollyDynamicToId(newProps.cy); if (cy != nil) { self.cy = [RCTConvert RNSVGLength:cy]; } id rx = RNSVGConvertFollyDynamicToId(newProps.rx); if (rx != nil) { self.rx = [RCTConvert RNSVGLength:rx]; } id ry = RNSVGConvertFollyDynamicToId(newProps.ry); if (ry != nil) { self.ry = [RCTConvert RNSVGLength:ry]; } setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _cx = nil; _cy = nil; _rx = nil; _ry = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setCx:(RNSVGLength *)cx { if ([cx isEqualTo:_cx]) { return; } [self invalidate]; _cx = cx; } - (void)setCy:(RNSVGLength *)cy { if ([cy isEqualTo:_cy]) { return; } [self invalidate]; _cy = cy; } - (void)setRx:(RNSVGLength *)rx { if ([rx isEqualTo:_rx]) { return; } [self invalidate]; _rx = rx; } - (void)setRy:(RNSVGLength *)ry { if ([ry isEqualTo:_ry]) { return; } [self invalidate]; _ry = ry; } - (CGPathRef)getPath:(CGContextRef)context { CGMutablePathRef path = CGPathCreateMutable(); CGFloat cx = [self relativeOnWidth:self.cx]; CGFloat cy = [self relativeOnHeight:self.cy]; CGFloat rx = [self relativeOnWidth:self.rx]; CGFloat ry = [self relativeOnHeight:self.ry]; CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2)); return (CGPathRef)CFAutorelease(path); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGEllipseCls(void) { return RNSVGEllipse.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Shapes/RNSVGLine.h ================================================ /** * 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 #import "RNSVGPath.h" @interface RNSVGLine : RNSVGRenderable @property (nonatomic, strong) RNSVGLength *x1; @property (nonatomic, strong) RNSVGLength *y1; @property (nonatomic, strong) RNSVGLength *x2; @property (nonatomic, strong) RNSVGLength *y2; @end ================================================ FILE: apple/Shapes/RNSVGLine.mm ================================================ /** * 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 "RNSVGLine.h" #import #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGLine #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x1 = RNSVGConvertFollyDynamicToId(newProps.x1); if (x1 != nil) { self.x1 = [RCTConvert RNSVGLength:x1]; } id y1 = RNSVGConvertFollyDynamicToId(newProps.y1); if (y1 != nil) { self.y1 = [RCTConvert RNSVGLength:y1]; } id x2 = RNSVGConvertFollyDynamicToId(newProps.x2); if (x2 != nil) { self.x2 = [RCTConvert RNSVGLength:x2]; } id y2 = RNSVGConvertFollyDynamicToId(newProps.y2); if (y2 != nil) { self.y2 = [RCTConvert RNSVGLength:y2]; } setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x1 = nil; _y1 = nil; _x2 = nil; _y2 = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setX1:(RNSVGLength *)x1 { if ([x1 isEqualTo:_x1]) { return; } [self invalidate]; _x1 = x1; } - (void)setY1:(RNSVGLength *)y1 { if ([y1 isEqualTo:_y1]) { return; } [self invalidate]; _y1 = y1; } - (void)setX2:(RNSVGLength *)x2 { if ([x2 isEqualTo:_x2]) { return; } [self invalidate]; _x2 = x2; } - (void)setY2:(RNSVGLength *)y2 { if ([y2 isEqualTo:_y2]) { return; } [self invalidate]; _y2 = y2; } - (CGPathRef)getPath:(CGContextRef)context { CGMutablePathRef path = CGPathCreateMutable(); CGFloat x1 = [self relativeOnWidth:self.x1]; CGFloat y1 = [self relativeOnHeight:self.y1]; CGFloat x2 = [self relativeOnWidth:self.x2]; CGFloat y2 = [self relativeOnHeight:self.y2]; CGPathMoveToPoint(path, nil, x1, y1); CGPathAddLineToPoint(path, nil, x2, y2); return (CGPathRef)CFAutorelease(path); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGLineCls(void) { return RNSVGLine.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Shapes/RNSVGRect.h ================================================ /** * 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 #import "RNSVGPath.h" @interface RNSVGRect : RNSVGRenderable @property (nonatomic, strong) RNSVGLength *x; @property (nonatomic, strong) RNSVGLength *y; @property (nonatomic, strong) RNSVGLength *rectwidth; @property (nonatomic, strong) RNSVGLength *rectheight; @property (nonatomic, strong) RNSVGLength *rx; @property (nonatomic, strong) RNSVGLength *ry; @end ================================================ FILE: apple/Shapes/RNSVGRect.mm ================================================ /** * 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 "RNSVGRect.h" #import #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGRect #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); id x = RNSVGConvertFollyDynamicToId(newProps.x); if (x != nil) { self.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(newProps.y); if (y != nil) { self.y = [RCTConvert RNSVGLength:y]; } id rectheight = RNSVGConvertFollyDynamicToId(newProps.height); if (rectheight != nil) { self.rectheight = [RCTConvert RNSVGLength:rectheight]; } id rectwidth = RNSVGConvertFollyDynamicToId(newProps.width); if (rectwidth != nil) { self.rectwidth = [RCTConvert RNSVGLength:rectwidth]; } id rx = RNSVGConvertFollyDynamicToId(newProps.rx); if (rx != nil) { self.rx = [RCTConvert RNSVGLength:rx]; } id ry = RNSVGConvertFollyDynamicToId(newProps.ry); if (ry != nil) { self.ry = [RCTConvert RNSVGLength:ry]; } setCommonRenderableProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _x = nil; _y = nil; _rectwidth = nil; _rectheight = nil; _rx = nil; _ry = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setX:(RNSVGLength *)x { if ([x isEqualTo:_x]) { return; } [self invalidate]; _x = x; } - (void)setY:(RNSVGLength *)y { if ([y isEqualTo:_y]) { return; } [self invalidate]; _y = y; } - (void)setRectwidth:(RNSVGLength *)rectwidth { if ([rectwidth isEqualTo:_rectwidth]) { return; } [self invalidate]; _rectwidth = rectwidth; } - (void)setRectheight:(RNSVGLength *)rectheight { if ([rectheight isEqualTo:_rectheight]) { return; } [self invalidate]; _rectheight = rectheight; } - (void)setRx:(RNSVGLength *)rx { if ([rx isEqualTo:_rx]) { return; } [self invalidate]; _rx = rx; } - (void)setRy:(RNSVGLength *)ry { if ([ry isEqualTo:_ry]) { return; } [self invalidate]; _ry = ry; } - (CGPathRef)getPath:(CGContextRef)context { CGMutablePathRef path = CGPathCreateMutable(); CGFloat x = [self relativeOnWidth:self.x]; CGFloat y = [self relativeOnHeight:self.y]; CGFloat width = [self relativeOnWidth:self.rectwidth]; CGFloat height = [self relativeOnHeight:self.rectheight]; if (self.rx != nil || self.ry != nil) { CGFloat rx = 0; CGFloat ry = 0; if (self.rx == nil) { ry = [self relativeOnHeight:self.ry]; rx = ry; } else if (self.ry == nil) { rx = [self relativeOnWidth:self.rx]; ry = rx; } else { rx = [self relativeOnWidth:self.rx]; ry = [self relativeOnHeight:self.ry]; } if (rx > width / 2) { rx = width / 2; } if (ry > height / 2) { ry = height / 2; } CGPathAddRoundedRect(path, nil, CGRectMake(x, y, width, height), rx, ry); } else { CGPathAddRect(path, nil, CGRectMake(x, y, width, height)); } return (CGPathRef)CFAutorelease(path); } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGRectCls(void) { return RNSVGRect.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Text/RNSVGFontData.h ================================================ #import #import "RNSVGUIKit.h" #import "RNSVGPropHelper.h" #import "RNSVGTextProperties.h" @interface RNSVGFontData : NSObject { @public CGFloat fontSize; NSString *fontSize_; NSString *fontFamily; enum RNSVGFontStyle fontStyle; NSDictionary *fontData; enum RNSVGFontWeight fontWeight; int absoluteFontWeight; NSString *fontFeatureSettings; enum RNSVGFontVariantLigatures fontVariantLigatures; enum RNSVGTextAnchor textAnchor; enum RNSVGTextDecoration textDecoration; CGFloat kerning; CGFloat wordSpacing; CGFloat letterSpacing; bool manualKerning; } + (instancetype)Defaults; + (CGFloat)toAbsoluteWithNSString:(NSString *)string fontSize:(CGFloat)fontSize; + (instancetype)initWithNSDictionary:(NSDictionary *)font parent:(RNSVGFontData *)parent; @end #define RNSVGFontData_DEFAULT_FONT_SIZE 12.0 ================================================ FILE: apple/Text/RNSVGFontData.mm ================================================ #import "RNSVGFontData.h" #import "RNSVGNode.h" #import "RNSVGPropHelper.h" #import "RNSVGTextProperties.h" #define RNSVG_DEFAULT_KERNING 0.0 #define RNSVG_DEFAULT_WORD_SPACING 0.0 #define RNSVG_DEFAULT_LETTER_SPACING 0.0 static NSString *KERNING = @"kerning"; static NSString *FONT_SIZE = @"fontSize"; static NSString *FONT_DATA = @"fontData"; static NSString *FONT_STYLE = @"fontStyle"; static NSString *FONT_WEIGHT = @"fontWeight"; static NSString *FONT_FAMILY = @"fontFamily"; static NSString *TEXT_ANCHOR = @"textAnchor"; static NSString *WORD_SPACING = @"wordSpacing"; static NSString *LETTER_SPACING = @"letterSpacing"; static NSString *TEXT_DECORATION = @"textDecoration"; static NSString *FONT_FEATURE_SETTINGS = @"fontFeatureSettings"; static NSString *FONT_VARIANT_LIGATURES = @"fontVariantLigatures"; RNSVGFontData *RNSVGFontData_Defaults; @implementation RNSVGFontData + (instancetype)Defaults { if (!RNSVGFontData_Defaults) { RNSVGFontData *defaults = [RNSVGFontData alloc]; defaults->fontData = nil; defaults->fontFamily = @""; defaults->fontStyle = RNSVGFontStyleNormal; defaults->fontWeight = RNSVGFontWeightNormal; defaults->absoluteFontWeight = 400; defaults->fontFeatureSettings = @""; defaults->fontVariantLigatures = RNSVGFontVariantLigaturesNormal; defaults->textAnchor = RNSVGTextAnchorStart; defaults->textDecoration = RNSVGTextDecorationNone; defaults->manualKerning = false; defaults->kerning = RNSVG_DEFAULT_KERNING; defaults->fontSize = RNSVG_DEFAULT_FONT_SIZE; defaults->wordSpacing = RNSVG_DEFAULT_WORD_SPACING; defaults->letterSpacing = RNSVG_DEFAULT_LETTER_SPACING; RNSVGFontData_Defaults = defaults; } return RNSVGFontData_Defaults; } + (CGFloat)toAbsoluteWithNSString:(NSString *)string fontSize:(CGFloat)fontSize { return [RNSVGPropHelper fromRelativeWithNSString:string relative:0 fontSize:fontSize]; } - (void)setInheritedWeight:(RNSVGFontData *)parent { absoluteFontWeight = parent->absoluteFontWeight; fontWeight = parent->fontWeight; } RNSVGFontWeight nearestFontWeight(int absoluteFontWeight) { return RNSVGFontWeights[(int)round(absoluteFontWeight / 100.0)]; } - (void)handleNumericWeight:(RNSVGFontData *)parent weight:(double)weight { long roundWeight = round(weight); if (roundWeight >= 1 && roundWeight <= 1000) { absoluteFontWeight = (int)roundWeight; fontWeight = nearestFontWeight(absoluteFontWeight); } else { [self setInheritedWeight:parent]; } } // https://drafts.csswg.org/css-fonts-4/#relative-weights int AbsoluteFontWeight(RNSVGFontWeight fontWeight, RNSVGFontData *parent) { if (fontWeight == RNSVGFontWeightBolder) { return bolder(parent->absoluteFontWeight); } else if (fontWeight == RNSVGFontWeightLighter) { return lighter(parent->absoluteFontWeight); } else { return RNSVGAbsoluteFontWeights[fontWeight]; } } int bolder(int inherited) { if (inherited < 350) { return 400; } else if (inherited < 550) { return 700; } else if (inherited < 900) { return 900; } else { return inherited; } } int lighter(int inherited) { if (inherited < 100) { return inherited; } else if (inherited < 550) { return 100; } else if (inherited < 750) { return 400; } else { return 700; } } + (instancetype)initWithNSDictionary:(NSDictionary *)font parent:(RNSVGFontData *)parent { RNSVGFontData *data = [RNSVGFontData alloc]; CGFloat parentFontSize = parent->fontSize; if ([font objectForKey:FONT_SIZE]) { id fontSize = [font objectForKey:FONT_SIZE]; if ([fontSize isKindOfClass:NSNumber.class]) { NSNumber *fs = fontSize; data->fontSize = (CGFloat)[fs doubleValue]; } else { data->fontSize = [RNSVGPropHelper fromRelativeWithNSString:fontSize relative:parentFontSize fontSize:parentFontSize]; } } else { data->fontSize = parentFontSize; } if ([font objectForKey:FONT_WEIGHT]) { id fontWeight = [font objectForKey:FONT_WEIGHT]; if ([fontWeight isKindOfClass:NSNumber.class]) { [data handleNumericWeight:parent weight:[fontWeight doubleValue]]; } else { NSString *weight = fontWeight; NSInteger fw = RNSVGFontWeightFromString(weight); if (fw != -1) { data->absoluteFontWeight = AbsoluteFontWeight((RNSVGFontWeight)fw, parent); data->fontWeight = nearestFontWeight(data->absoluteFontWeight); } else if ([weight length] != 0) { [data handleNumericWeight:parent weight:[weight doubleValue]]; } else { [data setInheritedWeight:parent]; } } } else { [data setInheritedWeight:parent]; } data->fontData = [font objectForKey:FONT_DATA] ? [font objectForKey:FONT_DATA] : parent->fontData; data->fontFamily = [font objectForKey:FONT_FAMILY] ? [font objectForKey:FONT_FAMILY] : parent->fontFamily; NSString *style = [font objectForKey:FONT_STYLE]; data->fontStyle = style ? RNSVGFontStyleFromString(style) : parent->fontStyle; NSString *feature = [font objectForKey:FONT_FEATURE_SETTINGS]; data->fontFeatureSettings = feature ? [font objectForKey:FONT_FEATURE_SETTINGS] : parent->fontFeatureSettings; NSString *variant = [font objectForKey:FONT_VARIANT_LIGATURES]; data->fontVariantLigatures = variant ? RNSVGFontVariantLigaturesFromString(variant) : parent->fontVariantLigatures; NSString *anchor = [font objectForKey:TEXT_ANCHOR]; data->textAnchor = anchor ? RNSVGTextAnchorFromString(anchor) : parent->textAnchor; NSString *decoration = [font objectForKey:TEXT_DECORATION]; data->textDecoration = decoration ? RNSVGTextDecorationFromString(decoration) : parent->textDecoration; CGFloat fontSize = data->fontSize; id kerning = [font objectForKey:KERNING]; data->manualKerning = (kerning || parent->manualKerning); if ([kerning isKindOfClass:NSNumber.class]) { NSNumber *kern = kerning; data->kerning = (CGFloat)[kern doubleValue]; } else { data->kerning = kerning ? [RNSVGFontData toAbsoluteWithNSString:kerning fontSize:fontSize] : parent->kerning; } id wordSpacing = [font objectForKey:WORD_SPACING]; if ([wordSpacing isKindOfClass:NSNumber.class]) { NSNumber *ws = wordSpacing; data->wordSpacing = (CGFloat)[ws doubleValue]; } else { data->wordSpacing = wordSpacing ? [RNSVGFontData toAbsoluteWithNSString:wordSpacing fontSize:fontSize] : parent->wordSpacing; } id letterSpacing = [font objectForKey:LETTER_SPACING]; if ([letterSpacing isKindOfClass:NSNumber.class]) { NSNumber *ls = letterSpacing; data->letterSpacing = (CGFloat)[ls doubleValue]; } else { data->letterSpacing = letterSpacing ? [RNSVGFontData toAbsoluteWithNSString:letterSpacing fontSize:fontSize] : parent->letterSpacing; } return data; } @end ================================================ FILE: apple/Text/RNSVGGlyphContext.h ================================================ #import #import #import "RNSVGFontData.h" @class RNSVGText; @class RNSVGGroup; @class RNSVGGlyphContext; @interface RNSVGGlyphContext : NSObject - (CTFontRef)getGlyphFont; - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height; - (RNSVGFontData *)getFont; - (CGFloat)getFontSize; - (CGFloat)getHeight; - (CGFloat)getWidth; - (CGFloat)nextDeltaX; - (CGFloat)nextDeltaY; - (CGFloat)nextRotation; - (CGFloat)nextXWithDouble:(CGFloat)advance; - (CGFloat)nextY; - (void)popContext; - (void)pushContext:(RNSVGText *)node font:(NSDictionary *)font x:(NSArray *)x y:(NSArray *)y deltaX:(NSArray *)deltaX deltaY:(NSArray *)deltaY rotate:(NSArray *)rotate; - (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font; - (NSArray *)getFontContext; @end ================================================ FILE: apple/Text/RNSVGGlyphContext.mm ================================================ #import "RNSVGGlyphContext.h" #import #import "RNSVGFontData.h" #import "RNSVGNode.h" #import "RNSVGPropHelper.h" #import "RNSVGText.h" // https://www.w3.org/TR/SVG/text.html#TSpanElement @interface RNSVGGlyphContext () { @public // Current stack (one per node push/pop) NSMutableArray *mFontContext_; // Unique input attribute lists (only added if node sets a value) NSMutableArray *> *mXsContext_; NSMutableArray *> *mYsContext_; NSMutableArray *> *mDXsContext_; NSMutableArray *> *mDYsContext_; NSMutableArray *> *mRsContext_; // Unique index into attribute list (one per unique list) NSMutableArray *mXIndices_; NSMutableArray *mYIndices_; NSMutableArray *mDXIndices_; NSMutableArray *mDYIndices_; NSMutableArray *mRIndices_; // Index of unique context used (one per node push/pop) NSMutableArray *mXsIndices_; NSMutableArray *mYsIndices_; NSMutableArray *mDXsIndices_; NSMutableArray *mDYsIndices_; NSMutableArray *mRsIndices_; // Calculated on push context, percentage and em length depends on parent font size CGFloat mFontSize_; RNSVGFontData *topFont_; // Current accumulated values // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate // syntax is the same as that for CGFloat mX_; CGFloat mY_; // https://www.w3.org/TR/SVG/types.html#Length CGFloat mDX_; CGFloat mDY_; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates // https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute NSArray *mXs_; // https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute NSArray *mYs_; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeLengths // https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute NSArray *mDXs_; // https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute NSArray *mDYs_; // Current SVGLengthList // https://www.w3.org/TR/SVG/types.html#DataTypeNumbers // https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute NSArray *mRs_; // Current attribute list index long mXsIndex_; long mYsIndex_; long mDXsIndex_; long mDYsIndex_; long mRsIndex_; // Current value index in current attribute list long mXIndex_; long mYIndex_; long mDXIndex_; long mDYIndex_; long mRIndex_; // Top index of stack long mTop_; // Constructor parameters CGFloat mWidth_; CGFloat mHeight_; } - (void)pushContext:(RNSVGText *)node font:(NSDictionary *)font x:(NSArray *)x y:(NSArray *)y deltaX:(NSArray *)deltaX deltaY:(NSArray *)deltaY rotate:(NSArray *)rotate; - (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font; @end @implementation RNSVGGlyphContext - (NSArray *)getFontContext { return mFontContext_; } - (CTFontRef)getGlyphFont { CGFloat size = topFont_->fontSize; NSString *fontFamily = topFont_->fontFamily; NSString *fontStyle = RNSVGFontStyleStrings[topFont_->fontStyle]; NSString *fontWeight = RNSVGFontWeightStrings[topFont_->fontWeight]; UIFont *font = [RCTFont updateFont:nil withFamily:[fontFamily isEqualToString:@""] ? nil : fontFamily size:@(isnan(size) ? 0 : size) weight:fontWeight style:fontStyle variant:nil scaleMultiplier:1.0]; CTFontRef ref = (__bridge CTFontRef)font; double weight = topFont_->absoluteFontWeight; if (weight == 400) { return ref; } CFArrayRef cgAxes = CTFontCopyVariationAxes(ref); if (cgAxes == 0) { return ref; } CFIndex cgAxisCount = CFArrayGetCount(cgAxes); CFNumberRef wght_id = 0; for (CFIndex i = 0; i < cgAxisCount; ++i) { CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i); if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { continue; } CFDictionaryRef cgAxisDict = (CFDictionaryRef)cgAxis; CFTypeRef axisName = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisNameKey); if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { continue; } CFStringRef axisNameString = (CFStringRef)axisName; NSString *axisNameNSString = (__bridge NSString *)(axisNameString); if (![@"Weight" isEqualToString:axisNameNSString] && ![@"Size" isEqualToString:axisNameNSString]) { continue; } CFTypeRef axisMinValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMinimumValueKey); if (axisMinValue && CFGetTypeID(axisMinValue) == CFNumberGetTypeID()) { CFNumberRef axisMinValueNumber = (CFNumberRef)axisMinValue; double axisMinValueDouble; if (CFNumberGetValue(axisMinValueNumber, kCFNumberDoubleType, &axisMinValueDouble)) { weight = fmax(axisMinValueDouble, weight); } } CFTypeRef axisMaxValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMaximumValueKey); if (axisMaxValue && CFGetTypeID(axisMaxValue) == CFNumberGetTypeID()) { CFNumberRef axisMaxValueNumber = (CFNumberRef)axisMaxValue; double axisMaxValueDouble; if (CFNumberGetValue(axisMaxValueNumber, kCFNumberDoubleType, &axisMaxValueDouble)) { weight = fmin(axisMaxValueDouble, weight); } } CFTypeRef axisId = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisIdentifierKey); if (!axisId || CFGetTypeID(axisId) != CFNumberGetTypeID()) { continue; } wght_id = (CFNumberRef)axisId; break; } CFRelease(cgAxes); if (wght_id == 0) { return ref; } UIFontDescriptor *uifd = font.fontDescriptor; CTFontDescriptorRef ctfd = (__bridge CTFontDescriptorRef)(uifd); CTFontDescriptorRef newfd = CTFontDescriptorCreateCopyWithVariation(ctfd, wght_id, (CGFloat)weight); CTFontRef newfont = CTFontCreateCopyWithAttributes(ref, size, nil, newfd); CFRelease(newfd); return (CTFontRef)CFAutorelease(newfont); } - (void)pushIndices { [self->mXsIndices_ addObject:[NSNumber numberWithLong:self->mXsIndex_]]; [self->mYsIndices_ addObject:[NSNumber numberWithLong:self->mYsIndex_]]; [self->mDXsIndices_ addObject:[NSNumber numberWithLong:self->mDXsIndex_]]; [self->mDYsIndices_ addObject:[NSNumber numberWithLong:self->mDYsIndex_]]; [self->mRsIndices_ addObject:[NSNumber numberWithLong:self->mRsIndex_]]; } - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height { self = [super init]; self->mFontContext_ = [[NSMutableArray alloc] init]; self->mXsContext_ = [[NSMutableArray alloc] init]; self->mYsContext_ = [[NSMutableArray alloc] init]; self->mDXsContext_ = [[NSMutableArray alloc] init]; self->mDYsContext_ = [[NSMutableArray alloc] init]; self->mRsContext_ = [[NSMutableArray alloc] init]; self->mXIndices_ = [[NSMutableArray alloc] init]; self->mYIndices_ = [[NSMutableArray alloc] init]; self->mDXIndices_ = [[NSMutableArray alloc] init]; self->mDYIndices_ = [[NSMutableArray alloc] init]; self->mRIndices_ = [[NSMutableArray alloc] init]; self->mXsIndices_ = [[NSMutableArray alloc] init]; self->mYsIndices_ = [[NSMutableArray alloc] init]; self->mDXsIndices_ = [[NSMutableArray alloc] init]; self->mDYsIndices_ = [[NSMutableArray alloc] init]; self->mRsIndices_ = [[NSMutableArray alloc] init]; self->mFontSize_ = RNSVGFontData_DEFAULT_FONT_SIZE; self->topFont_ = [RNSVGFontData Defaults]; self->mXs_ = [[NSArray alloc] init]; self->mYs_ = [[NSArray alloc] init]; self->mDXs_ = [[NSArray alloc] init]; self->mDYs_ = [[NSArray alloc] init]; self->mRs_ = [[NSArray alloc] initWithObjects:[RNSVGLength lengthWithNumber:0], nil]; self->mXIndex_ = -1; self->mYIndex_ = -1; self->mDXIndex_ = -1; self->mDYIndex_ = -1; self->mRIndex_ = -1; self->mWidth_ = width; self->mHeight_ = height; [self->mXsContext_ addObject:self->mXs_]; [self->mYsContext_ addObject:self->mYs_]; [self->mDXsContext_ addObject:self->mDXs_]; [self->mDYsContext_ addObject:self->mDYs_]; [self->mRsContext_ addObject:self->mRs_]; [self->mXIndices_ addObject:[NSNumber numberWithLong:self->mXIndex_]]; [self->mYIndices_ addObject:[NSNumber numberWithLong:self->mYIndex_]]; [self->mDXIndices_ addObject:[NSNumber numberWithLong:self->mDXIndex_]]; [self->mDYIndices_ addObject:[NSNumber numberWithLong:self->mDYIndex_]]; [self->mRIndices_ addObject:[NSNumber numberWithLong:self->mRIndex_]]; [self->mFontContext_ addObject:self->topFont_]; [self pushIndices]; return self; } - (RNSVGFontData *)getFont { return topFont_; } - (RNSVGFontData *)getTopOrParentFont:(RNSVGGroup *)child { if (self->mTop_ > 0) { return self->topFont_; } else { RNSVGGroup *parentRoot = [child getParentTextRoot]; RNSVGFontData *Defaults = [RNSVGFontData Defaults]; while (parentRoot != nil) { RNSVGFontData *map = [[parentRoot getGlyphContext] getFont]; if (map != Defaults) { return map; } parentRoot = [parentRoot getParentTextRoot]; } return Defaults; } } - (void)pushNode:(RNSVGGroup *)node andFont:(NSDictionary *)font { RNSVGFontData *parent = [self getTopOrParentFont:node]; self->mTop_++; if (font == nil) { [self->mFontContext_ addObject:parent]; return; } RNSVGFontData *data = [RNSVGFontData initWithNSDictionary:font parent:parent]; self->mFontSize_ = data->fontSize; [self->mFontContext_ addObject:data]; self->topFont_ = data; } - (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font { [self pushNode:node andFont:font]; [self pushIndices]; } - (void)pushContext:(RNSVGText *)node font:(NSDictionary *)font x:(NSArray *)x y:(NSArray *)y deltaX:(NSArray *)deltaX deltaY:(NSArray *)deltaY rotate:(NSArray *)rotate { [self pushNode:(RNSVGGroup *)node andFont:font]; if (x != nil && [x count] != 0) { mXsIndex_++; mXIndex_ = -1; [mXIndices_ addObject:[NSNumber numberWithLong:mXIndex_]]; mXs_ = x; [mXsContext_ addObject:mXs_]; } if (y != nil && [y count] != 0) { mYsIndex_++; mYIndex_ = -1; [mYIndices_ addObject:[NSNumber numberWithLong:mYIndex_]]; mYs_ = y; [mYsContext_ addObject:mYs_]; } if (deltaX != nil && [deltaX count] != 0) { mDXsIndex_++; mDXIndex_ = -1; [mDXIndices_ addObject:[NSNumber numberWithLong:mDXIndex_]]; mDXs_ = deltaX; [mDXsContext_ addObject:mDXs_]; } if (deltaY != nil && [deltaY count] != 0) { mDYsIndex_++; mDYIndex_ = -1; [mDYIndices_ addObject:[NSNumber numberWithLong:mDYIndex_]]; mDYs_ = deltaY; [mDYsContext_ addObject:mDYs_]; } if (rotate != nil && [rotate count] != 0) { mRsIndex_++; mRIndex_ = -1; [mRIndices_ addObject:[NSNumber numberWithLong:mRIndex_]]; mRs_ = rotate; [mRsContext_ addObject:mRs_]; } [self pushIndices]; } - (void)popContext { [mFontContext_ removeLastObject]; [mXsIndices_ removeLastObject]; [mYsIndices_ removeLastObject]; [mDXsIndices_ removeLastObject]; [mDYsIndices_ removeLastObject]; [mRsIndices_ removeLastObject]; mTop_--; long x = mXsIndex_; long y = mYsIndex_; long dx = mDXsIndex_; long dy = mDYsIndex_; long r = mRsIndex_; topFont_ = [mFontContext_ lastObject]; mXsIndex_ = [[mXsIndices_ lastObject] longValue]; mYsIndex_ = [[mYsIndices_ lastObject] longValue]; mDXsIndex_ = [[mDXsIndices_ lastObject] longValue]; mDYsIndex_ = [[mDYsIndices_ lastObject] longValue]; mRsIndex_ = [[mRsIndices_ lastObject] longValue]; if (x != mXsIndex_) { [mXsContext_ removeObjectAtIndex:x]; mXs_ = [mXsContext_ objectAtIndex:mXsIndex_]; mXIndex_ = [[mXIndices_ objectAtIndex:mXsIndex_] longValue]; } if (y != mYsIndex_) { [mYsContext_ removeObjectAtIndex:y]; mYs_ = [mYsContext_ objectAtIndex:mYsIndex_]; mYIndex_ = [[mYIndices_ objectAtIndex:mYsIndex_] longValue]; } if (dx != mDXsIndex_) { [mDXsContext_ removeObjectAtIndex:dx]; mDXs_ = [mDXsContext_ objectAtIndex:mDXsIndex_]; mDXIndex_ = [[mDXIndices_ objectAtIndex:mDXsIndex_] longValue]; } if (dy != mDYsIndex_) { [mDYsContext_ removeObjectAtIndex:dy]; mDYs_ = [mDYsContext_ objectAtIndex:mDYsIndex_]; mDYIndex_ = [[mDYIndices_ objectAtIndex:mDYsIndex_] longValue]; } if (r != mRsIndex_) { [mRsContext_ removeObjectAtIndex:r]; mRs_ = [mRsContext_ objectAtIndex:mRsIndex_]; mRIndex_ = [[mRIndices_ objectAtIndex:mRsIndex_] longValue]; } } + (void)incrementIndices:(NSMutableArray *)indices topIndex:(long)topIndex { for (long index = topIndex; index >= 0; index--) { long xIndex = [[indices objectAtIndex:index] longValue]; [indices setObject:[NSNumber numberWithLong:xIndex + 1] atIndexedSubscript:index]; } } // https://www.w3.org/TR/SVG11/text.html#FontSizeProperty /** * Get font size from context. *

* ‘font-size’ * Value: < absolute-size > | < relative-size > | < length > | < percentage > | inherit * Initial: medium * Applies to: text content elements * Inherited: yes, the computed value is inherited * Percentages: refer to parent element's font size * Media: visual * Animatable: yes *

* This property refers to the size of the font from baseline to * baseline when multiple lines of text are set solid in a multiline * layout environment. *

* For SVG, if a < length > is provided without a unit identifier * (e.g., an unqualified number such as 128), the SVG user agent * processes the < length > as a height value in the current user * coordinate system. *

* If a < length > is provided with one of the unit identifiers * (e.g., 12pt or 10%), then the SVG user agent converts the * < length > into a corresponding value in the current user * coordinate system by applying the rules described in Units. *

* Except for any additional information provided in this specification, * the normative definition of the property is in CSS2 ([CSS2], section 15.2.4). */ - (CGFloat)getFontSize { return mFontSize_; } - (CGFloat)nextXWithDouble:(CGFloat)advance { [RNSVGGlyphContext incrementIndices:mXIndices_ topIndex:mXsIndex_]; long nextIndex = mXIndex_ + 1; if (nextIndex < (long)[mXs_ count]) { mDX_ = 0; mXIndex_ = nextIndex; RNSVGLength *length = [mXs_ objectAtIndex:nextIndex]; mX_ = [RNSVGPropHelper fromRelative:length relative:mWidth_ fontSize:mFontSize_]; } mX_ += advance; return mX_; } - (CGFloat)nextY { [RNSVGGlyphContext incrementIndices:mYIndices_ topIndex:mYsIndex_]; long nextIndex = mYIndex_ + 1; if (nextIndex < (long)[mYs_ count]) { mDY_ = 0; mYIndex_ = nextIndex; RNSVGLength *length = [mYs_ objectAtIndex:nextIndex]; mY_ = [RNSVGPropHelper fromRelative:length relative:mHeight_ fontSize:mFontSize_]; } return mY_; } - (CGFloat)nextDeltaX { [RNSVGGlyphContext incrementIndices:mDXIndices_ topIndex:mDXsIndex_]; long nextIndex = mDXIndex_ + 1; if (nextIndex < (long)[mDXs_ count]) { mDXIndex_ = nextIndex; RNSVGLength *length = [mDXs_ objectAtIndex:nextIndex]; CGFloat val = [RNSVGPropHelper fromRelative:length relative:mWidth_ fontSize:mFontSize_]; mDX_ += val; } return mDX_; } - (CGFloat)nextDeltaY { [RNSVGGlyphContext incrementIndices:mDYIndices_ topIndex:mDYsIndex_]; long nextIndex = mDYIndex_ + 1; if (nextIndex < (long)[mDYs_ count]) { mDYIndex_ = nextIndex; RNSVGLength *length = [mDYs_ objectAtIndex:nextIndex]; CGFloat val = [RNSVGPropHelper fromRelative:length relative:mHeight_ fontSize:mFontSize_]; mDY_ += val; } return mDY_; } - (CGFloat)nextRotation { [RNSVGGlyphContext incrementIndices:mRIndices_ topIndex:mRsIndex_]; long nextIndex = mRIndex_ + 1; long count = [mRs_ count]; if (nextIndex < count) { mRIndex_ = nextIndex; } else { mRIndex_ = count - 1; } return [mRs_[mRIndex_] value]; } - (CGFloat)getWidth { return mWidth_; } - (CGFloat)getHeight { return mHeight_; } @end ================================================ FILE: apple/Text/RNSVGPropHelper.h ================================================ #import #import #import "RNSVGLength.h" #ifndef RNSVGPropHelper_h #define RNSVGPropHelper_h @interface RNSVGPropHelper : NSObject + (CGFloat)fromRelativeWithNSString:(NSString *)length relative:(CGFloat)relative fontSize:(CGFloat)fontSize; + (CGFloat)fromRelative:(RNSVGLength *)length relative:(CGFloat)relative fontSize:(CGFloat)fontSize; + (CGFloat)fromRelative:(RNSVGLength *)length relative:(CGFloat)relative; @end #endif ================================================ FILE: apple/Text/RNSVGPropHelper.mm ================================================ #include "RNSVGPropHelper.h" @implementation RNSVGPropHelper + (CGFloat)fromRelativeWithNSString:(NSString *)length relative:(CGFloat)relative fontSize:(CGFloat)fontSize { length = [length stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSUInteger stringLength = [length length]; NSInteger percentIndex = stringLength - 1; if (stringLength == 0) { return 0; } else if ([length characterAtIndex:percentIndex] == '%') { return (CGFloat)[[length substringWithRange:NSMakeRange(0, percentIndex)] doubleValue] / 100 * relative; } else { NSInteger twoLetterUnitIndex = stringLength - 2; if (twoLetterUnitIndex > 0) { NSString *lastTwo = [length substringFromIndex:twoLetterUnitIndex]; NSUInteger end = twoLetterUnitIndex; CGFloat unit = 1; if ([lastTwo isEqualToString:@"px"]) { } else if ([lastTwo isEqualToString:@"em"]) { unit = fontSize; } else if ([lastTwo isEqualToString:@"ex"]) { unit = fontSize / 2; } else if ([lastTwo isEqualToString:@"pt"]) { unit = 1.25; } else if ([lastTwo isEqualToString:@"pc"]) { unit = 15; } else if ([lastTwo isEqualToString:@"mm"]) { unit = (CGFloat)3.543307; } else if ([lastTwo isEqualToString:@"cm"]) { unit = (CGFloat)35.43307; } else if ([lastTwo isEqualToString:@"in"]) { unit = 90; } else { end = stringLength; } return (CGFloat)[[length substringWithRange:NSMakeRange(0, end)] doubleValue] * unit; } else { return (CGFloat)[length doubleValue]; } } } + (CGFloat)fromRelative:(RNSVGLength *)length relative:(CGFloat)relative fontSize:(CGFloat)fontSize { RNSVGLengthUnitType unitType = length.unit; CGFloat value = length.value; CGFloat unit = 1; switch (unitType) { case SVG_LENGTHTYPE_NUMBER: case SVG_LENGTHTYPE_PX: return value; break; case SVG_LENGTHTYPE_PERCENTAGE: return value / 100 * relative; case SVG_LENGTHTYPE_EMS: unit = fontSize; break; case SVG_LENGTHTYPE_EXS: unit = fontSize / 2; break; case SVG_LENGTHTYPE_CM: unit = (CGFloat)35.43307; break; case SVG_LENGTHTYPE_MM: unit = (CGFloat)3.543307; break; case SVG_LENGTHTYPE_IN: unit = 90; break; case SVG_LENGTHTYPE_PT: unit = 1.25; break; case SVG_LENGTHTYPE_PC: unit = 15; break; default: case SVG_LENGTHTYPE_UNKNOWN: return value; } return value * unit; } + (CGFloat)fromRelative:(RNSVGLength *)length relative:(CGFloat)relative { RNSVGLengthUnitType unitType = length.unit; CGFloat value = length.value; CGFloat unit = 1; switch (unitType) { case SVG_LENGTHTYPE_NUMBER: case SVG_LENGTHTYPE_PX: return value; break; case SVG_LENGTHTYPE_PERCENTAGE: return value / 100 * relative; case SVG_LENGTHTYPE_EMS: unit = 12; break; case SVG_LENGTHTYPE_EXS: unit = 6; break; case SVG_LENGTHTYPE_CM: unit = (CGFloat)35.43307; break; case SVG_LENGTHTYPE_MM: unit = (CGFloat)3.543307; break; case SVG_LENGTHTYPE_IN: unit = 90; break; case SVG_LENGTHTYPE_PT: unit = 1.25; break; case SVG_LENGTHTYPE_PC: unit = 15; break; default: case SVG_LENGTHTYPE_UNKNOWN: return value; } return value * unit; } @end ================================================ FILE: apple/Text/RNSVGTSpan.h ================================================ /** * 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 #import #import "RNSVGUIKit.h" #import "RNSVGText.h" @interface RNSVGTSpan : RNSVGText @property (nonatomic, strong) NSString *content; @end ================================================ FILE: apple/Text/RNSVGTSpan.mm ================================================ /** * 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 "RNSVGTSpan.h" #import "RNSVGFontData.h" #import "RNSVGPathMeasure.h" #import "RNSVGText.h" #import "RNSVGTextPath.h" #import "RNSVGTextProperties.h" #import "RNSVGTopAlignedLabel.h" #import "RNSVGUIKit.h" static NSCharacterSet *RNSVGTSpan_separators = nil; static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGTSpan { CGFloat startOffset; RNSVGTextPath *textPath; NSMutableArray *emoji; NSMutableArray *emojiTransform; CGFloat cachedAdvance; CTFontRef fontRef; CGFloat firstX; CGFloat firstY; RNSVGPathMeasure *measure; RNSVGTopAlignedLabel *label; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.content = RCTNSStringFromStringNilIfEmpty(newProps.content); setCommonTextProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _content = nil; startOffset = 0; textPath = nil; cachedAdvance = 0; // these crash, hopefully it is always released by here // if (fontRef != nil) { // CFRelease(fontRef); // } fontRef = nil; firstX = 0; firstY = 0; emoji = [NSMutableArray arrayWithCapacity:0]; emojiTransform = [NSMutableArray arrayWithCapacity:0]; measure = [[RNSVGPathMeasure alloc] init]; RNSVGTSpan_separators = [NSCharacterSet whitespaceCharacterSet]; } #endif // RCT_NEW_ARCH_ENABLED - (id)init { self = [super init]; if (RNSVGTSpan_separators == nil) { RNSVGTSpan_separators = [NSCharacterSet whitespaceCharacterSet]; } emoji = [NSMutableArray arrayWithCapacity:0]; emojiTransform = [NSMutableArray arrayWithCapacity:0]; measure = [[RNSVGPathMeasure alloc] init]; return self; } - (void)clearPath { [super clearPath]; cachedAdvance = NAN; } - (void)setContent:(NSString *)content { if ([content isEqualToString:_content]) { return; } [self invalidate]; _content = content; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { if (self.content) { RNSVGGlyphContext *gc = [self.textRoot getGlyphContext]; if (self.inlineSize != nil && self.inlineSize.value != 0) { if (self.fill) { if (self.fill.class == RNSVGBrush.class) { CGColorRef color = [self getCurrentColor]; [self drawWrappedText:context gc:gc rect:rect color:color]; } else { CGColorRef color = [self.fill getColorWithOpacity:self.fillOpacity]; [self drawWrappedText:context gc:gc rect:rect color:color]; CGColorRelease(color); } } if (self.stroke) { if (self.stroke.class == RNSVGBrush.class) { CGColorRef color = [self getCurrentColor]; [self drawWrappedText:context gc:gc rect:rect color:color]; } else { CGColorRef color = [self.stroke getColorWithOpacity:self.strokeOpacity]; [self drawWrappedText:context gc:gc rect:rect color:color]; CGColorRelease(color); } } } else { if (self.path) { NSUInteger count = [emoji count]; CGFloat fontSize = [gc getFontSize]; for (NSUInteger i = 0; i < count; i++) { RNSVGPlatformView *emojiLabel = [emoji objectAtIndex:i]; NSValue *transformValue = [emojiTransform objectAtIndex:i]; CGAffineTransform transform = [transformValue CGAffineTransformValue]; CGContextConcatCTM(context, transform); CGContextTranslateCTM(context, 0, -fontSize); [emojiLabel.layer renderInContext:context]; CGContextTranslateCTM(context, 0, fontSize); CGContextConcatCTM(context, CGAffineTransformInvert(transform)); } } [self renderPathTo:context rect:rect]; } } else { [self clip:context]; [self renderGroupTo:context rect:rect]; } } - (NSMutableDictionary *)getAttributes:(RNSVGFontData *)fontdata { NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init]; if (fontRef != nil) { attrs[NSFontAttributeName] = (__bridge id)fontRef; } CGFloat letterSpacing = fontdata->letterSpacing; bool allowOptionalLigatures = letterSpacing == 0 && fontdata->fontVariantLigatures == RNSVGFontVariantLigaturesNormal; NSNumber *lig = [NSNumber numberWithInt:allowOptionalLigatures ? 2 : 1]; attrs[NSLigatureAttributeName] = lig; CGFloat kerning = fontdata->kerning; float kern = (float)(letterSpacing + kerning); NSNumber *kernAttr = [NSNumber numberWithFloat:kern]; #if DTCORETEXT_SUPPORT_NS_ATTRIBUTES if (___useiOS6Attributes) { [attrs setObject:kernAttr forKey:NSKernAttributeName]; } else #endif // DTCORETEXT_SUPPORT_NS_ATTRIBUTES { [attrs setObject:kernAttr forKey:(id)kCTKernAttributeName]; } return attrs; } - (void)drawWrappedText:(CGContextRef)context gc:(RNSVGGlyphContext *)gc rect:(CGRect)rect color:(CGColorRef)color { [self pushGlyphContext]; if (fontRef != nil) { CFRelease(fontRef); } fontRef = [self getFontFromContext]; RNSVGFontData *fontdata = [gc getFont]; CFStringRef string = (__bridge CFStringRef)self.content; NSMutableDictionary *attrs = [self getAttributes:fontdata]; CFMutableDictionaryRef attributes = (__bridge CFMutableDictionaryRef)attrs; CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); enum RNSVGTextAnchor textAnchor = fontdata->textAnchor; NSTextAlignment align; switch (textAnchor) { case RNSVGTextAnchorStart: align = NSTextAlignmentLeft; break; case RNSVGTextAnchorMiddle: align = NSTextAlignmentCenter; break; case RNSVGTextAnchorEnd: align = NSTextAlignmentRight; break; default: align = NSTextAlignmentLeft; break; } UIFont *font = (__bridge UIFont *)(fontRef); if (!label) { label = [[RNSVGTopAlignedLabel alloc] init]; } label.attributedText = (__bridge NSAttributedString *_Nullable)(attrString); label.lineBreakMode = NSLineBreakByWordWrapping; label.backgroundColor = RNSVGColor.clearColor; label.textAlignment = align; label.numberOfLines = 0; #if !TARGET_OS_OSX // On macOS, views are transparent by default label.opaque = NO; #endif // TARGET_OS_OSX label.font = font; label.textColor = [RNSVGColor colorWithCGColor:color]; CGFloat fontSize = [gc getFontSize]; CGFloat height = CGRectGetHeight(rect); CGFloat width = [RNSVGPropHelper fromRelative:self.inlineSize relative:[gc getWidth] fontSize:fontSize]; CGRect constrain = CGRectMake(0, 0, width, height); CGRect s = [self.content boundingRectWithSize:constrain.size options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil]; CGRect bounds = CGRectMake(0, 0, width, s.size.height); label.frame = bounds; label.bounds = bounds; firstX = [gc nextXWithDouble:0]; firstY = [gc nextY] - font.ascender; CGFloat dx = firstX; CGFloat dy = firstY; CGContextTranslateCTM(context, dx, dy); [label.layer renderInContext:context]; CGContextTranslateCTM(context, -dx, -dy); [self popGlyphContext]; [self renderPathTo:context rect:rect]; } - (CGPathRef)getPath:(CGContextRef)context { CGPathRef path = self.path; if (path) { return path; } NSString *text = self.content; if (!text) { return [self getGroupPath:context]; } if (self.inlineSize != nil && self.inlineSize.value != 0) { CGAffineTransform transform = CGAffineTransformMakeTranslation(firstX, firstY); path = CGPathCreateWithRect(label.bounds, &transform); self.path = CGPathRetain(path); self.skip = true; return path; } [self setupTextPath:context]; [self pushGlyphContext]; path = [self getLinePath:text context:context]; self.path = CGPathRetain(path); [self popGlyphContext]; return path; } - (CGFloat)getSubtreeTextChunksTotalAdvance { if (!isnan(cachedAdvance)) { return cachedAdvance; } CGFloat advance = 0; NSString *str = self.content; if (!str) { for (RNSVGPlatformView *node in self.subviews) { if ([node isKindOfClass:[RNSVGText class]]) { RNSVGText *text = (RNSVGText *)node; advance += [text getSubtreeTextChunksTotalAdvance]; } } cachedAdvance = advance; return advance; } // Create a dictionary for this font fontRef = [self getFontFromContext]; RNSVGGlyphContext *gc = [self.textRoot getGlyphContext]; RNSVGFontData *fontdata = [gc getFont]; NSMutableDictionary *attrs = [self getAttributes:fontdata]; CFStringRef string = (__bridge CFStringRef)str; CFMutableDictionaryRef attributes = (__bridge CFMutableDictionaryRef)attrs; CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); CTLineRef line = CTLineCreateWithAttributedString(attrString); CGRect textBounds = CTLineGetBoundsWithOptions(line, 0); CGFloat textMeasure = CGRectGetWidth(textBounds); cachedAdvance = textMeasure; CFRelease(attrString); CFRelease(line); return textMeasure; } - (CGPathRef)getLinePath:(NSString *)str context:(CGContextRef)context { // Create a dictionary for this font fontRef = [self getFontFromContext]; CGMutablePathRef path = CGPathCreateMutable(); RNSVGGlyphContext *gc = [self.textRoot getGlyphContext]; RNSVGFontData *font = [gc getFont]; NSUInteger n = str.length; /* * * Three properties affect the space between characters and words: * * ‘kerning’ indicates whether the user agent should adjust inter-glyph spacing * based on kerning tables that are included in the relevant font * (i.e., enable auto-kerning) or instead disable auto-kerning * and instead set inter-character spacing to a specific length (typically, zero). * * ‘letter-spacing’ indicates an amount of space that is to be added between text * characters supplemental to any spacing due to the ‘kerning’ property. * * ‘word-spacing’ indicates the spacing behavior between words. * * Letter-spacing is applied after bidi reordering and is in addition to any word-spacing. * Depending on the justification rules in effect, user agents may further increase * or decrease the space between typographic character units in order to justify text. * * */ CGFloat kerning = font->kerning; CGFloat wordSpacing = font->wordSpacing; CGFloat letterSpacing = font->letterSpacing; bool autoKerning = !font->manualKerning; /* 11.1.2. Fonts and glyphs A font consists of a collection of glyphs together with other information (collectively, the font tables) necessary to use those glyphs to present characters on some visual medium. The combination of the collection of glyphs and the font tables is called the font data. A font may supply substitution and positioning tables that can be used by a formatter (text shaper) to re-order, combine and position a sequence of glyphs to form one or more composite glyphs. The combining may be as simple as a ligature, or as complex as an indic syllable which combines, usually with some re-ordering, multiple consonants and vowel glyphs. The tables may be language dependent, allowing the use of language appropriate letter forms. When a glyph, simple or composite, represents an indivisible unit for typesetting purposes, it is know as a typographic character. Ligatures are an important feature of advance text layout. Some ligatures are discretionary while others (e.g. in Arabic) are required. The following explicit rules apply to ligature formation: Ligature formation should not be enabled when characters are in different DOM text nodes; thus, characters separated by markup should not use ligatures. Ligature formation should not be enabled when characters are in different text chunks. Discretionary ligatures should not be used when the spacing between two characters is not the same as the default space (e.g. when letter-spacing has a non-default value, or text-align has a value of justify and text-justify has a value of distribute). (See CSS Text Module Level 3, ([css-text-3]). SVG attributes such as ‘dx’, ‘textLength’, and ‘spacing’ (in ‘textPath’) that may reposition typographic characters do not break discretionary ligatures. If discretionary ligatures are not desired they can be turned off by using the font-variant-ligatures property. When the effective letter-spacing between two characters is not zero (due to either justification or non-zero computed ‘letter-spacing’), user agents should not apply optional ligatures. https://www.w3.org/TR/css-text-3/#letter-spacing-property */ bool allowOptionalLigatures = letterSpacing == 0 && font->fontVariantLigatures == RNSVGFontVariantLigaturesNormal; /* For OpenType fonts, discretionary ligatures include those enabled by the liga, clig, dlig, hlig, and cala features; required ligatures are found in the rlig feature. https://svgwg.org/svg2-draft/text.html#FontsGlyphs http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings https://www.microsoft.com/typography/otspec/featurelist.htm https://www.microsoft.com/typography/otspec/featuretags.htm https://www.microsoft.com/typography/otspec/features_pt.htm https://www.microsoft.com/typography/otfntdev/arabicot/features.aspx http://unifraktur.sourceforge.net/testcases/enable_opentype_features/ https://en.wikipedia.org/wiki/List_of_typographic_features http://ilovetypography.com/OpenType/opentype-features.html https://www.typotheque.com/articles/opentype_features_in_css https://practice.typekit.com/lesson/caring-about-opentype-features/ http://stateofwebtype.com/ 6.12. Low-level font feature settings control: the font-feature-settings property Name: font-feature-settings Value: normal | # Initial: normal Applies to: all elements Inherited: yes Percentages: N/A Media: visual Computed value: as specified Animatable: no https://drafts.csswg.org/css-fonts-3/#default-features 7.1. Default features For OpenType fonts, user agents must enable the default features defined in the OpenType documentation for a given script and writing mode. Required ligatures, common ligatures and contextual forms must be enabled by default (OpenType features: rlig, liga, clig, calt), along with localized forms (OpenType feature: locl), and features required for proper display of composed characters and marks (OpenType features: ccmp, mark, mkmk). These features must always be enabled, even when the value of the ‘font-variant’ and ‘font-feature-settings’ properties is ‘normal’. Individual features are only disabled when explicitly overridden by the author, as when ‘font-variant-ligatures’ is set to ‘no-common-ligatures’. TODO For handling complex scripts such as Arabic, Mongolian or Devanagari additional features are required. TODO For upright text within vertical text runs, vertical alternates (OpenType feature: vert) must be enabled. */ // OpenType.js font data NSDictionary *fontData = font->fontData; NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init]; CFMutableDictionaryRef attributes = (__bridge CFMutableDictionaryRef)attrs; NSNumber *lig = [NSNumber numberWithInt:allowOptionalLigatures ? 2 : 1]; attrs[NSLigatureAttributeName] = lig; if (fontRef != nil) { attrs[NSFontAttributeName] = (__bridge id)fontRef; } if (!autoKerning) { NSNumber *noAutoKern = [NSNumber numberWithFloat:0.0f]; #if DTCORETEXT_SUPPORT_NS_ATTRIBUTES if (___useiOS6Attributes) { [attrs setObject:noAutoKern forKey:NSKernAttributeName]; } else #endif // DTCORETEXT_SUPPORT_NS_ATTRIBUTES { [attrs setObject:noAutoKern forKey:(id)kCTKernAttributeName]; } } CFStringRef string = (__bridge CFStringRef)str; CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); CTLineRef line = CTLineCreateWithAttributedString(attrString); /* Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ and property text-anchor. For text-anchor:start, startpoint-on-the-path is the point on the path which represents the point on the path which is ‘startOffset’ distance along the path from the start of the path, calculated using the user agent's distance along the path algorithm. For text-anchor:middle, startpoint-on-the-path is the point on the path which represents the point on the path which is [ ‘startOffset’ minus half of the total advance values for all of the glyphs in the ‘textPath’ element ] distance along the path from the start of the path, calculated using the user agent's distance along the path algorithm. For text-anchor:end, startpoint-on-the-path is the point on the path which represents the point on the path which is [ ‘startOffset’ minus the total advance values for all of the glyphs in the ‘textPath’ element ]. Before rendering the first glyph, the horizontal component of the startpoint-on-the-path is adjusted to take into account various horizontal alignment text properties and attributes, such as a ‘dx’ attribute value on a ‘tspan’ element. */ enum RNSVGTextAnchor textAnchor = font->textAnchor; RNSVGText *anchorRoot = [self getTextAnchorRoot]; CGFloat textMeasure = [anchorRoot getSubtreeTextChunksTotalAdvance]; CGFloat offset = [RNSVGTSpan getTextAnchorOffset:textAnchor width:textMeasure]; bool hasTextPath = textPath != nil; int side = 1; CGFloat startOfRendering = 0; CGFloat endOfRendering = measure.pathLength; CGFloat fontSize = [gc getFontSize]; // bool sharpMidLine = false; if (hasTextPath) { // sharpMidLine = RNSVGTextPathMidLineFromString([textPath midLine]) == RNSVGTextPathMidLineSharp; /* Name side Value left | right initial value left Animatable yes Determines the side of the path the text is placed on (relative to the path direction). Specifying a value of right effectively reverses the path. Added in SVG 2 to allow text either inside or outside closed subpaths and basic shapes (e.g. rectangles, circles, and ellipses). Adding 'side' was resolved at the Sydney (2015) meeting. */ side = RNSVGTextPathSideFromString([textPath side]) == RNSVGTextPathSideRight ? -1 : 1; /* Name startOffset Value | | initial value 0 Animatable yes An offset from the start of the path for the initial current text position, calculated using the user agent's distance along the path algorithm, after converting the path to the ‘textPath’ element's coordinate system. If a other than a percentage is given, then the ‘startOffset’ represents a distance along the path measured in the current user coordinate system for the ‘textPath’ element. If a percentage is given, then the ‘startOffset’ represents a percentage distance along the entire path. Thus, startOffset="0%" indicates the start point of the path and startOffset="100%" indicates the end point of the path. Negative values and values larger than the path length (e.g. 150%) are allowed. Any typographic characters with mid-points that are not on the path are not rendered For paths consisting of a single closed subpath (including an equivalent path for a basic shape), typographic characters are rendered along one complete circuit of the path. The text is aligned as determined by the text-anchor property to a position along the path set by the ‘startOffset’ attribute. For the start (end) value, the text is rendered from the start (end) of the line until the initial position along the path is reached again. For the middle, the text is rendered from the middle point in both directions until a point on the path equal distance in both directions from the initial position on the path is reached. */ CGFloat absoluteStartOffset = [RNSVGPropHelper fromRelative:textPath.startOffset relative:measure.pathLength fontSize:fontSize]; offset += absoluteStartOffset; if (measure.isClosed) { CGFloat halfPathDistance = measure.pathLength / 2; startOfRendering = absoluteStartOffset + (textAnchor == RNSVGTextAnchorMiddle ? -halfPathDistance : 0); endOfRendering = startOfRendering + measure.pathLength; } /* RNSVGTextPathSpacing spacing = textPath.getSpacing(); if (spacing == RNSVGTextPathSpacing.auto) { // Hmm, what to do here? // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute } */ } /* Name method Value align | stretch initial value align Animatable yes Indicates the method by which text should be rendered along the path. A value of align indicates that the typographic character should be rendered using simple 2×3 matrix transformations such that there is no stretching/warping of the typographic characters. Typically, supplemental rotation, scaling and translation transformations are done for each typographic characters to be rendered. As a result, with align, in fonts where the typographic characters are designed to be connected (e.g., cursive fonts), the connections may not align properly when text is rendered along a path. A value of stretch indicates that the typographic character outlines will be converted into paths, and then all end points and control points will be adjusted to be along the perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. With this approach, connected typographic characters, such as in cursive scripts, will maintain their connections. (Non-vertical straight path segments should be converted to Bézier curves in such a way that horizontal straight paths have an (approximately) constant offset from the path along which the typographic characters are rendered.) TODO implement stretch */ /* Name Value Initial value Animatable textLength | | See below yes The author's computation of the total sum of all of the advance values that correspond to character data within this element, including the advance value on the glyph (horizontal or vertical), the effect of properties letter-spacing and word-spacing and adjustments due to attributes ‘dx’ and ‘dy’ on this ‘text’ or ‘tspan’ element or any descendants. This value is used to calibrate the user agent's own calculations with that of the author. The purpose of this attribute is to allow the author to achieve exact alignment, in visual rendering order after any bidirectional reordering, for the first and last rendered glyphs that correspond to this element; thus, for the last rendered character (in visual rendering order after any bidirectional reordering), any supplemental inter-character spacing beyond normal glyph advances are ignored (in most cases) when the user agent determines the appropriate amount to expand/compress the text string to fit within a length of ‘textLength’. If attribute ‘textLength’ is specified on a given element and also specified on an ancestor, the adjustments on all character data within this element are controlled by the value of ‘textLength’ on this element exclusively, with the possible side-effect that the adjustment ratio for the contents of this element might be different than the adjustment ratio used for other content that shares the same ancestor. The user agent must assume that the total advance values for the other content within that ancestor is the difference between the advance value on that ancestor and the advance value for this element. This attribute is not intended for use to obtain effects such as shrinking or expanding text. A negative value is an error (see Error processing). The ‘textLength’ attribute is only applied when the wrapping area is not defined by the TODO shape-inside or the inline-size properties. It is also not applied for any ‘text’ or TODO ‘tspan’ element that has forced line breaks (due to a white-space value of pre or pre-line). If the attribute is not specified anywhere within a ‘text’ element, the effect is as if the author's computation exactly matched the value calculated by the user agent; thus, no advance adjustments are made. */ CGFloat scaleSpacingAndGlyphs = 1; RNSVGLength *mTextLength = [self textLength]; enum RNSVGTextLengthAdjust mLengthAdjust = RNSVGTextLengthAdjustFromString([self lengthAdjust]); if (mTextLength != nil) { CGFloat author = [RNSVGPropHelper fromRelative:mTextLength relative:[gc getWidth] fontSize:fontSize]; if (author < 0) { NSException *e = [NSException exceptionWithName:@"NegativeTextLength" reason:@"Negative textLength value" userInfo:nil]; @throw e; } switch (mLengthAdjust) { default: case RNSVGTextLengthAdjustSpacing: // TODO account for ligatures letterSpacing += (author - textMeasure) / (n - 1); break; case RNSVGTextLengthAdjustSpacingAndGlyphs: scaleSpacingAndGlyphs = author / textMeasure; break; } } CGFloat scaledDirection = scaleSpacingAndGlyphs * side; /* https://developer.mozilla.org/en/docs/Web/CSS/vertical-align https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html https://www.microsoft.com/typography/otspec/base.htm http://apike.ca/prog_svg_text_style.html https://www.w3schools.com/tags/canvas_textbaseline.asp http://vanseodesign.com/web-design/svg-text-baseline-alignment/ https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align https://tympanus.net/codrops/css_reference/vertical-align/ https://svgwg.org/svg2-draft/text.html#AlignmentBaselineProperty 11.10.2.6. The ‘alignment-baseline’ property This property is defined in the CSS Line Layout Module 3 specification. See 'alignment-baseline'. [css-inline-3] https://drafts.csswg.org/css-inline/#propdef-alignment-baseline The vertical-align property shorthand should be preferred in new content. SVG 2 introduces some changes to the definition of this property. In particular: the values 'auto', 'before-edge', and 'after-edge' have been removed. For backwards compatibility, 'text-before-edge' should be mapped to 'text-top' and 'text-after-edge' should be mapped to 'text-bottom'. Neither 'text-before-edge' nor 'text-after-edge' should be used with the vertical-align property. */ /* CGRect fontBounds = CTFontGetBoundingBox(fontRef); CGFloat textHeight = CGRectGetHeight(textBounds); CGFloat fontWidth = CGRectGetWidth(textBounds); CGPoint fontOrigin = fontBounds.origin; CGFloat fontMinX = fontOrigin.x; CGFloat fontMinY = fontOrigin.y; CGFloat fontMaxX = fontMinX + fontWidth; CGFloat fontMaxY = fontMinY + textHeight; */ // TODO CGFloat descenderDepth = CTFontGetDescent(fontRef); CGFloat bottom = descenderDepth + CTFontGetLeading(fontRef); CGFloat ascenderHeight = CTFontGetAscent(fontRef); CGFloat top = ascenderHeight; CGFloat totalHeight = top + bottom; CGFloat baselineShift = 0; NSString *baselineShiftString = self.baselineShift; enum RNSVGAlignmentBaseline baseline = RNSVGAlignmentBaselineFromString(self.alignmentBaseline); if (baseline != RNSVGAlignmentBaselineBaseline) { // TODO alignment-baseline, test / verify behavior // TODO get per glyph baselines from font baseline table, for high-precision alignment CGFloat xHeight = CTFontGetXHeight(fontRef); switch (baseline) { // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling default: case RNSVGAlignmentBaselineBaseline: // Use the dominant baseline choice of the parent. // Match the box’s corresponding baseline to that of its parent. baselineShift = 0; break; case RNSVGAlignmentBaselineTextBottom: case RNSVGAlignmentBaselineAfterEdge: case RNSVGAlignmentBaselineTextAfterEdge: // Match the bottom of the box to the bottom of the parent’s content area. // text-after-edge = text-bottom // text-after-edge = descender depth baselineShift = -descenderDepth; break; case RNSVGAlignmentBaselineAlphabetic: // Match the box’s alphabetic baseline to that of its parent. // alphabetic = 0 baselineShift = 0; break; case RNSVGAlignmentBaselineIdeographic: // Match the box’s ideographic character face under-side baseline to that of its parent. // ideographic = descender depth baselineShift = -descenderDepth; break; case RNSVGAlignmentBaselineMiddle: // Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the // parent. TODO middle = x height / 2 baselineShift = xHeight / 2; break; case RNSVGAlignmentBaselineCentral: // Match the box’s central baseline to the central baseline of its parent. // central = (ascender height - descender depth) / 2 baselineShift = (ascenderHeight - descenderDepth) / 2; break; case RNSVGAlignmentBaselineMathematical: // Match the box’s mathematical baseline to that of its parent. // Hanging and mathematical baselines // There are no obvious formulas to calculate the position of these baselines. // At the time of writing FOP puts the hanging baseline at 80% of the ascender // height and the mathematical baseline at 50%. baselineShift = (CGFloat)0.5 * ascenderHeight; break; case RNSVGAlignmentBaselineHanging: baselineShift = (CGFloat)0.8 * ascenderHeight; break; case RNSVGAlignmentBaselineTextTop: case RNSVGAlignmentBaselineBeforeEdge: case RNSVGAlignmentBaselineTextBeforeEdge: // Match the top of the box to the top of the parent’s content area. // text-before-edge = text-top // text-before-edge = ascender height baselineShift = ascenderHeight; break; case RNSVGAlignmentBaselineBottom: // Align the top of the aligned subtree with the top of the line box. baselineShift = bottom; break; case RNSVGAlignmentBaselineCenter: // Align the center of the aligned subtree with the center of the line box. baselineShift = totalHeight / 2; break; case RNSVGAlignmentBaselineTop: // Align the bottom of the aligned subtree with the bottom of the line box. baselineShift = top; break; } } /* 2.2.2. Alignment Shift: baseline-shift longhand This property specifies by how much the box is shifted up from its alignment point. It does not apply when alignment-baseline is top or bottom. Authors should use the vertical-align shorthand instead of this property. Values have the following meanings: Raise (positive value) or lower (negative value) by the specified length. Raise (positive value) or lower (negative value) by the specified percentage of the line-height. TODO sub Lower by the offset appropriate for subscripts of the parent’s box. (The UA should use the parent’s font data to find this offset whenever possible.) TODO super Raise by the offset appropriate for superscripts of the parent’s box. (The UA should use the parent’s font data to find this offset whenever possible.) User agents may additionally support the keyword baseline as computing to 0 if is necessary for them to support legacy SVG content. Issue: We would prefer to remove this, and are looking for feedback from SVG user agents as to whether it’s necessary. https://www.w3.org/TR/css-inline-3/#propdef-baseline-shift */ if (baselineShiftString != nil && ![baselineShiftString isEqualToString:@""]) { switch (baseline) { case RNSVGAlignmentBaselineTop: case RNSVGAlignmentBaselineBottom: break; default: if (fontData != nil && [baselineShiftString isEqualToString:@"sub"]) { // TODO NSDictionary *tables = [fontData objectForKey:@"tables"]; NSNumber *unitsPerEm = [fontData objectForKey:@"unitsPerEm"]; NSDictionary *os2 = [tables objectForKey:@"os2"]; NSNumber *ySubscriptYOffset = [os2 objectForKey:@"ySubscriptYOffset"]; if (ySubscriptYOffset) { CGFloat subOffset = (CGFloat)[ySubscriptYOffset doubleValue]; baselineShift += fontSize * subOffset / [unitsPerEm doubleValue]; } } else if (fontData != nil && [baselineShiftString isEqualToString:@"super"]) { // TODO NSDictionary *tables = [fontData objectForKey:@"tables"]; NSNumber *unitsPerEm = [fontData objectForKey:@"unitsPerEm"]; NSDictionary *os2 = [tables objectForKey:@"os2"]; NSNumber *ySuperscriptYOffset = [os2 objectForKey:@"ySuperscriptYOffset"]; if (ySuperscriptYOffset) { CGFloat superOffset = (CGFloat)[ySuperscriptYOffset doubleValue]; baselineShift -= fontSize * superOffset / [unitsPerEm doubleValue]; } } else if ([baselineShiftString isEqualToString:@"baseline"]) { } else { baselineShift -= [RNSVGPropHelper fromRelativeWithNSString:baselineShiftString relative:fontSize fontSize:fontSize]; } break; } } [emoji removeAllObjects]; [emojiTransform removeAllObjects]; CFArrayRef runs = CTLineGetGlyphRuns(line); CFIndex runEnd = CFArrayGetCount(runs); for (CFIndex ri = 0; ri < runEnd; ri++) { CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, ri); CFIndex runGlyphCount = CTRunGetGlyphCount(run); CFIndex indices[runGlyphCount]; CGSize advances[runGlyphCount]; CGGlyph glyphs[runGlyphCount]; // Grab the glyphs and font CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); CTRunGetStringIndices(run, CFRangeMake(0, 0), indices); CTFontRef runFont = (CTFontRef)CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName); CTFontGetAdvancesForGlyphs(runFont, kCTFontOrientationHorizontal, glyphs, advances, runGlyphCount); CFIndex nextOrEndRunIndex = n; if (ri + 1 < runEnd) { CTRunRef nextRun = (CTRunRef)CFArrayGetValueAtIndex(runs, ri + 1); CFIndex nextRunGlyphCount = CTRunGetGlyphCount(nextRun); CFIndex nextIndices[nextRunGlyphCount]; CTRunGetStringIndices(nextRun, CFRangeMake(0, 0), nextIndices); nextOrEndRunIndex = nextIndices[0]; } for (CFIndex g = 0; g < runGlyphCount; g++) { CGGlyph glyph = glyphs[g]; /* Determine the glyph's charwidth (i.e., the amount which the current text position advances horizontally when the glyph is drawn using horizontal text layout). For each subsequent glyph, set a new startpoint-on-the-path as the previous endpoint-on-the-path, but with appropriate adjustments taking into account horizontal kerning tables in the font and current values of various attributes and properties, including spacing properties (e.g. letter-spacing and word-spacing) and ‘tspan’ elements with values provided for attributes ‘dx’ and ‘dy’. All adjustments are calculated as distance adjustments along the path, calculated using the user agent's distance along the path algorithm. */ CGFloat charWidth = advances[g].width * scaleSpacingAndGlyphs; CFIndex currIndex = indices[g]; unichar currentChar = [str characterAtIndex:currIndex]; bool isWordSeparator = [RNSVGTSpan_separators characterIsMember:currentChar]; CGFloat wordSpace = isWordSeparator ? wordSpacing : 0; CGFloat spacing = wordSpace + letterSpacing; CGFloat advance = charWidth + spacing; CGFloat x = [gc nextXWithDouble:kerning + advance]; CGFloat y = [gc nextY]; CGFloat dx = [gc nextDeltaX]; CGFloat dy = [gc nextDeltaY]; CGFloat r = [gc nextRotation] / RNSVGTSpan_radToDeg; if (isWordSeparator) { continue; } CFIndex endIndex = g + 1 == runGlyphCount ? nextOrEndRunIndex : indices[g + 1]; while (++currIndex < endIndex) { // Skip rendering other grapheme clusters of ligatures (already rendered), // And, make sure to increment index positions by making gc.next() calls. [gc nextXWithDouble:0]; [gc nextY]; [gc nextDeltaX]; [gc nextDeltaY]; [gc nextRotation]; } CGPathRef glyphPath = CTFontCreatePathForGlyph(runFont, glyph, nil); advance *= side; charWidth *= side; CGFloat cursor = offset + (x + dx) * side; CGFloat startPoint = cursor - advance; CGAffineTransform transform = CGAffineTransformIdentity; if (hasTextPath) { /* Determine the point on the curve which is charwidth distance along the path from the startpoint-on-the-path for this glyph, calculated using the user agent's distance along the path algorithm. This point is the endpoint-on-the-path for the glyph. */ // TODO CGFloat endPoint = startPoint + charWidth; /* Determine the midpoint-on-the-path, which is the point on the path which is "halfway" (user agents can choose either a distance calculation or a parametric calculation) between the startpoint-on-the-path and the endpoint-on-the-path. */ CGFloat halfWay = charWidth / 2; CGFloat midPoint = startPoint + halfWay; // Glyphs whose midpoint-on-the-path are off the path are not rendered. if (midPoint > endOfRendering) { CGPathRelease(glyphPath); continue; } else if (midPoint < startOfRendering) { CGPathRelease(glyphPath); continue; } CGFloat angle; CGFloat px; CGFloat py; [measure getPosAndTan:&angle midPoint:midPoint x:&px y:&py]; transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(px, py), transform); transform = CGAffineTransformConcat(CGAffineTransformMakeRotation(angle + r), transform); transform = CGAffineTransformScale(transform, scaledDirection, side); transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-halfWay, y + dy + baselineShift), transform); } else { transform = CGAffineTransformMakeTranslation(startPoint, y + dy + baselineShift); transform = CGAffineTransformConcat(CGAffineTransformMakeRotation(r), transform); } CGRect box = CGPathGetBoundingBox(glyphPath); CGFloat width = box.size.width; if (width == 0) { // Render unicode emoji RNSVGTextView *emojiLabel = [[RNSVGTextView alloc] init]; CFIndex startIndex = indices[g]; long len = MAX(1, endIndex - startIndex); NSRange range = NSMakeRange(startIndex, len); NSString *currChars = [str substringWithRange:range]; #if TARGET_OS_OSX emojiLabel.string = currChars; #else emojiLabel.text = currChars; emojiLabel.opaque = NO; #endif // TARGET_OS_OSX emojiLabel.backgroundColor = RNSVGColor.clearColor; UIFont *customFont = [UIFont systemFontOfSize:fontSize]; CGSize measuredSize = [currChars sizeWithAttributes:@{NSFontAttributeName : customFont}]; emojiLabel.font = customFont; CGFloat width = ceil(measuredSize.width); CGFloat height = ceil(measuredSize.height); CGRect bounds = CGRectMake(0, 0, width, height); emojiLabel.frame = bounds; CGContextConcatCTM(context, transform); CGContextTranslateCTM(context, 0, -fontSize); #if TARGET_OS_OSX [emojiLabel.layer renderInContext:context]; #else [emojiLabel drawTextInRect:emojiLabel.bounds]; #endif // TARGET_OS_OSX CGContextTranslateCTM(context, 0, fontSize); CGContextConcatCTM(context, CGAffineTransformInvert(transform)); [emoji addObject:emojiLabel]; [emojiTransform addObject:[NSValue valueWithCGAffineTransform:transform]]; } else { transform = CGAffineTransformScale(transform, 1.0, -1.0); CGPathAddPath(path, &transform, glyphPath); } CGPathRelease(glyphPath); } } CFRelease(attrString); CFRelease(line); return (CGPathRef)CFAutorelease(path); } + (CGFloat)getTextAnchorOffset:(RNSVGTextAnchor)textAnchor width:(CGFloat)width { switch (textAnchor) { case RNSVGTextAnchorStart: return 0; case RNSVGTextAnchorMiddle: return -width / 2; case RNSVGTextAnchorEnd: return -width; } return 0; } - (void)setupTextPath:(CGContextRef)context { textPath = nil; RNSVGText *parent = (RNSVGText *)[self superview]; CGPathRef path = nil; while (parent) { if ([parent class] == [RNSVGTextPath class]) { textPath = (RNSVGTextPath *)parent; RNSVGNode *definedTemplate = [self.svgView getDefinedTemplate:textPath.href]; path = [definedTemplate getPath:context]; [measure extractPathData:path]; break; } else if (![parent isKindOfClass:[RNSVGText class]]) { break; } parent = (RNSVGText *)[parent superview]; } if (!path) { [measure reset]; } } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGTSpanCls(void) { return RNSVGTSpan.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Text/RNSVGText.h ================================================ /** * 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 #import "RNSVGGroup.h" @interface RNSVGText : RNSVGGroup @property (nonatomic, strong) RNSVGLength *inlineSize; @property (nonatomic, strong) RNSVGLength *textLength; @property (nonatomic, strong) NSString *baselineShift; @property (nonatomic, strong) NSString *lengthAdjust; @property (nonatomic, strong) NSString *alignmentBaseline; @property (nonatomic, strong) NSArray *deltaX; @property (nonatomic, strong) NSArray *deltaY; @property (nonatomic, strong) NSArray *positionX; @property (nonatomic, strong) NSArray *positionY; @property (nonatomic, strong) NSArray *rotate; - (CGPathRef)getGroupPath:(CGContextRef)context; - (CTFontRef)getFontFromContext; - (CGFloat)getSubtreeTextChunksTotalAdvance; - (RNSVGText *)getTextAnchorRoot; @end ================================================ FILE: apple/Text/RNSVGText.mm ================================================ /** * 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 "RNSVGText.h" #import #import #import "RNSVGGlyphContext.h" #import "RNSVGTextPath.h" #import "RNSVGTextProperties.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGText { RNSVGGlyphContext *_glyphContext; NSString *_alignmentBaseline; NSString *_baselineShift; CGFloat cachedAdvance; } #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); setCommonTextProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _deltaX = nil; _deltaY = nil; _positionX = nil; _positionY = nil; _rotate = nil; _inlineSize = nil; _textLength = nil; _baselineShift = nil; _lengthAdjust = nil; _alignmentBaseline = nil; _glyphContext = nil; _alignmentBaseline = nil; _baselineShift = nil; cachedAdvance = 0; } #endif // RCT_NEW_ARCH_ENABLED - (void)invalidate { if (self.dirty || self.merging) { return; } [super invalidate]; [self clearChildCache]; } - (void)clearPath { [super clearPath]; cachedAdvance = NAN; } - (void)setInlineSize:(RNSVGLength *)inlineSize { if ([inlineSize isEqualTo:_inlineSize]) { return; } [self invalidate]; _inlineSize = inlineSize; } - (void)setTextLength:(RNSVGLength *)textLength { if ([textLength isEqualTo:_textLength]) { return; } [self invalidate]; _textLength = textLength; } - (void)setBaselineShift:(NSString *)baselineShift { if ([baselineShift isEqualToString:_baselineShift]) { return; } [self invalidate]; _baselineShift = baselineShift; } - (void)setLengthAdjust:(NSString *)lengthAdjust { if ([lengthAdjust isEqualToString:_lengthAdjust]) { return; } [self invalidate]; _lengthAdjust = lengthAdjust; } - (void)setAlignmentBaseline:(NSString *)alignmentBaseline { if ([alignmentBaseline isEqualToString:_alignmentBaseline]) { return; } [self invalidate]; _alignmentBaseline = alignmentBaseline; } - (void)setDeltaX:(NSArray *)deltaX { if (deltaX == _deltaX) { return; } [self invalidate]; _deltaX = deltaX; } - (void)setDeltaY:(NSArray *)deltaY { if (deltaY == _deltaY) { return; } [self invalidate]; _deltaY = deltaY; } - (void)setPositionX:(NSArray *)positionX { if (positionX == _positionX) { return; } [self invalidate]; _positionX = positionX; } - (void)setPositionY:(NSArray *)positionY { if (positionY == _positionY) { return; } [self invalidate]; _positionY = positionY; } - (void)setRotate:(NSArray *)rotate { if (rotate == _rotate) { return; } [self invalidate]; _rotate = rotate; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { CGContextSaveGState(context); [self clip:context]; [self setupGlyphContext:context]; [self pushGlyphContext]; [super renderGroupTo:context rect:rect]; [self popGlyphContext]; CGContextRestoreGState(context); } - (void)setupGlyphContext:(CGContextRef)context { CGRect bounds = CGContextGetClipBoundingBox(context); CGSize size = bounds.size; _glyphContext = [[RNSVGGlyphContext alloc] initWithWidth:size.width height:size.height]; } - (CGPathRef)getGroupPath:(CGContextRef)context { CGPathRef path = self.path; if (path) { return path; } [self pushGlyphContext]; path = [super getPath:context]; [self popGlyphContext]; self.path = path; return path; } - (CGPathRef)getPath:(CGContextRef)context { CGPathRef path = self.path; if (path) { return path; } [self setupGlyphContext:context]; return [self getGroupPath:context]; } - (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect { [self pushGlyphContext]; [super renderGroupTo:context rect:rect]; [self popGlyphContext]; } // TODO: Optimisation required - (RNSVGText *)textRoot { RNSVGText *root = self; while (root && [root class] != [RNSVGText class]) { if (![root isKindOfClass:[RNSVGText class]]) { // todo: throw exception here break; } root = (RNSVGText *)[root superview]; } return root; } - (NSString *)alignmentBaseline { if (_alignmentBaseline != nil) { return _alignmentBaseline; } RNSVGPlatformView *parent = self.superview; while (parent != nil) { if ([parent isKindOfClass:[RNSVGText class]]) { RNSVGText *node = (RNSVGText *)parent; NSString *baseline = node.alignmentBaseline; if (baseline != nil) { _alignmentBaseline = baseline; return baseline; } } parent = [parent superview]; } if (_alignmentBaseline == nil) { _alignmentBaseline = RNSVGAlignmentBaselineStrings[0]; } return _alignmentBaseline; } - (NSString *)baselineShift { if (_baselineShift != nil) { return _baselineShift; } RNSVGPlatformView *parent = [self superview]; while (parent != nil) { if ([parent isKindOfClass:[RNSVGText class]]) { RNSVGText *node = (RNSVGText *)parent; NSString *baselineShift = node.baselineShift; if (baselineShift != nil) { _baselineShift = baselineShift; return baselineShift; } } parent = [parent superview]; } // set default value _baselineShift = @""; return _baselineShift; } - (RNSVGGlyphContext *)getGlyphContext { return _glyphContext; } - (void)pushGlyphContext { [[self.textRoot getGlyphContext] pushContext:self font:self.font x:self.positionX y:self.positionY deltaX:self.deltaX deltaY:self.deltaY rotate:self.rotate]; } - (void)popGlyphContext { [[self.textRoot getGlyphContext] popContext]; } - (CTFontRef)getFontFromContext { return [[self.textRoot getGlyphContext] getGlyphFont]; } - (RNSVGText *)getTextAnchorRoot { RNSVGGlyphContext *gc = [self.textRoot getGlyphContext]; NSArray *font = [gc getFontContext]; RNSVGText *node = self; RNSVGPlatformView *parent = [self superview]; for (NSInteger i = [font count] - 1; i >= 0; i--) { RNSVGFontData *fontData = [font objectAtIndex:i]; if (![parent isKindOfClass:[RNSVGText class]] || fontData->textAnchor == RNSVGTextAnchorStart || node.positionX != nil) { return node; } node = (RNSVGText *)parent; parent = [node superview]; } return node; } - (CGFloat)getSubtreeTextChunksTotalAdvance { if (!isnan(cachedAdvance)) { return cachedAdvance; } CGFloat advance = 0; for (RNSVGPlatformView *node in self.subviews) { if ([node isKindOfClass:[RNSVGText class]]) { RNSVGText *text = (RNSVGText *)node; advance += [text getSubtreeTextChunksTotalAdvance]; } } cachedAdvance = advance; return advance; } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGTextCls(void) { return RNSVGText.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Text/RNSVGTextPath.h ================================================ /** * 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 #import #import "RNSVGLength.h" #import "RNSVGText.h" @interface RNSVGTextPath : RNSVGText @property (nonatomic, strong) NSString *href; @property (nonatomic, strong) NSString *side; @property (nonatomic, strong) NSString *method; @property (nonatomic, strong) NSString *midLine; @property (nonatomic, strong) NSString *spacing; @property (nonatomic, strong) RNSVGLength *startOffset; @end ================================================ FILE: apple/Text/RNSVGTextPath.mm ================================================ /** * 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 "RNSVGTextPath.h" #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import "RNSVGFabricConversions.h" #endif // RCT_NEW_ARCH_ENABLED @implementation RNSVGTextPath #ifdef RCT_NEW_ARCH_ENABLED using namespace facebook::react; // Needed because of this: https://github.com/facebook/react-native/pull/37274 + (void)load { [super load]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; } return self; } #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider { return concreteComponentDescriptorProvider(); } - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &newProps = static_cast(*props); self.href = RCTNSStringFromStringNilIfEmpty(newProps.href); self.side = RCTNSStringFromStringNilIfEmpty(newProps.side); self.method = RCTNSStringFromStringNilIfEmpty(newProps.method); self.midLine = RCTNSStringFromStringNilIfEmpty(newProps.midLine); self.spacing = RCTNSStringFromStringNilIfEmpty(newProps.spacing); id startOffset = RNSVGConvertFollyDynamicToId(newProps.startOffset); if (startOffset != nil) { self.startOffset = [RCTConvert RNSVGLength:startOffset]; } setCommonTextProps(newProps, self); _props = std::static_pointer_cast(props); } - (void)prepareForRecycle { [super prepareForRecycle]; _href = nil; _side = nil; _method = nil; _midLine = nil; _spacing = nil; _startOffset = nil; } #endif // RCT_NEW_ARCH_ENABLED - (void)setHref:(NSString *)href { if ([href isEqualToString:_href]) { return; } [self invalidate]; _href = href; } - (void)setSide:(NSString *)side { if ([side isEqualToString:_side]) { return; } [self invalidate]; _side = side; } - (void)setMethod:(NSString *)method { if ([method isEqualToString:_method]) { return; } [self invalidate]; _method = method; } - (void)setMidLine:(NSString *)midLine { if ([midLine isEqualToString:_midLine]) { return; } [self invalidate]; _midLine = midLine; } - (void)setSpacing:(NSString *)spacing { if ([spacing isEqualToString:_spacing]) { return; } [self invalidate]; _spacing = spacing; } - (void)setStartOffset:(RNSVGLength *)startOffset { if ([startOffset isEqualTo:_startOffset]) { return; } [self invalidate]; _startOffset = startOffset; } - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect { [self renderGroupTo:context rect:rect]; } - (CGPathRef)getPath:(CGContextRef)context { return [self getGroupPath:context]; } - (void)pushGlyphContext { // TextPath do not affect the glyphContext } - (void)popGlyphContext { // TextPath do not affect the glyphContext } @end #ifdef RCT_NEW_ARCH_ENABLED Class RNSVGTextPathCls(void) { return RNSVGTextPath.class; } #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Text/RNSVGTextProperties.h ================================================ #import #ifndef RNTextProperties_h #define RNTextProperties_h typedef NS_ENUM(NSInteger, RNSVGAlignmentBaseline) { RNSVGAlignmentBaselineBaseline, RNSVGAlignmentBaselineTextBottom, RNSVGAlignmentBaselineAlphabetic, RNSVGAlignmentBaselineIdeographic, RNSVGAlignmentBaselineMiddle, RNSVGAlignmentBaselineCentral, RNSVGAlignmentBaselineMathematical, RNSVGAlignmentBaselineTextTop, RNSVGAlignmentBaselineBottom, RNSVGAlignmentBaselineCenter, RNSVGAlignmentBaselineTop, /* SVG implementations may support the following aliases in order to support legacy content: text-before-edge = text-top text-after-edge = text-bottom */ RNSVGAlignmentBaselineTextBeforeEdge, RNSVGAlignmentBaselineTextAfterEdge, // SVG 1.1 RNSVGAlignmentBaselineBeforeEdge, RNSVGAlignmentBaselineAfterEdge, RNSVGAlignmentBaselineHanging, RNSVGAlignmentBaselineDEFAULT = RNSVGAlignmentBaselineBaseline }; static NSString *const RNSVGAlignmentBaselineStrings[] = { @"baseline", @"text-bottom", @"alphabetic", @"ideographic", @"middle", @"central", @"mathematical", @"text-top", @"bottom", @"center", @"top", @"text-before-edge", @"text-after-edge", @"before-edge", @"after-edge", @"hanging", @"central", @"mathematical", @"text-top", @"bottom", @"center", @"top", nil}; NSString *RNSVGAlignmentBaselineToString(enum RNSVGAlignmentBaseline fw); enum RNSVGAlignmentBaseline RNSVGAlignmentBaselineFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGFontStyle) { RNSVGFontStyleNormal, RNSVGFontStyleItalic, RNSVGFontStyleOblique, RNSVGFontStyleDEFAULT = RNSVGFontStyleNormal, }; static NSString *const RNSVGFontStyleStrings[] = {@"normal", @"italic", @"oblique", nil}; NSString *RNSVGFontStyleToString(enum RNSVGFontStyle fw); enum RNSVGFontStyle RNSVGFontStyleFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGFontVariantLigatures) { RNSVGFontVariantLigaturesNormal, RNSVGFontVariantLigaturesNone, RNSVGFontVariantLigaturesDEFAULT = RNSVGFontVariantLigaturesNormal, }; static NSString *const RNSVGFontVariantLigaturesStrings[] = {@"normal", @"none", nil}; NSString *RNSVGFontVariantLigaturesToString(enum RNSVGFontVariantLigatures fw); enum RNSVGFontVariantLigatures RNSVGFontVariantLigaturesFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGFontWeight) { // Absolute RNSVGFontWeightNormal, RNSVGFontWeightBold, RNSVGFontWeight100, RNSVGFontWeight200, RNSVGFontWeight300, RNSVGFontWeight400, RNSVGFontWeight500, RNSVGFontWeight600, RNSVGFontWeight700, RNSVGFontWeight800, RNSVGFontWeight900, // Relative RNSVGFontWeightBolder, RNSVGFontWeightLighter, RNSVGFontWeightDEFAULT = RNSVGFontWeightNormal, }; static NSString *const RNSVGFontWeightStrings[] = { @"normal", @"bold", @"100", @"200", @"300", @"400", @"500", @"600", @"700", @"800", @"900", @"bolder", @"lighter", nil}; static int const RNSVGAbsoluteFontWeights[] = {400, 700, 100, 200, 300, 400, 500, 600, 700, 800, 900}; static RNSVGFontWeight const RNSVGFontWeights[] = { RNSVGFontWeight100, RNSVGFontWeight100, RNSVGFontWeight200, RNSVGFontWeight300, RNSVGFontWeightNormal, RNSVGFontWeight500, RNSVGFontWeight600, RNSVGFontWeightBold, RNSVGFontWeight800, RNSVGFontWeight900, RNSVGFontWeight900}; NSString *RNSVGFontWeightToString(enum RNSVGFontWeight fw); NSInteger RNSVGFontWeightFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextAnchor) { RNSVGTextAnchorStart, RNSVGTextAnchorMiddle, RNSVGTextAnchorEnd, RNSVGTextAnchorDEFAULT = RNSVGTextAnchorStart, }; static NSString *const RNSVGTextAnchorStrings[] = {@"start", @"middle", @"end", nil}; NSString *RNSVGTextAnchorToString(enum RNSVGTextAnchor fw); enum RNSVGTextAnchor RNSVGTextAnchorFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextDecoration) { RNSVGTextDecorationNone, RNSVGTextDecorationUnderline, RNSVGTextDecorationOverline, RNSVGTextDecorationLineThrough, RNSVGTextDecorationBlink, RNSVGTextDecorationDEFAULT = RNSVGTextDecorationNone, }; static NSString *const RNSVGTextDecorationStrings[] = {@"None", @"Underline", @"Overline", @"LineThrough", @"Blink", nil}; NSString *RNSVGTextDecorationToString(enum RNSVGTextDecoration fw); enum RNSVGTextDecoration RNSVGTextDecorationFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextLengthAdjust) { RNSVGTextLengthAdjustSpacing, RNSVGTextLengthAdjustSpacingAndGlyphs, RNSVGTextLengthAdjustDEFAULT = RNSVGTextLengthAdjustSpacing, }; static NSString *const RNSVGTextLengthAdjustStrings[] = {@"spacing", @"spacingAndGlyphs", nil}; NSString *RNSVGTextLengthAdjustToString(enum RNSVGTextLengthAdjust fw); enum RNSVGTextLengthAdjust RNSVGTextLengthAdjustFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextPathMethod) { RNSVGTextPathMethodAlign, RNSVGTextPathMethodStretch, RNSVGTextPathMethodDEFAULT = RNSVGTextPathMethodAlign, }; static NSString *const RNSVGTextPathMethodStrings[] = {@"align", @"stretch", nil}; NSString *RNSVGTextPathMethodToString(enum RNSVGTextPathMethod fw); enum RNSVGTextPathMethod RNSVGTextPathMethodFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextPathMidLine) { RNSVGTextPathMidLineSharp, RNSVGTextPathMidLineSmooth, RNSVGTextPathMidLineDEFAULT = RNSVGTextPathMidLineSharp, }; static NSString *const RNSVGTextPathMidLineStrings[] = {@"sharp", @"smooth", nil}; NSString *RNSVGTextPathMidLineToString(enum RNSVGTextPathMidLine fw); enum RNSVGTextPathMidLine RNSVGTextPathMidLineFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextPathSide) { RNSVGTextPathSideLeft, RNSVGTextPathSideRight, RNSVGTextPathSideDEFAULT = RNSVGTextPathSideLeft, }; static NSString *const RNSVGTextPathSideStrings[] = {@"left", @"right", nil}; NSString *RNSVGTextPathSideToString(enum RNSVGTextPathSide fw); enum RNSVGTextPathSide RNSVGTextPathSideFromString(NSString *s); typedef NS_ENUM(NSInteger, RNSVGTextPathSpacing) { RNSVGTextPathSpacingAutoSpacing, RNSVGTextPathSpacingExact, RNSVGTextPathSpacingDEFAULT = RNSVGTextPathSpacingAutoSpacing, }; static NSString *const RNSVGTextPathSpacingStrings[] = {@"auto", @"exact", nil}; NSString *RNSVGTextPathSpacingToString(enum RNSVGTextPathSpacing fw); enum RNSVGTextPathSpacing RNSVGTextPathSpacingFromString(NSString *s); #endif ================================================ FILE: apple/Text/RNSVGTextProperties.mm ================================================ #import "RNSVGTextProperties.h" #pragma mark - RNSVGAlignmentBaseline NSString *RNSVGAlignmentBaselineToString(enum RNSVGAlignmentBaseline fw) { return RNSVGAlignmentBaselineStrings[fw]; } enum RNSVGAlignmentBaseline RNSVGAlignmentBaselineFromString(NSString *s) { if ([s length] == 0) { return RNSVGAlignmentBaselineDEFAULT; } const NSUInteger l = sizeof(RNSVGAlignmentBaselineStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGAlignmentBaselineStrings[i]]) { return (RNSVGAlignmentBaseline)i; } } return RNSVGAlignmentBaselineDEFAULT; } #pragma mark - RNSVGFontStyle NSString *RNSVGFontStyleToString(enum RNSVGFontStyle fw) { return RNSVGFontStyleStrings[fw]; } enum RNSVGFontStyle RNSVGFontStyleFromString(NSString *s) { if ([s length] == 0) { return RNSVGFontStyleDEFAULT; } const NSUInteger l = sizeof(RNSVGFontStyleStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGFontStyleStrings[i]]) { return (RNSVGFontStyle)i; } } return RNSVGFontStyleDEFAULT; } #pragma mark - RNSVGFontVariantLigatures NSString *RNSVGFontVariantLigaturesToString(enum RNSVGFontVariantLigatures fw) { return RNSVGFontVariantLigaturesStrings[fw]; } enum RNSVGFontVariantLigatures RNSVGFontVariantLigaturesFromString(NSString *s) { if ([s length] == 0) { return RNSVGFontVariantLigaturesDEFAULT; } const NSUInteger l = sizeof(RNSVGFontVariantLigaturesStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGFontVariantLigaturesStrings[i]]) { return (RNSVGFontVariantLigatures)i; } } return RNSVGFontVariantLigaturesDEFAULT; } #pragma mark - RNSVGFontWeight NSString *RNSVGFontWeightToString(enum RNSVGFontWeight fw) { return RNSVGFontWeightStrings[fw]; } NSInteger RNSVGFontWeightFromString(NSString *s) { if ([s length] == 0) { return -1; } const NSInteger l = sizeof(RNSVGFontWeightStrings) / sizeof(NSString *); for (NSInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGFontWeightStrings[i]]) { return i; } } return -1; } #pragma mark - RNSVGTextAnchor NSString *RNSVGTextAnchorToString(enum RNSVGTextAnchor fw) { return RNSVGTextAnchorStrings[fw]; } enum RNSVGTextAnchor RNSVGTextAnchorFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextAnchorDEFAULT; } const NSUInteger l = sizeof(RNSVGTextAnchorStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextAnchorStrings[i]]) { return (RNSVGTextAnchor)i; } } return RNSVGTextAnchorDEFAULT; } #pragma mark - RNSVGTextDecoration NSString *RNSVGTextDecorationToString(enum RNSVGTextDecoration fw) { return RNSVGTextDecorationStrings[fw]; } enum RNSVGTextDecoration RNSVGTextDecorationFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextDecorationDEFAULT; } const NSUInteger l = sizeof(RNSVGTextDecorationStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextDecorationStrings[i]]) { return (RNSVGTextDecoration)i; } } return RNSVGTextDecorationDEFAULT; } #pragma mark - RNSVGTextLengthAdjust NSString *RNSVGTextLengthAdjustToString(enum RNSVGTextLengthAdjust fw) { return RNSVGTextLengthAdjustStrings[fw]; } enum RNSVGTextLengthAdjust RNSVGTextLengthAdjustFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextLengthAdjustDEFAULT; } const NSUInteger l = sizeof(RNSVGTextLengthAdjustStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextLengthAdjustStrings[i]]) { return (RNSVGTextLengthAdjust)i; } } return RNSVGTextLengthAdjustDEFAULT; } #pragma mark - RNSVGTextPathMethod NSString *RNSVGTextPathMethodToString(enum RNSVGTextPathMethod fw) { return RNSVGTextPathMethodStrings[fw]; } enum RNSVGTextPathMethod RNSVGTextPathMethodFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextPathMethodDEFAULT; } const NSUInteger l = sizeof(RNSVGTextPathMethodStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextPathMethodStrings[i]]) { return (RNSVGTextPathMethod)i; } } return RNSVGTextPathMethodDEFAULT; } #pragma mark - RNSVGTextPathMidLine NSString *RNSVGTextPathMidLineToString(enum RNSVGTextPathMidLine fw) { return RNSVGTextPathMidLineStrings[fw]; } enum RNSVGTextPathMidLine RNSVGTextPathMidLineFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextPathMidLineDEFAULT; } const NSUInteger l = sizeof(RNSVGTextPathMidLineStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextPathMidLineStrings[i]]) { return (RNSVGTextPathMidLine)i; } } return RNSVGTextPathMidLineDEFAULT; } #pragma mark - RNSVGTextPathSide NSString *RNSVGTextPathSideToString(enum RNSVGTextPathSide fw) { return RNSVGTextPathSideStrings[fw]; } enum RNSVGTextPathSide RNSVGTextPathSideFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextPathSideDEFAULT; } const NSUInteger l = sizeof(RNSVGTextPathSideStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextPathSideStrings[i]]) { return (RNSVGTextPathSide)i; } } return RNSVGTextPathSideDEFAULT; } #pragma mark - RNSVGTextPathSpacing NSString *RNSVGTextPathSpacingToString(enum RNSVGTextPathSpacing fw) { return RNSVGTextPathSpacingStrings[fw]; } enum RNSVGTextPathSpacing RNSVGTextPathSpacingFromString(NSString *s) { if ([s length] == 0) { return RNSVGTextPathSpacingDEFAULT; } const NSUInteger l = sizeof(RNSVGTextPathSpacingStrings) / sizeof(NSString *); for (NSUInteger i = 0; i < l; i++) { if ([s isEqualToString:RNSVGTextPathSpacingStrings[i]]) { return (RNSVGTextPathSpacing)i; } } return RNSVGTextPathSpacingDEFAULT; } ================================================ FILE: apple/Text/RNSVGTopAlignedLabel.h ================================================ #import #if TARGET_OS_OSX #import @interface RNSVGTopAlignedLabel : NSTextView @property NSAttributedString *attributedText; @property NSLineBreakMode lineBreakMode; @property NSInteger numberOfLines; @property NSString *text; @property NSTextAlignment textAlignment; #else #import @interface RNSVGTopAlignedLabel : UILabel #endif @end ================================================ FILE: apple/Text/RNSVGTopAlignedLabel.ios.mm ================================================ #import "RNSVGTopAlignedLabel.h" #if !TARGET_OS_OSX @implementation RNSVGTopAlignedLabel - (void)drawTextInRect:(CGRect)rect { NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.text attributes:@{NSFontAttributeName : self.font}]; rect.size.height = [attributedText boundingRectWithSize:rect.size options:NSStringDrawingUsesLineFragmentOrigin context:nil] .size.height; if (self.numberOfLines != 0) { rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight); } [super drawTextInRect:rect]; } @end #endif // !TARGET_OS_OSX ================================================ FILE: apple/Text/RNSVGTopAlignedLabel.macos.mm ================================================ #import "RNSVGTopAlignedLabel.h" #if TARGET_OS_OSX @implementation RNSVGTopAlignedLabel - (NSAttributedString *)attributedText { return self.attributedString; } - (NSLineBreakMode)lineBreakMode { return self.textContainer.lineBreakMode; } - (NSInteger)numberOfLines { return self.textContainer.maximumNumberOfLines; } - (NSString *)text { return self.string; } - (NSTextAlignment)textAlignment { return self.alignment; } - (void)setAttributedText:(NSAttributedString *)attributedString { [self.textStorage setAttributedString:attributedString]; } - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode { self.textContainer.lineBreakMode = lineBreakMode; } - (void)setNumberOfLines:(NSInteger)numberOfLines { self.textContainer.maximumNumberOfLines = numberOfLines; } - (void)setText:(NSString *)text { self.string = text; } - (void)setTextAlignment:(NSTextAlignment)textAlignment { self.alignment = textAlignment; } @end #endif // TARGET_OS_OSX ================================================ FILE: apple/Utils/RCTConvert+RNSVG.h ================================================ /** * 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 #import #import #import "RCTConvert+RNSVG.h" #import "RNSVGBlendMode.h" #import "RNSVGCGFCRule.h" #import "RNSVGColorMatrixType.h" #import "RNSVGCompositeOperator.h" #import "RNSVGEdgeMode.h" #import "RNSVGLength.h" #import "RNSVGMaskType.h" #import "RNSVGPathParser.h" #import "RNSVGUnits.h" #import "RNSVGVBMOS.h" @class RNSVGBrush; @interface RCTConvert (RNSVG) + (RNSVGLength *)RNSVGLength:(id)json; + (NSArray *)RNSVGLengthArray:(id)json; + (RNSVGCGFCRule)RNSVGCGFCRule:(id)json; + (RNSVGVBMOS)RNSVGVBMOS:(id)json; + (RNSVGUnits)RNSVGUnits:(id)json; + (RNSVGMaskType)RNSVGMaskType:(id)json; + (RNSVGBrush *)RNSVGBrush:(id)json; + (RNSVGPathParser *)RNSVGCGPath:(NSString *)d; + (CGRect)RNSVGCGRect:(id)json offset:(NSUInteger)offset; + (RNSVGColor *)RNSVGColor:(id)json offset:(NSUInteger)offset; + (CGGradientRef)RNSVGCGGradient:(id)json; @end ================================================ FILE: apple/Utils/RCTConvert+RNSVG.mm ================================================ /** * 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 "RCTConvert+RNSVG.h" #import #import #import "RNSVGContextBrush.h" #import "RNSVGPainterBrush.h" #import "RNSVGSolidColorBrush.h" NSRegularExpression *RNSVGDigitRegEx; @implementation RCTConvert (RNSVG) RCT_ENUM_CONVERTER( RNSVGCGFCRule, (@{ @"evenodd" : @(kRNSVGCGFCRuleEvenodd), @"nonzero" : @(kRNSVGCGFCRuleNonzero), }), kRNSVGCGFCRuleNonzero, intValue) RCT_ENUM_CONVERTER( RNSVGVBMOS, (@{@"meet" : @(kRNSVGVBMOSMeet), @"slice" : @(kRNSVGVBMOSSlice), @"none" : @(kRNSVGVBMOSNone)}), kRNSVGVBMOSMeet, intValue) RCT_ENUM_CONVERTER( RNSVGUnits, (@{ @"objectBoundingBox" : @(kRNSVGUnitsObjectBoundingBox), @"userSpaceOnUse" : @(kRNSVGUnitsUserSpaceOnUse), }), kRNSVGUnitsObjectBoundingBox, intValue) RCT_ENUM_CONVERTER( RNSVGMaskType, (@{ @"luminance" : @(kRNSVGMaskTypeLuminance), @"alpha" : @(kRNSVGMaskTypeAlpha), }), kRNSVGMaskTypeLuminance, intValue) RCT_ENUM_CONVERTER( RNSVGEdgeMode, (@{ @"duplicate" : @(SVG_EDGEMODE_DUPLICATE), @"wrap" : @(SVG_EDGEMODE_WRAP), @"none" : @(SVG_EDGEMODE_NONE), }), SVG_EDGEMODE_UNKNOWN, intValue) RCT_ENUM_CONVERTER( RNSVGColorMatrixType, (@{ @"matrix" : @(SVG_FECOLORMATRIX_TYPE_MATRIX), @"saturate" : @(SVG_FECOLORMATRIX_TYPE_SATURATE), @"hueRotate" : @(SVG_FECOLORMATRIX_TYPE_HUEROTATE), @"luminanceToAlpha" : @(SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA), }), SVG_FECOLORMATRIX_TYPE_UNKNOWN, intValue) RCT_ENUM_CONVERTER( RNSVGBlendMode, (@{ @"unknown" : @(SVG_FEBLEND_MODE_UNKNOWN), @"normal" : @(SVG_FEBLEND_MODE_NORMAL), @"multiply" : @(SVG_FEBLEND_MODE_MULTIPLY), @"screen" : @(SVG_FEBLEND_MODE_SCREEN), @"darken" : @(SVG_FEBLEND_MODE_DARKEN), @"lighten" : @(SVG_FEBLEND_MODE_LIGHTEN), }), SVG_FEBLEND_MODE_UNKNOWN, intValue) RCT_ENUM_CONVERTER( RNSVGCompositeOperator, (@{ @"over" : @(SVG_FECOMPOSITE_OPERATOR_OVER), @"in" : @(SVG_FECOMPOSITE_OPERATOR_IN), @"out" : @(SVG_FECOMPOSITE_OPERATOR_OUT), @"atop" : @(SVG_FECOMPOSITE_OPERATOR_ATOP), @"xor" : @(SVG_FECOMPOSITE_OPERATOR_XOR), @"arithmetic" : @(SVG_FECOMPOSITE_OPERATOR_ARITHMETIC), }), SVG_FECOMPOSITE_OPERATOR_UNKNOWN, intValue) + (RNSVGBrush *)RNSVGBrush:(id)json { if (json == nil) { return nil; } if ([json isKindOfClass:[NSNumber class]]) { return [[RNSVGSolidColorBrush alloc] initWithNumber:json]; } if ([json isKindOfClass:[NSString class]]) { NSString *value = [self NSString:json]; if (!RNSVGDigitRegEx) { RNSVGDigitRegEx = [NSRegularExpression regularExpressionWithPattern:@"[0-9.-]+" options:NSRegularExpressionCaseInsensitive error:nil]; } NSArray *_matches = [RNSVGDigitRegEx matchesInString:value options:0 range:NSMakeRange(0, [value length])]; NSMutableArray *output = [NSMutableArray array]; NSUInteger i = 0; [output addObject:[NSNumber numberWithInteger:0]]; for (NSTextCheckingResult *match in _matches) { NSString *strNumber = [value substringWithRange:match.range]; [output addObject:[NSNumber numberWithDouble:(i++ < 3 ? strNumber.doubleValue / 255 : strNumber.doubleValue)]]; } if ([output count] < 5) { [output addObject:[NSNumber numberWithDouble:1]]; } return [[RNSVGSolidColorBrush alloc] initWithArray:output]; } NSDictionary *dict = [self NSDictionary:json]; int type = [dict[@"type"] intValue]; switch (type) { case 0: // solid color // These are probably expensive allocations since it's often the same value. // We should memoize colors but look ups may be just as expensive. { NSArray *arr = @[ @(0), dict[@"payload"] ]; return [[RNSVGSolidColorBrush alloc] initWithArray:arr]; } case 1: // brush { NSArray *arr = @[ @(1), dict[@"brushRef"] ]; return [[RNSVGPainterBrush alloc] initWithArray:arr]; } case 2: // currentColor return [[RNSVGBrush alloc] initWithArray:nil]; case 3: // context-fill return [[RNSVGContextBrush alloc] initFill]; case 4: // context-stroke return [[RNSVGContextBrush alloc] initStroke]; default: RCTLogError(@"Unknown brush type: %zd", (unsigned long)type); return nil; } } + (RNSVGPathParser *)RNSVGCGPath:(NSString *)d { return [[RNSVGPathParser alloc] initWithPathString:d]; } + (RNSVGLength *)RNSVGLength:(id)json { if ([json isKindOfClass:[NSNumber class]]) { return [RNSVGLength lengthWithNumber:(CGFloat)[json doubleValue]]; } else if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; return [RNSVGLength lengthWithString:stringValue]; } else { return [[RNSVGLength alloc] init]; } } + (NSArray *)RNSVGLengthArray:(id)json { if ([json isKindOfClass:[NSNumber class]]) { RNSVGLength *length = [RNSVGLength lengthWithNumber:(CGFloat)[json doubleValue]]; return [NSArray arrayWithObject:length]; } else if ([json isKindOfClass:[NSArray class]]) { NSArray *arrayValue = (NSArray *)json; NSMutableArray *lengths = [NSMutableArray arrayWithCapacity:[arrayValue count]]; for (id obj in arrayValue) { [lengths addObject:[self RNSVGLength:obj]]; } return lengths; } else if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; stringValue = [stringValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; stringValue = [stringValue stringByReplacingOccurrencesOfString:@"," withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, stringValue.length)]; NSArray *array = [stringValue componentsSeparatedByString:@" "]; NSMutableArray *svgLengthArray = [NSMutableArray array]; for (NSString *string in array) { RNSVGLength *length = [RNSVGLength lengthWithString:string]; [svgLengthArray addObject:length]; } return svgLengthArray; } else { return nil; } } + (CGRect)RNSVGCGRect:(id)json offset:(NSUInteger)offset { NSArray *arr = [self NSArray:json]; if (arr.count < offset + 4) { RCTLogError(@"Too few elements in array (expected at least %zd): %@", (ssize_t)(4 + offset), arr); return CGRectZero; } return (CGRect){ {[self CGFloat:arr[offset]], [self CGFloat:arr[offset + 1]]}, {[self CGFloat:arr[offset + 2]], [self CGFloat:arr[offset + 3]]}, }; } + (RNSVGColor *)RNSVGColor:(id)json offset:(NSUInteger)offset { NSArray *arr = [self NSArray:json]; if (arr.count == offset + 1) { return [self RNSVGColor:[arr objectAtIndex:offset]]; } if (arr.count < offset + 4) { RCTLogError(@"Too few elements in array (expected at least %zd): %@", (ssize_t)(4 + offset), arr); return nil; } return [self RNSVGColor:[arr subarrayWithRange:(NSRange){offset, 4}]]; } + (CGGradientRef)RNSVGCGGradient:(id)json { NSArray *arr = [self NSArray:json]; NSUInteger count = arr.count / 2; NSUInteger values = count * 5; NSUInteger offsetIndex = values - count; CGFloat colorsAndOffsets[values]; for (NSUInteger i = 0; i < count; i++) { NSUInteger stopIndex = i * 2; CGFloat offset = (CGFloat)[arr[stopIndex] doubleValue]; NSUInteger argb = [self NSUInteger:arr[stopIndex + 1]]; CGFloat a = ((argb >> 24) & 0xFF) / 255.0; CGFloat r = ((argb >> 16) & 0xFF) / 255.0; CGFloat g = ((argb >> 8) & 0xFF) / 255.0; CGFloat b = (argb & 0xFF) / 255.0; NSUInteger colorIndex = i * 4; colorsAndOffsets[colorIndex] = r; colorsAndOffsets[colorIndex + 1] = g; colorsAndOffsets[colorIndex + 2] = b; colorsAndOffsets[colorIndex + 3] = a; colorsAndOffsets[offsetIndex + i] = fmax(0, fmin(offset, 1)); } CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, colorsAndOffsets, colorsAndOffsets + offsetIndex, count); CGColorSpaceRelease(rgb); return (CGGradientRef)CFAutorelease(gradient); } @end ================================================ FILE: apple/Utils/RNSVGBezierElement.h ================================================ /* Erica Sadun, http://ericasadun.com https://github.com/erica/iOS-Drawing/tree/master/C08/Quartz%20Book%20Pack/Bezier */ #import #import "RNSVGUIKit.h" #define RNSVGNULLPOINT CGRectNull.origin @interface RNSVGBezierElement : NSObject // Element storage @property (nonatomic, assign) CGPathElementType elementType; @property (nonatomic, assign) CGPoint point; @property (nonatomic, assign) CGPoint controlPoint1; @property (nonatomic, assign) CGPoint controlPoint2; // Instance creation + (instancetype)elementWithPathElement:(CGPathElement)element; + (NSArray *)elementsFromCGPath:(CGPathRef)path; @end ================================================ FILE: apple/Utils/RNSVGBezierElement.mm ================================================ /* Erica Sadun, http://ericasadun.com https://github.com/erica/iOS-Drawing/tree/master/C08/Quartz%20Book%20Pack/Bezier */ #import "RNSVGBezierElement.h" #pragma mark - Bezier Element - @implementation RNSVGBezierElement - (instancetype)init { self = [super init]; if (self) { _elementType = kCGPathElementMoveToPoint; _point = RNSVGNULLPOINT; _controlPoint1 = RNSVGNULLPOINT; _controlPoint2 = RNSVGNULLPOINT; } return self; } + (instancetype)elementWithPathElement:(CGPathElement)element { RNSVGBezierElement *newElement = [[self alloc] init]; newElement.elementType = element.type; switch (newElement.elementType) { case kCGPathElementCloseSubpath: break; case kCGPathElementMoveToPoint: case kCGPathElementAddLineToPoint: { newElement.point = element.points[0]; break; } case kCGPathElementAddQuadCurveToPoint: { newElement.point = element.points[1]; newElement.controlPoint1 = element.points[0]; break; } case kCGPathElementAddCurveToPoint: { newElement.point = element.points[2]; newElement.controlPoint1 = element.points[0]; newElement.controlPoint2 = element.points[1]; break; } default: break; } return newElement; } // Convert one element to RNSVGBezierElement and save to array void RNSVGBezierElement_getBezierElements(void *info, const CGPathElement *element) { NSMutableArray *bezierElements = (__bridge NSMutableArray *)info; if (element) [bezierElements addObject:[RNSVGBezierElement elementWithPathElement:*element]]; } // Retrieve array of component elements + (NSArray *)elementsFromCGPath:(CGPathRef)path { NSMutableArray *elements = [NSMutableArray array]; CGPathApply(path, (__bridge void *)elements, RNSVGBezierElement_getBezierElements); return elements; } @end ================================================ FILE: apple/Utils/RNSVGCGFCRule.h ================================================ /** * 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 typedef CF_ENUM(int32_t, RNSVGCGFCRule) { kRNSVGCGFCRuleEvenodd, kRNSVGCGFCRuleNonzero }; ================================================ FILE: apple/Utils/RNSVGConvert.h ================================================ #ifdef RCT_NEW_ARCH_ENABLED #import #import "RNSVGBlendMode.h" #import "RNSVGColorMatrixType.h" #import "RNSVGCompositeOperator.h" #import "RNSVGEdgeMode.h" #import "RNSVGUnits.h" namespace react = facebook::react; @interface RNSVGConvert : NSObject + (RNSVGUnits)RNSVGUnitsFromFilterUnitsCppEquivalent:(react::RNSVGFilterFilterUnits)svgUnits; + (RNSVGUnits)RNSVGUnitsFromPrimitiveUnitsCppEquivalent:(react::RNSVGFilterPrimitiveUnits)svgUnits; + (RNSVGBlendMode)RNSVGBlendModeFromCppEquivalent:(react::RNSVGFeBlendMode)mode; + (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type; + (RNSVGCompositeOperator)RNSVGRNSVGCompositeOperatorFromCppEquivalent:(react::RNSVGFeCompositeOperator1)operator1; + (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode; @end #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Utils/RNSVGConvert.mm ================================================ #import "RNSVGConvert.h" #ifdef RCT_NEW_ARCH_ENABLED @implementation RNSVGConvert + (RNSVGUnits)RNSVGUnitsFromFilterUnitsCppEquivalent:(react::RNSVGFilterFilterUnits)svgUnits { switch (svgUnits) { case react::RNSVGFilterFilterUnits::UserSpaceOnUse: return kRNSVGUnitsUserSpaceOnUse; case react::RNSVGFilterFilterUnits::ObjectBoundingBox: return kRNSVGUnitsObjectBoundingBox; } } + (RNSVGUnits)RNSVGUnitsFromPrimitiveUnitsCppEquivalent:(react::RNSVGFilterPrimitiveUnits)svgUnits { switch (svgUnits) { case react::RNSVGFilterPrimitiveUnits::UserSpaceOnUse: return kRNSVGUnitsUserSpaceOnUse; case react::RNSVGFilterPrimitiveUnits::ObjectBoundingBox: return kRNSVGUnitsObjectBoundingBox; } } + (RNSVGBlendMode)RNSVGBlendModeFromCppEquivalent:(react::RNSVGFeBlendMode)mode { switch (mode) { case react::RNSVGFeBlendMode::Unknown: return SVG_FEBLEND_MODE_UNKNOWN; case react::RNSVGFeBlendMode::Normal: return SVG_FEBLEND_MODE_NORMAL; case react::RNSVGFeBlendMode::Multiply: return SVG_FEBLEND_MODE_MULTIPLY; case react::RNSVGFeBlendMode::Screen: return SVG_FEBLEND_MODE_SCREEN; case react::RNSVGFeBlendMode::Darken: return SVG_FEBLEND_MODE_DARKEN; case react::RNSVGFeBlendMode::Lighten: return SVG_FEBLEND_MODE_LIGHTEN; } } + (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type { switch (type) { case react::RNSVGFeColorMatrixType::Matrix: return SVG_FECOLORMATRIX_TYPE_MATRIX; case react::RNSVGFeColorMatrixType::Saturate: return SVG_FECOLORMATRIX_TYPE_SATURATE; case react::RNSVGFeColorMatrixType::HueRotate: return SVG_FECOLORMATRIX_TYPE_HUEROTATE; case react::RNSVGFeColorMatrixType::LuminanceToAlpha: return SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA; } } + (RNSVGCompositeOperator)RNSVGRNSVGCompositeOperatorFromCppEquivalent:(react::RNSVGFeCompositeOperator1)operator1 { switch (operator1) { case react::RNSVGFeCompositeOperator1::Over: return SVG_FECOMPOSITE_OPERATOR_OVER; case react::RNSVGFeCompositeOperator1::In: return SVG_FECOMPOSITE_OPERATOR_IN; case react::RNSVGFeCompositeOperator1::Out: return SVG_FECOMPOSITE_OPERATOR_OUT; case react::RNSVGFeCompositeOperator1::Atop: return SVG_FECOMPOSITE_OPERATOR_ATOP; case react::RNSVGFeCompositeOperator1::Xor: return SVG_FECOMPOSITE_OPERATOR_XOR; case react::RNSVGFeCompositeOperator1::Arithmetic: return SVG_FECOMPOSITE_OPERATOR_ARITHMETIC; } } + (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode { switch (edgeMode) { case react::RNSVGFeGaussianBlurEdgeMode::Duplicate: return SVG_EDGEMODE_DUPLICATE; case react::RNSVGFeGaussianBlurEdgeMode::Wrap: return SVG_EDGEMODE_WRAP; case react::RNSVGFeGaussianBlurEdgeMode::None: return SVG_EDGEMODE_NONE; default: return SVG_EDGEMODE_UNKNOWN; } } @end #endif // RCT_NEW_ARCH_ENABLED ================================================ FILE: apple/Utils/RNSVGFabricConversions.h ================================================ #import "RNSVGContextBrush.h" #import "RNSVGFilterPrimitive.h" #import "RNSVGGroup.h" #import "RNSVGLength.h" #import "RNSVGPainterBrush.h" #import "RNSVGRenderable.h" #import "RNSVGSolidColorBrush.h" #import "RNSVGText.h" #import "RNSVGVBMOS.h" #import #import #import // copied from RCTFollyConvert static id RNSVGConvertFollyDynamicToId(const folly::dynamic &dyn) { // I could imagine an implementation which avoids copies by wrapping the // dynamic in a derived class of NSDictionary. We can do that if profiling // implies it will help. switch (dyn.type()) { case folly::dynamic::NULLT: return nil; case folly::dynamic::BOOL: return dyn.getBool() ? @YES : @NO; case folly::dynamic::INT64: return @(dyn.getInt()); case folly::dynamic::DOUBLE: return @(dyn.getDouble()); case folly::dynamic::STRING: return [[NSString alloc] initWithBytes:dyn.c_str() length:dyn.size() encoding:NSUTF8StringEncoding]; case folly::dynamic::ARRAY: { NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:dyn.size()]; for (const auto &elem : dyn) { id value = RNSVGConvertFollyDynamicToId(elem); if (value) { [array addObject:value]; } } return array; } case folly::dynamic::OBJECT: { NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:dyn.size()]; for (const auto &elem : dyn.items()) { id key = RNSVGConvertFollyDynamicToId(elem.first); id value = RNSVGConvertFollyDynamicToId(elem.second); if (key && value) { dict[key] = value; } } return dict; } } } static const facebook::react::LayoutMetrics MinimalLayoutMetrics = {{{0, 0}, {1, 1}}}; template void setCommonNodeProps(const T &nodeProps, RNSVGNode *node) { node.name = RCTNSStringFromStringNilIfEmpty(nodeProps.name); node.opacity = nodeProps.opacity; if (nodeProps.matrix.size() == 6) { node.matrix = CGAffineTransformMake( nodeProps.matrix.at(0), nodeProps.matrix.at(1), nodeProps.matrix.at(2), nodeProps.matrix.at(3), nodeProps.matrix.at(4), nodeProps.matrix.at(5)); } if (nodeProps.transform.operations.size() > 0) { auto newTransform = nodeProps.resolveTransform(MinimalLayoutMetrics); CATransform3D transform3d = RCTCATransform3DFromTransformMatrix(newTransform); CGAffineTransform transform = CATransform3DGetAffineTransform(transform3d); node.transforms = transform; } node.mask = RCTNSStringFromStringNilIfEmpty(nodeProps.mask); node.markerStart = RCTNSStringFromStringNilIfEmpty(nodeProps.markerStart); node.markerMid = RCTNSStringFromStringNilIfEmpty(nodeProps.markerMid); node.markerEnd = RCTNSStringFromStringNilIfEmpty(nodeProps.markerEnd); node.clipPath = RCTNSStringFromStringNilIfEmpty(nodeProps.clipPath); node.clipRule = nodeProps.clipRule == 0 ? kRNSVGCGFCRuleEvenodd : kRNSVGCGFCRuleNonzero; node.responsible = nodeProps.responsible; // onLayout node.display = RCTNSStringFromStringNilIfEmpty(nodeProps.display); std::string pointerEvents = nodeProps.pointerEvents; NSString *pointerEventsString = RCTNSStringFromStringNilIfEmpty(pointerEvents); if ([pointerEventsString isEqualToString:@"auto"]) { node.pointerEvents = RCTPointerEventsUnspecified; } else if ([pointerEventsString isEqualToString:@"none"]) { node.pointerEvents = RCTPointerEventsNone; } else if ([pointerEventsString isEqualToString:@"box-none"]) { node.pointerEvents = RCTPointerEventsNone; } else if ([pointerEventsString isEqualToString:@"box-only"]) { node.pointerEvents = RCTPointerEventsNone; } else { node.pointerEvents = RCTPointerEventsUnspecified; } node.accessibilityIdentifier = RCTNSStringFromStringNilIfEmpty(nodeProps.testId); #if !TARGET_OS_OSX node.isAccessibilityElement = nodeProps.accessible; #else node.accessibilityElement = nodeProps.accessible; #endif // !TARGET_OS_OSX node.accessibilityLabel = RCTNSStringFromStringNilIfEmpty(nodeProps.accessibilityLabel); } template void setCommonRenderableProps(const T &renderableProps, RNSVGRenderable *renderableNode) { setCommonNodeProps(renderableProps, renderableNode); if (RCTUIColorFromSharedColor(renderableProps.color)) { [renderableNode setColor:RCTUIColorFromSharedColor(renderableProps.color)]; } id fill = RNSVGConvertFollyDynamicToId(renderableProps.fill); renderableNode.fill = [RCTConvert RNSVGBrush:fill]; renderableNode.fillOpacity = renderableProps.fillOpacity; renderableNode.fillRule = renderableProps.fillRule == 0 ? kRNSVGCGFCRuleEvenodd : kRNSVGCGFCRuleNonzero; id stroke = RNSVGConvertFollyDynamicToId(renderableProps.stroke); renderableNode.stroke = [RCTConvert RNSVGBrush:stroke]; renderableNode.strokeOpacity = renderableProps.strokeOpacity; id strokeWidth = RNSVGConvertFollyDynamicToId(renderableProps.strokeWidth); if (strokeWidth != nil) { renderableNode.strokeWidth = [RCTConvert RNSVGLength:strokeWidth]; } renderableNode.strokeLinecap = renderableProps.strokeLinecap == 0 ? kCGLineCapButt : renderableProps.strokeLinecap == 1 ? kCGLineCapRound : kCGLineCapSquare; renderableNode.strokeLinejoin = renderableProps.strokeLinejoin == 0 ? kCGLineJoinMiter : renderableProps.strokeLinejoin == 1 ? kCGLineJoinRound : kCGLineJoinBevel; id strokeDasharray = RNSVGConvertFollyDynamicToId(renderableProps.strokeDasharray); if (strokeDasharray != nil) { renderableNode.strokeDasharray = [RCTConvert RNSVGLengthArray:strokeDasharray]; } renderableNode.strokeDashoffset = renderableProps.strokeDashoffset; renderableNode.strokeMiterlimit = renderableProps.strokeMiterlimit; renderableNode.vectorEffect = renderableProps.vectorEffect == 0 ? kRNSVGVectorEffectDefault : renderableProps.vectorEffect == 1 ? kRNSVGVectorEffectNonScalingStroke : renderableProps.vectorEffect == 2 ? kRNSVGVectorEffectInherit : kRNSVGVectorEffectUri; if (renderableProps.propList.size() > 0) { NSMutableArray *propArray = [NSMutableArray new]; for (auto str : renderableProps.propList) { [propArray addObject:RCTNSStringFromString(str)]; } renderableNode.propList = propArray; } renderableNode.filter = RCTNSStringFromStringNilIfEmpty(renderableProps.filter); } template void setCommonGroupProps(const T &groupProps, RNSVGGroup *groupNode) { setCommonRenderableProps(groupProps, groupNode); id fontSize = RNSVGConvertFollyDynamicToId(groupProps.fontSize); if (fontSize != nil) { groupNode.font = @{@"fontSize" : fontSize}; } id fontWeight = RNSVGConvertFollyDynamicToId(groupProps.fontWeight); if (fontWeight != nil) { groupNode.font = @{@"fontWeight" : fontWeight}; } id font = RNSVGConvertFollyDynamicToId(groupProps.font); if (font != nil) { NSDictionary *fontDict = (NSDictionary *)font; if (groupNode.font == nil || fontDict.count > 0) { // some of text's rendering logic requires that `font` is not nil so we always set it // even if to an empty dict groupNode.font = fontDict; } } } template void setCommonFilterProps(const T &filterProps, RNSVGFilterPrimitive *filterPrimitiveNode) { id x = RNSVGConvertFollyDynamicToId(filterProps.x); if (x != nil) { filterPrimitiveNode.x = [RCTConvert RNSVGLength:x]; } id y = RNSVGConvertFollyDynamicToId(filterProps.y); if (y != nil) { filterPrimitiveNode.y = [RCTConvert RNSVGLength:y]; } id height = RNSVGConvertFollyDynamicToId(filterProps.height); if (height != nil) { filterPrimitiveNode.height = [RCTConvert RNSVGLength:height]; } id width = RNSVGConvertFollyDynamicToId(filterProps.width); if (width != nil) { filterPrimitiveNode.width = [RCTConvert RNSVGLength:width]; } filterPrimitiveNode.result = RCTNSStringFromStringNilIfEmpty(filterProps.result); } template void setCommonTextProps(const T &textProps, RNSVGText *textNode) { setCommonGroupProps(textProps, textNode); id deltaX = RNSVGConvertFollyDynamicToId(textProps.dx); if (deltaX != nil) { textNode.deltaX = [RCTConvert RNSVGLengthArray:deltaX]; } id deltaY = RNSVGConvertFollyDynamicToId(textProps.dy); if (deltaY != nil) { textNode.deltaY = [RCTConvert RNSVGLengthArray:deltaY]; } id positionX = RNSVGConvertFollyDynamicToId(textProps.x); if (positionX != nil) { textNode.positionX = [RCTConvert RNSVGLengthArray:positionX]; } id positionY = RNSVGConvertFollyDynamicToId(textProps.y); if (positionY != nil) { textNode.positionY = [RCTConvert RNSVGLengthArray:positionY]; } id rotate = RNSVGConvertFollyDynamicToId(textProps.rotate); if (rotate != nil) { textNode.rotate = [RCTConvert RNSVGLengthArray:rotate]; } id textLength = RNSVGConvertFollyDynamicToId(textProps.textLength); if (textLength != nil) { textNode.textLength = [RCTConvert RNSVGLength:textLength]; } id inlineSize = RNSVGConvertFollyDynamicToId(textProps.inlineSize); if (inlineSize != nil) { textNode.inlineSize = [RCTConvert RNSVGLength:inlineSize]; } id baselineShift = RNSVGConvertFollyDynamicToId(textProps.baselineShift); if (baselineShift != nil) { if ([baselineShift isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)baselineShift; textNode.baselineShift = stringValue; } else { textNode.baselineShift = [NSString stringWithFormat:@"%f", [baselineShift doubleValue]]; } } textNode.lengthAdjust = RCTNSStringFromStringNilIfEmpty(textProps.lengthAdjust); textNode.alignmentBaseline = RCTNSStringFromStringNilIfEmpty(textProps.alignmentBaseline); } static RNSVGVBMOS intToRNSVGVBMOS(int value) { switch (value) { case 0: return kRNSVGVBMOSMeet; case 1: return kRNSVGVBMOSSlice; case 2: return kRNSVGVBMOSNone; default: return kRNSVGVBMOSMeet; } } ================================================ FILE: apple/Utils/RNSVGLength.h ================================================ #import "RNSVGUIKit.h" #ifndef RNSVGLength_h #define RNSVGLength_h // https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength typedef CF_ENUM(unsigned short, RNSVGLengthUnitType) { SVG_LENGTHTYPE_UNKNOWN, SVG_LENGTHTYPE_NUMBER, SVG_LENGTHTYPE_PERCENTAGE, SVG_LENGTHTYPE_EMS, SVG_LENGTHTYPE_EXS, SVG_LENGTHTYPE_PX, SVG_LENGTHTYPE_CM, SVG_LENGTHTYPE_MM, SVG_LENGTHTYPE_IN, SVG_LENGTHTYPE_PT, SVG_LENGTHTYPE_PC, }; @interface RNSVGLength : NSObject @property (nonatomic, assign) CGFloat value; @property (nonatomic, assign) RNSVGLengthUnitType unit; + (instancetype)lengthWithNumber:(CGFloat)number; + (instancetype)lengthWithString:(NSString *)lengthString; - (BOOL)isEqualTo:(RNSVGLength *)other; @end #endif /* RNSVGLength_h */ ================================================ FILE: apple/Utils/RNSVGLength.mm ================================================ #import "RNSVGLength.h" #import @implementation RNSVGLength - (instancetype)init { self = [super init]; if (self) { _value = 0; _unit = SVG_LENGTHTYPE_UNKNOWN; } return self; } + (instancetype)lengthWithNumber:(CGFloat)number { RNSVGLength *length = [[self alloc] init]; length.unit = SVG_LENGTHTYPE_NUMBER; length.value = number; return length; } + (instancetype)lengthWithString:(NSString *)lengthString { NSString *length = [lengthString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSUInteger stringLength = [length length]; NSInteger percentIndex = stringLength - 1; RNSVGLength *output = [RNSVGLength alloc]; if (stringLength == 0) { output.unit = SVG_LENGTHTYPE_UNKNOWN; output.value = 0; return output; } else if ([length characterAtIndex:percentIndex] == '%') { output.unit = SVG_LENGTHTYPE_PERCENTAGE; output.value = (CGFloat)[[length substringWithRange:NSMakeRange(0, percentIndex)] doubleValue]; } else { NSInteger twoLetterUnitIndex = stringLength - 2; RNSVGLengthUnitType unit = SVG_LENGTHTYPE_NUMBER; if (twoLetterUnitIndex > 0) { NSString *lastTwo = [length substringFromIndex:twoLetterUnitIndex]; NSUInteger end = twoLetterUnitIndex; if ([lastTwo isEqualToString:@"px"]) { unit = SVG_LENGTHTYPE_PX; } else if ([lastTwo isEqualToString:@"em"]) { unit = SVG_LENGTHTYPE_EMS; } else if ([lastTwo isEqualToString:@"ex"]) { unit = SVG_LENGTHTYPE_EXS; } else if ([lastTwo isEqualToString:@"pt"]) { unit = SVG_LENGTHTYPE_PT; } else if ([lastTwo isEqualToString:@"pc"]) { unit = SVG_LENGTHTYPE_PC; } else if ([lastTwo isEqualToString:@"mm"]) { unit = SVG_LENGTHTYPE_MM; } else if ([lastTwo isEqualToString:@"cm"]) { unit = SVG_LENGTHTYPE_CM; } else if ([lastTwo isEqualToString:@"in"]) { unit = SVG_LENGTHTYPE_IN; } else { end = stringLength; } output.value = (CGFloat)[[length substringWithRange:NSMakeRange(0, end)] doubleValue]; } else { output.value = (CGFloat)[length doubleValue]; } output.unit = unit; } return output; } - (BOOL)isEqualTo:(RNSVGLength *)other { return self.unit == other.unit && self.value == other.value; } @end ================================================ FILE: apple/Utils/RNSVGMarkerPosition.h ================================================ #import #import "RNSVGUIKit.h" typedef enum RNSVGMarkerType { kStartMarker, kMidMarker, kEndMarker } RNSVGMarkerType; #define RNSVGZEROPOINT CGRectZero.origin @interface RNSVGMarkerPosition : NSObject // Element storage @property (nonatomic, assign) RNSVGMarkerType type; @property (nonatomic, assign) CGPoint origin; @property (nonatomic, assign) float angle; // Instance creation + (instancetype)markerPosition:(RNSVGMarkerType)type origin:(CGPoint)origin angle:(float)angle; + (NSArray *)fromCGPath:(CGPathRef)path; @end ================================================ FILE: apple/Utils/RNSVGMarkerPosition.mm ================================================ #import "RNSVGMarkerPosition.h" @implementation RNSVGMarkerPosition - (instancetype)init { self = [super init]; if (self) { _type = kStartMarker; _origin = RNSVGZEROPOINT; _angle = 0; } return self; } + (instancetype)markerPosition:(RNSVGMarkerType)type origin:(CGPoint)origin angle:(float)angle { RNSVGMarkerPosition *newElement = [[self alloc] init]; newElement.type = type; newElement.origin = origin; newElement.angle = angle; return newElement; } + (NSArray *)fromCGPath:(CGPathRef)path { positions_ = [[NSMutableArray alloc] init]; element_index_ = 0; origin_ = RNSVGZEROPOINT; subpath_start_ = RNSVGZEROPOINT; CGPathApply(path, (__bridge void *)positions_, UpdateFromPathElement); PathIsDone(); return positions_; } void PathIsDone() { float angle = CurrentAngle(kEndMarker); [positions_ addObject:[RNSVGMarkerPosition markerPosition:kEndMarker origin:origin_ angle:angle]]; } static double BisectingAngle(double in_angle, double out_angle) { // WK193015: Prevent bugs due to angles being non-continuous. if (fabs(in_angle - out_angle) > 180) in_angle += 360; return (in_angle + out_angle) / 2; } static CGFloat RNSVG_radToDeg = 180 / (CGFloat)M_PI; double rad2deg(CGFloat rad) { return rad * RNSVG_radToDeg; } CGFloat SlopeAngleRadians(CGSize p) { CGFloat angle = atan2(p.height, p.width); return angle; } double CurrentAngle(RNSVGMarkerType type) { // For details of this calculation, see: // http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement double in_angle = rad2deg(SlopeAngleRadians(in_slope_)); double out_angle = rad2deg(SlopeAngleRadians(out_slope_)); switch (type) { case kStartMarker: if (auto_start_reverse_) out_angle += 180; return out_angle; case kMidMarker: return BisectingAngle(in_angle, out_angle); case kEndMarker: return in_angle; } return 0; } typedef struct SegmentData { CGSize start_tangent; // Tangent in the start point of the segment. CGSize end_tangent; // Tangent in the end point of the segment. CGPoint position; // The end point of the segment. } SegmentData; CGSize subtract(CGPoint *p1, CGPoint *p2) { return CGSizeMake(p2->x - p1->x, p2->y - p1->y); } static void ComputeQuadTangents(SegmentData *data, CGPoint *start, CGPoint *control, CGPoint *end) { data->start_tangent = subtract(control, start); data->end_tangent = subtract(end, control); if (CGSizeEqualToSize(CGSizeZero, data->start_tangent)) data->start_tangent = data->end_tangent; else if (CGSizeEqualToSize(CGSizeZero, data->end_tangent)) data->end_tangent = data->start_tangent; } SegmentData ExtractPathElementFeatures(const CGPathElement *element) { SegmentData data; CGPoint *points = element->points; switch (element->type) { case kCGPathElementAddCurveToPoint: data.position = points[2]; data.start_tangent = subtract(&points[0], &origin_); data.end_tangent = subtract(&points[2], &points[1]); if (CGSizeEqualToSize(CGSizeZero, data.start_tangent)) ComputeQuadTangents(&data, &points[0], &points[1], &points[2]); else if (CGSizeEqualToSize(CGSizeZero, data.end_tangent)) ComputeQuadTangents(&data, &origin_, &points[0], &points[1]); break; case kCGPathElementAddQuadCurveToPoint: data.position = points[1]; ComputeQuadTangents(&data, &origin_, &points[0], &points[1]); break; case kCGPathElementMoveToPoint: case kCGPathElementAddLineToPoint: data.position = points[0]; data.start_tangent = subtract(&data.position, &origin_); data.end_tangent = subtract(&data.position, &origin_); break; case kCGPathElementCloseSubpath: data.position = subpath_start_; data.start_tangent = subtract(&data.position, &origin_); data.end_tangent = subtract(&data.position, &origin_); break; } return data; } void UpdateFromPathElement(__unused void *info, const CGPathElement *element) { SegmentData segment_data = ExtractPathElementFeatures(element); // First update the outgoing slope for the previous element. out_slope_ = segment_data.start_tangent; // Record the marker for the previous element. if (element_index_ > 0) { RNSVGMarkerType marker_type = element_index_ == 1 ? kStartMarker : kMidMarker; float angle = CurrentAngle(marker_type); [positions_ addObject:[RNSVGMarkerPosition markerPosition:marker_type origin:origin_ angle:angle]]; } // Update the incoming slope for this marker position. in_slope_ = segment_data.end_tangent; // Update marker position. origin_ = segment_data.position; // If this is a 'move to' segment, save the point for use with 'close'. if (element->type == kCGPathElementMoveToPoint) subpath_start_ = element->points[0]; else if (element->type == kCGPathElementCloseSubpath) subpath_start_ = CGPointZero; ++element_index_; } NSMutableArray *positions_; unsigned element_index_; CGPoint origin_; CGPoint subpath_start_; CGSize in_slope_; CGSize out_slope_; bool auto_start_reverse_; @end ================================================ FILE: apple/Utils/RNSVGMaskType.h ================================================ typedef CF_ENUM(int32_t, RNSVGMaskType) { kRNSVGMaskTypeLuminance, kRNSVGMaskTypeAlpha }; ================================================ FILE: apple/Utils/RNSVGPathMeasure.h ================================================ /** * Copyright (c) 2015-present, react-native-community. * 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 "RNSVGUIKit.h" @interface RNSVGPathMeasure : NSObject @property CGFloat pathLength; @property CGPathRef path; @property NSMutableArray *lengths; @property NSMutableArray *lines; @property NSUInteger lineCount; @property BOOL isClosed; - (void)reset; - (void)extractPathData:(CGPathRef)path; - (void)getPosAndTan:(CGFloat *)angle midPoint:(CGFloat)midPoint x:(CGFloat *)x y:(CGFloat *)y; @end ================================================ FILE: apple/Utils/RNSVGPathMeasure.mm ================================================ #import "RNSVGPathMeasure.h" #import "RNSVGBezierElement.h" /* Some Bezier logic from PerformanceBezier */ /* ## License Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 United States License. For attribution, please include: 1. Mention original author "Adam Wulf for Loose Leaf app" 2. Link to https://getlooseleaf.com/opensource/ 3. Link to https://github.com/adamwulf/PerformanceBezier */ static CGFloat idealFlatness = (CGFloat).01; /** * returns the distance between two points */ static CGFloat distance(CGPoint p1, CGPoint p2) { CGFloat dx = p2.x - p1.x; CGFloat dy = p2.y - p1.y; return hypot(dx, dy); } // Subdivide a Bézier (specific division) /* * (c) 2004 Alastair J. Houghton * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author of this software may not be used to endorse * or promote products derived from the software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ static void subdivideBezierAtT(const CGPoint bez[4], CGPoint bez1[4], CGPoint bez2[4], CGFloat t) { CGPoint q; CGFloat mt = 1 - t; bez1[0].x = bez[0].x; bez1[0].y = bez[0].y; bez2[3].x = bez[3].x; bez2[3].y = bez[3].y; q.x = mt * bez[1].x + t * bez[2].x; q.y = mt * bez[1].y + t * bez[2].y; bez1[1].x = mt * bez[0].x + t * bez[1].x; bez1[1].y = mt * bez[0].y + t * bez[1].y; bez2[2].x = mt * bez[2].x + t * bez[3].x; bez2[2].y = mt * bez[2].y + t * bez[3].y; bez1[2].x = mt * bez1[1].x + t * q.x; bez1[2].y = mt * bez1[1].y + t * q.y; bez2[1].x = mt * q.x + t * bez2[2].x; bez2[1].y = mt * q.y + t * bez2[2].y; bez1[3].x = bez2[0].x = mt * bez1[2].x + t * bez2[1].x; bez1[3].y = bez2[0].y = mt * bez1[2].y + t * bez2[1].y; } @implementation RNSVGPathMeasure - (void)addLine:(CGPoint *)last next:(const CGPoint *)next { NSArray *line = @[ [NSValue valueWithCGPoint:*last], [NSValue valueWithCGPoint:*next] ]; _pathLength += distance(*last, *next); [_lengths addObject:[NSNumber numberWithDouble:_pathLength]]; [_lines addObject:line]; *last = *next; } - (void)reset { _lengths = nil; _lines = nil; _isClosed = NO; _lineCount = 0; _pathLength = 0; _path = nil; } - (void)extractPathData:(CGPathRef)path { if (path == _path) { return; } _path = path; CGPoint origin = CGPointMake(0.0, 0.0); CGPoint last = CGPointMake(0.0, 0.0); _lengths = [NSMutableArray array]; _lines = [NSMutableArray array]; _isClosed = NO; _lineCount = 0; _pathLength = 0; NSArray *elements = [RNSVGBezierElement elementsFromCGPath:path]; for (RNSVGBezierElement *element in elements) { switch (element.elementType) { case kCGPathElementMoveToPoint: origin = last = element.point; break; case kCGPathElementAddLineToPoint: { CGPoint next = element.point; [self addLine:&last next:&next]; _lineCount++; break; } case kCGPathElementAddQuadCurveToPoint: case kCGPathElementAddCurveToPoint: { // handle both curve types gracefully CGPoint curveTo = element.point; CGPoint ctrl1 = element.controlPoint1; CGPoint ctrl2 = element.elementType == kCGPathElementAddQuadCurveToPoint ? ctrl1 : element.controlPoint2; // this is the bezier for our current element CGPoint bezier[4] = {last, ctrl1, ctrl2, curveTo}; NSValue *arr = [NSValue valueWithBytes:&bezier objCType:@encode(CGPoint[4])]; NSMutableArray *curves = [NSMutableArray arrayWithObjects:arr, nil]; for (NSInteger curveIndex = 0; curveIndex >= 0; curveIndex--) { CGPoint bez[4]; [curves[curveIndex] getValue:&bez]; [curves removeLastObject]; // calculate the error rate of the curve vs // a line segment between the start and end points ctrl1 = bez[1]; ctrl2 = bez[2]; CGPoint next = bez[3]; CGFloat polyLen = distance(last, ctrl1) + distance(ctrl1, ctrl2) + distance(ctrl2, next); CGFloat chordLen = distance(last, next); CGFloat error = polyLen - chordLen; // if the error is less than our accepted level of error // then add a line, else, split the curve in half if (error <= idealFlatness) { [self addLine:&last next:&next]; _lineCount++; } else { CGPoint bez1[4], bez2[4]; subdivideBezierAtT(bez, bez1, bez2, .5); [curves addObject:[NSValue valueWithBytes:&bez2 objCType:@encode(CGPoint[4])]]; [curves addObject:[NSValue valueWithBytes:&bez1 objCType:@encode(CGPoint[4])]]; curveIndex += 2; } } break; } case kCGPathElementCloseSubpath: { CGPoint next = origin; [self addLine:&last next:&next]; _lineCount++; _isClosed = YES; break; } default: break; } } } - (void)getPosAndTan:(CGFloat *)angle midPoint:(CGFloat)midPoint x:(CGFloat *)x y:(CGFloat *)y { // Investigation suggests binary search is faster at lineCount >= 16 // https://gist.github.com/msand/4c7993319425f9d7933be58ad9ada1a4 NSUInteger i = _lineCount < 16 ? [_lengths indexOfObjectPassingTest:^(NSNumber *length, __unused NSUInteger index, __unused BOOL *_Nonnull stop) { BOOL contains = midPoint <= [length doubleValue]; return contains; }] : [_lengths indexOfObject:[NSNumber numberWithDouble:midPoint] inSortedRange:NSMakeRange(0, _lineCount) options:NSBinarySearchingInsertionIndex usingComparator:^(NSNumber *obj1, NSNumber *obj2) { return [obj1 compare:obj2]; }]; CGFloat totalLength = (CGFloat)[_lengths[i] doubleValue]; CGFloat prevLength = i == 0 ? 0 : (CGFloat)[_lengths[i - 1] doubleValue]; CGFloat length = totalLength - prevLength; CGFloat percent = (midPoint - prevLength) / length; NSArray *points = [_lines objectAtIndex:i]; CGPoint p1 = [[points objectAtIndex:0] CGPointValue]; CGPoint p2 = [[points objectAtIndex:1] CGPointValue]; CGFloat ldx = p2.x - p1.x; CGFloat ldy = p2.y - p1.y; *angle = atan2(ldy, ldx); *x = p1.x + ldx * percent; *y = p1.y + ldy * percent; } @end ================================================ FILE: apple/Utils/RNSVGPathParser.h ================================================ /** * 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 "RNSVGUIKit.h" @interface RNSVGPathParser : NSObject - (instancetype)initWithPathString:(NSString *)d; - (CGPathRef)getPath; @end ================================================ FILE: apple/Utils/RNSVGPathParser.mm ================================================ /** * 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 "RNSVGPathParser.h" #import #import #import "RNSVGBezierElement.h" @implementation RNSVGPathParser { char prev_cmd; NSUInteger i; NSUInteger l; NSString *s; float _penX; float _penY; float _penDownX; float _penDownY; float _pivotX; float _pivotY; BOOL _valid; BOOL _penDownSet; } - (instancetype)initWithPathString:(NSString *)d { if (self = [super init]) { prev_cmd = ' '; l = [d length]; i = 0; s = d; } return self; } #define NEXT_FLOAT [self parse_list_number] #define NEXT_BOOL [self parse_flag] - (CGPathRef)getPath { CGMutablePathRef path = CGPathCreateMutable(); while (i < l) { [self skip_spaces]; if (i >= l) { break; } bool has_prev_cmd = prev_cmd != ' '; char first_char = [s characterAtIndex:i]; if (!has_prev_cmd && first_char != 'M' && first_char != 'm') { // The first segment must be a MoveTo. RCTLogError(@"UnexpectedData: %@", s); CGPathRelease(path); return nil; } // TODO: simplify bool is_implicit_move_to = false; char cmd = ' '; if ([self is_cmd:first_char]) { is_implicit_move_to = false; cmd = first_char; i += 1; } else if ([self is_number_start:first_char] && has_prev_cmd) { if (prev_cmd == 'Z' || prev_cmd == 'z') { // ClosePath cannot be followed by a number. RCTLogError(@"UnexpectedData: %@", s); CGPathRelease(path); return nil; } if (prev_cmd == 'M' || prev_cmd == 'm') { // 'If a moveto is followed by multiple pairs of coordinates, // the subsequent pairs are treated as implicit lineto commands.' // So we parse them as LineTo. is_implicit_move_to = true; if ([self is_absolute:prev_cmd]) { cmd = 'L'; } else { cmd = 'l'; } } else { is_implicit_move_to = false; cmd = prev_cmd; } } else { RCTLogError(@"UnexpectedData: %@", s); CGPathRelease(path); return nil; } bool absolute = [self is_absolute:cmd]; switch (cmd) { case 'm': { [self move:path x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'M': { [self moveTo:path x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'l': { [self line:path x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'L': { [self lineTo:path x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'h': { [self line:path x:NEXT_FLOAT y:0]; break; } case 'H': { [self lineTo:path x:NEXT_FLOAT y:_penY]; break; } case 'v': { [self line:path x:0 y:NEXT_FLOAT]; break; } case 'V': { [self lineTo:path x:_penX y:NEXT_FLOAT]; break; } case 'c': { [self curve:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT c2x:NEXT_FLOAT c2y:NEXT_FLOAT ex:NEXT_FLOAT ey:NEXT_FLOAT]; break; } case 'C': { [self curveTo:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT c2x:NEXT_FLOAT c2y:NEXT_FLOAT ex:NEXT_FLOAT ey:NEXT_FLOAT]; break; } case 's': { [self smoothCurve:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT ex:NEXT_FLOAT ey:NEXT_FLOAT]; break; } case 'S': { [self smoothCurveTo:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT ex:NEXT_FLOAT ey:NEXT_FLOAT]; break; } case 'q': { [self quadraticBezierCurve:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT c2x:NEXT_FLOAT c2y:NEXT_FLOAT]; break; } case 'Q': { [self quadraticBezierCurveTo:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT c2x:NEXT_FLOAT c2y:NEXT_FLOAT]; break; } case 't': { [self smoothQuadraticBezierCurve:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT]; break; } case 'T': { [self smoothQuadraticBezierCurveTo:path c1x:NEXT_FLOAT c1y:NEXT_FLOAT]; break; } case 'a': { [self arc:path rx:NEXT_FLOAT ry:NEXT_FLOAT rotation:NEXT_FLOAT outer:NEXT_BOOL clockwise:NEXT_BOOL x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'A': { [self arcTo:path rx:NEXT_FLOAT ry:NEXT_FLOAT rotation:NEXT_FLOAT outer:NEXT_BOOL clockwise:NEXT_BOOL x:NEXT_FLOAT y:NEXT_FLOAT]; break; } case 'z': case 'Z': { [self close:path]; break; } default: { RCTLogError(@"UnexpectedData: %@", s); CGPathRelease(path); return nil; } } if (is_implicit_move_to) { if (absolute) { prev_cmd = 'M'; } else { prev_cmd = 'm'; } } else { prev_cmd = cmd; } } return (CGPathRef)CFAutorelease(path); } - (void)move:(CGMutablePathRef)path x:(float)x y:(float)y { [self moveTo:path x:x + _penX y:y + _penY]; } - (void)moveTo:(CGMutablePathRef)path x:(float)x y:(float)y { // RCTLogInfo(@"move x: %f y: %f", x, y); _penDownX = _pivotX = _penX = x; _penDownY = _pivotY = _penY = y; CGPathMoveToPoint(path, nil, x, y); } - (void)line:(CGMutablePathRef)path x:(float)x y:(float)y { [self lineTo:path x:x + _penX y:y + _penY]; } - (void)lineTo:(CGMutablePathRef)path x:(float)x y:(float)y { // RCTLogInfo(@"line x: %f y: %f", x, y); [self setPenDown]; _pivotX = _penX = x; _pivotY = _penY = y; CGPathAddLineToPoint(path, nil, x, y); } - (void)curve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey { [self curveTo:path c1x:c1x + _penX c1y:c1y + _penY c2x:c2x + _penX c2y:c2y + _penY ex:ex + _penX ey:ey + _penY]; } - (void)curveTo:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey { // RCTLogInfo(@"curve c1x: %f c1y: %f c2x: %f c2y: %f ex: %f ey: %f", c1x, c1y, c2x, c2y, ex, ey); _pivotX = c2x; _pivotY = c2y; [self curveToPoint:path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey]; } - (void)curveToPoint:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey { [self setPenDown]; _penX = ex; _penY = ey; CGPathAddCurveToPoint(path, nil, c1x, c1y, c2x, c2y, ex, ey); } - (void)smoothCurve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y ex:(float)ex ey:(float)ey { [self smoothCurveTo:path c1x:c1x + _penX c1y:c1y + _penY ex:ex + _penX ey:ey + _penY]; } - (void)smoothCurveTo:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y ex:(float)ex ey:(float)ey { // RCTLogInfo(@"smoothcurve c1x: %f c1y: %f ex: %f ey: %f", c1x, c1y, ex, ey); float c2x = c1x; float c2y = c1y; c1x = (_penX * 2) - _pivotX; c1y = (_penY * 2) - _pivotY; _pivotX = c2x; _pivotY = c2y; [self curveToPoint:path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey]; } - (void)quadraticBezierCurve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y { [self quadraticBezierCurveTo:path c1x:(float)c1x + _penX c1y:(float)c1y + _penY c2x:(float)c2x + _penX c2y:(float)c2y + _penY]; } - (void)quadraticBezierCurveTo:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y { // RCTLogInfo(@"quad c1x: %f c1y: %f c2x: %f c2y: %f", c1x, c1y, c2x, c2y); _pivotX = c1x; _pivotY = c1y; float ex = c2x; float ey = c2y; c2x = (ex + c1x * 2) / 3; c2y = (ey + c1y * 2) / 3; c1x = (_penX + c1x * 2) / 3; c1y = (_penY + c1y * 2) / 3; [self curveToPoint:path c1x:(float)c1x c1y:(float)c1y c2x:(float)c2x c2y:(float)c2y ex:(float)ex ey:(float)ey]; } - (void)smoothQuadraticBezierCurve:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y { [self smoothQuadraticBezierCurveTo:path c1x:c1x + _penX c1y:c1y + _penY]; } - (void)smoothQuadraticBezierCurveTo:(CGMutablePathRef)path c1x:(float)c1x c1y:(float)c1y { // RCTLogInfo(@"smoothquad c1x: %f c1y: %f", c1x, c1y); float c2x = c1x; float c2y = c1y; c1x = (_penX * 2) - _pivotX; c1y = (_penY * 2) - _pivotY; [self quadraticBezierCurveTo:path c1x:c1x c1y:c1y c2x:c2x c2y:c2y]; } - (void)arc:(CGMutablePathRef)path rx:(float)rx ry:(float)ry rotation:(float)rotation outer:(BOOL)outer clockwise:(BOOL)clockwise x:(float)x y:(float)y { [self arcTo:path rx:rx ry:ry rotation:rotation outer:outer clockwise:clockwise x:x + _penX y:y + _penY]; } - (void)arcTo:(CGMutablePathRef)path rx:(float)rx ry:(float)ry rotation:(float)rotation outer:(BOOL)outer clockwise:(BOOL)clockwise x:(float)x y:(float)y { // RCTLogInfo(@"arc rx: %f ry: %f rotation: %f outer: %i clockwise: %i x: %f y: %f", rx, ry, rotation, outer, // clockwise, x, y); float tX = _penX; float tY = _penY; ry = fabsf(ry == 0 ? (rx == 0 ? (y - tY) : rx) : ry); rx = fabsf(rx == 0 ? (x - tX) : rx); if (rx == 0 || ry == 0 || (x == tX && y == tY)) { [self lineTo:path x:x y:y]; return; } float rad = rotation * (float)M_PI / 180; float cosed = cosf(rad); float sined = sinf(rad); x -= tX; y -= tY; // Ellipse Center float cx = cosed * x / 2 + sined * y / 2; float cy = -sined * x / 2 + cosed * y / 2; float rxry = rx * rx * ry * ry; float rycx = ry * ry * cx * cx; float rxcy = rx * rx * cy * cy; float a = rxry - rxcy - rycx; if (a < 0) { a = sqrtf(1 - a / rxry); rx *= a; ry *= a; cx = x / 2; cy = y / 2; } else { a = sqrtf(a / (rxcy + rycx)); if (outer == clockwise) { a = -a; } float cxd = -a * cy * rx / ry; float cyd = a * cx * ry / rx; cx = cosed * cxd - sined * cyd + x / 2; cy = sined * cxd + cosed * cyd + y / 2; } // Rotation + Scale Transform float xx = cosed / rx; float yx = sined / rx; float xy = -sined / ry; float yy = cosed / ry; // Start and End Angle float sa = atan2f(xy * -cx + yy * -cy, xx * -cx + yx * -cy); float ea = atan2f(xy * (x - cx) + yy * (y - cy), xx * (x - cx) + yx * (y - cy)); cx += tX; cy += tY; x += tX; y += tY; [self setPenDown]; _penX = _pivotX = x; _penY = _pivotY = y; [self arcToBezier:path cx:cx cy:cy rx:rx ry:ry sa:sa ea:ea clockwise:clockwise rad:rad]; } - (void)arcToBezier:(CGMutablePathRef)path cx:(float)cx cy:(float)cy rx:(float)rx ry:(float)ry sa:(float)sa ea:(float)ea clockwise:(BOOL)clockwise rad:(float)rad { // Inverse Rotation + Scale Transform float cosed = cosf(rad); float sined = sinf(rad); float xx = cosed * rx; float yx = -sined * ry; float xy = sined * rx; float yy = cosed * ry; // Bezier Curve Approximation float arc = ea - sa; if (arc < 0 && clockwise) { arc += M_PI * 2; } else if (arc > 0 && !clockwise) { arc -= M_PI * 2; } int n = (int)ceilf(fabsf(arc / ((float)M_PI / 2))); float step = arc / n; float k = (4.0f / 3.0f) * tanf(step / 4); float x = cosf(sa); float y = sinf(sa); for (int j = 0; (int)j < n; j++) { float cp1x = x - k * y; float cp1y = y + k * x; sa += step; x = cosf(sa); y = sinf(sa); float cp2x = x + k * y; float cp2y = y - k * x; float c1x = cx + xx * cp1x + yx * cp1y; float c1y = cy + xy * cp1x + yy * cp1y; float c2x = cx + xx * cp2x + yx * cp2y; float c2y = cy + xy * cp2x + yy * cp2y; float ex = cx + xx * x + yx * y; float ey = cy + xy * x + yy * y; CGPathAddCurveToPoint(path, nil, c1x, c1y, c2x, c2y, ex, ey); } } - (void)close:(CGMutablePathRef)path { if (_penDownSet) { _penX = _penDownX; _penY = _penDownY; _penDownSet = NO; CGPathCloseSubpath(path); } } - (void)setPenDown { if (!_penDownSet) { _penDownX = _penX; _penDownY = _penY; _penDownSet = YES; } } - (void)skip_spaces { while (i < l && [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:[s characterAtIndex:i]]) i++; } - (bool)is_cmd:(char)c { switch (c) { case 'M': case 'm': case 'Z': case 'z': case 'L': case 'l': case 'H': case 'h': case 'V': case 'v': case 'C': case 'c': case 'S': case 's': case 'Q': case 'q': case 'T': case 't': case 'A': case 'a': return true; } return false; } - (bool)is_number_start:(char)c { return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+'; } - (bool)is_absolute:(char)c { return [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:c]; } // By the SVG spec 'large-arc' and 'sweep' must contain only one char // and can be written without any separators, e.g.: 10 20 30 01 10 20. - (bool)parse_flag { [self skip_spaces]; char c = [s characterAtIndex:i]; switch (c) { case '0': case '1': { i += 1; if (i < l && [s characterAtIndex:i] == ',') { i += 1; } [self skip_spaces]; break; } default: RCTLogError(@"UnexpectedData: %@", s); } return c == '1'; } - (float)parse_list_number { if (i == l) { RCTLogError(@"UnexpectedEnd: %@", s); } float n = [self parse_number]; [self skip_spaces]; [self parse_list_separator]; return n; } - (float)parse_number { // Strip off leading whitespaces. [self skip_spaces]; if (i == l) { RCTLogError(@"InvalidNumber: %@", s); } NSUInteger start = i; char c = [s characterAtIndex:i]; // Consume sign. if (c == '-' || c == '+') { i += 1; c = [s characterAtIndex:i]; } // Consume integer. if (c >= '0' && c <= '9') { [self skip_digits]; if (i < l) { c = [s characterAtIndex:i]; } } else if (c != '.') { RCTLogError(@"InvalidNumber: %@", s); } // Consume fraction. if (c == '.') { i += 1; [self skip_digits]; if (i < l) { c = [s characterAtIndex:i]; } } if ((c == 'e' || c == 'E') && i + 1 < l) { char c2 = [s characterAtIndex:i + 1]; // Check for `em`/`ex`. if (c2 != 'm' && c2 != 'x') { i += 1; c = [s characterAtIndex:i]; if (c == '+' || c == '-') { i += 1; [self skip_digits]; } else if (c >= '0' && c <= '9') { [self skip_digits]; } else { RCTLogError(@"InvalidNumber: %@", s); } } } NSString *num = [s substringWithRange:NSMakeRange(start, i - start)]; float n = [num floatValue]; // inf, nan, etc. are an error. if (!isfinite(n)) { RCTLogError(@"InvalidNumber: %@", s); } return n; } - (void)parse_list_separator { if (i < l && [s characterAtIndex:i] == ',') { i += 1; } } - (void)skip_digits { while (i < l && [[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[s characterAtIndex:i]]) i++; } @end ================================================ FILE: apple/Utils/RNSVGRenderUtils.h ================================================ #import "RNSVGRenderable.h" @interface RNSVGRenderUtils : NSObject + (CIContext *)sharedCIContext; + (CGFloat)getScreenScale; + (CGImage *)renderToImage:(RNSVGRenderable *)renderable ctm:(CGAffineTransform)ctm rect:(CGRect)rect clip:(CGRect *)clip; @end ================================================ FILE: apple/Utils/RNSVGRenderUtils.mm ================================================ #import "RNSVGRenderUtils.h" @implementation RNSVGRenderUtils + (CIContext *)sharedCIContext { static CIContext *sharedCIContext = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedCIContext = [[CIContext alloc] init]; }); return sharedCIContext; } + (CGFloat)getScreenScale { CGFloat scale = 0.0; #if TARGET_OS_OSX scale = [[NSScreen mainScreen] backingScaleFactor]; #else if (@available(iOS 13.0, *)) { scale = [UITraitCollection currentTraitCollection].displayScale; } else { #if !TARGET_OS_VISION scale = [[UIScreen mainScreen] scale]; #endif } #endif // TARGET_OS_OSX return scale; } + (CGImage *)renderToImage:(RNSVGRenderable *)renderable ctm:(CGAffineTransform)ctm rect:(CGRect)rect clip:(CGRect *)clip { CGFloat scale = [self getScreenScale]; #if TARGET_OS_OSX // [macOS RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.0); #else // macOS] RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, scale); #endif // [macOS] CGContextRef cgContext = UIGraphicsGetCurrentContext(); CGContextConcatCTM(cgContext, CGAffineTransformInvert(CGContextGetCTM(cgContext))); #if TARGET_OS_OSX // [macOS CGContextConcatCTM(cgContext, CGAffineTransformMakeScale(scale, scale)); #endif // macOS] CGContextConcatCTM(cgContext, ctm); if (clip) { CGContextClipToRect(cgContext, *clip); } [renderable renderLayerTo:cgContext rect:rect]; CGImageRef contentImage = CGBitmapContextCreateImage(cgContext); RNSVGUIGraphicsEndImageContext(); return contentImage; } @end ================================================ FILE: apple/Utils/RNSVGUnits.h ================================================ /** * 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. */ typedef CF_ENUM(int32_t, RNSVGUnits) { kRNSVGUnitsObjectBoundingBox, kRNSVGUnitsUserSpaceOnUse }; ================================================ FILE: apple/Utils/RNSVGVBMOS.h ================================================ /** * 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. */ typedef CF_ENUM(int32_t, RNSVGVBMOS) { kRNSVGVBMOSMeet, kRNSVGVBMOSSlice, kRNSVGVBMOSNone }; ================================================ FILE: apple/Utils/RNSVGVectorEffect.h ================================================ /** * Copyright (c) 2015-present, react-native-community. * 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. */ typedef CF_ENUM(int32_t, RNSVGVectorEffect) { kRNSVGVectorEffectDefault, kRNSVGVectorEffectNonScalingStroke, kRNSVGVectorEffectInherit, kRNSVGVectorEffectUri }; ================================================ FILE: apple/Utils/RNSVGViewBox.h ================================================ /** * 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 "RNSVGUIKit.h" #import "RNSVGVBMOS.h" @interface RNSVGViewBox : NSObject + (CGAffineTransform)getTransform:(CGRect)vbRect eRect:(CGRect)eRect align:(NSString *)align meetOrSlice:(RNSVGVBMOS)meetOrSlice; @end ================================================ FILE: apple/Utils/RNSVGViewBox.mm ================================================ /** * 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 "RNSVGViewBox.h" #import #import "RNSVGUse.h" @implementation RNSVGViewBox + (CGAffineTransform)getTransform:(CGRect)vbRect eRect:(CGRect)eRect align:(NSString *)align meetOrSlice:(RNSVGVBMOS)meetOrSlice { // based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform // Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute // respectively. CGFloat vbX = CGRectGetMinX(vbRect); CGFloat vbY = CGRectGetMinY(vbRect); CGFloat vbWidth = CGRectGetWidth(vbRect); CGFloat vbHeight = CGRectGetHeight(vbRect); // Let e-x, e-y, e-width, e-height be the position and size of the element respectively. CGFloat eX = CGRectGetMinX(eRect); CGFloat eY = CGRectGetMinY(eRect); CGFloat eWidth = CGRectGetWidth(eRect); CGFloat eHeight = CGRectGetHeight(eRect); // Let align be the align value of preserveAspectRatio, or 'xMidyMid' if preserveAspectRatio is not defined. // Let meetOrSlice be the meetOrSlice value of preserveAspectRatio, or 'meet' if preserveAspectRatio is not defined or // if meetOrSlice is missing from this value. // Initialize scale-x to e-width/vb-width. CGFloat scaleX = eWidth / vbWidth; // Initialize scale-y to e-height/vb-height. CGFloat scaleY = eHeight / vbHeight; // Initialize translate-x to e-x - (vb-x * scale-x). // Initialize translate-y to e-y - (vb-y * scale-y). CGFloat translateX = eX - (vbX * scaleX); CGFloat translateY = eY - (vbY * scaleY); // If align is 'none' if (meetOrSlice == kRNSVGVBMOSNone) { // Let scale be set the smaller value of scale-x and scale-y. // Assign scale-x and scale-y to scale. CGFloat scale = scaleX = scaleY = fmin(scaleX, scaleY); // If scale is greater than 1 if (scale > 1) { // Minus translateX by (eWidth / scale - vbWidth) / 2 // Minus translateY by (eHeight / scale - vbHeight) / 2 translateX -= (eWidth / scale - vbWidth) / 2; translateY -= (eHeight / scale - vbHeight) / 2; } else { translateX -= (eWidth - vbWidth * scale) / 2; translateY -= (eHeight - vbHeight * scale) / 2; } } else { // If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller. // Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the // larger. if (![align isEqualToString:@"none"] && meetOrSlice == kRNSVGVBMOSMeet) { scaleX = scaleY = fmin(scaleX, scaleY); } else if (![align isEqualToString:@"none"] && meetOrSlice == kRNSVGVBMOSSlice) { scaleX = scaleY = fmax(scaleX, scaleY); } translateX = eX - (vbX * scaleX); translateY = eY - (vbY * scaleY); // If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x. if ([align containsString:@"xMid"]) { translateX += (eWidth - vbWidth * scaleX) / 2.0; } // If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x. if ([align containsString:@"xMax"]) { translateX += (eWidth - vbWidth * scaleX); } // If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y. if ([align containsString:@"YMid"]) { translateY += (eHeight - vbHeight * scaleY) / 2.0; } // If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y. if ([align containsString:@"YMax"]) { translateY += (eHeight - vbHeight * scaleY); } } // The transform applied to content contained by the element is given by // translate(translate-x, translate-y) scale(scale-x, scale-y). CGAffineTransform transform = CGAffineTransformMakeTranslation(translateX, translateY); return CGAffineTransformScale(transform, scaleX, scaleY); } @end ================================================ FILE: apple/ViewManagers/RNSVGCircleManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGCircleManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGCircleManager.mm ================================================ /** * 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 "RNSVGCircleManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGCircle.h" @implementation RNSVGCircleManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGCircle new]; } RCT_EXPORT_VIEW_PROPERTY(cx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(cy, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(r, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGClipPathManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGClipPathManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGClipPathManager.mm ================================================ /** * 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 "RNSVGClipPathManager.h" #import "RNSVGClipPath.h" @implementation RNSVGClipPathManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGClipPath new]; } @end ================================================ FILE: apple/ViewManagers/RNSVGDefsManager.h ================================================ /** * 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 "RNSVGNodeManager.h" @interface RNSVGDefsManager : RNSVGNodeManager @end ================================================ FILE: apple/ViewManagers/RNSVGDefsManager.mm ================================================ /** * 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 "RNSVGDefsManager.h" #import "RNSVGDefs.h" @implementation RNSVGDefsManager RCT_EXPORT_MODULE() - (RNSVGDefs *)node { return [RNSVGDefs new]; } - (RNSVGPlatformView *)view { return [self node]; } @end ================================================ FILE: apple/ViewManagers/RNSVGEllipseManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGEllipseManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGEllipseManager.mm ================================================ /** * 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 "RNSVGEllipseManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGEllipse.h" @implementation RNSVGEllipseManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGEllipse new]; } RCT_EXPORT_VIEW_PROPERTY(cx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(cy, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(rx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(ry, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGFeBlendManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeBlendManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeBlendManager.mm ================================================ #import "RNSVGFeBlendManager.h" #import "RNSVGBlendMode.h" #import "RNSVGFeBlend.h" @implementation RNSVGFeBlendManager RCT_EXPORT_MODULE() - (RNSVGFeBlend *)node { return [RNSVGFeBlend new]; } RCT_EXPORT_VIEW_PROPERTY(in1, NSString) RCT_EXPORT_VIEW_PROPERTY(in2, NSString) RCT_EXPORT_VIEW_PROPERTY(mode, RNSVGBlendMode) @end ================================================ FILE: apple/ViewManagers/RNSVGFeColorMatrixManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeColorMatrixManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeColorMatrixManager.mm ================================================ #import "RNSVGFeColorMatrixManager.h" #import "RNSVGColorMatrixType.h" #import "RNSVGFeColorMatrix.h" @implementation RNSVGFeColorMatrixManager RCT_EXPORT_MODULE() - (RNSVGFeColorMatrix *)node { return [RNSVGFeColorMatrix new]; } RCT_EXPORT_VIEW_PROPERTY(in1, NSString) RCT_EXPORT_VIEW_PROPERTY(type, RNSVGColorMatrixType) RCT_EXPORT_VIEW_PROPERTY(values, NSArray) @end ================================================ FILE: apple/ViewManagers/RNSVGFeCompositeManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeCompositeManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeCompositeManager.mm ================================================ #import "RNSVGFeCompositeManager.h" #import "RNSVGCompositeOperator.h" #import "RNSVGFeComposite.h" @implementation RNSVGFeCompositeManager RCT_EXPORT_MODULE() - (RNSVGFeComposite *)node { return [RNSVGFeComposite new]; } RCT_EXPORT_VIEW_PROPERTY(in1, NSString) RCT_EXPORT_VIEW_PROPERTY(in2, NSString) RCT_EXPORT_VIEW_PROPERTY(operator1, RNSVGCompositeOperator) RCT_EXPORT_VIEW_PROPERTY(k1, NSNumber *) RCT_EXPORT_VIEW_PROPERTY(k2, NSNumber *) RCT_EXPORT_VIEW_PROPERTY(k3, NSNumber *) RCT_EXPORT_VIEW_PROPERTY(k4, NSNumber *) @end ================================================ FILE: apple/ViewManagers/RNSVGFeFloodManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeFloodManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeFloodManager.mm ================================================ #import "RNSVGFeFloodManager.h" #import "RNSVGFeFlood.h" @implementation RNSVGFeFloodManager RCT_EXPORT_MODULE() - (RNSVGFeFlood *)node { return [RNSVGFeFlood new]; } RCT_EXPORT_VIEW_PROPERTY(floodColor, RNSVGBrush) RCT_EXPORT_VIEW_PROPERTY(floodOpacity, CGFloat) @end ================================================ FILE: apple/ViewManagers/RNSVGFeGaussianBlurManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeGaussianBlurManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeGaussianBlurManager.mm ================================================ #import "RNSVGFeGaussianBlurManager.h" #import "RNSVGEdgeMode.h" #import "RNSVGFeGaussianBlur.h" @implementation RNSVGFeGaussianBlurManager RCT_EXPORT_MODULE() - (RNSVGFeGaussianBlur *)node { return [RNSVGFeGaussianBlur new]; } RCT_EXPORT_VIEW_PROPERTY(in1, NSString) RCT_EXPORT_VIEW_PROPERTY(stdDeviationX, NSNumber) RCT_EXPORT_VIEW_PROPERTY(stdDeviationY, NSNumber) RCT_EXPORT_VIEW_PROPERTY(edgeMode, RNSVGEdgeMode) @end ================================================ FILE: apple/ViewManagers/RNSVGFeMergeManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeMergeManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeMergeManager.mm ================================================ #import "RNSVGFeMergeManager.h" #import "RNSVGFeMerge.h" @implementation RNSVGFeMergeManager RCT_EXPORT_MODULE() - (RNSVGFeMerge *)node { return [RNSVGFeMerge new]; } RCT_EXPORT_VIEW_PROPERTY(nodes, NSArray) @end ================================================ FILE: apple/ViewManagers/RNSVGFeOffsetManager.h ================================================ #import "RNSVGFilterPrimitiveManager.h" @interface RNSVGFeOffsetManager : RNSVGFilterPrimitiveManager @end ================================================ FILE: apple/ViewManagers/RNSVGFeOffsetManager.mm ================================================ #import "RNSVGFeOffsetManager.h" #import "RNSVGFeOffset.h" @implementation RNSVGFeOffsetManager RCT_EXPORT_MODULE() - (RNSVGFeOffset *)node { return [RNSVGFeOffset new]; } RCT_EXPORT_VIEW_PROPERTY(in1, NSString) RCT_EXPORT_VIEW_PROPERTY(dx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(dy, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGFilterManager.h ================================================ #import "RNSVGNodeManager.h" @interface RNSVGFilterManager : RNSVGNodeManager @end ================================================ FILE: apple/ViewManagers/RNSVGFilterManager.mm ================================================ #import "RNSVGFilterManager.h" #import "RNSVGFilter.h" @implementation RNSVGFilterManager RCT_EXPORT_MODULE() - (RNSVGFilter *)node { return [RNSVGFilter new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGFilter) { view.width = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGFilter) { view.height = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(filterUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(primitiveUnits, RNSVGUnits) @end ================================================ FILE: apple/ViewManagers/RNSVGFilterPrimitiveManager.h ================================================ #import "RNSVGNodeManager.h" @interface RNSVGFilterPrimitiveManager : RNSVGNodeManager @end ================================================ FILE: apple/ViewManagers/RNSVGFilterPrimitiveManager.mm ================================================ #import "RNSVGFilterPrimitiveManager.h" #import "RNSVGFilterPrimitive.h" @implementation RNSVGFilterPrimitiveManager RCT_EXPORT_MODULE() - (RNSVGFilterPrimitive *)node { return [RNSVGFilterPrimitive new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGFilterPrimitive) { view.width = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGFilterPrimitive) { view.height = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(result, NSString) @end ================================================ FILE: apple/ViewManagers/RNSVGForeignObjectManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGForeignObjectManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGForeignObjectManager.mm ================================================ /** * 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 "RNSVGForeignObjectManager.h" #import "RNSVGForeignObject.h" @implementation RNSVGForeignObjectManager RCT_EXPORT_MODULE() - (RNSVGForeignObject *)node { return [RNSVGForeignObject new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGForeignObject) { view.foreignObjectheight = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGForeignObject) { view.foreignObjectwidth = [RCTConvert RNSVGLength:json]; } @end ================================================ FILE: apple/ViewManagers/RNSVGGroupManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGGroupManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGGroupManager.mm ================================================ /** * 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 "RNSVGGroupManager.h" #import "RNSVGCGFCRule.h" #import "RNSVGGroup.h" @implementation RNSVGGroupManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGGroup new]; } RCT_EXPORT_VIEW_PROPERTY(font, NSDictionary) RCT_CUSTOM_VIEW_PROPERTY(fontSize, id, RNSVGGroup) { if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; view.font = @{@"fontSize" : stringValue}; } else { NSNumber *number = (NSNumber *)json; double num = [number doubleValue]; view.font = @{@"fontSize" : [NSNumber numberWithDouble:num]}; } } RCT_CUSTOM_VIEW_PROPERTY(fontWeight, id, RNSVGGroup) { if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; view.font = @{@"fontWeight" : stringValue}; } else { NSNumber *number = (NSNumber *)json; double num = [number doubleValue]; view.font = @{@"fontWeight" : [NSNumber numberWithDouble:num]}; } } @end ================================================ FILE: apple/ViewManagers/RNSVGImageManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGImageManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGImageManager.mm ================================================ /** * 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 "RNSVGImageManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGImage.h" #import "RNSVGVBMOS.h" @implementation RNSVGImageManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { RNSVGImage *svgImage = [RNSVGImage new]; svgImage.bridge = self.bridge; return svgImage; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGImage) { view.imagewidth = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGImage) { view.imageheight = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(src, RCTImageSource) RCT_EXPORT_VIEW_PROPERTY(align, NSString) RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock); @end ================================================ FILE: apple/ViewManagers/RNSVGLineManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGLineManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGLineManager.mm ================================================ /** * 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 "RNSVGLineManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGLine.h" @implementation RNSVGLineManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGLine new]; } RCT_EXPORT_VIEW_PROPERTY(x1, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y1, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(x2, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y2, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGLinearGradientManager.h ================================================ /** * 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 "RNSVGNodeManager.h" @interface RNSVGLinearGradientManager : RNSVGNodeManager @end ================================================ FILE: apple/ViewManagers/RNSVGLinearGradientManager.mm ================================================ /** * 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 "RNSVGLinearGradientManager.h" #import "RNSVGLinearGradient.h" @implementation RNSVGLinearGradientManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGLinearGradient new]; } RCT_EXPORT_VIEW_PROPERTY(x1, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y1, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(x2, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y2, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(gradient, NSArray) RCT_EXPORT_VIEW_PROPERTY(gradientUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(gradientTransform, CGAffineTransform) @end ================================================ FILE: apple/ViewManagers/RNSVGMarkerManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGMarkerManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGMarkerManager.mm ================================================ /** * 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 "RNSVGMarkerManager.h" #import "RNSVGMarker.h" @implementation RNSVGMarkerManager RCT_EXPORT_MODULE() - (RNSVGMarker *)node { return [RNSVGMarker new]; } RCT_EXPORT_VIEW_PROPERTY(refX, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(refY, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(markerHeight, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(markerWidth, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(markerUnits, NSString *) RCT_EXPORT_VIEW_PROPERTY(orient, NSString *) RCT_EXPORT_VIEW_PROPERTY(minX, CGFloat) RCT_EXPORT_VIEW_PROPERTY(minY, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat) RCT_EXPORT_VIEW_PROPERTY(align, NSString) RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) @end ================================================ FILE: apple/ViewManagers/RNSVGMaskManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGMaskManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGMaskManager.mm ================================================ /** * 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 "RNSVGMaskManager.h" #import "RNSVGMask.h" @implementation RNSVGMaskManager RCT_EXPORT_MODULE() - (RNSVGMask *)node { return [RNSVGMask new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGMask) { view.maskheight = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGMask) { view.maskwidth = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(maskUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(maskContentUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(maskType, RNSVGMaskType) @end ================================================ FILE: apple/ViewManagers/RNSVGNodeManager.h ================================================ /** * 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 #import "RNSVGNode.h" @interface RNSVGNodeManager : RCTViewManager - (RNSVGNode *)node; @end ================================================ FILE: apple/ViewManagers/RNSVGNodeManager.mm ================================================ /** * 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 "RNSVGNodeManager.h" #import "RNSVGNode.h" #import @implementation RNSVGNodeManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGNode new]; } - (RNSVGPlatformView *)view { return [self node]; } RCT_EXPORT_VIEW_PROPERTY(name, NSString) RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat) RCT_EXPORT_VIEW_PROPERTY(matrix, CGAffineTransform) RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RNSVGNode) { CATransform3D transform3d = json ? [RCTConvert CATransform3D:json] : defaultView.layer.transform; CGAffineTransform transform = CATransform3DGetAffineTransform(transform3d); view.transforms = transform; } RCT_EXPORT_VIEW_PROPERTY(mask, NSString) RCT_EXPORT_VIEW_PROPERTY(markerStart, NSString) RCT_EXPORT_VIEW_PROPERTY(markerMid, NSString) RCT_EXPORT_VIEW_PROPERTY(markerEnd, NSString) RCT_EXPORT_VIEW_PROPERTY(clipPath, NSString) RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule) RCT_EXPORT_VIEW_PROPERTY(responsible, BOOL) RCT_EXPORT_VIEW_PROPERTY(onSvgLayout, RCTDirectEventBlock) RCT_CUSTOM_SHADOW_PROPERTY(top, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(right, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(start, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(end, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(bottom, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(left, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(width, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(height, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(minWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(maxWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(minHeight, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(maxHeight, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderTopWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderRightWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderBottomWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderLeftWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderStartWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderEndWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(borderWidth, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginTop, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginRight, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginBottom, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginLeft, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginStart, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginEnd, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginVertical, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(marginHorizontal, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(margin, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingTop, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingRight, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingBottom, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingLeft, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingStart, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingEnd, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingVertical, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(paddingHorizontal, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(padding, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flex, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flexGrow, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flexShrink, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flexBasis, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flexDirection, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(flexWrap, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(justifyContent, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(alignItems, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(alignSelf, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(alignContent, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(position, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(aspectRatio, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(overflow, id, RNSVGNode) {} RCT_CUSTOM_SHADOW_PROPERTY(display, id, RNSVGNode) {} RCT_CUSTOM_VIEW_PROPERTY(display, id, RNSVGNode) { view.display = json; } RCT_CUSTOM_SHADOW_PROPERTY(direction, id, RNSVGNode) {} RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTPointerEvents, RNSVGNode) { view.pointerEvents = json ? [RCTConvert RCTPointerEvents:json] : defaultView.pointerEvents; } @end ================================================ FILE: apple/ViewManagers/RNSVGPathManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGPathManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGPathManager.mm ================================================ /** * 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 "RNSVGPathManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGPath.h" @implementation RNSVGPathManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGPath new]; } RCT_EXPORT_VIEW_PROPERTY(d, RNSVGCGPath) @end ================================================ FILE: apple/ViewManagers/RNSVGPatternManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGPatternManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGPatternManager.mm ================================================ /** * 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 "RNSVGPatternManager.h" #import "RNSVGPattern.h" @implementation RNSVGPatternManager RCT_EXPORT_MODULE() - (RNSVGPattern *)node { return [RNSVGPattern new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGPattern) { view.patternheight = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGPattern) { view.patternwidth = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(patternUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(patternContentUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(patternTransform, CGAffineTransform) RCT_EXPORT_VIEW_PROPERTY(minX, CGFloat) RCT_EXPORT_VIEW_PROPERTY(minY, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat) RCT_EXPORT_VIEW_PROPERTY(align, NSString) RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) @end ================================================ FILE: apple/ViewManagers/RNSVGRadialGradientManager.h ================================================ /** * 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 "RNSVGNodeManager.h" @interface RNSVGRadialGradientManager : RNSVGNodeManager @end ================================================ FILE: apple/ViewManagers/RNSVGRadialGradientManager.mm ================================================ /** * 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 "RNSVGRadialGradientManager.h" #import "RNSVGRadialGradient.h" @implementation RNSVGRadialGradientManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGRadialGradient new]; } RCT_EXPORT_VIEW_PROPERTY(fx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(fy, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(cx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(cy, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(rx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(ry, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(gradient, NSArray) RCT_EXPORT_VIEW_PROPERTY(gradientUnits, RNSVGUnits) RCT_EXPORT_VIEW_PROPERTY(gradientTransform, CGAffineTransform) @end ================================================ FILE: apple/ViewManagers/RNSVGRectManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGRectManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGRectManager.mm ================================================ /** * 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 "RNSVGRectManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGRect.h" @implementation RNSVGRectManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGRect new]; } RCT_EXPORT_VIEW_PROPERTY(x, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(y, RNSVGLength *) RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGRect) { view.rectheight = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGRect) { view.rectwidth = [RCTConvert RNSVGLength:json]; } RCT_EXPORT_VIEW_PROPERTY(rx, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(ry, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGRenderableManager.h ================================================ /** * 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 "RNSVGNodeManager.h" #import "RNSVGRenderable.h" @interface RNSVGRenderableManager : RNSVGNodeManager - (RNSVGRenderable *)node; @end ================================================ FILE: apple/ViewManagers/RNSVGRenderableManager.mm ================================================ /** * 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 "RNSVGRenderableManager.h" #import #import #import #import "RNSVGPathMeasure.h" #import "RCTConvert+RNSVG.h" #import "RNSVGCGFCRule.h" @implementation RNSVGRenderableManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGRenderable new]; } RCT_EXPORT_VIEW_PROPERTY(color, UIColor) RCT_EXPORT_VIEW_PROPERTY(fill, RNSVGBrush) RCT_EXPORT_VIEW_PROPERTY(fillOpacity, CGFloat) RCT_EXPORT_VIEW_PROPERTY(fillRule, RNSVGCGFCRule) RCT_EXPORT_VIEW_PROPERTY(stroke, RNSVGBrush) RCT_EXPORT_VIEW_PROPERTY(strokeOpacity, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeWidth, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap) RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin) RCT_EXPORT_VIEW_PROPERTY(strokeDasharray, NSArray) RCT_EXPORT_VIEW_PROPERTY(strokeDashoffset, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vectorEffect, int) RCT_EXPORT_VIEW_PROPERTY(propList, NSArray) RCT_EXPORT_VIEW_PROPERTY(filter, NSString) @end ================================================ FILE: apple/ViewManagers/RNSVGSvgViewManager.h ================================================ /** * 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 @interface RNSVGSvgViewManager : RCTViewManager @end ================================================ FILE: apple/ViewManagers/RNSVGSvgViewManager.mm ================================================ /** * 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 "RNSVGSvgViewManager.h" #import "RNSVGSvgView.h" @implementation RNSVGSvgViewManager RCT_EXPORT_MODULE() - (RNSVGPlatformView *)view { return [RNSVGSvgView new]; } RCT_EXPORT_VIEW_PROPERTY(bbWidth, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(bbHeight, RNSVGLength *) RCT_EXPORT_VIEW_PROPERTY(minX, CGFloat) RCT_EXPORT_VIEW_PROPERTY(minY, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat) RCT_EXPORT_VIEW_PROPERTY(align, NSString) RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) RCT_EXPORT_VIEW_PROPERTY(color, UIColor) RCT_CUSTOM_VIEW_PROPERTY(hitSlop, UIEdgeInsets, RNSVGSvgView) { if ([view respondsToSelector:@selector(setHitTestEdgeInsets:)]) { if (json) { UIEdgeInsets hitSlopInsets = [RCTConvert UIEdgeInsets:json]; [view setHitTestEdgeInsets:UIEdgeInsetsMake( -hitSlopInsets.top, -hitSlopInsets.left, -hitSlopInsets.bottom, -hitSlopInsets.right)]; } else { view.hitTestEdgeInsets = defaultView.hitTestEdgeInsets; } } } @end ================================================ FILE: apple/ViewManagers/RNSVGSymbolManager.h ================================================ /** * 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 "RNSVGGroupManager.h" @interface RNSVGSymbolManager : RNSVGGroupManager @end ================================================ FILE: apple/ViewManagers/RNSVGSymbolManager.mm ================================================ /** * 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 "RNSVGSymbolManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGRenderable.h" #import "RNSVGSymbol.h" #import "RNSVGVBMOS.h" @implementation RNSVGSymbolManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGSymbol new]; } RCT_EXPORT_VIEW_PROPERTY(minX, CGFloat) RCT_EXPORT_VIEW_PROPERTY(minY, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat) RCT_EXPORT_VIEW_PROPERTY(align, NSString) RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS) @end ================================================ FILE: apple/ViewManagers/RNSVGTSpanManager.h ================================================ /** * 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 "RNSVGTextManager.h" @interface RNSVGTSpanManager : RNSVGTextManager @end ================================================ FILE: apple/ViewManagers/RNSVGTSpanManager.mm ================================================ /** * 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 "RNSVGTSpanManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGTSpan.h" @implementation RNSVGTSpanManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGTSpan new]; } RCT_EXPORT_VIEW_PROPERTY(content, NSString) @end ================================================ FILE: apple/ViewManagers/RNSVGTextManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGTextManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGTextManager.mm ================================================ /** * 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 "RNSVGTextManager.h" #import "RCTConvert+RNSVG.h" #import "RNSVGText.h" @implementation RNSVGTextManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGText new]; } RCT_CUSTOM_VIEW_PROPERTY(dx, id, RNSVGText) { view.deltaX = [RCTConvert RNSVGLengthArray:json]; } RCT_CUSTOM_VIEW_PROPERTY(dy, id, RNSVGText) { view.deltaY = [RCTConvert RNSVGLengthArray:json]; } RCT_CUSTOM_VIEW_PROPERTY(x, id, RNSVGText) { view.positionX = [RCTConvert RNSVGLengthArray:json]; } RCT_CUSTOM_VIEW_PROPERTY(y, id, RNSVGText) { view.positionY = [RCTConvert RNSVGLengthArray:json]; } RCT_CUSTOM_VIEW_PROPERTY(rotate, id, RNSVGText) { view.rotate = [RCTConvert RNSVGLengthArray:json]; } RCT_EXPORT_VIEW_PROPERTY(font, NSDictionary) RCT_CUSTOM_VIEW_PROPERTY(inlineSize, id, RNSVGText) { view.inlineSize = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(textLength, id, RNSVGText) { view.textLength = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(baselineShift, id, RNSVGText) { if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; view.baselineShift = stringValue; } else { view.baselineShift = [NSString stringWithFormat:@"%f", [json doubleValue]]; } } RCT_EXPORT_VIEW_PROPERTY(lengthAdjust, NSString) RCT_EXPORT_VIEW_PROPERTY(alignmentBaseline, NSString) RCT_EXPORT_VIEW_PROPERTY(verticalAlign, NSString) // unused on iOS RCT_CUSTOM_VIEW_PROPERTY(fontSize, id, RNSVGText) { if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; view.font = @{@"fontSize" : stringValue}; } else { NSNumber *number = (NSNumber *)json; double num = [number doubleValue]; view.font = @{@"fontSize" : [NSNumber numberWithDouble:num]}; } } RCT_CUSTOM_VIEW_PROPERTY(fontWeight, id, RNSVGText) { if ([json isKindOfClass:[NSString class]]) { NSString *stringValue = (NSString *)json; view.font = @{@"fontWeight" : stringValue}; } else { NSNumber *number = (NSNumber *)json; double num = [number doubleValue]; view.font = @{@"fontWeight" : [NSNumber numberWithDouble:num]}; } } @end ================================================ FILE: apple/ViewManagers/RNSVGTextPathManager.h ================================================ /** * 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 "RNSVGTextManager.h" @interface RNSVGTextPathManager : RNSVGTextManager @end ================================================ FILE: apple/ViewManagers/RNSVGTextPathManager.mm ================================================ /** * 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 "RNSVGTextPathManager.h" #import "RNSVGTextPath.h" @implementation RNSVGTextPathManager RCT_EXPORT_MODULE() - (RNSVGRenderable *)node { return [RNSVGTextPath new]; } RCT_EXPORT_VIEW_PROPERTY(href, NSString) RCT_EXPORT_VIEW_PROPERTY(side, NSString) RCT_EXPORT_VIEW_PROPERTY(method, NSString) RCT_EXPORT_VIEW_PROPERTY(midLine, NSString) RCT_EXPORT_VIEW_PROPERTY(spacing, NSString) RCT_EXPORT_VIEW_PROPERTY(startOffset, RNSVGLength *) @end ================================================ FILE: apple/ViewManagers/RNSVGUseManager.h ================================================ /** * 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 "RNSVGRenderableManager.h" @interface RNSVGUseManager : RNSVGRenderableManager @end ================================================ FILE: apple/ViewManagers/RNSVGUseManager.mm ================================================ /** * 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 "RNSVGUseManager.h" #import "RNSVGUse.h" @implementation RNSVGUseManager RCT_EXPORT_MODULE() - (RNSVGNode *)node { return [RNSVGUse new]; } RCT_EXPORT_VIEW_PROPERTY(href, NSString) RCT_CUSTOM_VIEW_PROPERTY(x, id, RNSVGUse) { view.x = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(y, id, RNSVGUse) { view.y = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(height, id, RNSVGUse) { view.useheight = [RCTConvert RNSVGLength:json]; } RCT_CUSTOM_VIEW_PROPERTY(width, id, RNSVGUse) { view.usewidth = [RCTConvert RNSVGLength:json]; } @end ================================================ FILE: apps/common/.eslintrc.js ================================================ module.exports = { root: true, extends: '@react-native', }; ================================================ FILE: apps/common/.prettierrc.js ================================================ module.exports = { arrowParens: 'avoid', bracketSameLine: true, bracketSpacing: false, singleQuote: true, trailingComma: 'all', }; ================================================ FILE: apps/common/example/ListScreen.tsx ================================================ import React, {useState} from 'react'; import { FlatList, Platform, Pressable, Text, TouchableOpacity, View, } from 'react-native'; import {commonStyles} from './utils/commonStyles'; import {Examples, NavigationProp} from './utils/types'; export type ListScreenProps = { navigation: NavigationProp; examples: Examples; }; export function ListScreen({navigation, examples}: ListScreenProps) { const [wasClicked, setWasClicked] = useState([]); return ( ( { navigation.navigate(name as any); if (!wasClicked.includes(name)) { setTimeout(() => setWasClicked([...wasClicked, name]), 500); } }} wasClicked={wasClicked.includes(name)} /> )} ItemSeparatorComponent={ItemSeparator} /> ); } function ItemSeparator() { return ; } type ItemProps = { title: string; onPress: () => void; icon?: React.ReactNode; wasClicked?: boolean; }; function Item({icon, title, onPress, wasClicked}: ItemProps) { const Button = Platform.OS === 'macos' ? Pressable : TouchableOpacity; return ( ); } ================================================ FILE: apps/common/example/e2e/TestingView.tsx ================================================ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Platform, Text, View} from 'react-native'; import * as RNSVG from 'react-native-svg'; import ViewShot from 'react-native-view-shot'; const address = ['ios', 'web'].includes(Platform.OS) ? 'localhost' : '10.0.2.2'; const wsUri = `ws://${address}:7123`; export const TestingView = () => { const wrapperRef = useRef(null); const [wsClient, setWsClient] = useState(null); const [renderedContent, setRenderedContent] = useState(); const [readyToSnapshot, setReadyToSnapshot] = useState(false); const [resolution, setResolution] = useState({width: 0, height: 0}); // placeholder value, later updated by incoming render requests const [message, setMessage] = useState('⏳ Connecting to Jest server...'); const connect = useCallback(() => { setMessage('⏳ Connecting to Jest server...'); const startTime = Date.now(); const MAX_TIMEOUT = 10000; let client = null; const attemptConnect = () => { client = new WebSocket(wsUri); setWsClient(client); client.onopen = () => { client.send( JSON.stringify({ os: Platform.OS, version: Platform.Version, arch: isFabric() ? 'fabric' : 'paper', connectionTime: new Date(), }), ); setMessage('✅ Connected to Jest server. Waiting for render requests.'); }; client.onerror = (err: any) => { const elapsed = Date.now() - startTime; if (elapsed >= MAX_TIMEOUT) { setMessage(`❌ Failed to connect within ${MAX_TIMEOUT} milliseconds`); return; } console.error( `Error connecting to E2E WebSocket at ${wsUri}: ${ err.message ?? '' }. Retrying...`, ); setMessage(`🚨 Failed to connect: ${err.message ?? ''}. Retrying...`); setTimeout(attemptConnect, 500); }; client.onmessage = ({data: rawMessage}) => { const message = JSON.parse(rawMessage); if (message.type === 'renderRequest') { setMessage(`✅ Rendering tests, please don't close this tab.`); const {width, height} = message; setResolution({width, height}); setRenderedContent( createElementFromObject( message.data.type || 'SvgFromXml', message.data.props, ), ); setReadyToSnapshot(true); } }; client.onclose = event => { if (event.code === 1006 && event.reason) return; setMessage( `✅ Connection closed. You can close this tab safely. (${event.code})`, ); }; }; attemptConnect(); return () => { setWsClient(null); client.close(); }; }, [wsClient]); // Create initial connection when rendering the view useEffect(connect, []); // Whenever new content is rendered, send renderResponse with snapshot view useEffect(() => { if (!readyToSnapshot || !wrapperRef.current) { return; } wrapperRef.current.capture?.().then((value: string) => { wsClient?.send( JSON.stringify({ type: 'renderResponse', data: value, }), ); setReadyToSnapshot(false); }); }, [wrapperRef, readyToSnapshot]); return ( {message} {renderedContent} ); }; function isFabric(): boolean { // @ts-expect-error nativeFabricUIManager is not yet included in the RN types return !!global?.nativeFabricUIManager; } const createElementFromObject = ( element: keyof typeof RNSVG, props: any, ): React.ReactElement => { const children: any[] = []; if (props.children) { if (Array.isArray(props.children)) { props?.children.forEach((child: {type: any; props: any}) => children.push(createElementFromObject(child.type, child?.props)), ); } else if (typeof props.children === 'object') { children.push( createElementFromObject(props.children.type, props.children?.props), ); } else { children.push(props.children); } } return React.createElement(RNSVG[element] as any, {...props, children}); }; ================================================ FILE: apps/common/example/e2e/icon.tsx ================================================ import React from 'react'; import Svg, {Path, Rect} from 'react-native-svg'; export const icon = ( ); ================================================ FILE: apps/common/example/e2e/index.macos.tsx ================================================ import React from 'react'; import {icon} from './icon'; const component = () => ; export {component, icon}; ================================================ FILE: apps/common/example/e2e/index.tsx ================================================ import {icon} from './icon'; import {TestingView as component} from './TestingView'; export {component, icon}; ================================================ FILE: apps/common/example/e2e/index.web.tsx ================================================ import React from 'react'; import {icon} from './icon'; const component = () => ; export {component, icon}; ================================================ FILE: apps/common/example/e2e/index.windows.tsx ================================================ import React from 'react'; import {icon} from './icon'; const component = () => ; export {component, icon}; ================================================ FILE: apps/common/example/examples/Circle.tsx ================================================ import React from 'react'; import {Circle, Svg} from 'react-native-svg'; function CircleExample() { return ( ); } CircleExample.title = 'Circle'; function StrokeCircle() { return ( ); } StrokeCircle.title = 'Stroke Circle'; function StrokeOpacityCircle() { return ( ); } StrokeOpacityCircle.title = 'Circle with strokeOpacity'; function PieCircle() { return ( ); } PieCircle.title = 'Draw a Pie shape with circle'; const icon = ( ); const samples = [CircleExample, StrokeCircle, StrokeOpacityCircle, PieCircle]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Clipping.tsx ================================================ import React from 'react'; import { Circle, ClipPath, Defs, Ellipse, G, Path, Polygon, RadialGradient, Rect, Stop, Svg, Text, } from 'react-native-svg'; function ClipPathElement() { return ( Q ); } ClipPathElement.title = 'Clip by set clip-path with a path data'; function ClipRule() { return ( ); } ClipRule.title = 'Clip a group with clipRule="evenodd"'; function TextClipping() { return ( NOT THE FACE ); } TextClipping.title = 'Transform the text'; const icon = ( ); const samples = [ClipPathElement, ClipRule, TextClipping]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Ellipse.tsx ================================================ import React from 'react'; import {Ellipse, Svg} from 'react-native-svg'; function EllipseExample() { return ( ); } EllipseExample.title = 'Ellipse'; function PileEllipses() { return ( ); } PileEllipses.title = 'The following example creates three ellipses on top of each other'; function CombinedEllipses() { return ( ); } CombinedEllipses.title = 'The following example combines two ellipses (one yellow and one white)'; const icon = ( ); const samples = [EllipseExample, PileEllipses, CombinedEllipses]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Empty.tsx ================================================ import React from 'react'; import {Rect, Svg} from 'react-native-svg'; function EmptyExample() { return ; } EmptyExample.title = ''; const icon = ( ); const samples = [EmptyExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/FilterImage/FilterPicker.tsx ================================================ import React, {useState} from 'react'; import { Dimensions, FlatList, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import {FilterImage, Filters} from 'react-native-svg/filter-image'; const img = require('../../assets/office.jpg'); const normal: Filters = []; const losAngeles: Filters = [ { name: 'feColorMatrix', type: 'matrix', values: [1.8, 0, 0, 0, 0, 0, 1.3, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0], }, ]; const lagos: Filters = [ { name: 'feColorMatrix', type: 'matrix', values: [ 1.4, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.5, 0, 0, 0, 0, 0, 0.9, 0, ], }, ]; const tokyo: Filters = [ {name: 'feColorMatrix', type: 'saturate', values: [1.5]}, { name: 'feColorMatrix', type: 'matrix', values: [ 0.2, 0.2, 0.2, 0, 0, 0.2, 0.2, 0.2, 0, 0, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 1, 0, ], }, ]; const saturated: Filters = [ {name: 'feColorMatrix', type: 'saturate', values: [1.5]}, ]; const boring: Filters = [ { name: 'feColorMatrix', type: 'matrix', values: [ 0.6965, 0.3845, 0.0945, 0, 0, 0.1745, 0.8430000000000001, 0.084, 0, 0, 0.136, 0.267, 0.5655, 0, 0, 0, 0, 0, 1, 0, ], }, ]; const filters = { normal, losAngeles, lagos, tokyo, saturated, boring, } as const; type FilterKeys = | 'normal' | 'losAngeles' | 'lagos' | 'tokyo' | 'saturated' | 'boring'; const filterKeys = Object.keys(filters) as FilterKeys[]; FilterImagePickerExample.title = 'Filter picker'; function FilterImagePickerExample() { const [currentFilter, setCurrentFilter] = useState('normal'); return ( { return ( setCurrentFilter(item)}> {item} ); }} /> ); } const styles = StyleSheet.create({ container: { flex: 1, height: Dimensions.get('window').height - 150, width: '100%', }, image: {flex: 1, width: '100%', height: '100%'}, list: { marginTop: 8, marginHorizontal: 8, }, listElement: {gap: 8}, listElementImage: {width: 70, height: 70}, listElementTitle: { width: 70, textAlign: 'center', marginTop: 2, marginBottom: 8, }, }); const icon = ( ); const samples = [FilterImagePickerExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/FilterImage/LocalImage.tsx ================================================ import React from 'react'; import {View} from 'react-native'; import {FilterImage} from 'react-native-svg/filter-image'; const testImage = require('../../assets/image.jpg'); const FilterImageLocalExampleStyleCSS = () => { return ( ); }; FilterImageLocalExampleStyleCSS.title = 'With style filter CSS'; const FilterImageLocalExampleStyleSVG = () => { return ( ); }; FilterImageLocalExampleStyleSVG.title = 'With style filter SVG'; const FilterImageLocalExamplePropSVG = () => { return ( ); }; FilterImageLocalExamplePropSVG.title = 'With prop filters SVG'; const icon = ( ); const samples = [ FilterImageLocalExampleStyleCSS, FilterImageLocalExampleStyleSVG, FilterImageLocalExamplePropSVG, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/FilterImage/RemoteImage.tsx ================================================ import React from 'react'; import {StyleSheet, View} from 'react-native'; import {FilterImage} from 'react-native-svg/filter-image'; const testSource = { uri: 'https://cdn.pixabay.com/photo/2023/03/17/11/39/mountain-7858482_1280.jpg', }; const FilterImageRemoteExampleCSS = () => { return ( ); }; FilterImageRemoteExampleCSS.title = 'Remote image with CSS filter'; const FilterImageRemoteExample = () => { return ( ); }; FilterImageRemoteExample.title = 'Remote image with prop filters'; const FilterImageFewFiltersExample = () => { return ( ); }; FilterImageFewFiltersExample.title = 'Remote image with filters'; const icon = ( ); const styles = StyleSheet.create({ image: { width: 200, height: 200, }, }); const samples = [ FilterImageRemoteExampleCSS, FilterImageRemoteExample, FilterImageFewFiltersExample, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/FilterImage/index.tsx ================================================ import React from 'react'; import {FilterImage} from 'react-native-svg/filter-image'; import * as FilterPicker from './FilterPicker'; import * as LocalImage from './LocalImage'; import * as RemoteImage from './RemoteImage'; const samples = { LocalImage, RemoteImage, FilterPicker, }; const icon = ( ); export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeBlend.tsx ================================================ import React from 'react'; import { Circle, FeBlend, FeFlood, Filter, G, Image, LinearGradient, Rect, Stop, Svg, Text, } from 'react-native-svg'; W3Blend.title = 'W3 FeBlend example'; function W3Blend() { return ( Normal Multiply Screen Darken Lighten ); } SimpleExample.title = 'MDN example'; function SimpleExample() { return ( ); } MDNExample.title = 'MDN example'; function MDNExample() { return ( ); } const icon = ( ); const samples = [W3Blend, SimpleExample, MDNExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeColorMatrix.tsx ================================================ import React from 'react'; import {Circle, FeColorMatrix, Filter, G, Svg} from 'react-native-svg'; function ReferenceExample() { return ( ); } ReferenceExample.title = 'Reference'; function IdentityExample() { return ( ); } IdentityExample.title = 'Identity matrix'; function RgbToGreenExample() { return ( ); } RgbToGreenExample.title = 'RGB to Green'; function SaturateExample() { return ( ); } SaturateExample.title = 'Saturate'; function HueRotateExample() { return ( ); } HueRotateExample.title = 'Hue Rotate'; function LuminanceToAlphaExample() { return ( ); } LuminanceToAlphaExample.title = 'Luminance to alpha'; const icon = ( ); const samples = [ ReferenceExample, IdentityExample, RgbToGreenExample, SaturateExample, HueRotateExample, LuminanceToAlphaExample, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeComposite.tsx ================================================ import {Image, Text as RNText, View} from 'react-native'; import { Defs, FeComposite, FeFlood, FeMerge, FeMergeNode, Filter, G, Path, Rect, Svg, Text, Use, } from 'react-native-svg'; import React from 'react'; QuickTestExample.title = 'Quick Test Example'; function QuickTestExample() { return ( ); } ReferenceExample.title = 'FeComposite W3 reference'; function ReferenceExample() { return ( opacity 1.0 (with FeFlood) opacity 0.5 (with FeFlood) over in out atop xor arithmetic opacity 1.0 (without FeFlood) opacity 0.5 (without FeFlood) over in out atop xor arithmetic W3 Reference ); } const icon = ( ); const samples = [QuickTestExample, ReferenceExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeDropShadow.tsx ================================================ import React from 'react'; import {Circle, FeDropShadow, Filter, Svg} from 'react-native-svg'; BasicMDN.title = 'Basic MDN example'; function BasicMDN() { return ( ); } const icon = ( ); const samples = [BasicMDN]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeFlood.tsx ================================================ import React from 'react'; import { Circle, FeFlood, FeMerge, FeMergeNode, Filter, G, Line, Rect, Svg, } from 'react-native-svg'; BasicFlood.title = 'Basic MDN example with Use'; function BasicFlood() { return ( ); } TestCase1.title = 'Custom Test Case 1'; function TestCase1() { return ( ); } TestCase2.title = 'Custom Test Case 2'; function TestCase2() { return ( ); } const icon = ( ); const samples = [BasicFlood, TestCase1, TestCase2]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeGaussianBlur.tsx ================================================ import React from 'react'; import {Circle, FeGaussianBlur, Filter, G, Svg} from 'react-native-svg'; function StdDeviation3Example() { return ( ); } StdDeviation3Example.title = 'stdDeviation="3"'; function StdDeviation7Example() { return ( ); } StdDeviation7Example.title = 'stdDeviation="7"'; function StdDeviation150Example() { return ( ); } StdDeviation150Example.title = 'stdDeviation="15 0"'; function StdDeviation025Example() { return ( ); } StdDeviation025Example.title = 'stdDeviation="0 25"'; const icon = ( ); const samples = [ StdDeviation3Example, StdDeviation7Example, StdDeviation150Example, StdDeviation025Example, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeMerge.tsx ================================================ import React from 'react'; import { Svg, FeColorMatrix, Filter, FeMerge, FeMergeNode, Rect, FeOffset, } from 'react-native-svg'; function WithOffsetsExample() { return ( ); } WithOffsetsExample.title = 'Merge with SourceGraphic and offsets'; function WithHueRotateExample() { return ( ); } WithHueRotateExample.title = 'Merge with SourceGraphic and HueRotate'; const icon = ( ); const samples = [WithOffsetsExample, WithHueRotateExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/FeOffset.tsx ================================================ import React from 'react'; import {FeOffset, Filter, Rect, Svg} from 'react-native-svg'; function ReferenceExample() { return ( ); } ReferenceExample.title = 'Offset'; const icon = ( ); const samples = [ReferenceExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/ReanimatedFeColorMatrix.tsx ================================================ import React, {useEffect} from 'react'; import Animated, { AnimatedProps, useAnimatedProps, useSharedValue, withRepeat, withTiming, } from 'react-native-reanimated'; import { Circle, FeColorMatrix, FeColorMatrixProps, Filter, Image, Svg, } from 'react-native-svg'; const AnimatedFeColorMatrix = Animated.createAnimatedComponent( FeColorMatrix as any, ) as React.FunctionComponent>; const ReanimatedHueRotateExample = () => { const hue = useSharedValue(0); useEffect(() => { hue.value = withRepeat(withTiming(360, {duration: 2000}), -1, true); }, []); const animatedProps = useAnimatedProps(() => { return {values: [hue.value]}; }); return ( ); }; ReanimatedHueRotateExample.title = 'Reanimated Hue Rotate'; const icon = ( ); const samples = [ReanimatedHueRotateExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Filters/index.tsx ================================================ import React from 'react'; import Svg, {Circle} from 'react-native-svg'; import * as FeBlend from './FeBlend'; import * as FeColorMatrix from './FeColorMatrix'; import * as FeComposite from './FeComposite'; import * as FeDropShadow from './FeDropShadow'; import * as FeFlood from './FeFlood'; import * as FeGaussianBlur from './FeGaussianBlur'; import * as FeMerge from './FeMerge'; import * as FeOffset from './FeOffset'; import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix'; const samples = { FeBlend, FeColorMatrix, FeComposite, FeDropShadow, FeFlood, FeGaussianBlur, FeMerge, FeOffset, ReanimatedFeColorMatrix, }; const icon = ( ); export {icon, samples}; ================================================ FILE: apps/common/example/examples/ForeignObject.tsx ================================================ import React from 'react'; import {StyleSheet, Text, View} from 'react-native'; import {ForeignObject, Svg} from 'react-native-svg'; function ForeignObjectExample() { return ( Centered Text ); } ForeignObjectExample.title = 'ForeignObject with centered Text'; function ForeignObjectWithView() { return ( ); } ForeignObjectWithView.title = 'ForeignObject with full size View'; function ForeignObjectWithBigView() { return ( ); } ForeignObjectWithBigView.title = 'ForeignObject with big View'; function ForeignObjectWithFlexView() { return ( ); } ForeignObjectWithFlexView.title = 'ForeignObject with flex View'; const styles = StyleSheet.create({ iconContainer: { width: 15, height: 15, backgroundColor: 'red', justifyContent: 'center', alignItems: 'center', }, iconInnerContainer: { width: 7.5, height: 7.5, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center', }, }); const icon = ( ); const samples = [ ForeignObjectExample, ForeignObjectWithView, ForeignObjectWithBigView, ForeignObjectWithFlexView, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/G.tsx ================================================ import React, {useEffect, useState} from 'react'; import {Circle, G, Line, Rect, Svg, Text, Use} from 'react-native-svg'; const GExample = () => { const [fill, setFill] = useState('purple'); useEffect(() => { let mounted = true; const timer = setTimeout(() => { if (mounted) { setFill('#856'); } }, 2000); return () => { mounted = false; clearTimeout(timer); }; }, []); return ( ); }; GExample.title = 'G children props inherit'; function GTransform() { return ( Text grouped with shapes ); } GTransform.title = 'G transform'; const icon = ( ); const samples = [GExample, GTransform]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Gradients.tsx ================================================ import React from 'react'; import {View} from 'react-native'; import { Circle, Defs, Ellipse, LinearGradient, RadialGradient, Rect, Stop, Svg, Text, } from 'react-native-svg'; function LinearGradientHorizontal() { return ( ); } LinearGradientHorizontal.title = 'Define an ellipse with a horizontal linear gradient from yellow to red'; function LinearGradientHorizontalBug() { return ( ); } LinearGradientHorizontalBug.title = 'Define an ellipse with a horizontal linear gradient from transparent yellow to red, buggy on android'; function LinearGradientRotated() { return ( ); } LinearGradientRotated.title = 'Define an ellipse with a rotated linear gradient from yellow to red'; function GradientUnits() { return ( ); } GradientUnits.title = 'Compare gradientUnits="userSpaceOnUse" with default'; function LinearGradientPercent() { return ( x1=0% x2=100% ); } LinearGradientPercent.title = 'Define a linear gradient in percent unit'; function RadialGradientExample() { return ( ); } RadialGradientExample.title = 'Define an ellipse with a radial gradient from yellow to purple'; function RadialGradientPercent() { return ( ); } RadialGradientPercent.title = 'Define a radial gradient in percent unit'; function RadialGradientPart() { return ( ); } RadialGradientPart.title = 'Define another ellipse with a radial gradient from white to blue'; function FillGradientWithOpacity() { return ( ); } FillGradientWithOpacity.title = 'Fill a radial gradient with fillOpacity prop'; function FillGradientInRect() { return ( ); } FillGradientInRect.title = 'Fill a radial gradient inside a rect and stroke it'; const icon = ( ); const samples = [ LinearGradientHorizontal, LinearGradientHorizontalBug, LinearGradientRotated, GradientUnits, LinearGradientPercent, RadialGradientExample, RadialGradientPercent, RadialGradientPart, FillGradientWithOpacity, FillGradientInRect, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Image.tsx ================================================ import React from 'react'; import {Alert, Platform} from 'react-native'; import {Circle, ClipPath, Defs, Image, Rect, Svg, Text} from 'react-native-svg'; function ImageExample() { return ( HOGWARTS ); } ImageExample.title = 'Draw Image with preserveAspectRatio prop'; function ClipImage() { return ( Alert.alert('press on Image')} x="5%" y="5%" width="90%" height="90%" href={require('../assets/image.jpg')} opacity="0.6" clipPath="url(#clip-image)" /> HOGWARTS ); } ClipImage.title = 'Clip Image'; function DataURI() { return ( ); } DataURI.title = 'Data URI'; const icon = ( ); const samples = [ImageExample, ClipImage, DataURI]; export {icon, samples}; const dataUriExample = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxMTEhUTExMWFhQWFhgXGRgXGB0gGBgaIBseGhsbHRoeHSggGh0lGx8aITIhJSorLi4uHR8zODMuNygtLisBCgoKDg0OGxAQGysmICYwLS42Ni0tLTItLy0vLy0tMjA1LS0tLS0tLzUtLTUvLS0tLS0tKy8tLS0tLy0tLzUvLf/AABEIAOkA2AMBIgACEQEDEQH/xAAcAAACAwEBAQEAAAAAAAAAAAAABgQFBwMCAQj/xABLEAACAQIEBAQCBgcECAMJAAABAgMAEQQSITEFBkFREyJhcTKBBxQjQpGhUmJyscHR8CQzU+FDgpKissLT8RVEZEVjc4OTo7PD0v/EABoBAAIDAQEAAAAAAAAAAAAAAAADAgQFAQb/xAAzEQACAgEDAQQKAgICAwAAAAABAgADEQQSITETQVGhBSIyYXGBkcHR8LHhFDMjUhUk8f/aAAwDAQACEQMRAD8A3GiiiiEKKKKIQqBx3iS4aCSdyAqC5J6agfPU7VPrJPpr5lDKOHxG9yGnI7DVI/xsx7WXuahY2FMfpqGusCLKvGfSdC0ly8rC/wB1Rb82Bpr4Bzasq5sPMHtqY2v+BB1X9oae9YXHhh0Gg/rWvcTSQOssTFHU3BH9aishtPzuRyG95mzb6McJkc/KfqfhPFEnUldGXR0PxKfX0PQ7Gp1YzyrzYZ7SoRHiYxZl+646gjqhPzU/K+qcD4zHiUzLoy6Oh+JD2PcHodjV3S6rtPUfhx+5ExLKyvwllRRRV2KhRRRRCFFFFEIUUVyxOIVBdjXCQBkwn2eYKLmk7mnmqKAXlmEYI0UaufZR09Tp6iqnnnncQrljs07/AAJ0H67enYdfxNZTieC4jEFpXZnlJuQ5Hm06G/lPSx006Cs5i+p9k4TzMmx7MdMmOZ+kiDZJJoz0cqNOx0Y39rVqvJ3F2xeCgxDWzOnmsCAWBKsQDqASCQOxr8yRwgggja++hBG4I3BG1j1rXfoX5lAT6jJ5d2gJO99Xj/G7D3bsK7pNtbFcnnxMrDV9odrDE1eiiitGOhRRRRCFFFFEIUUUUQhRULH8RWPTc9qWuOPJionhMjxq43jbKw+Y/MbGqd+uqpODyfdGJWWlbz/9JMeHDQYVhJiDcFxqkXc9mcdth12scVZ2YlmJLEliSbsSdSSTubm96mcxcvy4GTK3mjb4ZAN/Q9jUbD+4/r1pTW9p6w6T1noyqlU/4/n4zlfp2r04013PT+VfJiLXO+w7ntbqfbvVdxTFzQNkeLI5AYZmBNjfWw266XriKW6R+p1dVHtmSYHkicSxmzqb+/8AMGnzgHNudlkiPhYhdCL/ABDS9x99D23Hodazw49fDvnIc28hUkEnY/CMv4t6VInw4vrmRxYgEFWN9iAwBt62rltG7BPBHQzIYU6kk1HnwPfP0fwbnKGQWmtFIN+qH1B6A/rW+dMMGLjf4HVv2WB/dX5Xi4tiUFmIkXs2/wCO/wCN6lYfmeRfiWQfsm4/hTFuuUYYA/CZ76IjuI+U/UlFfnDh/N8hkR4pHEkTCRVc2DW0ZTa91Kkqe2a41Fbtw3mWCbCjFK1kI1U2zK43RuzA/K2u2tWKrw+cjBEqWVFJc1zeZRuwHuRWD8z89g4hjnex6J26bkW9u1qqH586KsrftPYflekHVsfZTM6a0X2mAm88V5mghB8wLdAP5dazTm7n3IuYkGQ/DFfbsWtsPT/M0iScQxOJ1zeGpVmUINTbdcx3I62qPNwMFM6XZwSCBrmFrnKdmYam25BO9gKi9VtwzZ08B+ZxrFRfUGTIacQkaQzSgO7Nmvcg+w6ewt26U28PnYtGUkur5dwbWLEMDdiQQFcbizAXvShGQw0PtrpV5wSQ+DZTeTxmyhdbL5L39Q6lh872Usabp7CTt8JQpuZ2IaeeZZFGJzqLZrgnozJZcwPc6qQf8P1qrw8rKwObK2jKwJBBBuCCOul71cc1qB4ZKhZH8zgG/wAIt7buBf09KpYpAR6+vQdqRqRh8iV9QMPxNv5E+keOcLBi2WPEbK50SXoPRXPbYnbew0OvzRyxypNj2vfwsOps8rC9z1WNfvN+Q69juHB0OHhSGOSRlQWDSsXc+5PTsBYAaCpjWLWALOsvacWMvrRnoqpwXGVLCOSys2in7rHt6N6fherarldi2LuU8RpBHWFFFFTnIVC4vjPCiLddh7/9r1Nqg51OXDh/upIhb0U3Qn2GYE+gNJ1DMtTFeuJJMbhmZ3zZz6uEOQr4kx1AvZV9zub9vz7qeH+lzEZrvDGV7KGB/HMR+VRvpa4Q64hcQASkihSR0YAC3poAfnSAPn/Xz96oaTSU20hm5J6/GMd2DYm5JxjD8TgZQdLaqfiQ9/b1rMJ4WhlaJt1OnqOhqs4JxWTDyrIh2NiL6Feot2P9bU0c1IJY0xCa2sfXKe/sf40sUHTWbM+q3T3GX9FqSp3fWK3MTHyHXW/XtbW3zqUFjZVEIyGaWRYg40CufCync+VMtm1FzJ1GtJxBmzeZrjUj0BN6aOBKZ4YIY4fFkRpCSt1MQJjyEMd5c4JtqLED9nQI2oIjVWdrqGOP3iN3LXMOHV1iWGNY/GSJoyyCONk83jZsl5DdRZnYE2sLm9W2N49Ciu04fEJIxYKoRleMs8cYUNoQURnYhlFyunmpOg4Xh+HYnEeO0igeGkbC5RmIzvmVbZ1BCDIdSGDW7RxzThpAIZY5ZsjERuj5HZdbI5Pb9MWJG4FqomkMcoCRxJ1uMgP5dZxaGPMxhR1iB8iubuF28xvudTb1t0r40YOtesG3kHmzEWB9W2OvvXpyu5On777C3U36U3nM9SiIlYA6Y75WTwspDpoVO/r/ACtVlHzI6YdgLgOwuvQsBbU7kWH5V25p4ZPhY43doUzqGMTP9qAx08gN9BvpptrVHOn2aX2zn+NSKhgCZ5/WWVes1XdCOIsczEljqa6+Df8AyqXDFYfl/wB6+Rs2ayjMx2UddQN+mpA+dK3FjhZ5Euzt4mWnBZ0UCOSTwxctHIdoyLki23mPf1HUU1rlc5JV8OUWBAtZtjYH7w1BtuPzpZxnLMgRWzxPmUkKCwNrdCRbt8WUVw4Fi5SxhK+Iig3Vr5ka1hlNiQ9hYDa17W63amcAK4lypnGFcS44vyojuDEXQvoSDmJNv0WOpt5txpGR1qVhskJyBBG4X/SsyxhBlF0YjzDMRpvc66Za6YWYkAFs0TOFUyWzRSXGSKS975xYXtdcw3uDXrjfD9PDkJACNkkF7Rs5y2BAGnlUFRuHYAWNg7AEdgDmJ3GuIfWJBKLhcqhB6WuTb1JPyAr5yzwY4zECMtliUB5XG4S+w/WY6D5nW1RsTJZcxsDbbsex9v4U28OIweEs2jW8WU9S5HlT/VFh7k1l2WkAtjnoPjEaSo32Fm6CN/GeZsPgoUWwVFGWOJN7D9w7sdz3NJUv0v4i9kgiy9jmLfiGH7qQeMcTkxErSOdSdugHQD0FQCL02j0egG6zljLz2dy9JufLPN0XElaJkKSBblQdNPvK26sDY/uJ1rSOS+JvPhQZdZY2eGQ/pMhtm9My5Xt+tWR/QnwBvClxb6LJaOK/UKTnYel7L8mrUPo9S8Esw+CfEySJ6oMsSsPRhHmHowqOlTs9Q6J7OPODnKgnrGmiiitOKhXLE4dZEaN1DI6lWU7FSLEH3FdaKITLuIcOEd+H4sZ43B+ryt/pFA0Un/GQaEffGo6gZDzfyjLhSXS7w75huv7Q/j/3r9R8X4XFiYmhmQOjdOoI2ZSNVYHUEaist5k4ViMGVSS88DHLHORqL7JMANG6Bxo3Wx0rNep9Mxer2e8fiPTD+q3WYP8A1vTly84kw2RthdD7H+PX51C5v4EIT4qABGNiP0T6DambhnK82DwsTzjK+IzS+GRZkRcoF/1iCCRuOut7S1LrbRvX3SVIKW7TM04lCVOu4JU+4p65W4ymCLeFGrSR4ZzNMFAQMVDRJmuc15MqEm1yRlG5ZY5lw6+LNbcMGB9Gsf41Qa29Dr/X508KLaxmdtyj58f/AJNb4hxCNpTiQViDi2J6xsLSaZWBXxRZJAg1PiWZb3zJ+BYTDxkwLWCss7wxlo0PRwjBox5dWQi2l1K7h75E5fwmMwZmxBVnYMoUWP1eEEoFRDcITlJz2zakgg3amSDmjhsAOHw13toYsPE7nYJ90WvYAb3qmbAmVVSSJIKWwScTIuWIJ8SzrFGoIAZmNkgiW2jMQNNPcta+utN+aHhJV2/teOkH2KZciQr1exJIvr5jYkAgWBJP3ifHsNhWIw2EmklDooOKzrFA+X7MCI/eVFFrKDlAOalmwLvLM+eaQ3ZybfIdgP4VIkuckYHh4/19JpaWu7UKE3eqv78z9QJL5m47isblM7IqqcwSNAMpta2c3Y+ovY9tKrMdFbCwuOsh/wCeu0+E8SCWUrN4QGRJIyuTxjsHJuxW5A8ulzYkVL4lhcvCcKx+IzEE/OShuAo9/wBjE641BWSscDv8TIMMgIt1A3/hV5yjh1vJM2Wy+QBj8ThS1gDvofXbbeqDh0BY7+RFzObgWX5+x1sbAGmfB8ShjijcXSNiUS4J0A88mTWw8uUddbm96dp6tp3meaorwd5lTDzFK9vFbxEJBPlF18p1Ww21vY3029bqBFzrLD5msrHLrmW4cPlHxMga2W/mU+U3Fqp+aZQ0qsHDjJ8emoNiuqixt5qOX+LLCTnLFQDkN9AbaI2hIW+ug0PcbNV9rFWMYtm1ijGXzYqPwpE8RDIySKAHu7MScpKkBolFhc6ZdzYC9MeJxSBLs65SNSSLEEfmP51RJjDOAcylGJtlJNitzclXXS40N+2g3qixvGVAbKxMhASMrcLHl+I32JBIATW2UX3LM4kAZMeSAMmVMUaSYpUX+78diOxUMW/AgafKpvO+OOQLf43Ykeg6fifyqFwWO0wA1yo1rfJf41bYzlmbGriHw4zNhY45PDAu0gdnDBf1gEuB11G9qzRh71+ZjtNgUMw7zEEC1O3JHIr4krNibx4XcdJJx2QdE7v66X3Hzk7gSKq4qdA5J+xiYeXQ/wB446i98o6+1aBwDAYriLtkdooASsuIt5mI0McI2uNi9rL0BNPuvYt2dQ58e4SS1gLubpLkZsW/1DCjJCgCTyJosEVv7lD/AIrLp+qCSdbVomGw6xosaKFRFCqo2CgWAHoBUfg/CocNEsMCBI12A3J6kk6sxOpJ1NTadRQKlx1PeYtmyYUUUU+RhRRRRCFI/wBJXF54lVEglaNhdpUQuqm50YLdl6EEi2u9xTxRULE3qVMkrbTmYrytw2XGYuE+DIsEUqzSSOjKnk8yImYDOTIF20ABvTB9MbWOF9pvlrH/ABrSqyr6aXzPCnZGOn6zAf8ALVS2laqCq/vMsVOXuBMyLiJVsSx7hb/gAa443g3jFBHYE2RAPvMzABbdB6+tc3k+2ct92w9dh+daryTweOF18Vc2LMfiEbjDodFBOwdr27mzW0BJS1ppUEeE2V7L/HKvyTn+f34y7wcWD4akUPkjDgRmUqBndV8viOB8TDNa+mhHa/zmrheGxMTLiEUgjR7DOvZlbcfuNVnNTlpSrCSLSyyCAz4eaM2LRzRgaENmte1gbg6kVB5fwSSS5IwvgxWaUxNIIS+6xrGzEKxOpA2A13FUwmR2hJz1lBm2+rjiKfN/EoL4KCUidMJCPHVZMplcqqAA/ET5b9wDUSbmVPL4PB8Ii3/0iB3PsWA19SprTsbyNgsSS7xCOQ388Nla51JIsVJv1Iqlxf0TTbwYpGHRZVKn5sua/wCAqxRqanUAef8AXEiiVZPaMR8B94iY3i+JlQLIyRxKbrh4EVIVPsBrrc6k61b8ZF+CYU9fHP75al476NeJL9yJ/wBmVdf9rLU3i/K+LPC8NhhDedZSzKHTyi8huWzZdiOvUV21lBTke19jHaw0mnbT/cSMBiyisAqkNobi4y5bWy6A636jRmFEmIaTKWKjKoUKNEUaXt0W9gbWt8rAXMXIeOIAIhT9qZf+TNUheQbaz4pfVYULE/6zZQPexprXDbgsMTAXT3ONvQRUTEkgLa9rKO5Fz+G4+d6u+F8HEoF3N+qKLBRqNWNs2otYW96vYsDh4ARDCCxFvElOd9NrCwRD7CqLhOM+rlo3cIBezkXYjdQq9Tv310t2ZRZVY3HWWbdKQe0cdZcYnCqALxgItlvoGC9FVRmLHew1JvbS1VHHm1jTqAXZSfh2RFIGgZVQ3toS3tXWfjQv9lmLWW80upuDclE2W+g6bbVVTjUtf4rkk7k31J9Tvep33LjaJSuuXG0STwU/av8AsgDtvWp/Qqbz479jC/vnrJeGyMs2mvl/jf8AjWpfQ1iLYzEqdDJBGwH7DsD/APkFV6Bi4H3TQo50gx+8yHzfwmXD42YvHKYJGMkciIzIA3mZGKg5CHLWBsLWt1pm+iyacNLGIpBhMudWkQoBKW8wQNZmVrliQLAg63atEoq2umVbDYCftBriy7TCiiirEVCiiiiEKKKKIQoooohCsb+krErJjmDHyxIBcW6W79cxI/GtexmIEcbO2yqT+HSvzdzTxVn8d2OrkgepJ3/MmqWsJICDvlrSjkt4Sl5aAkx8JJ0eZit9swDGO/fz5a27gvDkw8YVf2pHY+eR7eZ3PUn8hYDQVhHAYicfgkXcTRMfbxF/gK3jjnChiEWJjaMupkF7F0W7ZPYsFB9L1Q1w9ZRniXxwSO8Y/j8xH+kHHy44rgsAQ6tG00rq3lKglVUNsQWB23OXpepX0U8T8TD/AFUqEaAkFQuU9mLDq+bc+orrg+MYeLH4mO6qfFihK6BUjEKCI+iiXOh7GRO9esXCMJxKHErosx8KXsbjysf3f7Paouu6rssY4yP5lZupeaHhMP1ql49zimDkEc0ZGYFkbN5XAIBscuhFxcHXUb0woKzP6aV8+CPpiPX/AAvQ1HRVqXCkRFhPWW0/0mQGwWMuzEKqhtWZiFVRdQLkm2pFWfFIpGHlYI9r2+Jb9tgbX6j86xTBNaeA/wDqID/9xb/wrcOI4gC5+VT9IUpWylRO0EnMzCLnNnUEqwJtpdbD55da6YDjrzIXbRWuFUWuLEi7NbUkjYDT16KMHwL10/Df/P8Ao1d8soDAv7Un/G1WtbTWleVUDnwktKxZ/WMl4ibXU1Q8fkuVVRqPMTb4R/K/7qYsTg9DeqLgWLVpJHB+0LeVT95R0XXe2vfek6OsO2fCP1bgV48eJDiF6++FfQm1hpr1q1x+FCWkUBVY2KjZTa4I/VYbdARbrpVNL270x1ZWxPLOjKxE+YOQCaMnqbfKtG5Gm8HiWGY7SeJh27DOudfxeNR86zbF2IuPiGtNGExjSQq8f96uWRL/AOIhDp/vAVAttZX+U2PR7b6Wrn6QoqHwbiKYmCKeP4ZUVx3Fxex9RsfaplbEjCiiiiEKKKKIQoooohCiiuGNxSxIXbYD8a4SAMmESfpV4+IoRAp877j0/rX/AGawfjuMBZY7iyasfW1h+At+JrQOd8TnLzvrtlHck2AHqfyHtVBgIcQPhwsfm11yk6jfzRE1k9uHc2d3d0+80UxWoHzilwXiQglGKtfLKjBeuVWBI9yK03Ec+L4UuLIKIEKYdGtnkY6l2AJsLhQB2DHqKqnmxINjhIRY7WT/AKVWUfFplK58Dh2JvYMUu3e32Xtt6dxRaVsIJXzHT6wa49x7vPJOfOZZxMuztiFfzPcsCRcA9P1hbS1WnD+ZpBhCkrmVUdMgb443BzpZvvIcpH6th0NadFx2VdDwuA9Pu+/+DRiOaCnx8KwwG+6/9Kmi8MMFfMfmIsKk5QYj4vFIkhjklkVAyra+5JsNBudSNu4rPPpfxKyDBuoa15x51ZD/AKPo6g2+VMvMvBJsdhcLPGww2LhyzRgG8YJscjEAaaIb5dLbUi89Y/EypCuNh8GZGcKVN45bhQSCCcoFgbE9elK06qLFweec8/uflFt0MUkezxnoJou+v2imtR45jzmsugv/AJ1lEz6KTuGQ33Gjg20F7+16f5MXJKfJA2tzeU+EnzuDK3yVfemekKS5U5AHPUxmmcLmIMA8q9rfy7+vtVzy/i0jh1zkhn0SJ3+8TqQAoPzqraXP58gW+uVAcqjsASf6FWPAGIh9nf8A4zVjWFRX6wzzI6YEtgHHEsJOJs+FlmyhUysIyfibdcxXXKL7a/IaXSsJIq7n89vb+dPmPxIjheRkDhcpym1jdgOoPvUfh30hqnxYCF/kg/8A11T0qs4Y1pxnu/uR1qA4DNIP1yJsNnYgsUF++fMBf8QDbpftVBNiFvoRT0/0lRHQcMh/3P8Ap1Gk+kND/wCz4R8k/wCnVyyu5iD2Z+o/MpulbnJcRRWcdSLW6VP5Ux9i0Z/aX+v62q3fnXxBZMFCDZiTZPKF3Y/Z7VBn5nmGUfV41MighVVA2X1IS4BtffYHsarNWxBXb5j8yxpqVpbfu8jNY+iri4R5MCx8rZp4PYm8sfyY+IP22/RrS6/NeF4m/wBniIWCyRtnQ9mF9D3U6qe4av0By1xuPGYaPER6Bh5lO6ONGQ+oNx679as6Swsm1uojtRXtbcOhlpRRRVuV4UUUUQhRRRRCFZ5zxxvxG8FCMoBJ13/r93uavecePCFPDUjOwPy/r/Lrpj3G8W7uIomvLJqxH3F6t+0dh86zNZduPZJ85apTA3tOSg4nEgC5iiOnXM+xI722HzpzxChIrM3hlSgMpFxEpYB5CoNjlUlr7aa6A1y5f4QkcSRjMHAOw3Ft7W3HberLh3BDxK4LsuCF1kK6NO4Jui/oxI2jHW5FhaxqnXX2tioo4H75zrNgEmUGN5iwwiMckuWaFkIbCymVMRHYAqJniskgF7kKouNDYkC74NxDg0isy4mSKWWNoy+IkbxEDW0DSZo9CARa4vfuatZPom4cRYLKvqJST/vXFV2I+iGPXwcXIl1ZfPGj6EFT+iNidRYjpatwVoOgH0lXJkrGYdoXRJyJI5j9lKgsrG2YKQD5WygtoSGCki1stUvM0OVGQHcZQCDrfYa9zpTHwrgWMwkC4b+z4zDodAzNFKmt/KfONDqNVI76CyzgsRLiuIeFJF4aQS5srOGcZBm82UWsTkt3DA3N6ytRotj9ons+EetuRgx+eyIqj7oC/gLVln0sOL4b9qX9y1pGLmAB1Hv0rKvpCxSyMmUSExl/hR2vew0IWwta+p9utVdIS+pDdwz/ABJsMIYk4k6Dp5k/4hp71oZck721IrOsUWtpHLcFTbw21sQeopyTGB/OpIB11BBHoQdb1c9JAnaR7/tJ6TvEUMOBkW47a/17b1a8vC8ZHTxZP+KqqNSFF9CBrcbemvX/ACq95TjujX28V/x0P8as6/8A1fOK0n+z5SXxQZsPKv6hIHt5v4Um4YeX36+1aO2GBBvsdLVnPhFHaM38rEH5Hf1pnoG0bnT5xPpVMqGEkLHfb+v51Kw3DfFkWNLlmNrjoN2PyUGueEiZ2EcaM7nUKv3e7MdlHqSBVtJh1jEJ8NZFaYDxVfyOuSxQEj4CxNwpuVBLC1gNnW61KVKr7Z8vfMrS6Z7GDH2R5zlHgFiYiKJpVnCrlBsHa4KWY6CMlWY6EnUHQ17ggOWSxUyNcS4hv7uMaApGTudAN7jS5UkKtpzCBJG8rFykYYmxyKzZdmkGljcLZCR9258pTzHgInVGllOJCqAkeHTLAlhYANcLf1Z1PcHavMpbxlj9/wB+eB456TcZe4RZ4XLHHKYM32bfCT+lte3QHb8DYbDQ+Q+O/UJvO39mlYLKP8N9lm9tlb0sfu0h8x4VgwXwkjFjZFPmT3sBcnvbL+j1q55Xx4nXw3/vFFiD95dr+42Pyp+pVqwNTX0PXv8AP8cZkaLQ+aX6ifpEGikbkLjZS2CmbYfYMTuoH90T+ko27r+ybvNW6rFsUMsSylTgwooopkjCofE8aIlJ69BXbEzhFuaz3mrjyxq00pso0UdSegHqfyHtVDWavssIvLGNrTdyekXuc+KZAXbzSOSqL1J/kNyf51A5P4QyHxXsZHNyTt7e3QWqLy8wxc31iR1Zz5Vj1AUb5VvbMe9tetaBDhVjHiEWA6liALWub36679hWY4NQ2n2j1ljdu+Erub8cR4OGiOWbElUU9Y1JAZ+19bD5npatE4CiLhoREmSPwkyL+iuUZQfW2/rWLcb42H4hFKDmWMKBp1zEkgdtd+vtY1oXCeZD9XUDyiONUJNr+VRmIuQL+p0UZdywWtfRU9nUMjk9ZWsbLRsx2PSIakliDZVVmY+uVAWttc2sL1hkX0i8SklQfWAgdkBCRR2FyAbZlY9epNW/MfGWxAN1JU3IBdrOehfLlzWGw0UXOmpvT/R1Cn1+KRwMisdxoCVYL+ZUfOrR6RcdZeFwZzL4Mfi3uZMgDX7lgB+XrUbgGPhGImDSKszEIkZ0OUeZiNLEsbab2W9OWP4IwBEYBF79M40tbUgNppqQR60h808utILvGyOLWexFiOuYeW43rDOntGRZn49ZZ3L3S0x+NF7VWY3FBhf+u1LqjiMwCZUW2hkIuWt13AB/GvsfL05ID4l9r+XKPyAvVNdMV9phLHaL3ZkfiV9x+NVTMWP/AHpgxXJjAXaWVx0PiNY6ejUucU4SyQRsHcK02UnMb7PpmPTSrVaAYwZPtwQQRPH/AIajElvEJO58SS5/3qt+C8HRCTHmFzc+ckE9yCTrVHhOFyHFeB48gBjDjzNqSSN7A9OgI9a84jG4nDmPJM3miWQhgDoxIG4vYgdR7E1Z7G649mrZzENdUg3FcRrfCHNc3NKHNkaDEBkYFmAzgbhhpr8rV2k5uxJQoVXMRYMosR62va9UscYGrHU9Se9XPRno6+u7e/GPOVNbra3r2rzmNHK3nTE4cBQ0sJKsctrqMpFiPMBctY3AJvpvUnFnNicG0TEuwzWIe4j8Mk3LMzgAka31uNrLaPyZAxxkJspy573AuFykXF7WsSNRrbvrf66uZMLFnIBxDyAIMhADyEEeSP4hm+F2Y2sDqLc9I1hNW2O8Z+oP4kdG+6hfdx9DPPMWFabw1C5isqWHiDz2uWCiRnVdL/GEF9PN8NMPFsCxXOz4pCRopMYY+l0mVT+NqruKzkz4eJ1kaJ5tmgYqTlbUocuax1IN2sNNRV4+GyiykJ3COIT7lTHcf7RrNZ2XbiXAAczNcRFllKEOgtmIfLcg/euqga9gT7mvELPGwlj0dTceo7VI41F/anytnUjUrIJLH9dt82m3avKnS3T8P+9eu04F+mG/nI/fGYF7Gm4lO6aXy/i48XEGBIIIvlPmjcagg+h1B/zFaVyzxkzKY5bCeMea20i7CRfQ9R0OnYn838L4nJhJfFjNxs630Zf61v0/Gtg4RjFxMceIw72ZdVbqrW1Vx1B2I6jUdDXmbkf0ddzyhmvXcupTPfNMoqv4LxQTobjLIukiX+E+ndTuD19wQCtNWDDI6RZGIq43i0rYlsNiFEbi7R2N0mjv8aGw1GgZN1PcEEofPfBJXmzySfZtZYja6x6C4I/WNzffbtati5i4HHi4sjEq6nPHIvxxONnX9xGxBIOhpUwg8US4TFqBOgAcD4XU/DNHf7rW91IIO1Y+o07UXdsvIPlHqwZdpmcLwXEoqpHhs6nqCuQ9QRrp10IBrjNh8WGtJh5Rk8wJR2Gn62oHyPSmnAYg4SdsPN5stmjP6S9LetMeG4uS1zqDpa342/rrXX9IWKeVBE6KgR1mTObnN946mrfC8Qzgqb7fDf2ufa/7hWh8ewUMiESKMmUa9hqbqx0Fh12FZPHlhLFnzDMyqbasl7Breosau6TVi8HjGIt69ssppgNNu1zXfh+IKkldCQynTowIP5H91UfGJfgHuf3V34XiCwvcafvHX8KuRc2HBc5K3nOmU2kTqV/TTuVJsRuRr0tTMuNidM6uGW2a666d/l/A1ggxLXte1+3epeB4jJGR4cjLqDodjtf3t+I0ohHjm/Ew6NCfDxAPlNgY5QRfw5O2YAFW03BViC1onAsYJ4QwRRc2cZtVcaWOl9ihGmx6dFzGYxpl84UEE2sLWve4HQAnWw0Bva1zfzydihFiXjf4Z1AB6ZlvcemZbf7NutUNdQGQuByP4jam5xHnikahMq5bqLXHSs55nlX6jApNrYo3P/1O9vStF4k6xw6LY2I9h/Ksp5jjEmHhjb72Ia4G/wB/uRWXRyV+P2MeR1+E7YZ1+vAEh82HS2q2aztt9plNu1zvt2ssbwATxGIDJPh1+zzeVGiJJAI1W3xLddiouQDaqLDYQ6FFh+tYcHIgAySxtsV8zEuDcXAIBzL6i34XxW7RSSKYru8UiELZsqOwVrLZ/tIyLqF6jXU1bLOjB6zyP36ESGFYbWHWQ+XuTnlxDLOCkcY8yhhmkY7WZSSo+9fQkFbb0/YHg0SBUWBUVdQqH0t5rWzG1tDcepsDVbgBIsrgspxC3LBhupXySeUnynKAT7iruUlwrRyZToQNCr373sSLbWI6Gk6zVW3vlz/OBO0UJUuFETIcTCs7yR4MpKLiPIM8UiE/EHHliuoJOToDqbFar8HGYZF8aNh4UAIICDMWJSUHOlnABQlVNhqRckCu/G55ZGfwZpEOcpfOrm7BnLKblkUBTddACpGay6VrPJLAPHnBw7BoyZCc4A8mdGUqJULBrMWYfBmJsTTva5Pu8SZLCgSby5EZZ2xBFlAMcIvIBlve6qOpABzC6lSLgUwYnEGIWDMVF7iMoUX2kSJSPmK+YLAkxogJKqgCkLoU30te4OmkeZQNjULmDj0cELoJmz2sY42iXLcaXEiB19rG/Y0r/Y2AMznsiJGIxPj4iSU7LdAS4Zha5AuqhTc+51rjbbt+6ueBYiMX81+mlhfta2UdtNNq6Kf5f517bT1iupVHhPM3OXsZjOcn9fuv+FaH9EvL86q2LdjHA4skfWb9f0UdDudenxUXIPLX16ctIP7LCQZP/eNusY99z2X9oGtb4zxBwyYbDKpxMo8ikeSGMaGVwNkXYD7xsBWJ6W1Af/10GSfKaWhpKjeZFlxsjYuKLCLfELYysf7uKAnXxbb5vupuTroATRTVy7wOPCRZEJZmOeSRvjlkO7se/YbAWA2r5SdNR2NYXOZbZsnMtaouaeBmdVlhIXFQ3aJzsb/FG/eNwLHsbEagVe0U9lDDBkZlXMEAx2GEsalMRCW8jfGrjSSJvXT2+EjQ1nMPMMzyPaZ1CW8oIUj8NT8yd62fm3A/V5fryD7N8qYodvupP7rorH9Gx+5SDzXwZIcQJREskU58wKBssm5sLG4bf3vWOoGntKOMjqPx+/ePzuGRFfivNjyKFklaQC1lawX0uFUZv9a+3euPDuFYvEt4iIbdXbyovbfcewNPY4ZkAkkjCBVtHDlA3HxyKAANNl39qrMBjWwkwOZvBbT9n0/lTP8ANC+pWoB/fDHM72JI3Eyj5p4DNBkZm8SMqAZFFgrdQwvtfQN120OhpMFijHe2oYfge/tW04WcSIwGVkK7MBZwbi1ttvSl3i30cwOpkw7tGw1KZbp3sB8S/In2rlHpEezb18Zxqe9YoxYsFQRb130PWpPDZA2vW+3a1q5PyfjYyVjQSXNmEbaDe1w2UjbauEGAxOGYmSGQKCM10Ngfe1uvfW4rRW6tvZYfWKKkd0u5B2uL9648Gw74jEoEBASSN7/oAMGJProQB1JtXaGXML9N6ZOUgohkAuJPFckC/vqOvly/lUNVYa6yR8J1Bky24vJdCrDKwvvroe+utZPxqf7OG/SY9L/p6269K1zjlxGASSwXYjf5206dfesZ5rF41uR/ff8A9HprWNpF3MB7/wAy0xwCfdLvH4Vpo1dXJmQEAs5WMKfivla6KQL3Lr8OgOtL8sRTEh3VrxunlVgWdQpYuSbHyRgnzjTS5tvZ8uYhpRZ7jLlAAsC7G5VIkFwoGUm+trX0BNo3MXDi2ebXxGPhpZiEyAMJdb6x6lSx3IJ18QVaXdXYa34/uQ4Zdyx4x0rNCkkrFZB4ZHhTao1mUkSHyvc28r+UlTc2qLJLlLtK+IRWChhJ4QWVyWtGj3JFwxBKgCwuCNapuCFV8AqSB5XzRyARqrIfK6kZr2WQ5fbXS4suI4u7St4rCQraFWUiwzMCEW2YufOoJBsQNGGlVDkHb+/eOxxmQ+YHRbymQMQsLKiebKFZWZBqLpora5SWAOlr1DwbPnhw0bDLEFaSNbq2ZLEhAUYq1/Mcp81mZRc3NZxriueK10yhXIANtGBUkXclzaxAbQgLrqAfXKeNKx5lUOXbzqWIDj4iq/oSqRnRlIDAON00shCtef39+8VkFsR3fFBBnRyq76SZFtfqw8gX2ux9KROaMSjYoGJjovnBkJUX6qNxfchtb2OxFXPG+MRqpbMyubjOo84a1xnUaMSotewJGxUEFvHIvKisi4jFi6v5oobWDjo722j7KPi9qdoWWn/nsOAPOK1KGwdmvfFwPe1t/wChX3C4d5nSKIXkkcIo9T1PYAa+gBpm5o5RmVnmgXMrEsUUWK3/AEVHTpYVffRby6Y0ONlUq8gKRKwsUjBszkHYsRYX6D9atmz0vUdMbVPPh75lpoGFu09I04WOPhuESKNS5UhUUfFPOx6erN+CjsKaeVeBHDq0kxD4qazTONh+jGnaNBoB11O5ql5OwX1mX6+4+yXMmEU/o7PPbu/wr+qP1qd6zNHSwBss9puZouR0HSFFFFXZCFFFFEJ4miV1ZGAZWBUg7EEWII7EVnWHw7YaV8IxP2VmhYk3eE3CG/Vk1Q+wP3q0iqTmblxMZ4d5HieMm0kdg+RhZ0uQbBrKb7gqCKp63S/5Fe0dR0k632mI7pLi5/q2GsWUgzSsLpAu9jqM0jdEv6mwqq4vwqWGU4XFZSWUskiAhJkGjEKSSrrcXW5tcEE1rfCOFQ4aJYYECIvQbkncknVmPUnU1E5p4CuMgMZOSRTniktcxyDZrdQdQR1BIquPRiLVtHtePv8AxGi87s90ybgvEThpFhkGZb3Rj1H86eBKGUOjnzaaWIt1HqPSlObDrKHgnTJiIzZ0/RPR1P3kbcN8jqDbhhMfJhlySDMt9HtpY9+3vWYwLHB4YdY7HeOkaOJLKYpPAfLKUbITsjZcoFyNBcb69u9IuNwuNRMuIEjEWuDKDGTf4tXy2vqNAb+tOmExa2z3UgaD2I7adf31y5n4YmKCMHICMHBW1x5StiCb2sdgOwpmlu7J8EDB7yOki67hEfh8hOZiMt/0tbkXFx30sPlVnwTiBixCKtys7CNgdrn4HA7g2+VWuF5LhAzTzSaDyomVQfU2LMfxG9WnD+UoIysyJc5SQWdmI9gSQLi+taF+upZCvJiVrbOZI4h5ULs17i2ttT/X8axXmNwQBaw8U7fOtm4zleLykE6ggaXv1FyPTvWM8yoci/8AxT+Pmqp6O/2DPiI6z2G+BkWLQhlJUgWBXRgCCp82+xa/vXWbFSkx3IZY1RQhFkypaykb2NgW/SNugAEaFh1NulSI1L2VbFiQq3Nhc9yfhFe0uppZd9gHA6zz1dtqnahM8wY9jPmcAgMrMHYZLsSZDZtMpYs2UFQLkdCTKlx4IIJGkYUqwVVaxFs5sDmLRISbkZjYhbkVX4iPVlFgpIa+bMGXuDYKVtbzGw0G2gaqnne5GYltANx6eXY9fW4tfsPOtWjtlRgTbDMFw3WWGNOZVtmKg3K5mIsddbWCr4fl8oJujjQAVInxMrXuQLlSdBfTq2lixIB2tcA2B1qtwoIUqTbOCwD2I8pFtG00GYXt0YbE2d+VuTJMUqSuGiwp1F753F9owdwRY5zprp2D6TQmTaOBE3dqcdmZE5L5X+tSePMCYI21zEkzOALICdbCwzegA66ah4cuIxAw+HCeIFDyyOCUgQ6KMoIzObHKlxoCTUXEXi8PD4eMGVhkw8C/CoG7seiDdnO/ua0DlbgK4OHw755GJeWQjWSQ/E3oNgB0AAqkCdbZvYYQdBGgdiu0Hnvif54J/q+JADsT4MiiyTrvYanLIB8SX9RcV64ij4qVMCrH7QZp2BN0w4NmAPRnPkHpmPSnri3C4sTEYpkDodbHcEbMpGqsDqGFiKr+WeW0wfikSPK8rAmSSxfKosiXAFwuvuWJ61z/AMaouDj2fD3zvbHbiXMMSooVQFVQFAGwAFgAOwFe6KK04mFFFFEIUUUUQhRRRRCFFFFEJRc0crxYwK1zFOl/DmQDMvdSDo6Hqp+VjrSJj4psLpjIsqj/AMxGC0DDux+KH2cW/WNaxQRVXUaSu8et18R1jEsZOkyWLg8bgSQtlvrmiIKN6kbH3FeDh8TEbhRKoN/IbN/st69iaesfyVhHYvGrYeQ6l8O2S57sn925/aU1T4nl3Hxao8WKTs32UtvcXjc/JBWe+huQcesPP9+caLVPulPw3jUeazAqwHwvdTptoR+dTIeIF/PcXGnyOpt0tpt71U43FrmEWJjaF2PlTEKACf1JLlG/1WNcMTwhovNBdtNUbUH9m/z3vVIkBtrAqffGY4yOYw8XTNHntbTWx0vbtWSc2xgYdD18Y/ub/KtHwvFBMhLAAgWy9V9KRedU/sMbf+oPv9+rOkUpYmf+w+8g7ZVvgYrYQAkC6j1YgD19evQE+9N0WFgXDmMWbxFBZiLlx91hqcqDQgddNTe5S8NC8jpHGheRjlVQLkn0Ht19zWlcv/R4iDNjpDNJbWJWtGosBZnGrEAWstgNRcit30zZgKGfA8O/P3+0o6BQMnbz4xQfCePI6QlnIJfIguXOYEAZMttiMxBsHsLWpki5OxExR51iw+Vr2azuVykZciGwF2a1yLC3a1NmGx0YPg4KJpSuhiwiDIp/Xk0RT+216t8PyzjpTd2iwiHon2stvc2jQ/J6x1N1n+tePE8S+xUdTF7B8tYLDASOolZdfFxGXKhAAuqfCuwOt9as8LisRiz/AGOMuDviZbrAvqv3pvQIMv6wpo4fyRhI2DyK2IlGofENnIPdUPkQ/sqKZAKsJoSxzc2fcOkUbf8AqJR8tctR4QM+Yy4iS3iTPbM3ZQBoiDog09zrV5RRWgAAMCJhRRRXYQoooohCiiiiEKKKKIQoooohCiiiiEKKKKIQoooohOOLwqSoUkRXRhYq4BUj1B0NJnFeUpMODJgCWQanCu11I6+C7G8bdkJynby7080Uu2pLV2uMidDEdJivF8MJojisNcML50sQ1xoysp1V1O4P/dd5lRn4XhsqlnfEWVRuWJkAFupJrVOcOG/V5RjIxaOQqmJUbXNljm9wbIx6gqfu1CjcApZV+z+Dyjy6EaaaGxOvrXn7WbR2qpGQCCPh4SyB2imL/AODRcLgMkpzYlwFdlGZrt8MEQ3JJ0NtWPoBZr4XyjJiQJMfdUOq4RGsoHTxnGsjd1Byj9avHJPDvrMxx8gvHGWjwoO2nlkn92N1U9FBP3qfa1NPQ1h7e/lj5RLMFG1ek44TCpEgSNFRFFgqABQPQDQV2oorQi4UUUUQhRRRRCFFFFEIUUUUQhRRRRCFFFFEIUUUUQhRRRRCFFFFEIUUUUQhRRRRCcMbhUljeKQZkdSjDuCLEfhWPSQYo4j/AML831g+Uy20+r9cTfa+Ty2/xNOlbRVf/wCa/wDkf89Iu06W43DpJq5XOJJwOESGNIo1ypGqooHRQLAfhXeiinyEKKKKIQoooohCiiiiEKKKKIQoooohCiiiiE//2Q=='; ================================================ FILE: apps/common/example/examples/Line.tsx ================================================ import React from 'react'; import {Line, Svg} from 'react-native-svg'; function LineExample() { return ( ); } LineExample.title = 'Line'; function LineWithStrokeLinecap() { return ( ); } LineWithStrokeLinecap.title = 'Line'; const icon = ( ); const samples = [LineExample, LineWithStrokeLinecap]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Markers.tsx ================================================ import React from 'react'; import { Circle, Defs, Ellipse, Line, Marker, Path, Polygon, Rect, Svg, } from 'react-native-svg'; function EllipseExample() { return ( ); } EllipseExample.title = 'Circle shaped marker on ellipse'; function LineExample() { return ( ); } LineExample.title = 'Triangle shaped marker on line'; function CircleExample() { return ( ); } CircleExample.title = 'Rect shaped marker on circle'; function RectExample() { return ( ); } RectExample.title = 'Ellipse shaped marker on rect'; function PathExample() { return ( ); } PathExample.title = 'Path shaped marker on line'; const icon = ( ); const samples = [ EllipseExample, LineExample, CircleExample, RectExample, PathExample, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Mask.tsx ================================================ import React from 'react'; import {StyleSheet, View} from 'react-native'; import { Circle, Defs, LinearGradient, Mask, Path, Polygon, Rect, Stop, Svg, Text, } from 'react-native-svg'; const styles = StyleSheet.create({ container: { flex: 1, height: 100, width: 200, }, }); function SimpleMask() { return ( ); } SimpleMask.title = 'Simple svg with mask'; function AnotherMask() { return ( ); } AnotherMask.title = 'Another svg with mask'; function MaskWithText() { return ( {'This text is under the rectangle'} ); } MaskWithText.title = 'Svg with with text and a mask with gradient'; const icon = ( ); const samples = [SimpleMask, AnotherMask, MaskWithText]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/PanResponder.tsx ================================================ import React, {useRef} from 'react'; import { Animated, PanResponder, TouchableWithoutFeedback, View, } from 'react-native'; import {G, Line, Path, Polyline, Svg, Text} from 'react-native-svg'; const AnimatedSvg = Animated.createAnimatedComponent(Svg); const zeroDelta = {x: 0, y: 0}; const PanExample = () => { const xy = useRef(new Animated.ValueXY()).current; let offset = zeroDelta; xy.addListener(flatOffset => { offset = flatOffset; }); const panResponder = useRef( PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponderCapture: () => true, onPanResponderGrant: () => { xy.setOffset(offset); xy.setValue(zeroDelta); }, onPanResponderMove: Animated.event([null, {dx: xy.x, dy: xy.y}], { useNativeDriver: false, }), onPanResponderRelease: () => { xy.flattenOffset(); }, }), ).current; const panStyle = { transform: xy.getTranslateTransform(), }; return ( STAR ); }; PanExample.title = 'Bind PanResponder on the SVG Shape'; const icon = ( ); const shouldBeRenderInView = true; const samples = [PanExample]; export {icon, samples, shouldBeRenderInView}; ================================================ FILE: apps/common/example/examples/Path.tsx ================================================ import React from 'react'; import {Circle, G, Path, Svg, Text} from 'react-native-svg'; function PathExample() { return ( ); } PathExample.title = 'Path'; function UnclosedPath() { return ( ); } UnclosedPath.title = 'Unclosed paths'; function BezierCurve() { return ( A B C ); } BezierCurve.title = 'The following example creates a quadratic Bézier curve, where A and C are the start and end points, B is the control point'; const icon = ( ); const samples = [PathExample, UnclosedPath, BezierCurve]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Polygon.tsx ================================================ import React from 'react'; import {G, Path, Polygon, Svg} from 'react-native-svg'; function PolygonExample() { return ( ); } PolygonExample.title = 'The following example creates a polygon with three sides'; function FourSidePolygon() { return ( ); } FourSidePolygon.title = 'The following example creates a polygon with four sides'; function StarPolygon() { return ( ); } StarPolygon.title = 'Use the element to create a star'; function EvenOddPolygon() { return ( ); } EvenOddPolygon.title = 'Change the fill-rule property to "evenodd"'; const icon = ( ); const samples = [PolygonExample, FourSidePolygon, StarPolygon, EvenOddPolygon]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Polyline.tsx ================================================ import React from 'react'; import {Polyline, Svg} from 'react-native-svg'; function PolylineExample() { return ( ); } PolylineExample.title = 'The element is used to create any shape that consists of only straight lines'; function StraightLines() { return ( ); } StraightLines.title = 'Another example with only straight lines'; function PolylineFill() { return ( ); } PolylineFill.title = 'Fill Polyline'; function PolylineFillStroke() { return ( ); } PolylineFillStroke.title = 'Stroke Polyline with strokeLinecap and strokeLinejoin'; const icon = ( ); const samples = [ PolylineExample, StraightLines, PolylineFill, PolylineFillStroke, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Reanimated.tsx ================================================ import React, {useEffect} from 'react'; import {StyleSheet, Text} from 'react-native'; import Reanimated, { useAnimatedProps, useSharedValue, withClamp, withRepeat, withSpring, withTiming, } from 'react-native-reanimated'; import {Rect, Svg} from 'react-native-svg'; // @ts-ignore broken reanimated types const ReanimatedRect = Reanimated.createAnimatedComponent(Rect); function ReanimatedRectExample() { const height = useSharedValue(10); const position = useSharedValue(0); useEffect(() => { height.value = withClamp({min: 0}, withRepeat(withSpring(100), -1, true)); position.value = withRepeat(withTiming(300, {duration: 5000}), -1); }); const animatedProps = useAnimatedProps(() => ({ width: 30, height: height.value, x: position.value, y: 20, })); return ( {/* @ts-ignore broken reanimated types */} ); } ReanimatedRectExample.title = 'reanimated rectangle'; const title = 'Reanimated'; const samples = [ReanimatedRectExample]; const style = StyleSheet.create({text: {width: 30, height: 30}}); const icon = R; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Reanimated.windows.tsx ================================================ import React from 'react'; import {StyleSheet, Text} from 'react-native'; function ReanimatedRectExample() { return ( Reanimated not supported in react-native-windows new arch currently ); } ReanimatedRectExample.title = 'reanimated rectangle'; const title = 'Reanimated'; const samples = [ReanimatedRectExample]; const style = StyleSheet.create({text: {width: 30, height: 30}}); const icon = R; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Rect.tsx ================================================ import React from 'react'; import {ScrollView} from 'react-native'; import {Rect, Svg} from 'react-native-svg'; function RectExample() { return ( ); } RectExample.title = 'Rect'; function RectStrokeFill() { return ( ); } RectStrokeFill.title = '`stroke` and `fill` Rect'; function RoundedRect() { return ( ); } RoundedRect.title = 'A rectangle with rounded corners'; function EllipseRect() { return ( ); } EllipseRect.title = 'Rect with different `rx` and `ry`'; function RoundOverflowRect() { return ( ); } RoundOverflowRect.title = 'Rect with `rx` or `ry` overflowed'; const icon = ( ); const samples = [ RectExample, RectStrokeFill, RoundedRect, EllipseRect, RoundOverflowRect, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Reusable.tsx ================================================ import React from 'react'; import { Circle, ClipPath, Defs, G, LinearGradient, Path, RadialGradient, Rect, Stop, Svg, Symbol, Use, } from 'react-native-svg'; function UseExample() { return ( ); } UseExample.title = 'Reuse svg code'; function UseShapes() { return ( ); } UseShapes.title = 'Using Shapes Outside of a Defs Element'; function DefsExample() { return ( ); } DefsExample.title = 'Basic Defs usage'; function SymbolExample() { return ( ); } SymbolExample.title = 'Symbol example, reuse elements with viewBox prop'; const icon = ( ); const samples = [UseExample, UseShapes, DefsExample, SymbolExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Stroking.tsx ================================================ import React from 'react'; import { Circle, ClipPath, Defs, G, Path, Polyline, RadialGradient, Rect, Stop, Svg, Text, } from 'react-native-svg'; function StrokeExample() { return ( ); } StrokeExample.title = 'The stroke property defines the color of a line, text or outline of an element'; function StrokeLinecap() { return ( ); } StrokeLinecap.title = 'The strokeLinecap property defines different types of endings to an open path'; function StrokeDasharray() { return ( ); } StrokeDasharray.title = 'strokeDasharray'; function StrokeDashoffset() { return ( STROKE ); } StrokeDashoffset.title = 'the strokeDashoffset attribute specifies the distance into the dash pattern to start the dash.'; function StrokePattern() { return ( ); } StrokePattern.title = 'Advanced stroke example.'; const icon = ( ); const samples = [ StrokeExample, StrokeLinecap, StrokeDasharray, StrokeDashoffset, StrokePattern, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Svg.tsx ================================================ import React, {useRef, useState} from 'react'; import {Image, StyleSheet, View} from 'react-native'; import {Circle, G, Line, Path, Rect, Svg} from 'react-native-svg'; const styles = StyleSheet.create({ container: { flex: 1, height: 100, width: 200, }, svg: { flex: 1, alignSelf: 'stretch', }, }); function SvgExample() { return ( ); } SvgExample.title = 'SVG'; function SvgOpacity() { return ( ); } SvgOpacity.title = 'SVG with `opacity` prop'; function SvgViewbox() { return ( ); } SvgViewbox.title = 'SVG with `viewBox="40 20 100 40" and preserveAspectRatio="none"'; function SvgLayout() { return ( ); } SvgLayout.title = 'SVG with flex layout'; function SvgNativeMethods() { const [base64, setBase64] = useState(''); const rootRef = useRef(null); const circleRef = useRef(null); const alert = () => { console.log('PRESSED'); rootRef.current?.toDataURL(data => { setBase64(data); }); console.log(circleRef.current?.isPointInFill({x: 200, y: 100})); console.log(circleRef.current?.isPointInStroke({x: 200, y: 100})); console.log(circleRef.current?.getTotalLength()); console.log(circleRef.current?.getPointAtLength(25)); console.log(circleRef.current?.getBBox({fill: true})); console.log(circleRef.current?.getCTM()); console.log(circleRef.current?.getScreenCTM()); }; return ( <> {base64 && ( )} ); } SvgNativeMethods.title = 'Tap the shapes to render the Image below based on the base64-data of the Svg'; const icon = ( ); const samples = [ SvgExample, SvgOpacity, SvgViewbox, SvgLayout, SvgNativeMethods, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Text.tsx ================================================ import React from 'react'; import {Text as RNText, ScrollView} from 'react-native'; import { Defs, G, LinearGradient, Path, Stop, Svg, Text, TextPath, TSpan, } from 'react-native-svg'; function TextExample() { return ( Text I love SVG! ); } TextExample.title = 'Text'; function TextRotate() { return ( I love SVG I love SVG I love SVG ); } TextRotate.title = 'Transform the text'; function TextStroke() { return ( {['STROKE TEXT']} ); } TextStroke.title = 'Stroke the text'; function TextFill() { return ( FILL TEXT ); } TextFill.title = 'Fill the text with LinearGradient'; const path = ` M 10 20 C 40 10 60 0 80 10 C 100 20 120 30 140 20 C 160 10 180 10 180 10 `; function TextPathExample() { return ( We go up and down, then up again ); } TextPathExample.title = 'Draw text along path'; function TSpanExample() { return ( tspan line 1 tspan line 2 tspan line 3 12345 6 7 89a delta on text ); } TSpanExample.title = 'TSpan nest'; const icon = ( ); const samples = [ TextExample, TextRotate, TextStroke, TextFill, TextPathExample, TSpanExample, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Text.windows.tsx ================================================ import React from 'react'; import { Defs, G, LinearGradient, Path, Stop, Svg, Text, TSpan, } from 'react-native-svg'; function TextExample() { return ( I love SVG! ); } TextExample.title = 'Text'; function TextRotate() { return ( I love SVG I love SVG I love SVG ); } TextRotate.title = 'Transform the text'; function TextStroke() { return ( {['STROKE TEXT']} ); } TextStroke.title = 'Stroke the text'; function TextFill() { return ( FILL TEXT ); } TextFill.title = 'Fill the text with LinearGradient'; const path = ` M 10 20 C 40 10 60 0 80 10 C 100 20 120 30 140 20 C 160 10 180 10 180 10 `; function TextPathExample() { return ( TextPath not implemented ); } function TSpanExample() { return ( tspan line 1 tspan line 2 tspan line 3 12345 6 7 89a delta on text ); } TSpanExample.title = 'TSpan nest'; const icon = ( ); const samples = [ TextExample, TextRotate, TextStroke, TextFill, TextPathExample, TSpanExample, ]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/TouchEvents.tsx ================================================ import React, {useState} from 'react'; import {Alert} from 'react-native'; import { Circle, ClipPath, Defs, G, Path, Rect, Svg, Text, } from 'react-native-svg'; function PressExample() { return ( Alert.alert('Press on Circle')} /> Alert.alert('Long press on Rect')} /> ); } PressExample.title = 'Press on the red circle or long press on the blue rectangle to trigger the events'; function HoverExample() { const [hover, setHover] = useState(false); const toggle = () => { setHover(!hover); }; return ( ); } HoverExample.title = 'Hover the svg path'; function GroupExample() { return ( Alert.alert('Pressed on G')} scale="1.4"> Alert.alert('Pressed on Text')}> H ); } GroupExample.title = 'Bind touch events callback on Group element with viewBox'; const icon = ( ); const samples = [PressExample, HoverExample, GroupExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/Transforms.tsx ================================================ import React from 'react'; import {Platform} from 'react-native'; import { Circle, Defs, G, Pattern, RadialGradient, Rect, Stop, Svg, SvgXml, } from 'react-native-svg'; const patternXml = ` `; function PatternTransformExample() { return ( <> {Platform.OS !== 'web' && ( )} ); } PatternTransformExample.title = 'Pattern transform'; function GradientTransformExample() { return ( ); } GradientTransformExample.title = 'Gradient transform'; const icon = ( ); const samples = [PatternTransformExample, GradientTransformExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/complex/PolygonBunny.tsx ================================================ import React from 'react'; import {Polygon, Svg} from 'react-native-svg'; // Example copied from https://github.com/mikolalysenko/svg-3d-simplicial-complex/tree/03ec401fec67d4f9323f52896cb609c22be7ffa6 export default () => { return ( ); }; ================================================ FILE: apps/common/example/examples/complex/WorldMap.tsx ================================================ import React from 'react'; import {Svg, Rect, G, Path, Circle, Text} from 'react-native-svg'; // Example copied from hhttps://github.com/raphaellepuschitz/SVG-World-Map/tree/c7d20284d66a62f3f549c48eab611bb3ca10ae09 export default () => { return ( Andorra United Arab Emirates Afghanistan Antigua and Barbuda Anguilla Albania Armenia Angola Antarctica Argentina American Samoa Austria Australia Aruba Azerbaijan Bosnia and Herzegovina Barbados Bangladesh Belgium Burkina Faso Bulgaria Bahrain Burundi Benin Saint Barthélemy Bermuda Brunei Bolivia Bonaire, Sint Eustatius and Saba Brazil Bahamas Bhutan Botswana Belarus Belize Canada Congo (Dem. Rep.) Central African Republic Congo Switzerland Côte d'Ivoire Cook Islands Chile Cameroon China Colombia Costa Rica Cuba Cabo Verde Curaçao Cyprus Czechia Germany Djibouti Denmark Dominica Dominican Republic Algeria Ecuador Estonia Egypt Western Sahara Eritrea Spain Ethiopia Finland Fiji Falkland Islands Micronesia Faroe Islands France Gabon United Kingdom Grenada Georgia French Guiana Guernsey Ghana Gibraltar Greenland Gambia Guinea Guadeloupe Equatorial Guinea Greece South Georgia and the South Sandwich Islands Guatemala Guam Guinea-Bissau Guyana Honduras Croatia Haiti Hungary Indonesia Ireland Israel Isle of Man India Iraq Iran Iceland Italy Jersey Jamaica Jordan Japan Kenya Kyrgyzstan Cambodia Kiribati Comoros Saint Kitts and Nevis North Korea South Korea Kuwait Cayman Islands Kazakhstan Laos Lebanon Saint Lucia Liechtenstein Sri Lanka Liberia Lesotho Lithuania Luxembourg Latvia Libya Morocco Monaco Moldova Montenegro Saint Martin (French part) Madagascar Marshall Islands North Macedonia Mali Myanmar Mongolia Northern Mariana Islands Martinique Mauritania Montserrat Malta Mauritius Maldives Malawi Mexico Malaysia Mozambique Namibia New Caledonia Niger Norfolk Island Nigeria Nicaragua Netherlands Norway Nepal Nauru Niue New Zealand Oman Panama Peru French Polynesia Papua New Guinea Philippines Pakistan Poland Saint Pierre and Miquelon Pitcairn Islands Puerto Rico Palestine Portugal Palau Paraguay Qatar Réunion Romania Serbia Russia Rwanda Saudi Arabia Solomon Islands Seychelles Sudan Sweden Singapore Saint Helena, Ascension and Tristan da Cunha Slovenia Slovakia Sierra Leone San Marino Senegal Somalia Suriname South Sudan São Tomé and Principe El Salvador Sint Maarten (Dutch part) Syria Eswatini (Swaziland) Turks and Caicos Islands Chad Togo Thailand Tajikistan Tokelau Timor-Leste (East Timor) Turkmenistan Tunisia Tonga Turkey Trinidad and Tobago Tuvalu Taiwan Tanzania Ukraine Uganda United States Uruguay Uzbekistan Holy See Saint Vincent and the Grenadines Venezuela Virgin Islands (British) Virgin Islands (U.S.) Viet Nam Vanuatu Wallis and Futuna Samoa Kosovo Yemen Mayotte South Africa Zambia Zimbabwe ); }; ================================================ FILE: apps/common/example/examples/complex/index.tsx ================================================ import React from 'react'; import {Circle, G, Svg} from 'react-native-svg'; import PolygonBunny from './PolygonBunny'; import WorldMap from './WorldMap'; const PolygonBunnyExample = () => ; PolygonBunnyExample.title = 'Polygon Bunny'; const WorldMapExample = () => ; WorldMapExample.title = 'WorldMap'; const icon = ( ); const samples = [PolygonBunnyExample, WorldMapExample]; export {icon, samples}; ================================================ FILE: apps/common/example/examples/index.tsx ================================================ import * as Circle from './Circle'; import * as Clipping from './Clipping'; import * as Complex from './complex'; import * as Ellipse from './Ellipse'; import * as Empty from './Empty'; import * as ForeignObject from './ForeignObject'; import * as G from './G'; import * as Gradients from './Gradients'; import * as Image from './Image'; import * as Line from './Line'; import * as Markers from './Markers'; import * as Mask from './Mask'; import * as PanResponder from './PanResponder'; import * as Path from './Path'; import * as Polygon from './Polygon'; import * as Polyline from './Polyline'; import * as Reanimated from './Reanimated'; import * as Rect from './Rect'; import * as Reusable from './Reusable'; import * as Stroking from './Stroking'; import * as Svg from './Svg'; import * as Text from './Text'; import * as TouchEvents from './TouchEvents'; import * as Transforms from './Transforms'; export const examples = { Empty, Svg, Rect, Circle, Ellipse, ForeignObject, Line, Polygon, Polyline, Path, Text, Stroking, G, Gradients, Clipping, Image, TouchEvents, Reusable, PanResponder, Reanimated, Transforms, Markers, Mask, Complex, }; ================================================ FILE: apps/common/example/index.tsx ================================================ /** * Sample React Native App for react-native-svg library * https://github.com/software-mansion/react-native-svg/tree/main/apps/common/example */ 'use strict'; import {NavigationContainer} from '@react-navigation/native'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import {createStackNavigator} from '@react-navigation/stack'; import React from 'react'; import {ActivityIndicator, Platform, View} from 'react-native'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; import {ListScreen} from './ListScreen'; import * as E2e from './e2e/index'; import {examples} from './examples'; import * as FilterImage from './examples/FilterImage'; import * as Filters from './examples/Filters'; import {commonStyles} from './utils/commonStyles'; import composeComponents from './utils/composeComponent'; import { Example, Examples, NavigationProp, RootStackParamList, } from './utils/types'; import {usePersistNavigation} from './utils/usePersistNavigation'; export default function App() { const {isReady, initialState, persistNavigationState} = usePersistNavigation(); if (!isReady) { return ( ); } if (process.env.E2E) { console.log('Opening E2E example, as E2E env is set to ' + process.env.E2E); return ; } return ( {allScreensKeys.map(name => ( ))} ); } type ScreenProps = {navigation: NavigationProp}; const HomeList = (props: ScreenProps) => ( ); const FiltersList = (props: ScreenProps) => ( ); const FilterImageList = (props: ScreenProps) => ( ); const Stack = Platform.OS === 'macos' || Platform.OS === 'windows' ? createStackNavigator() : createNativeStackNavigator(); const allScreens = { ...examples, ...Filters.samples, ...FilterImage.samples, }; const allScreensKeys = Object.keys(allScreens) as (keyof typeof allScreens)[]; ================================================ FILE: apps/common/example/utils/commonStyles.ts ================================================ import {StyleSheet} from 'react-native'; export const commonStyles = StyleSheet.create({ container: { flex: 1, }, center: { alignItems: 'center', justifyContent: 'center', }, list: { backgroundColor: '#EFEFF4', width: '100%', }, separator: { height: 1, backgroundColor: '#DBDBE0', }, button: { flex: 1, height: 60, padding: 15, flexDirection: 'row', alignItems: 'center', backgroundColor: 'white', }, disabledButton: { backgroundColor: 'grey', opacity: 0.5, }, title: { fontSize: 16, color: 'black', }, visitedItem: { backgroundColor: '#e6f0f7', }, }); ================================================ FILE: apps/common/example/utils/composeComponent.tsx ================================================ import React, {Fragment} from 'react'; import {ScrollView, Text, View} from 'react-native'; import {Examples, Sample} from './types'; export default function composeComponents( components: Sample[] | Examples, renderInView?: boolean, ) { const Wrapper = renderInView ? View : ScrollView; return function ComposedComponent() { return ( {Array.isArray(components) ? components.map((Component, index) => ( {index !== components.length - 1 && } )) : null} ); }; } function ComponentTitle({title}: {title?: string}) { if (!title) return null; return ( {title} ); } function Separator() { return ( ); } ================================================ FILE: apps/common/example/utils/types.ts ================================================ import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {StackNavigationProp} from '@react-navigation/stack'; import {allScreens} from '../index'; export type ExamplesKey = keyof typeof allScreens; export interface Example { samples: Sample[] | Examples; icon: React.JSX.Element; shouldBeRenderInView?: boolean; } export type Examples = Record; export type NavigationProp = | NativeStackNavigationProp | StackNavigationProp; export type RootStackParamList = {[P in ExamplesKey]: undefined} & { RNSVG: undefined; Filters: undefined; 'Filter Image': undefined; E2E: undefined; }; export type Sample = React.FC & {title: string}; ================================================ FILE: apps/common/example/utils/usePersistNavigation.ts ================================================ import AsyncStorage from '@react-native-async-storage/async-storage'; import {NavigationState} from '@react-navigation/native'; import {useCallback, useEffect, useState} from 'react'; import {Linking, Platform} from 'react-native'; function noop() {} // do nothing // copied from https://reactnavigation.org/docs/state-persistence/ const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1'; export const usePersistNavigation = () => { const [isReady, setIsReady] = useState(!__DEV__); const [initialState, setInitialState] = useState(); useEffect(() => { const restoreState = async () => { try { const initialUrl = await Linking.getInitialURL(); if ( Platform.OS !== 'web' && Platform.OS !== 'macos' && initialUrl == null ) { // Only restore state if there's no deep link and we're not on web const savedStateString = await AsyncStorage.getItem(PERSISTENCE_KEY); const state = savedStateString ? JSON.parse(savedStateString) : undefined; if (state !== undefined) { setInitialState(state); } } } finally { setIsReady(true); } }; if (!isReady) { restoreState().catch(noop); } }, [isReady]); const persistNavigationState = useCallback((state?: NavigationState) => { AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state)).catch(noop); }, []); return {isReady, initialState, persistNavigationState}; }; ================================================ FILE: apps/common/index.tsx ================================================ import App from './example'; export default App; ================================================ FILE: apps/common/noNavigationApp.tsx ================================================ /** * Sample React Native App for react-native-svg library * https://github.com/software-mansion/react-native-svg/tree/main/apps/common/example */ /** * This is a very simple render of the examples for react-native-svg library, to avoid dependencies on @react-navigation, * which may not be fully supported on all platforms and versions of react-native */ 'use strict'; import React from 'react'; import {ScrollView, Text, View} from 'react-native'; import {examples} from './example/examples'; import type {Example} from './example/utils/types'; import {commonStyles} from './example/utils/commonStyles'; const ExampleBlock = ({example, index}: {example: Example; index: number}) => { if (Array.isArray(example.samples)) { return ( {example.icon} {example.samples.map((sample, index) => { return ( {sample.title} {sample({})} ); })} ); } throw new Error('Unhandled Example type'); }; export default function App() { return ( {Object.values(examples).map((example, index) => { return ; })} ); } ================================================ FILE: apps/common/test/ColorTest.tsx ================================================ import React from 'react'; import {PlatformColor, Platform, Button, DynamicColorIOS} from 'react-native'; import {Svg, Circle, Rect, Text, TSpan} from 'react-native-svg'; const color = Platform.OS !== 'web' ? PlatformColor( Platform.select({ ios: 'systemTealColor', android: '@android:color/holo_blue_bright', default: 'black', }), ) : 'black'; // const customContrastDynamicTextColor = DynamicColorIOS({ // dark: 'hsla(360, 40%, 30%, 1.0)', // light: '#ff00ff55', // highContrastDark: 'black', // highContrastLight: 'white', // }); export default () => { const [test, setTest] = React.useState(50); return ( <> Testing word-wrap... Testing word-wrap... Testing word-wrap... Testing word-wrap... Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample-macOS/FabricMacOSExample.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only com.apple.security.network.client ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample-macOS/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains localhost NSExceptionAllowsInsecureHTTPLoads NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample-macOS/main.m ================================================ #import int main(int argc, const char *argv[]) { return NSApplicationMain(argc, argv); } ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 0BADD780AB7E6F1B127032BA /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 65EACEEA33179874AA79EA13 /* PrivacyInfo.xcprivacy */; }; 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5142014C2437B4B30078DB4F /* AppDelegate.mm */; }; 514201522437B4B40078DB4F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 514201512437B4B40078DB4F /* Assets.xcassets */; }; 514201552437B4B40078DB4F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 514201532437B4B40078DB4F /* Main.storyboard */; }; 514201582437B4B40078DB4F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 514201572437B4B40078DB4F /* main.m */; }; 8C9D3995C4FF4A43AEF4F4AA /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 65EACEEA33179874AA79EA13 /* PrivacyInfo.xcprivacy */; }; B5BBE56A9DAF3997A2B25A15 /* libPods-FabricMacOSExample-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F040659B7DBE8B9C12EE1D0 /* libPods-FabricMacOSExample-macOS.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 13B07F961A680F5B00A75B9A /* FabricMacOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FabricMacOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1F040659B7DBE8B9C12EE1D0 /* libPods-FabricMacOSExample-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FabricMacOSExample-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 40EEEE7084233A710915BA16 /* Pods-FabricMacOSExample-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricMacOSExample-macOS.debug.xcconfig"; path = "Target Support Files/Pods-FabricMacOSExample-macOS/Pods-FabricMacOSExample-macOS.debug.xcconfig"; sourceTree = ""; }; 514201492437B4B30078DB4F /* FabricMacOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FabricMacOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5142014B2437B4B30078DB4F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 5142014C2437B4B30078DB4F /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = ""; }; 514201512437B4B40078DB4F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 514201542437B4B40078DB4F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 514201562437B4B40078DB4F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 514201572437B4B40078DB4F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 514201592437B4B40078DB4F /* FabricMacOSExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FabricMacOSExample.entitlements; sourceTree = ""; }; 65EACEEA33179874AA79EA13 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 716A8CAE85BB1EEFECD54675 /* Pods-FabricMacOSExample-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricMacOSExample-macOS.release.xcconfig"; path = "Target Support Files/Pods-FabricMacOSExample-macOS/Pods-FabricMacOSExample-macOS.release.xcconfig"; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 514201462437B4B30078DB4F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( B5BBE56A9DAF3997A2B25A15 /* libPods-FabricMacOSExample-macOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 1F040659B7DBE8B9C12EE1D0 /* libPods-FabricMacOSExample-macOS.a */, ); name = Frameworks; sourceTree = ""; }; 5142014A2437B4B30078DB4F /* FabricMacOSExample-macOS */ = { isa = PBXGroup; children = ( 5142014B2437B4B30078DB4F /* AppDelegate.h */, 5142014C2437B4B30078DB4F /* AppDelegate.mm */, 514201512437B4B40078DB4F /* Assets.xcassets */, 514201532437B4B40078DB4F /* Main.storyboard */, 514201562437B4B40078DB4F /* Info.plist */, 514201572437B4B40078DB4F /* main.m */, 514201592437B4B40078DB4F /* FabricMacOSExample.entitlements */, ); path = "FabricMacOSExample-macOS"; sourceTree = ""; }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( ); name = Libraries; sourceTree = ""; }; 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( 5142014A2437B4B30078DB4F /* FabricMacOSExample-macOS */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, 65EACEEA33179874AA79EA13 /* PrivacyInfo.xcprivacy */, FC1773CB15EAC76EA1E9B8A6 /* Pods */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* FabricMacOSExample.app */, 514201492437B4B30078DB4F /* FabricMacOSExample.app */, ); name = Products; sourceTree = ""; }; FC1773CB15EAC76EA1E9B8A6 /* Pods */ = { isa = PBXGroup; children = ( 40EEEE7084233A710915BA16 /* Pods-FabricMacOSExample-macOS.debug.xcconfig */, 716A8CAE85BB1EEFECD54675 /* Pods-FabricMacOSExample-macOS.release.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 13B07F861A680F5B00A75B9A /* FabricMacOSExample-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "FabricMacOSExample-iOS" */; buildPhases = ( 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, ); buildRules = ( ); dependencies = ( ); name = "FabricMacOSExample-iOS"; productName = FabricMacOSExample; productReference = 13B07F961A680F5B00A75B9A /* FabricMacOSExample.app */; productType = "com.apple.product-type.application"; }; 514201482437B4B30078DB4F /* FabricMacOSExample-macOS */ = { isa = PBXNativeTarget; buildConfigurationList = 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "FabricMacOSExample-macOS" */; buildPhases = ( 9369CACD11C4BD55628BF3CD /* [CP] Check Pods Manifest.lock */, 514201452437B4B30078DB4F /* Sources */, 514201462437B4B30078DB4F /* Frameworks */, 514201472437B4B30078DB4F /* Resources */, 381D8A6E24576A4E00465D17 /* Bundle React Native code and images */, 570208882C43F96B25B8608C /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = "FabricMacOSExample-macOS"; productName = FabricMacOSExample; productReference = 514201492437B4B30078DB4F /* FabricMacOSExample.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1130; TargetAttributes = { 13B07F861A680F5B00A75B9A = { LastSwiftMigration = 1120; }; 514201482437B4B30078DB4F = { CreatedOnToolsVersion = 11.4; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "FabricMacOSExample" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 83CBB9F61A601CBA00E9B192; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* FabricMacOSExample-iOS */, 514201482437B4B30078DB4F /* FabricMacOSExample-macOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 13B07F8E1A680F5B00A75B9A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8C9D3995C4FF4A43AEF4F4AA /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 514201472437B4B30078DB4F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 514201522437B4B40078DB4F /* Assets.xcassets in Resources */, 514201552437B4B40078DB4F /* Main.storyboard in Resources */, 0BADD780AB7E6F1B127032BA /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native-macos/scripts/react-native-xcode.sh\n"; }; 381D8A6E24576A4E00465D17 /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Bundle React Native code and images"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native-macos/scripts/react-native-xcode.sh\n"; }; 570208882C43F96B25B8608C /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-FabricMacOSExample-macOS/Pods-FabricMacOSExample-macOS-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FabricMacOSExample-macOS/Pods-FabricMacOSExample-macOS-resources.sh\"\n"; showEnvVarsInLog = 0; }; 9369CACD11C4BD55628BF3CD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-FabricMacOSExample-macOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 13B07F871A680F5B00A75B9A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 514201452437B4B30078DB4F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 514201582437B4B40078DB4F /* main.m in Sources */, 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 514201532437B4B40078DB4F /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 514201542437B4B40078DB4F /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; INFOPLIST_FILE = "FabricMacOSExample-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = FabricMacOSExample; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = "FabricMacOSExample-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = FabricMacOSExample; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 5142015B2437B4B40078DB4F /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40EEEE7084233A710915BA16 /* Pods-FabricMacOSExample-macOS.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; INFOPLIST_FILE = "FabricMacOSExample-macos/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = FabricMacOSExample; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 5142015C2437B4B40078DB4F /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 716A8CAE85BB1EEFECD54675 /* Pods-FabricMacOSExample-macOS.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = "FabricMacOSExample-macos/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 11.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = FabricMacOSExample; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Release; }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = false; }; name = Debug; }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = false; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "FabricMacOSExample-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, 13B07F951A680F5B00A75B9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "FabricMacOSExample-macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 5142015B2437B4B40078DB4F /* Debug */, 5142015C2437B4B40078DB4F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "FabricMacOSExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA211A601CBA00E9B192 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; } ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample.xcodeproj/xcshareddata/xcschemes/FabricMacOSExample-macOS.xcscheme ================================================ ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: apps/fabric-macos-example/macos/FabricMacOSExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: apps/fabric-macos-example/macos/Podfile ================================================ require_relative '../node_modules/react-native-macos/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' ENV['RCT_NEW_ARCH_ENABLED'] = '1' prepare_react_native_project! target 'FabricMacOSExample-macOS' do platform :macos, '11.0' use_native_modules! # Flags change depending on the env values. flags = get_default_flags() use_react_native!( :path => '../node_modules/react-native-macos', :hermes_enabled => false, :fabric_enabled => ENV['RCT_NEW_ARCH_ENABLED'] == '1', # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) post_install do |installer| react_native_post_install(installer) end end ================================================ FILE: apps/fabric-macos-example/macos/PrivacyInfo.xcprivacy ================================================ NSPrivacyAccessedAPITypes NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons C617.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons CA92.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategorySystemBootTime NSPrivacyAccessedAPITypeReasons 35F9.1 NSPrivacyCollectedDataTypes NSPrivacyTracking ================================================ FILE: apps/fabric-macos-example/metro.config.js ================================================ /** * Metro configuration for React Native * https://reactnative.dev/docs/metro * * @format */ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const path = require('path'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const modules = [...Object.keys(pack.peerDependencies), 'react-native-macos']; const config = { projectRoot: __dirname, watchFolders: [root], resolver: { blockList: exclusionList( modules.map( m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), ), ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, }, }), assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry', }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/fabric-macos-example/package.json ================================================ { "name": "FabricMacOSExample", "version": "0.0.1", "private": true, "scripts": { "macos": "react-native run-macos", "lint": "eslint .", "start": "react-native start", "test": "jest", "postinstall": "patch-package" }, "dependencies": { "@react-native-async-storage/async-storage": "^2.0.0", "@react-navigation/native": "^6.1.18", "@react-navigation/native-stack": "^6.11.0", "@react-navigation/stack": "^6.4.1", "react": "19.0.0", "react-native": "0.78.3", "react-native-gesture-handler": "https://github.com/software-mansion/react-native-gesture-handler", "react-native-macos": "^0.78.6", "react-native-reanimated": "^3.19.1", "react-native-svg": "link:../../" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", "@react-native-community/cli": "15.0.1", "@react-native-community/cli-platform-android": "15.0.1", "@react-native-community/cli-platform-ios": "15.0.1", "@react-native/babel-preset": "0.78.3", "@react-native/eslint-config": "0.78.3", "@react-native/metro-config": "0.78.3", "@react-native/typescript-config": "0.78.3", "@types/jest": "^29.5.13", "@types/react": "^19.0.0", "@types/react-test-renderer": "^19.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "patch-package": "^8.0.0", "prettier": "2.8.8", "react-test-renderer": "19.0.0", "typescript": "5.0.4" }, "engines": { "node": ">=18" } } ================================================ FILE: apps/fabric-windows-example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate **/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof .cxx/ *.keystore !debug.keystore # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ **/fastlane/report.xml **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output # Locally installed nuget packages /windows/packages # Bundle artifact *.jsbundle # Ruby / CocoaPods **/Pods/ /vendor/bundle/ # Temporary files created by Metro to check the health of the file watcher .metro-health-check* # testing /coverage # Yarn .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions ================================================ FILE: apps/fabric-windows-example/.prettierrc.js ================================================ module.exports = { arrowParens: 'avoid', bracketSameLine: true, bracketSpacing: false, singleQuote: true, trailingComma: 'all', }; ================================================ FILE: apps/fabric-windows-example/.ruby-version ================================================ 2.7.6 ================================================ FILE: apps/fabric-windows-example/.watchmanconfig ================================================ {} ================================================ FILE: apps/fabric-windows-example/app.json ================================================ { "name": "FabricExample", "displayName": "FabricWindowsExample" } ================================================ FILE: apps/fabric-windows-example/babel.config.js ================================================ module.exports = { presets: ['module:@react-native/babel-preset'], }; ================================================ FILE: apps/fabric-windows-example/index.js ================================================ /** * @format */ import {AppRegistry} from 'react-native'; import App from '../common/noNavigationApp'; import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => App); AppRegistry.registerComponent("Example", () => App); ================================================ FILE: apps/fabric-windows-example/jest.config.js ================================================ module.exports = { preset: 'react-native', }; ================================================ FILE: apps/fabric-windows-example/jest.config.windows.js ================================================ const config = {}; module.exports = require('@rnx-kit/jest-preset')('windows', config); ================================================ FILE: apps/fabric-windows-example/metro.config.js ================================================ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); /** * Metro configuration * https://facebook.github.io/metro/docs/configuration * * @type {import('metro-config').MetroConfig} */ const path = require('path'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const escape = require('escape-string-regexp'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const fs = require('fs'); const rnwPath = fs.realpathSync( path.resolve(require.resolve('react-native-windows/package.json'), '..'), ); const modules = [...Object.keys(pack.peerDependencies), 'react-native-windows']; const config = { projectRoot: __dirname, watchFolders: [root], // We need to make sure that only one version is loaded for peerDependencies // So we exclude them at the root, and alias them to the versions in example's node_modules resolver: { blockList: exclusionList( modules.map( m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), ), // This stops "react-native run-windows" from causing the metro server to // crash if its already running new RegExp( `${path.join(__dirname, 'windows').replace(/[/\\]+/g, '/')}.*`, ), // This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip or other files produced by msbuild new RegExp(`${rnwPath}/build/.*`), new RegExp(`${rnwPath}/target/.*`), /.*\.ProjectImports\.zip/, ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, }, }), // This fixes the 'missing-asset-registry-path` error (see https://github.com/microsoft/react-native-windows/issues/11437) assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry', }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/fabric-windows-example/package.json ================================================ { "name": "FabricWindowsExample", "version": "0.0.1", "private": true, "scripts": { "windows": "react-native run-windows", "lint": "eslint .", "start": "react-native start", "test": "jest" }, "dependencies": { "react": "18.2.0", "react-native": "0.74.2", "react-native-windows": "0.74.24", "react-native-svg": "link:../../" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native/babel-preset": "0.74.81", "@react-native/eslint-config": "0.74.81", "@react-native/metro-config": "0.74.81", "@react-native/typescript-config": "0.74.81", "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", "react-test-renderer": "18.2.0", "typescript": "5.0.4", "@rnx-kit/jest-preset": "^0.1.16" }, "engines": { "node": ">=18" } } ================================================ FILE: apps/fabric-windows-example/windows/.gitignore ================================================ *AppPackages* *BundleArtifacts* #OS junk files [Tt]humbs.db *.DS_Store #Visual Studio files *.[Oo]bj *.user *.aps *.pch *.vspscc *.vssscc *_i.c *_p.c *.ncb *.suo *.tlb *.tlh *.bak *.[Cc]ache *.ilk *.log *.lib *.sbr *.sdf *.opensdf *.opendb *.unsuccessfulbuild ipch/ [Oo]bj/ [Bb]in [Dd]ebug*/ [Rr]elease*/ Ankh.NoLoad .vs/ # Visual C++ cache files #Files generated by the VS build **/Generated Files/** ================================================ FILE: apps/fabric-windows-example/windows/ExperimentalFeatures.props ================================================ true true true ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/.gitignore ================================================ /Bundle ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/AutolinkedNativeModules.g.cpp ================================================ // AutolinkedNativeModules.g.cpp contents generated by "react-native autolink-windows" // clang-format off #include "pch.h" #include "AutolinkedNativeModules.g.h" // Includes from react-native-svg #include namespace winrt::Microsoft::ReactNative { void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders) { // IReactPackageProviders from react-native-svg packageProviders.Append(winrt::RNSVG::ReactPackageProvider()); } } ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/AutolinkedNativeModules.g.h ================================================ // AutolinkedNativeModules.g.h contents generated by "react-native autolink-windows" // clang-format off #pragma once namespace winrt::Microsoft::ReactNative { void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders); } ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/AutolinkedNativeModules.g.props ================================================ ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/AutolinkedNativeModules.g.targets ================================================ {7acf84ec-efba-4043-8e14-40b159508902} ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/FabricExample.cpp ================================================ // FabricExample.cpp : Defines the entry point for the application. // #include "pch.h" #include "FabricExample.h" #include "AutolinkedNativeModules.g.h" #include "NativeModules.h" struct CompReactPackageProvider : winrt::implements { public: // IReactPackageProvider void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept { AddAttributedModules(packageBuilder, true); } }; // Global Variables: constexpr PCWSTR windowTitle = L"FabricExample"; constexpr PCWSTR mainComponentName = L"FabricExample"; float ScaleFactor(HWND hwnd) noexcept { return GetDpiForWindow(hwnd) / static_cast(USER_DEFAULT_SCREEN_DPI); } void UpdateRootViewSizeToAppWindow( winrt::Microsoft::ReactNative::ReactNativeIsland const &rootView, winrt::Microsoft::UI::Windowing::AppWindow const &window) { auto hwnd = winrt::Microsoft::UI::GetWindowFromWindowId(window.Id()); auto scaleFactor = ScaleFactor(hwnd); winrt::Windows::Foundation::Size size{ window.ClientSize().Width / scaleFactor, window.ClientSize().Height / scaleFactor}; // Do not relayout when minimized if (window.Presenter().as().State() != winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) { winrt::Microsoft::ReactNative::LayoutConstraints constraints; constraints.MaximumSize = constraints.MinimumSize = size; constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined; rootView.Arrange(constraints, {0, 0}); } } // Create and configure the ReactNativeHost winrt::Microsoft::ReactNative::ReactNativeHost CreateReactNativeHost( HWND hwnd, const winrt::Microsoft::UI::Composition::Compositor &compositor) { WCHAR appDirectory[MAX_PATH]; GetModuleFileNameW(NULL, appDirectory, MAX_PATH); PathCchRemoveFileSpec(appDirectory, MAX_PATH); auto host = winrt::Microsoft::ReactNative::ReactNativeHost(); // Include any autolinked modules RegisterAutolinkedNativeModulePackages(host.PackageProviders()); host.PackageProviders().Append(winrt::make()); #if BUNDLE host.InstanceSettings().JavaScriptBundleFile(L"index.windows"); host.InstanceSettings().BundleRootPath(std::wstring(L"file://").append(appDirectory).append(L"\\Bundle\\").c_str()); host.InstanceSettings().UseFastRefresh(false); #else host.InstanceSettings().JavaScriptBundleFile(L"index"); host.InstanceSettings().UseFastRefresh(true); #endif #if _DEBUG host.InstanceSettings().UseDirectDebugger(true); host.InstanceSettings().UseDeveloperSupport(true); #else host.InstanceSettings().UseDirectDebugger(false); host.InstanceSettings().UseDeveloperSupport(false); #endif winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId( host.InstanceSettings().Properties(), reinterpret_cast(hwnd)); winrt::Microsoft::ReactNative::Composition::CompositionUIService::SetCompositor( host.InstanceSettings(), compositor); return host; } _Use_decl_annotations_ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE, PSTR /* commandLine */, int showCmd) { // Initialize WinRT. winrt::init_apartment(winrt::apartment_type::single_threaded); // Enable per monitor DPI scaling SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); // Create a DispatcherQueue for this thread. This is needed for Composition, Content, and // Input APIs. auto dispatcherQueueController{winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread()}; // Create a Compositor for all Content on this thread. auto compositor{winrt::Microsoft::UI::Composition::Compositor()}; // Create a top-level window. auto window = winrt::Microsoft::UI::Windowing::AppWindow::Create(); window.Title(windowTitle); window.Resize({1000, 1000}); window.Show(); auto hwnd = winrt::Microsoft::UI::GetWindowFromWindowId(window.Id()); auto scaleFactor = ScaleFactor(hwnd); auto host = CreateReactNativeHost(hwnd, compositor); // Start the react-native instance, which will create a JavaScript runtime and load the applications bundle host.ReloadInstance(); // Create a RootView which will present a react-native component winrt::Microsoft::ReactNative::ReactViewOptions viewOptions; viewOptions.ComponentName(mainComponentName); auto rootView = winrt::Microsoft::ReactNative::ReactNativeIsland(compositor); rootView.ReactViewHost(winrt::Microsoft::ReactNative::ReactCoreInjection::MakeViewHost(host, viewOptions)); // Update the size of the RootView when the AppWindow changes size window.Changed([wkRootView = winrt::make_weak(rootView)]( winrt::Microsoft::UI::Windowing::AppWindow const &window, winrt::Microsoft::UI::Windowing::AppWindowChangedEventArgs const &args) { if (args.DidSizeChange() || args.DidVisibilityChange()) { if (auto rootView = wkRootView.get()) { UpdateRootViewSizeToAppWindow(rootView, window); } } }); // Quit application when main window is closed window.Destroying( [host](winrt::Microsoft::UI::Windowing::AppWindow const &window, winrt::IInspectable const & /*args*/) { // Before we shutdown the application - unload the ReactNativeHost to give the javascript a chance to save any // state auto async = host.UnloadInstance(); async.Completed([host](auto asyncInfo, winrt::Windows::Foundation::AsyncStatus asyncStatus) { assert(asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed); host.InstanceSettings().UIDispatcher().Post([]() { PostQuitMessage(0); }); }); }); // DesktopChildSiteBridge create a ContentSite that can host the RootView ContentIsland auto bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(compositor, window.Id()); bridge.Connect(rootView.Island()); bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow); rootView.ScaleFactor(scaleFactor); // Set the intialSize of the root view UpdateRootViewSizeToAppWindow(rootView, window); bridge.Show(); // Run the main application event loop dispatcherQueueController.DispatcherQueue().RunEventLoop(); // Rundown the DispatcherQueue. This drains the queue and raises events to let components // know the message loop has finished. dispatcherQueueController.ShutdownQueue(); bridge.Close(); bridge = nullptr; // Destroy all Composition objects compositor.Close(); compositor = nullptr; } ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/FabricExample.h ================================================ #pragma once #include "resource.h" ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/FabricExample.vcxproj ================================================ true true {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4} FabricExample Win32Proj FabricExample 10.0 en-US 17.0 false $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ Debug Win32 Release Win32 Debug x64 Release x64 Debug ARM64 Release ARM64 Application Unicode v143 true false true Use pch.h $(IntDir)pch.pch Level3 true %(AdditionalOptions) /bigobj 4453;28204 stdcpp20 shell32.lib;user32.lib;windowsapp.lib;%(AdditionalDependenices) Windows true _DEBUG;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) USE_FABRIC;%(PreprocessorDefinitions) Create Create Create Create Create Create This project references targets in your node_modules\react-native-windows folder. The missing file is {0}. ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/FabricExample.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Header Files Source Files Source Files Source Files Resource Files Resource Files Resource Files ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/packages.lock.json ================================================ { "version": 1, "dependencies": { "native,Version=v0.0": { "boost": { "type": "Direct", "requested": "[1.83.0, )", "resolved": "1.83.0", "contentHash": "cy53VNMzysEMvhBixDe8ujPk67Fcj3v6FPHQnH91NYJNLHpc6jxa2xq9ruCaaJjE4M3YrGSHDi4uUSTGBWw6EQ==" }, "Microsoft.JavaScript.Hermes": { "type": "Direct", "requested": "[0.1.23, )", "resolved": "0.1.23", "contentHash": "cA9t1GjY4Yo0JD1AfA//e1lOwk48hLANfuX6GXrikmEBNZVr2TIX5ONJt5tqCnpZyLz6xGiPDgTfFNKbSfb21g==" }, "Microsoft.VCRTForwarders.140": { "type": "Direct", "requested": "[1.0.2-rc, )", "resolved": "1.0.2-rc", "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" }, "Microsoft.Windows.CppWinRT": { "type": "Direct", "requested": "[2.0.230706.1, )", "resolved": "2.0.230706.1", "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" }, "Microsoft.WindowsAppSDK": { "type": "Direct", "requested": "[1.5.240227000, )", "resolved": "1.5.240227000", "contentHash": "6rESOsREi8534J7IDpNfFYPvxQaSleXKt4A7ZYPeQyckNMQ0o1W0jZ420bJbEMz9Cw/S/8IbpPftLLZ9w/GTCQ==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" } }, "Microsoft.UI.Xaml": { "type": "Transitive", "resolved": "2.8.0", "contentHash": "vxdHxTr63s5KVtNddMFpgvjBjUH50z7seq/5jLWmmSuf8poxg+sXrywkofUdE8ZstbpO9y3FL/IXXUcPYbeesA==", "dependencies": { "Microsoft.Web.WebView2": "1.0.1264.42" } }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" }, "Microsoft.Windows.SDK.BuildTools": { "type": "Transitive", "resolved": "10.0.22621.756", "contentHash": "7ZL2sFSioYm1Ry067Kw1hg0SCcW5kuVezC2SwjGbcPE61Nn+gTbH86T73G3LcEOVj0S3IZzNuE/29gZvOLS7VA==" }, "common": { "type": "Project", "dependencies": { "boost": "[1.83.0, )" } }, "fmt": { "type": "Project" }, "folly": { "type": "Project", "dependencies": { "Fmt": "[1.0.0, )", "boost": "[1.83.0, )" } }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.1.23, )", "Microsoft.WindowsAppSDK": "[1.5.240227000, )", "ReactCommon": "[1.0.0, )", "boost": "[1.83.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { "Folly": "[1.0.0, )", "boost": "[1.83.0, )" } }, "reactnativeasyncstorage": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "Microsoft.UI.Xaml": "[2.8.0, )" } }, "rnsvg": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "Microsoft.VCRTForwarders.140": "[1.0.2-rc, )", "Microsoft.WindowsAppSDK": "[1.5.240227000, )", "boost": "[1.83.0, )" } } }, "native,Version=v0.0/win": { "Microsoft.VCRTForwarders.140": { "type": "Direct", "requested": "[1.0.2-rc, )", "resolved": "1.0.2-rc", "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" }, "Microsoft.WindowsAppSDK": { "type": "Direct", "requested": "[1.5.240227000, )", "resolved": "1.5.240227000", "contentHash": "6rESOsREi8534J7IDpNfFYPvxQaSleXKt4A7ZYPeQyckNMQ0o1W0jZ420bJbEMz9Cw/S/8IbpPftLLZ9w/GTCQ==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" } }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win-arm64": { "Microsoft.VCRTForwarders.140": { "type": "Direct", "requested": "[1.0.2-rc, )", "resolved": "1.0.2-rc", "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" }, "Microsoft.WindowsAppSDK": { "type": "Direct", "requested": "[1.5.240227000, )", "resolved": "1.5.240227000", "contentHash": "6rESOsREi8534J7IDpNfFYPvxQaSleXKt4A7ZYPeQyckNMQ0o1W0jZ420bJbEMz9Cw/S/8IbpPftLLZ9w/GTCQ==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" } }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win-x64": { "Microsoft.VCRTForwarders.140": { "type": "Direct", "requested": "[1.0.2-rc, )", "resolved": "1.0.2-rc", "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" }, "Microsoft.WindowsAppSDK": { "type": "Direct", "requested": "[1.5.240227000, )", "resolved": "1.5.240227000", "contentHash": "6rESOsREi8534J7IDpNfFYPvxQaSleXKt4A7ZYPeQyckNMQ0o1W0jZ420bJbEMz9Cw/S/8IbpPftLLZ9w/GTCQ==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" } }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win-x86": { "Microsoft.VCRTForwarders.140": { "type": "Direct", "requested": "[1.0.2-rc, )", "resolved": "1.0.2-rc", "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" }, "Microsoft.WindowsAppSDK": { "type": "Direct", "requested": "[1.5.240227000, )", "resolved": "1.5.240227000", "contentHash": "6rESOsREi8534J7IDpNfFYPvxQaSleXKt4A7ZYPeQyckNMQ0o1W0jZ420bJbEMz9Cw/S/8IbpPftLLZ9w/GTCQ==", "dependencies": { "Microsoft.Windows.SDK.BuildTools": "10.0.22621.756" } }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } } } } ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/pch.cpp ================================================ #include "pch.h" ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/pch.h ================================================ // pch.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #define NOMINMAX 1 #define WIN32_LEAN_AND_MEAN 1 #define WINRT_LEAN_AND_MEAN 1 // Windows Header Files #include #undef GetCurrentTime #include #include // WinRT Header Files #include #include #include #include #include #include #include #include #include // C RunTime Header Files #include #include #include #include // Reference additional headers your project requires here ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/resource.h ================================================ // // Microsoft Visual C++ generated include file. // Used by FabricExample.rc #define IDI_ICON1 1008 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 130 #define _APS_NEXT_RESOURCE_VALUE 129 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif ================================================ FILE: apps/fabric-windows-example/windows/FabricExample/targetver.h ================================================ #pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #include ================================================ FILE: apps/fabric-windows-example/windows/FabricExample.Package/FabricExample.Package.wapproj ================================================ {9cf487c7-8a97-4df0-ac99-d53cfcf1d59b} en-US ..\FabricExample\FabricExample.vcxproj NativeOnly NativeOnly $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ Debug x86 Release x86 Debug x64 Release x64 Debug ARM64 Release ARM64 Designer True This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}. ================================================ FILE: apps/fabric-windows-example/windows/FabricExample.Package/Package.appxmanifest ================================================ FabricExample mcota Images\StoreLogo.png ================================================ FILE: apps/fabric-windows-example/windows/FabricExample.Package/packages.lock.json ================================================ { "version": 1, "dependencies": { "UAP,Version=v10.0.17763": { "common": { "type": "Project" }, "fabricexample": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "RNSVG": "[1.0.0, )" } }, "fmt": { "type": "Project" }, "folly": { "type": "Project", "dependencies": { "fmt": "[1.0.0, )" } }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", "Folly": "[1.0.0, )", "ReactCommon": "[1.0.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { "Folly": "[1.0.0, )" } }, "rnsvg": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )" } } }, "UAP,Version=v10.0.17763/win10-arm": {}, "UAP,Version=v10.0.17763/win10-arm-aot": {}, "UAP,Version=v10.0.17763/win10-arm64-aot": {}, "UAP,Version=v10.0.17763/win10-x64": {}, "UAP,Version=v10.0.17763/win10-x64-aot": {}, "UAP,Version=v10.0.17763/win10-x86": {}, "UAP,Version=v10.0.17763/win10-x86-aot": {} } } ================================================ FILE: apps/fabric-windows-example/windows/FabricExample.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "FabricExample.Package", "FabricExample.Package\FabricExample.Package.wapproj", "{9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FabricExample", "FabricExample\FabricExample.vcxproj", "{BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}" ProjectSection(ProjectDependencies) = postProject {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\node_modules\react-native-windows\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNSVG", "..\node_modules\react-native-svg\windows\RNSVG\RNSVG.vcxproj", "{7ACF84EC-EFBA-4043-8E14-40B159508902}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|ARM64.Build.0 = Debug|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|ARM64.Deploy.0 = Debug|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x64.ActiveCfg = Debug|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x64.Build.0 = Debug|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x64.Deploy.0 = Debug|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x86.ActiveCfg = Debug|x86 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x86.Build.0 = Debug|x86 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Debug|x86.Deploy.0 = Debug|x86 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|ARM64.ActiveCfg = Release|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|ARM64.Build.0 = Release|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|ARM64.Deploy.0 = Release|ARM64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x64.ActiveCfg = Release|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x64.Build.0 = Release|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x64.Deploy.0 = Release|x64 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x86.ActiveCfg = Release|x86 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x86.Build.0 = Release|x86 {9CF487C7-8A97-4DF0-AC99-D53CFCF1D59B}.Release|x86.Deploy.0 = Release|x86 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|ARM64.Build.0 = Debug|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|ARM64.Deploy.0 = Debug|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x64.ActiveCfg = Debug|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x64.Build.0 = Debug|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x64.Deploy.0 = Debug|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x86.ActiveCfg = Debug|Win32 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x86.Build.0 = Debug|Win32 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Debug|x86.Deploy.0 = Debug|Win32 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|ARM64.ActiveCfg = Release|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|ARM64.Build.0 = Release|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|ARM64.Deploy.0 = Release|ARM64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x64.ActiveCfg = Release|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x64.Build.0 = Release|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x64.Deploy.0 = Release|x64 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x86.ActiveCfg = Release|Win32 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x86.Build.0 = Release|Win32 {BD8F3BA2-CD81-4BA7-BAA0-B76D6E9EA0C4}.Release|x86.Deploy.0 = Release|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|ARM64.ActiveCfg = Debug|ARM64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|ARM64.Build.0 = Debug|ARM64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|x64.ActiveCfg = Debug|x64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|x64.Build.0 = Debug|x64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|x86.ActiveCfg = Debug|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|x86.Build.0 = Debug|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Debug|x86.Deploy.0 = Debug|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|ARM64.ActiveCfg = Release|ARM64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|ARM64.Build.0 = Release|ARM64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|x64.ActiveCfg = Release|x64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|x64.Build.0 = Release|x64 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|x86.ActiveCfg = Release|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|x86.Build.0 = Release|Win32 {85E8B53A-3B4C-40A6-97D7-67CA7082EC78}.Release|x86.Deploy.0 = Release|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM64.ActiveCfg = Debug|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM64.Build.0 = Debug|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x64.ActiveCfg = Debug|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x64.Build.0 = Debug|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x86.ActiveCfg = Debug|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x86.Build.0 = Debug|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM64.ActiveCfg = Release|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM64.Build.0 = Release|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x64.ActiveCfg = Release|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x64.Build.0 = Release|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x86.ActiveCfg = Release|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9 ..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 EndGlobalSection EndGlobal ================================================ FILE: apps/paper-example/.bundle/config ================================================ BUNDLE_PATH: "vendor/bundle" BUNDLE_FORCE_RUBY_PLATFORM: 1 ================================================ FILE: apps/paper-example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate **/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof .cxx/ *.keystore !debug.keystore .kotlin/ # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ **/fastlane/report.xml **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output # Bundle artifact *.jsbundle # Ruby / CocoaPods **/Pods/ /vendor/bundle/ # Temporary files created by Metro to check the health of the file watcher .metro-health-check* # testing /coverage # Yarn .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions ================================================ FILE: apps/paper-example/.watchmanconfig ================================================ {} ================================================ FILE: apps/paper-example/Gemfile ================================================ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby ">= 2.6.10" # Exclude problematic versions of cocoapods and activesupport that causes build failures. gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' gem 'xcodeproj', '< 1.26.0' gem 'concurrent-ruby', '< 1.3.4' # Ruby 3.4.0 has removed some libraries from the standard library. gem 'bigdecimal' gem 'logger' gem 'benchmark' gem 'mutex_m' ================================================ FILE: apps/paper-example/README.md ================================================ # SVG Example app Showcase of what this library can do 🚀 ================================================ FILE: apps/paper-example/android/app/build.gradle ================================================ apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. */ react { /* Folders */ // The root of your project, i.e. where "package.json" lives. Default is '../..' // root = file("../../") // The folder where the react-native NPM package is. Default is ../../node_modules/react-native // reactNativeDir = file("../../node_modules/react-native") // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen // codegenDir = file("../../node_modules/@react-native/codegen") // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js // cliFile = file("../../node_modules/react-native/cli.js") /* Variants */ // The list of variants to that are debuggable. For those we're going to // skip the bundling of the JS bundle and the assets. By default is just 'debug'. // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. // debuggableVariants = ["liteDebug", "prodDebug"] /* Bundling */ // A list containing the node command and its flags. Default is just 'node'. // nodeExecutableAndArgs = ["node"] // // The command to run when bundling. By default is 'bundle' // bundleCommand = "ram-bundle" // // The path to the CLI configuration file. Default is empty. // bundleConfig = file(../rn-cli.config.js) // // The name of the generated asset file containing your JS bundle // bundleAssetName = "MyApplication.android.bundle" // // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' // entryFile = file("../js/MyApplication.android.js") // // A list of extra flags to pass to the 'bundle' commands. // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle // extraPackagerArgs = [] /* Hermes Commands */ // The hermes compiler command to run. By default it is 'hermesc' // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" // // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // hermesFlags = ["-O", "-output-source-map"] /* Autolinking */ autolinkLibrariesWithApp() } /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false /** * The preferred build flavor of JavaScriptCore (JSC) * * For example, to use the international variant, you can use: * `def io.github.react-native-community:jsc-android-intl:2026004.+'` * * The international variant includes ICU i18n library and necessary data * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * give correct results when using with locales other than en-US. Note that * this variant is about 6MiB larger per architecture than default. */ def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' android { ndkVersion rootProject.ext.ndkVersion buildToolsVersion rootProject.ext.buildToolsVersion compileSdk rootProject.ext.compileSdkVersion namespace "com.paperexample" defaultConfig { applicationId "com.paperexample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } } buildTypes { debug { signingConfig signingConfigs.debug } release { // Caution! In production, you need to generate your own keystore file. // see https://reactnative.dev/docs/signed-apk-android. signingConfig signingConfigs.debug minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } } dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } } ================================================ FILE: apps/paper-example/android/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: ================================================ FILE: apps/paper-example/android/app/src/debug/AndroidManifest.xml ================================================ ================================================ FILE: apps/paper-example/android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: apps/paper-example/android/app/src/main/java/com/paperexample/MainActivity.kt ================================================ package com.paperexample import android.os.Bundle import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate class MainActivity : ReactActivity() { /** * Returns the name of the main component registered from JavaScript. This is used to schedule * rendering of the component. */ override fun getMainComponentName(): String = "PaperExample" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) } /** * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] */ override fun createReactActivityDelegate(): ReactActivityDelegate = DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) } ================================================ FILE: apps/paper-example/android/app/src/main/java/com/paperexample/MainApplication.kt ================================================ package com.paperexample import android.app.Application import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactHost import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative import com.facebook.react.ReactNativeHost import com.facebook.react.ReactPackage import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactNativeHost class MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) } override fun getJSMainModuleName(): String = "index" override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED } override val reactHost: ReactHost get() = getDefaultReactHost(applicationContext, reactNativeHost) override fun onCreate() { super.onCreate() loadReactNative(this) } } ================================================ FILE: apps/paper-example/android/app/src/main/res/drawable/rn_edit_text_material.xml ================================================ ================================================ FILE: apps/paper-example/android/app/src/main/res/values/strings.xml ================================================ PaperExample ================================================ FILE: apps/paper-example/android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: apps/paper-example/android/build.gradle ================================================ buildscript { ext { buildToolsVersion = "35.0.0" minSdkVersion = 24 compileSdkVersion = 35 targetSdkVersion = 35 ndkVersion = "27.1.12297006" kotlinVersion = "2.1.20" } repositories { google() mavenCentral() } dependencies { classpath("com.android.tools.build:gradle") classpath("com.facebook.react:react-native-gradle-plugin") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") } } apply plugin: "com.facebook.react.rootproject" ================================================ FILE: apps/paper-example/android/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: apps/paper-example/android/gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Use this property to specify which architecture you want to build. # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # Use this property to enable support to the new architecture. # This will allow you to use TurboModules and the Fabric render in # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. newArchEnabled=false # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. hermesEnabled=true ================================================ FILE: apps/paper-example/android/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # SPDX-License-Identifier: Apache-2.0 # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: apps/paper-example/android/gradlew.bat ================================================ @REM Copyright (c) Meta Platforms, Inc. and affiliates. @REM @REM This source code is licensed under the MIT license found in the @REM LICENSE file in the root directory of this source tree. @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @rem SPDX-License-Identifier: Apache-2.0 @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line set CLASSPATH= @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: apps/paper-example/android/settings.gradle ================================================ pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } plugins { id("com.facebook.react.settings") } extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } rootProject.name = 'PaperExample' include ':app' includeBuild('../node_modules/@react-native/gradle-plugin') ================================================ FILE: apps/paper-example/app.json ================================================ { "name": "PaperExample", "displayName": "PaperExample" } ================================================ FILE: apps/paper-example/babel.config.js ================================================ module.exports = { presets: ['module:@react-native/babel-preset'], plugins: ['module:react-native-dotenv', 'react-native-reanimated/plugin'], }; ================================================ FILE: apps/paper-example/index.js ================================================ /** * @format */ import { AppRegistry } from 'react-native'; import App from '../common'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => App); ================================================ FILE: apps/paper-example/ios/.xcode.env ================================================ # This `.xcode.env` file is versioned and is used to source the environment # used when running script phases inside Xcode. # To customize your local environment, you can create an `.xcode.env.local` # file that is not versioned. # NODE_BINARY variable contains the PATH to the node executable. # # Customize the NODE_BINARY variable here. # For example, to use nvm with brew, add the following line # . "$(brew --prefix nvm)/nvm.sh" --no-use export NODE_BINARY=$(command -v node) ================================================ FILE: apps/paper-example/ios/PaperExample/AppDelegate.swift ================================================ import UIKit import React import React_RCTAppDelegate import ReactAppDependencyProvider @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var reactNativeDelegate: ReactNativeDelegate? var reactNativeFactory: RCTReactNativeFactory? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() reactNativeDelegate = delegate reactNativeFactory = factory window = UIWindow(frame: UIScreen.main.bounds) factory.startReactNative( withModuleName: "PaperExample", in: window, launchOptions: launchOptions ) return true } } class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { override func sourceURL(for bridge: RCTBridge) -> URL? { self.bundleURL() } override func bundleURL() -> URL? { #if DEBUG RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") #else Bundle.main.url(forResource: "main", withExtension: "jsbundle") #endif } } ================================================ FILE: apps/paper-example/ios/PaperExample/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: apps/paper-example/ios/PaperExample/Images.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: apps/paper-example/ios/PaperExample/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName PaperExample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads NSAllowsLocalNetworking NSLocationWhenInUseUsageDescription RCTNewArchEnabled UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities arm64 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance ================================================ FILE: apps/paper-example/ios/PaperExample/LaunchScreen.storyboard ================================================ ================================================ FILE: apps/paper-example/ios/PaperExample/PrivacyInfo.xcprivacy ================================================ NSPrivacyAccessedAPITypes NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons C617.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons CA92.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategorySystemBootTime NSPrivacyAccessedAPITypeReasons 35F9.1 NSPrivacyCollectedDataTypes NSPrivacyTracking ================================================ FILE: apps/paper-example/ios/PaperExample.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 09D6C2F6F80442D389D9F399 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; FA33981304A4B453B3387650 /* libPods-PaperExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C81AC526FF905091FBC0B63F /* libPods-PaperExample.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 13B07F961A680F5B00A75B9A /* PaperExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PaperExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = PaperExample/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = PaperExample/Info.plist; sourceTree = ""; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = PaperExample/PrivacyInfo.xcprivacy; sourceTree = ""; }; 401A52CFE8F9BAEFBD1905C9 /* Pods-PaperExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PaperExample.release.xcconfig"; path = "Target Support Files/Pods-PaperExample/Pods-PaperExample.release.xcconfig"; sourceTree = ""; }; 551F51D17BE930B11AE7C3E5 /* Pods-PaperExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PaperExample.debug.xcconfig"; path = "Target Support Files/Pods-PaperExample/Pods-PaperExample.debug.xcconfig"; sourceTree = ""; }; 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = PaperExample/AppDelegate.swift; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = PaperExample/LaunchScreen.storyboard; sourceTree = ""; }; C81AC526FF905091FBC0B63F /* libPods-PaperExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PaperExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( FA33981304A4B453B3387650 /* libPods-PaperExample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 13B07FAE1A68108700A75B9A /* PaperExample */ = { isa = PBXGroup; children = ( 13B07FB51A68108700A75B9A /* Images.xcassets */, 761780EC2CA45674006654EE /* AppDelegate.swift */, 13B07FB61A68108700A75B9A /* Info.plist */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */, ); name = PaperExample; sourceTree = ""; }; 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, C81AC526FF905091FBC0B63F /* libPods-PaperExample.a */, ); name = Frameworks; sourceTree = ""; }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( ); name = Libraries; sourceTree = ""; }; 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( 13B07FAE1A68108700A75B9A /* PaperExample */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, BBD78D7AC51CEA395F1C20DB /* Pods */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* PaperExample.app */, ); name = Products; sourceTree = ""; }; BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( 551F51D17BE930B11AE7C3E5 /* Pods-PaperExample.debug.xcconfig */, 401A52CFE8F9BAEFBD1905C9 /* Pods-PaperExample.release.xcconfig */, ); path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 13B07F861A680F5B00A75B9A /* PaperExample */ = { isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "PaperExample" */; buildPhases = ( D8556900764C87D8F47B4542 /* [CP] Check Pods Manifest.lock */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 6D0E79A1C827968F3FB7C59F /* [CP] Embed Pods Frameworks */, ED2C8CD7D03C2FAEB6B9573D /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = PaperExample; productName = PaperExample; productReference = 13B07F961A680F5B00A75B9A /* PaperExample.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1210; TargetAttributes = { 13B07F861A680F5B00A75B9A = { LastSwiftMigration = 1120; }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "PaperExample" */; compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 83CBB9F61A601CBA00E9B192; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* PaperExample */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 13B07F8E1A680F5B00A75B9A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 09D6C2F6F80442D389D9F399 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/.xcode.env.local", "$(SRCROOT)/.xcode.env", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; 6D0E79A1C827968F3FB7C59F /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; D8556900764C87D8F47B4542 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-PaperExample-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; ED2C8CD7D03C2FAEB6B9573D /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-resources-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PaperExample/Pods-PaperExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 13B07F871A680F5B00A75B9A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 551F51D17BE930B11AE7C3E5 /* Pods-PaperExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; INFOPLIST_FILE = PaperExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperExample; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 401A52CFE8F9BAEFBD1905C9 /* Pods-PaperExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = PaperExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperExample; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", ); LIBRARY_SEARCH_PATHS = ( "\"$(SDKROOT)/usr/lib/swift\"", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = true; }; name = Debug; }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", ); LIBRARY_SEARCH_PATHS = ( "\"$(SDKROOT)/usr/lib/swift\"", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "PaperExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, 13B07F951A680F5B00A75B9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "PaperExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA211A601CBA00E9B192 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; } ================================================ FILE: apps/paper-example/ios/PaperExample.xcodeproj/xcshareddata/xcschemes/PaperExample.xcscheme ================================================ ================================================ FILE: apps/paper-example/ios/PaperExample.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: apps/paper-example/ios/PaperExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: apps/paper-example/ios/Podfile ================================================ ENV['RCT_NEW_ARCH_ENABLED'] = '0' # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]}, )', __dir__]).strip platform :ios, min_ios_version_supported prepare_react_native_project! linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => linkage.to_sym end target 'PaperExample' do config = use_native_modules! use_react_native!( :path => config[:reactNativePath], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) post_install do |installer| # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false, # :ccache_enabled => true ) end end ================================================ FILE: apps/paper-example/jest.config.js ================================================ module.exports = { preset: 'react-native', }; ================================================ FILE: apps/paper-example/metro.config.js ================================================ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); /** * Metro configuration * https://reactnative.dev/docs/metro * * @type {import('@react-native/metro-config').MetroConfig} */ const path = require('path'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const escape = require('escape-string-regexp'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const modules = [...Object.keys(pack.peerDependencies)]; const config = { projectRoot: __dirname, watchFolders: [root], // We need to make sure that only one version is loaded for peerDependencies // So we exclude them at the root, and alias them to the versions in example's node_modules resolver: { blacklistRE: exclusionList( modules.map( (m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) ) ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }), }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/paper-example/package.json ================================================ { "name": "PaperExample", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest", "postinstall": "patch-package" }, "dependencies": { "@react-native-async-storage/async-storage": "^2.0.0", "@react-navigation/native": "^7.1.17", "@react-navigation/native-stack": "^7.3.25", "@react-navigation/stack": "^7.4.7", "react": "19.1.0", "react-native": "0.80.0", "react-native-gesture-handler": "2.28.0", "react-native-reanimated": "3.19.1", "react-native-safe-area-context": "5.6.0", "react-native-screens": "4.13.1", "react-native-svg": "link:../../", "react-native-view-shot": "4.0.0-alpha.2" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", "@react-native-community/cli": "19.0.0", "@react-native-community/cli-platform-android": "19.0.0", "@react-native-community/cli-platform-ios": "19.0.0", "@react-native/babel-preset": "0.80.0", "@react-native/eslint-config": "0.80.0", "@react-native/metro-config": "0.80.0", "@react-native/typescript-config": "0.80.0", "@types/react": "^19.1.0", "@types/react-test-renderer": "^19.1.0", "eslint": "^8.19.0", "jest": "^29.6.3", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "prettier": "2.8.8", "react-native-dotenv": "^3.4.11", "react-test-renderer": "19.1.0", "typescript": "5.0.4" }, "engines": { "node": ">=18" } } ================================================ FILE: apps/paper-example/patches/react-native-view-shot+4.0.0-alpha.2.patch ================================================ diff --git a/node_modules/react-native-view-shot/ios/RNViewShot.m b/node_modules/react-native-view-shot/ios/RNViewShot.m index bd55b92..6a20e9d 100644 --- a/node_modules/react-native-view-shot/ios/RNViewShot.m +++ b/node_modules/react-native-view-shot/ios/RNViewShot.m @@ -106,7 +106,7 @@ - (dispatch_queue_t)methodQueue scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height); } - UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size]; + UIGraphicsBeginImageContextWithOptions(size, NO, 0); if (renderInContext) { // this comes with some trade-offs such as inability to capture gradients or scrollview's content in full but it works for large views @@ -117,8 +117,8 @@ - (dispatch_queue_t)methodQueue // this doesn't work for large views and reports incorrect success even though the image is blank success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES]; } - - UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {}]; + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); if (snapshotContentContainer) { // Restore scroll & frame @@ -152,11 +152,11 @@ - (dispatch_queue_t)methodQueue NSString *res = nil; if ([result isEqualToString:@"base64"]) { // Return as a base64 raw string - res = [data base64EncodedStringWithOptions: 0]; + res = [data base64EncodedStringWithOptions: NSDataBase64EncodingEndLineWithLineFeed]; } else if ([result isEqualToString:@"data-uri"]) { // Return as a base64 data uri string - NSString *base64 = [data base64EncodedStringWithOptions: 0]; + NSString *base64 = [data base64EncodedStringWithOptions: NSDataBase64EncodingEndLineWithLineFeed]; NSString *imageFormat = ([format isEqualToString:@"jpg"]) ? @"jpeg" : format; res = [NSString stringWithFormat:@"data:image/%@;base64,%@", imageFormat, base64]; } diff --git a/node_modules/react-native-view-shot/src/specs/NativeRNViewShot.ts b/node_modules/react-native-view-shot/src/specs/NativeRNViewShot.ts index a6f4c00..1e9e6ce 100644 --- a/node_modules/react-native-view-shot/src/specs/NativeRNViewShot.ts +++ b/node_modules/react-native-view-shot/src/specs/NativeRNViewShot.ts @@ -2,7 +2,7 @@ import type { TurboModule } from 'react-native'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { - releaseCapture: () => string; + releaseCapture: (uri: string) => void; captureRef: (tag: number, options: Object) => Promise captureScreen: (options: Object) => Promise; } ================================================ FILE: apps/paper-macos-example/.bundle/config ================================================ BUNDLE_PATH: "vendor/bundle" BUNDLE_FORCE_RUBY_PLATFORM: 1 ================================================ FILE: apps/paper-macos-example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate ios/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof .cxx/ *.keystore !debug.keystore # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ **/fastlane/report.xml **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output # Bundle artifact *.jsbundle # Ruby / CocoaPods /ios/Pods/ /vendor/bundle/ # Temporary files created by Metro to check the health of the file watcher .metro-health-check* # testing /coverage ================================================ FILE: apps/paper-macos-example/.prettierrc.js ================================================ module.exports = { arrowParens: 'avoid', bracketSameLine: true, bracketSpacing: false, singleQuote: true, trailingComma: 'all', }; ================================================ FILE: apps/paper-macos-example/.watchmanconfig ================================================ {} ================================================ FILE: apps/paper-macos-example/Gemfile ================================================ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby ">= 2.6.10" # Cocoapods 1.15 introduced a bug which break the build. We will remove the upper # bound in the template on Cocoapods with next React Native release. gem 'cocoapods', '>= 1.13', '< 1.15' gem 'activesupport', '>= 6.1.7.5', '< 7.1.0' gem "bigdecimal" gem "logger" gem "benchmark" gem "mutex_m" ================================================ FILE: apps/paper-macos-example/__tests__/App.test.tsx ================================================ /** * @format */ import 'react-native'; import React from 'react'; import App from '../App'; // Note: import explicitly to use the types shipped with jest. import {it} from '@jest/globals'; // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; it('renders correctly', () => { renderer.create(); }); ================================================ FILE: apps/paper-macos-example/app.json ================================================ { "name": "PaperMacOSExample", "displayName": "PaperMacOSExample" } ================================================ FILE: apps/paper-macos-example/babel.config.js ================================================ module.exports = { presets: ['module:metro-react-native-babel-preset'], plugins: [ [ 'module-resolver', { extensions: ['.js', '.ts', '.tsx'], alias: { 'react-native': './node_modules/react-native-macos', }, }, ], ['react-native-reanimated/plugin', {processNestedWorklets: true}], ], }; ================================================ FILE: apps/paper-macos-example/index.js ================================================ /** * @format */ import {AppRegistry} from 'react-native'; import App from '../common'; import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => App); ================================================ FILE: apps/paper-macos-example/jest.config.js ================================================ module.exports = { preset: 'react-native', }; ================================================ FILE: apps/paper-macos-example/macos/.gitignore ================================================ # CocoaPods Pods/ .xcode.env.local ================================================ FILE: apps/paper-macos-example/macos/.xcode.env ================================================ export NODE_BINARY=$(command -v node) ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/AppDelegate.h ================================================ #import #import @interface AppDelegate : RCTAppDelegate @end ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/AppDelegate.mm ================================================ #import "AppDelegate.h" #import @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)notification { self.moduleName = @"PaperMacOSExample"; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. self.initialProps = @{}; return [super applicationDidFinishLaunching:notification]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. /// /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. - (BOOL)concurrentRootEnabled { #ifdef RN_FABRIC_ENABLED return true; #else return false; #endif } @end ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { "idiom" : "mac", "scale" : "2x", "size" : "512x512" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains localhost NSExceptionAllowsInsecureHTTPLoads NSMainStoryboardFile Main NSPrincipalClass NSApplication NSSupportsAutomaticTermination NSSupportsSuddenTermination ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/PaperMacOSExample.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only com.apple.security.network.client ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample-macOS/main.m ================================================ #import int main(int argc, const char *argv[]) { return NSApplicationMain(argc, argv); } ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5142014C2437B4B30078DB4F /* AppDelegate.mm */; }; 514201522437B4B40078DB4F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 514201512437B4B40078DB4F /* Assets.xcassets */; }; 514201552437B4B40078DB4F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 514201532437B4B40078DB4F /* Main.storyboard */; }; 514201582437B4B40078DB4F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 514201572437B4B40078DB4F /* main.m */; }; 735DA51C525CB9043DAA8325 /* libPods-PaperMacOSExample-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E5D302ACB3EF5BE37E96E87 /* libPods-PaperMacOSExample-macOS.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 13B07F961A680F5B00A75B9A /* PaperMacOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PaperMacOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 514201492437B4B30078DB4F /* PaperMacOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PaperMacOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5142014B2437B4B30078DB4F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 5142014C2437B4B30078DB4F /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = ""; }; 514201512437B4B40078DB4F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 514201542437B4B40078DB4F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 514201562437B4B40078DB4F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 514201572437B4B40078DB4F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 514201592437B4B40078DB4F /* PaperMacOSExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PaperMacOSExample.entitlements; sourceTree = ""; }; 540B84DE650D6DCC381BBB64 /* Pods-PaperMacOSExample-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PaperMacOSExample-macOS.debug.xcconfig"; path = "Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS.debug.xcconfig"; sourceTree = ""; }; 6E5D302ACB3EF5BE37E96E87 /* libPods-PaperMacOSExample-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PaperMacOSExample-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B6263DDE42469F6A500FCF05 /* Pods-PaperMacOSExample-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PaperMacOSExample-macOS.release.xcconfig"; path = "Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS.release.xcconfig"; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 514201462437B4B30078DB4F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 735DA51C525CB9043DAA8325 /* libPods-PaperMacOSExample-macOS.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 6E5D302ACB3EF5BE37E96E87 /* libPods-PaperMacOSExample-macOS.a */, ); name = Frameworks; sourceTree = ""; }; 303D916010AF14CD581EE1BD /* Pods */ = { isa = PBXGroup; children = ( 540B84DE650D6DCC381BBB64 /* Pods-PaperMacOSExample-macOS.debug.xcconfig */, B6263DDE42469F6A500FCF05 /* Pods-PaperMacOSExample-macOS.release.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; 5142014A2437B4B30078DB4F /* PaperMacOSExample-macOS */ = { isa = PBXGroup; children = ( 5142014B2437B4B30078DB4F /* AppDelegate.h */, 5142014C2437B4B30078DB4F /* AppDelegate.mm */, 514201512437B4B40078DB4F /* Assets.xcassets */, 514201532437B4B40078DB4F /* Main.storyboard */, 514201562437B4B40078DB4F /* Info.plist */, 514201572437B4B40078DB4F /* main.m */, 514201592437B4B40078DB4F /* PaperMacOSExample.entitlements */, ); path = "PaperMacOSExample-macOS"; sourceTree = ""; }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( ); name = Libraries; sourceTree = ""; }; 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( 5142014A2437B4B30078DB4F /* PaperMacOSExample-macOS */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, 303D916010AF14CD581EE1BD /* Pods */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* PaperMacOSExample.app */, 514201492437B4B30078DB4F /* PaperMacOSExample.app */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 13B07F861A680F5B00A75B9A /* PaperMacOSExample-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "PaperMacOSExample-iOS" */; buildPhases = ( 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, ); buildRules = ( ); dependencies = ( ); name = "PaperMacOSExample-iOS"; productName = PaperMacOSExample; productReference = 13B07F961A680F5B00A75B9A /* PaperMacOSExample.app */; productType = "com.apple.product-type.application"; }; 514201482437B4B30078DB4F /* PaperMacOSExample-macOS */ = { isa = PBXNativeTarget; buildConfigurationList = 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "PaperMacOSExample-macOS" */; buildPhases = ( 61B2948F4C3B372137FE0033 /* [CP] Check Pods Manifest.lock */, 514201452437B4B30078DB4F /* Sources */, 514201462437B4B30078DB4F /* Frameworks */, 514201472437B4B30078DB4F /* Resources */, 381D8A6E24576A4E00465D17 /* Bundle React Native code and images */, A16FF77180B75F3128EDCEA7 /* [CP] Embed Pods Frameworks */, F98C670A7FD9C4F1ED76034E /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = "PaperMacOSExample-macOS"; productName = PaperMacOSExample; productReference = 514201492437B4B30078DB4F /* PaperMacOSExample.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1130; TargetAttributes = { 13B07F861A680F5B00A75B9A = { LastSwiftMigration = 1120; }; 514201482437B4B30078DB4F = { CreatedOnToolsVersion = 11.4; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "PaperMacOSExample" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 83CBB9F61A601CBA00E9B192; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* PaperMacOSExample-iOS */, 514201482437B4B30078DB4F /* PaperMacOSExample-macOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 13B07F8E1A680F5B00A75B9A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 514201472437B4B30078DB4F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 514201522437B4B40078DB4F /* Assets.xcassets in Resources */, 514201552437B4B40078DB4F /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native-macos/scripts/react-native-xcode.sh\n"; }; 381D8A6E24576A4E00465D17 /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Bundle React Native code and images"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native-macos/scripts/react-native-xcode.sh\n"; }; 61B2948F4C3B372137FE0033 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-PaperMacOSExample-macOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; A16FF77180B75F3128EDCEA7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS-frameworks.sh", "${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/macosx/hermes.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; F98C670A7FD9C4F1ED76034E /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PaperMacOSExample-macOS/Pods-PaperMacOSExample-macOS-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 13B07F871A680F5B00A75B9A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 514201452437B4B30078DB4F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 514201582437B4B40078DB4F /* main.m in Sources */, 5142014D2437B4B30078DB4F /* AppDelegate.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 514201532437B4B40078DB4F /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 514201542437B4B40078DB4F /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; INFOPLIST_FILE = "PaperMacOSExample-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperMacOSExample; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = "PaperMacOSExample-iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperMacOSExample; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 5142015B2437B4B40078DB4F /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 540B84DE650D6DCC381BBB64 /* Pods-PaperMacOSExample-macOS.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; INFOPLIST_FILE = "PaperMacOSExample-macos/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperMacOSExample; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 5142015C2437B4B40078DB4F /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = B6263DDE42469F6A500FCF05 /* Pods-PaperMacOSExample-macOS.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = "PaperMacOSExample-macos/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = PaperMacOSExample; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Release; }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; }; name = Debug; }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LIBRARY_SEARCH_PATHS = ( "$(SDKROOT)/usr/lib/swift", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", " ", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "PaperMacOSExample-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, 13B07F951A680F5B00A75B9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "PaperMacOSExample-macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 5142015B2437B4B40078DB4F /* Debug */, 5142015C2437B4B40078DB4F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "PaperMacOSExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA211A601CBA00E9B192 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; } ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample.xcodeproj/xcshareddata/xcschemes/PaperMacOSExample-macOS.xcscheme ================================================ ================================================ FILE: apps/paper-macos-example/macos/PaperMacOSExample.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: apps/paper-macos-example/macos/Podfile ================================================ require_relative '../node_modules/react-native-macos/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' ENV['RCT_NEW_ARCH_ENABLED'] = '0' prepare_react_native_project! target 'PaperMacOSExample-macOS' do platform :macos, '10.15' use_native_modules! # Flags change depending on the env values. flags = get_default_flags() use_react_native!( :path => '../node_modules/react-native-macos', :hermes_enabled => false, :fabric_enabled => false, # Flipper is not compatible w/ macOS :flipper_configuration => FlipperConfiguration.disabled, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) post_install do |installer| react_native_post_install(installer) end end ================================================ FILE: apps/paper-macos-example/macos/PrivacyInfo.xcprivacy ================================================ NSPrivacyAccessedAPITypes NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons C617.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons CA92.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategorySystemBootTime NSPrivacyAccessedAPITypeReasons 35F9.1 NSPrivacyCollectedDataTypes NSPrivacyTracking ================================================ FILE: apps/paper-macos-example/metro.config.js ================================================ /** * Metro configuration for React Native * https://github.com/facebook/react-native * * @format */ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const path = require('path'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const modules = [...Object.keys(pack.peerDependencies), 'react-native-macos']; const config = { projectRoot: __dirname, watchFolders: [root], resolver: { blockList: exclusionList( modules.map( m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), ), ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, }, }), assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry', }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/paper-macos-example/package.json ================================================ { "name": "PaperMacOSExample", "version": "0.0.1", "private": true, "scripts": { "macos": "react-native run-macos", "lint": "eslint .", "start": "react-native start", "test": "jest", "postinstall": "patch-package" }, "dependencies": { "@react-native-async-storage/async-storage": "^2.0.0", "@react-navigation/native": "^6.1.18", "@react-navigation/native-stack": "^6.11.0", "@react-navigation/stack": "^6.4.1", "react": "18.2.0", "react-native": "0.73.4", "react-native-gesture-handler": "^2.20.0", "react-native-macos": "^0.73.35", "react-native-reanimated": "3.15.0", "react-native-safe-area-context": "^4.11.0", "react-native-screens": "^3.34.0", "react-native-svg": "link:../../" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native-community/eslint-config": "^3.0.0", "@react-native/babel-preset": "0.73.21", "@react-native/eslint-config": "0.73.2", "@react-native/metro-config": "0.73.5", "@react-native/typescript-config": "0.73.1", "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "metro-react-native-babel-preset": "0.73.5", "patch-package": "^8.0.0", "prettier": "2.8.8", "react-test-renderer": "18.2.0", "typescript": "5.0.4" }, "engines": { "node": ">=18" } } ================================================ FILE: apps/paper-macos-example/tsconfig.json ================================================ { "extends": "@react-native/typescript-config/tsconfig.json" } ================================================ FILE: apps/paper-windows-example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate **/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof .cxx/ *.keystore !debug.keystore # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ **/fastlane/report.xml **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output # Bundle artifact *.jsbundle # Ruby / CocoaPods **/Pods/ /vendor/bundle/ # Temporary files created by Metro to check the health of the file watcher .metro-health-check* # testing /coverage # Yarn .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions ================================================ FILE: apps/paper-windows-example/.watchmanconfig ================================================ {} ================================================ FILE: apps/paper-windows-example/app.json ================================================ { "name": "Example", "displayName": "Example" } ================================================ FILE: apps/paper-windows-example/babel.config.js ================================================ module.exports = { presets: ['module:@react-native/babel-preset'], }; ================================================ FILE: apps/paper-windows-example/index.js ================================================ /** * @format */ import { AppRegistry } from 'react-native'; import App from '../common'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => App); ================================================ FILE: apps/paper-windows-example/jest.config.js ================================================ module.exports = { preset: 'react-native', }; ================================================ FILE: apps/paper-windows-example/metro.config.js ================================================ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); /** * Metro configuration * https://facebook.github.io/metro/docs/configuration * * @type {import('metro-config').MetroConfig} */ const path = require('path'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const escape = require('escape-string-regexp'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const fs = require('fs'); const rnwPath = fs.realpathSync( path.resolve(require.resolve('react-native-windows/package.json'), '..') ); const modules = [...Object.keys(pack.peerDependencies), 'react-native-windows']; const config = { projectRoot: __dirname, watchFolders: [root], // We need to make sure that only one version is loaded for peerDependencies // So we exclude them at the root, and alias them to the versions in example's node_modules resolver: { blockList: exclusionList( modules.map( (m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) ), // This stops "react-native run-windows" from causing the metro server to // crash if its already running new RegExp( `${path.join(__dirname, 'windows').replace(/[/\\]+/g, '/')}.*` ), new RegExp(`${path.join(__dirname, 'macos').replace(/[/\\]+/g, '/')}.*`), // This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip or other files produced by msbuild new RegExp(`${rnwPath}/build/.*`), new RegExp(`${rnwPath}/target/.*`), /.*\.ProjectImports\.zip/ ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, }, }), // This fixes the 'missing-asset-registry-path` error (see https://github.com/microsoft/react-native-windows/issues/11437) assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry', }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/paper-windows-example/package.json ================================================ { "name": "PaperWindowsExample", "version": "0.0.1", "private": true, "scripts": { "lint": "eslint .", "windows": "react-native run-windows", "start": "react-native start", "test": "jest", "tsc": "tsc --noEmit", "postinstall": "patch-package" }, "dependencies": { "@react-native-async-storage/async-storage": "^2.0.0", "@react-navigation/native": "^6.1.18", "@react-navigation/native-stack": "^6.11.0", "@react-navigation/stack": "^6.4.1", "react": "18.3.1", "react-dom": "^18.2.0", "react-native": "0.76.0", "react-native-gesture-handler": "^2.20.2", "react-native-reanimated": "^3.16.1", "react-native-safe-area-context": "^4.11.1", "react-native-screens": "3.35.0", "react-native-svg": "link:../../", "react-native-windows": "0.76.0" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", "@react-native-community/cli": "15.0.0-alpha.2", "@react-native-community/cli-platform-android": "15.0.0-alpha.2", "@react-native-community/cli-platform-ios": "15.0.0-alpha.2", "@react-native/babel-preset": "0.76.0", "@react-native/eslint-config": "0.76.0", "@react-native/metro-config": "0.76.0", "@react-native/typescript-config": "0.76.0", "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "prettier": "2.8.8", "react-native-dotenv": "^3.4.11", "react-test-renderer": "18.3.1", "typescript": "5.0.4" }, "engines": { "node": ">=18" } } ================================================ FILE: apps/paper-windows-example/patches/react-native-windows+0.74.23.patch ================================================ diff --git a/node_modules/react-native-windows/Microsoft.ReactNative/Modules/NativeUIManager.cpp b/node_modules/react-native-windows/Microsoft.ReactNative/Modules/NativeUIManager.cpp index fb25176..eb1201a 100644 --- a/node_modules/react-native-windows/Microsoft.ReactNative/Modules/NativeUIManager.cpp +++ b/node_modules/react-native-windows/Microsoft.ReactNative/Modules/NativeUIManager.cpp @@ -309,16 +309,10 @@ static YGValue YGValueOrDefault( return YGValue{static_cast(pct.asDouble()), YGUnitPercent}; } if (str.length() > 2 && (str.compare(str.length() - 2, 2, "pt") || str.compare(str.length() - 2, 2, "px"))) { - shadowNode.RedBox( - "Value '" + value.AsString() + "' for " + key + " is invalid. Cannot be converted to YGValue. '" + - str.substr((str.length() - 2), 2) + "' unit not needed. Simply use integer value."); return defaultValue; } } - shadowNode.RedBox( - "Value '" + value.AsString() + "' for " + key + - " is invalid. Cannot be converted to YGValue. Did you forget the %? Otherwise, simply use integer value."); return defaultValue; } ================================================ FILE: apps/paper-windows-example/windows/.gitignore ================================================ *AppPackages* *BundleArtifacts* #OS junk files [Tt]humbs.db *.DS_Store #Visual Studio files *.[Oo]bj *.user *.aps *.pch *.vspscc *.vssscc *_i.c *_p.c *.ncb *.suo *.tlb *.tlh *.bak *.[Cc]ache *.ilk *.log *.lib *.sbr *.sdf *.opensdf *.opendb *.unsuccessfulbuild ipch/ [Oo]bj/ [Bb]in [Dd]ebug*/ [Rr]elease*/ Ankh.NoLoad # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb #MonoDevelop *.pidb *.userprefs #Tooling _ReSharper*/ *.resharper [Tt]est[Rr]esult* *.sass-cache #Project files [Bb]uild/ #Subversion files .svn # Office Temp Files ~$* # vim Temp Files *~ #NuGet packages/ *.nupkg #ncrunch *ncrunch* *crunch*.local.xml # visual studio database projects *.dbmdl #Test files *.testsettings #Other files *.DotSettings .vs/ *project.lock.json #Files generated by the VS build **/Generated Files/** ================================================ FILE: apps/paper-windows-example/windows/Example/.gitignore ================================================ /Bundle ================================================ FILE: apps/paper-windows-example/windows/Example/App.cpp ================================================ #include "pch.h" #include "App.h" #include "AutolinkedNativeModules.g.h" #include "ReactPackageProvider.h" using namespace winrt; using namespace xaml; using namespace xaml::Controls; using namespace xaml::Navigation; using namespace Windows::ApplicationModel; namespace winrt::Example::implementation { /// /// Initializes the singleton application object. This is the first line of /// authored code executed, and as such is the logical equivalent of main() or /// WinMain(). /// App::App() noexcept { #if BUNDLE JavaScriptBundleFile(L"index.windows"); InstanceSettings().UseFastRefresh(false); #else JavaScriptBundleFile(L"index"); InstanceSettings().UseFastRefresh(true); #endif #if _DEBUG InstanceSettings().UseDirectDebugger(true); InstanceSettings().UseDeveloperSupport(true); #else InstanceSettings().UseDirectDebugger(false); InstanceSettings().UseDeveloperSupport(false); #endif RegisterAutolinkedNativeModulePackages(PackageProviders()); // Includes any autolinked modules PackageProviders().Append(make()); // Includes all modules in this project InitializeComponent(); } /// /// Invoked when the application is launched normally by the end user. Other entry points /// will be used such as when the application is launched to open a specific file. /// /// Details about the launch request and process. void App::OnLaunched(activation::LaunchActivatedEventArgs const& e) { super::OnLaunched(e); Frame rootFrame = Window::Current().Content().as(); rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); } /// /// Invoked when the application is activated by some means other than normal launching. /// void App::OnActivated(Activation::IActivatedEventArgs const &e) { auto preActivationContent = Window::Current().Content(); super::OnActivated(e); if (!preActivationContent && Window::Current()) { Frame rootFrame = Window::Current().Content().as(); rootFrame.Navigate(xaml_typename(), nullptr); } } /// /// Invoked when application execution is being suspended. Application state is saved /// without knowing whether the application will be terminated or resumed with the contents /// of memory still intact. /// /// The source of the suspend request. /// Details about the suspend request. void App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e) { // Save application state and stop any background activity } /// /// Invoked when Navigation to a certain page fails /// /// The Frame which failed navigation /// Details about the navigation failure void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e) { throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name); } } // namespace winrt::Example::implementation ================================================ FILE: apps/paper-windows-example/windows/Example/App.h ================================================ #pragma once #include "App.xaml.g.h" #include namespace activation = winrt::Windows::ApplicationModel::Activation; namespace winrt::Example::implementation { struct App : AppT { App() noexcept; void OnLaunched(activation::LaunchActivatedEventArgs const&); void OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs const &e); void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&); void OnNavigationFailed(IInspectable const&, xaml::Navigation::NavigationFailedEventArgs const&); private: using super = AppT; }; } // namespace winrt::Example::implementation ================================================ FILE: apps/paper-windows-example/windows/Example/App.idl ================================================ namespace Example { } ================================================ FILE: apps/paper-windows-example/windows/Example/App.xaml ================================================  ================================================ FILE: apps/paper-windows-example/windows/Example/AutolinkedNativeModules.g.cpp ================================================ // AutolinkedNativeModules.g.cpp contents generated by "npx @react-native-community/cli autolink-windows" // clang-format off #include "pch.h" #include "AutolinkedNativeModules.g.h" // Includes from @react-native-async-storage/async-storage #include // Includes from react-native-screens #include // Includes from react-native-svg #include namespace winrt::Microsoft::ReactNative { void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders) { // IReactPackageProviders from @react-native-async-storage/async-storage packageProviders.Append(winrt::ReactNativeAsyncStorage::ReactPackageProvider()); // IReactPackageProviders from react-native-screens packageProviders.Append(winrt::RNScreens::ReactPackageProvider()); // IReactPackageProviders from react-native-svg packageProviders.Append(winrt::RNSVG::ReactPackageProvider()); } } ================================================ FILE: apps/paper-windows-example/windows/Example/AutolinkedNativeModules.g.h ================================================ // AutolinkedNativeModules.g.h contents generated by "npx @react-native-community/cli autolink-windows" // clang-format off #pragma once namespace winrt::Microsoft::ReactNative { void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders); } ================================================ FILE: apps/paper-windows-example/windows/Example/AutolinkedNativeModules.g.props ================================================ ================================================ FILE: apps/paper-windows-example/windows/Example/AutolinkedNativeModules.g.targets ================================================ {4855D892-E16C-404D-8286-0089E0F7F9C4} {d638f49e-29d2-4699-ac52-facd82fa7138} {7acf84ec-efba-4043-8e14-40b159508902} ================================================ FILE: apps/paper-windows-example/windows/Example/Example.vcxproj ================================================ true true true {0d798b26-17a1-497a-8524-201a4eac00dc} Example Example en-US 17.0 true Windows Store 10.0 $([MSBuild]::GetDirectoryNameOfFileAbove($(SolutionDir), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ Debug ARM64 Debug Win32 Debug x64 Release ARM64 Release Win32 Release x64 Application Unicode true true false true false Use pch.h $(IntDir)pch.pch Level4 %(AdditionalOptions) /bigobj 4453;28204 _DEBUG;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) MainPage.xaml Code App.xaml Designer Designer MainPage.xaml Code Create App.xaml App.xaml MainPage.xaml Code false Designer This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}. ================================================ FILE: apps/paper-windows-example/windows/Example/Example.vcxproj.filters ================================================  Assets Assets Assets Assets Assets Assets Assets {e48dc53e-40b1-40cb-970a-f89935452892} ================================================ FILE: apps/paper-windows-example/windows/Example/MainPage.cpp ================================================ #include "pch.h" #include "MainPage.h" #if __has_include("MainPage.g.cpp") #include "MainPage.g.cpp" #endif #include "App.h" using namespace winrt; using namespace xaml; namespace winrt::Example::implementation { MainPage::MainPage() { InitializeComponent(); auto app = Application::Current().as(); ReactRootView().ReactNativeHost(app->Host()); } } ================================================ FILE: apps/paper-windows-example/windows/Example/MainPage.h ================================================ #pragma once #include "MainPage.g.h" #include namespace winrt::Example::implementation { struct MainPage : MainPageT { MainPage(); }; } namespace winrt::Example::factory_implementation { struct MainPage : MainPageT { }; } ================================================ FILE: apps/paper-windows-example/windows/Example/MainPage.idl ================================================ #include "NamespaceRedirect.h" namespace Example { [default_interface] runtimeclass MainPage : XAML_NAMESPACE.Controls.Page { MainPage(); } } ================================================ FILE: apps/paper-windows-example/windows/Example/MainPage.xaml ================================================ ================================================ FILE: apps/paper-windows-example/windows/Example/Package.appxmanifest ================================================  Example mcota Assets\StoreLogo.png ================================================ FILE: apps/paper-windows-example/windows/Example/PropertySheet.props ================================================ ================================================ FILE: apps/paper-windows-example/windows/Example/ReactPackageProvider.cpp ================================================ #include "pch.h" #include "ReactPackageProvider.h" #include "NativeModules.h" using namespace winrt::Microsoft::ReactNative; namespace winrt::Example::implementation { void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept { AddAttributedModules(packageBuilder, true); } } // namespace winrt::Example::implementation ================================================ FILE: apps/paper-windows-example/windows/Example/ReactPackageProvider.h ================================================ #pragma once #include "winrt/Microsoft.ReactNative.h" namespace winrt::Example::implementation { struct ReactPackageProvider : winrt::implements { public: // IReactPackageProvider void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept; }; } // namespace winrt::Example::implementation ================================================ FILE: apps/paper-windows-example/windows/Example/packages.lock.json ================================================ { "version": 1, "dependencies": { "native,Version=v0.0": { "Microsoft.JavaScript.Hermes": { "type": "Direct", "requested": "[0.1.23, )", "resolved": "0.1.23", "contentHash": "cA9t1GjY4Yo0JD1AfA//e1lOwk48hLANfuX6GXrikmEBNZVr2TIX5ONJt5tqCnpZyLz6xGiPDgTfFNKbSfb21g==" }, "Microsoft.UI.Xaml": { "type": "Direct", "requested": "[2.8.0, )", "resolved": "2.8.0", "contentHash": "vxdHxTr63s5KVtNddMFpgvjBjUH50z7seq/5jLWmmSuf8poxg+sXrywkofUdE8ZstbpO9y3FL/IXXUcPYbeesA==", "dependencies": { "Microsoft.Web.WebView2": "1.0.1264.42" } }, "Microsoft.Windows.CppWinRT": { "type": "Direct", "requested": "[2.0.230706.1, )", "resolved": "2.0.230706.1", "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" }, "boost": { "type": "Transitive", "resolved": "1.83.0", "contentHash": "cy53VNMzysEMvhBixDe8ujPk67Fcj3v6FPHQnH91NYJNLHpc6jxa2xq9ruCaaJjE4M3YrGSHDi4uUSTGBWw6EQ==" }, "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" }, "common": { "type": "Project", "dependencies": { "boost": "[1.83.0, )" } }, "fmt": { "type": "Project" }, "folly": { "type": "Project", "dependencies": { "Fmt": "[1.0.0, )", "boost": "[1.83.0, )" } }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.1.23, )", "Microsoft.UI.Xaml": "[2.8.0, )", "ReactCommon": "[1.0.0, )", "boost": "[1.83.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { "Folly": "[1.0.0, )", "boost": "[1.83.0, )" } }, "reactnativeasyncstorage": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "Microsoft.UI.Xaml": "[2.8.0, )" } }, "rnscreens": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "Microsoft.UI.Xaml": "[2.8.0, )" } }, "rnsvg": { "type": "Project", "dependencies": { "Microsoft.ReactNative": "[1.0.0, )", "Microsoft.UI.Xaml": "[2.8.0, )" } }, "rnviewshot": { "type": "Project" } }, "native,Version=v0.0/win10-arm": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-arm-aot": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-arm64-aot": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-x64": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-x64-aot": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-x86": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } }, "native,Version=v0.0/win10-x86-aot": { "Microsoft.Web.WebView2": { "type": "Transitive", "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" } } } } ================================================ FILE: apps/paper-windows-example/windows/Example/pch.cpp ================================================ #include "pch.h" ================================================ FILE: apps/paper-windows-example/windows/Example/pch.h ================================================ #pragma once #define NOMINMAX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace winrt::Windows::Foundation; ================================================ FILE: apps/paper-windows-example/windows/Example.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example", "Example\Example.vcxproj", "{0D798B26-17A1-497A-8524-201A4EAC00DC}" ProjectSection(ProjectDependencies) = postProject {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\node_modules\react-native-windows\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNSVG", "..\node_modules\react-native-svg\windows\RNSVG\RNSVG.vcxproj", "{7ACF84EC-EFBA-4043-8E14-40B159508902}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNScreens", "..\node_modules\react-native-screens\windows\RNScreens\RNScreens.vcxproj", "{D638F49E-29D2-4699-AC52-FACD82FA7138}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactNativeAsyncStorage", "..\node_modules\@react-native-async-storage\async-storage\windows\ReactNativeAsyncStorage\ReactNativeAsyncStorage.vcxproj", "{4855D892-E16C-404D-8286-0089E0F7F9C4}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ReactNative.Managed", "..\node_modules\react-native-windows\Microsoft.ReactNative.Managed\Microsoft.ReactNative.Managed.csproj", "{F2824844-CE15-4242-9420-308923CD76C3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ReactNative.Managed.CodeGen", "..\node_modules\react-native-windows\Microsoft.ReactNative.Managed.CodeGen\Microsoft.ReactNative.Managed.CodeGen.csproj", "{ADED4FBE-887D-4271-AF24-F0823BCE7961}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|ARM64.Build.0 = Debug|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|ARM64.Deploy.0 = Debug|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x64.ActiveCfg = Debug|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x64.Build.0 = Debug|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x64.Deploy.0 = Debug|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x86.ActiveCfg = Debug|Win32 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x86.Build.0 = Debug|Win32 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Debug|x86.Deploy.0 = Debug|Win32 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|ARM64.ActiveCfg = Release|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|ARM64.Build.0 = Release|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|ARM64.Deploy.0 = Release|ARM64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x64.ActiveCfg = Release|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x64.Build.0 = Release|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x64.Deploy.0 = Release|x64 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x86.ActiveCfg = Release|Win32 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x86.Build.0 = Release|Win32 {0D798B26-17A1-497A-8524-201A4EAC00DC}.Release|x86.Deploy.0 = Release|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32 {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32 {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM64.ActiveCfg = Debug|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM64.Build.0 = Debug|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x64.ActiveCfg = Debug|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x64.Build.0 = Debug|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x86.ActiveCfg = Debug|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x86.Build.0 = Debug|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|x86.Deploy.0 = Debug|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM64.ActiveCfg = Release|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM64.Build.0 = Release|ARM64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x64.ActiveCfg = Release|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x64.Build.0 = Release|x64 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x86.ActiveCfg = Release|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x86.Build.0 = Release|Win32 {7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|x86.Deploy.0 = Release|Win32 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|ARM64.Build.0 = Debug|ARM64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|x64.ActiveCfg = Debug|x64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|x64.Build.0 = Debug|x64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|x86.ActiveCfg = Debug|Win32 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Debug|x86.Build.0 = Debug|Win32 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|ARM64.ActiveCfg = Release|ARM64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|ARM64.Build.0 = Release|ARM64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|x64.ActiveCfg = Release|x64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|x64.Build.0 = Release|x64 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|x86.ActiveCfg = Release|Win32 {D638F49E-29D2-4699-AC52-FACD82FA7138}.Release|x86.Build.0 = Release|Win32 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|ARM64.Build.0 = Debug|ARM64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|x64.ActiveCfg = Debug|x64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|x64.Build.0 = Debug|x64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|x86.ActiveCfg = Debug|Win32 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Debug|x86.Build.0 = Debug|Win32 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|ARM64.ActiveCfg = Release|ARM64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|ARM64.Build.0 = Release|ARM64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|x64.ActiveCfg = Release|x64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|x64.Build.0 = Release|x64 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|x86.ActiveCfg = Release|Win32 {4855D892-E16C-404D-8286-0089E0F7F9C4}.Release|x86.Build.0 = Release|Win32 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM64.Build.0 = Debug|ARM64 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x64.ActiveCfg = Debug|x64 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x64.Build.0 = Debug|x64 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x86.ActiveCfg = Debug|x86 {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x86.Build.0 = Debug|x86 {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM64.ActiveCfg = Release|ARM64 {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM64.Build.0 = Release|ARM64 {F2824844-CE15-4242-9420-308923CD76C3}.Release|x64.ActiveCfg = Release|x64 {F2824844-CE15-4242-9420-308923CD76C3}.Release|x64.Build.0 = Release|x64 {F2824844-CE15-4242-9420-308923CD76C3}.Release|x86.ActiveCfg = Release|x86 {F2824844-CE15-4242-9420-308923CD76C3}.Release|x86.Build.0 = Release|x86 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM64.ActiveCfg = Debug|ARM64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM64.Build.0 = Debug|ARM64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x64.ActiveCfg = Debug|x64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x64.Build.0 = Debug|x64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x86.ActiveCfg = Debug|x86 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x86.Build.0 = Debug|x86 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM64.ActiveCfg = Release|ARM64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM64.Build.0 = Release|ARM64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x64.ActiveCfg = Release|x64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x64.Build.0 = Release|x64 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x86.ActiveCfg = Release|x86 {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9 ..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9 ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 EndGlobalSection EndGlobal ================================================ FILE: apps/paper-windows-example/windows/ExperimentalFeatures.props ================================================ true false false true ================================================ FILE: apps/paper-windows-example/windows/NuGet.Config ================================================ ================================================ FILE: apps/tests-example/.bundle/config ================================================ BUNDLE_PATH: "vendor/bundle" BUNDLE_FORCE_RUBY_PLATFORM: 1 ================================================ FILE: apps/tests-example/.gitignore ================================================ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate **/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof .cxx/ *.keystore !debug.keystore .kotlin/ # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ **/fastlane/report.xml **/fastlane/Preview.html **/fastlane/screenshots **/fastlane/test_output # Bundle artifact *.jsbundle # Ruby / CocoaPods **/Pods/ vendor/bundle/ # Temporary files created by Metro to check the health of the file watcher .metro-health-check* # testing /coverage # Yarn .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions ================================================ FILE: apps/tests-example/.watchmanconfig ================================================ {} ================================================ FILE: apps/tests-example/Gemfile ================================================ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby ">= 2.6.10" # Exclude problematic versions of cocoapods and activesupport that causes build failures. gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' gem 'xcodeproj', '< 1.26.0' gem 'concurrent-ruby', '< 1.3.4' # Ruby 3.4.0 has removed some libraries from the standard library. gem 'bigdecimal' gem 'logger' gem 'benchmark' gem 'mutex_m' ================================================ FILE: apps/tests-example/__tests__/App.test.tsx ================================================ /** * @format */ import 'react-native'; import React from 'react'; import App from '../App'; // Note: import explicitly to use the types shipped with jest. import { it } from '@jest/globals'; // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; it('renders correctly', () => { renderer.create(); }); ================================================ FILE: apps/tests-example/android/app/build.gradle ================================================ apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. */ react { /* Folders */ // The root of your project, i.e. where "package.json" lives. Default is '../..' // root = file("../../") // The folder where the react-native NPM package is. Default is ../../node_modules/react-native // reactNativeDir = file("../../node_modules/react-native") // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen // codegenDir = file("../../node_modules/@react-native/codegen") // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js // cliFile = file("../../node_modules/react-native/cli.js") /* Variants */ // The list of variants to that are debuggable. For those we're going to // skip the bundling of the JS bundle and the assets. By default is just 'debug'. // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. // debuggableVariants = ["liteDebug", "prodDebug"] /* Bundling */ // A list containing the node command and its flags. Default is just 'node'. // nodeExecutableAndArgs = ["node"] // // The command to run when bundling. By default is 'bundle' // bundleCommand = "ram-bundle" // // The path to the CLI configuration file. Default is empty. // bundleConfig = file(../rn-cli.config.js) // // The name of the generated asset file containing your JS bundle // bundleAssetName = "MyApplication.android.bundle" // // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' // entryFile = file("../js/MyApplication.android.js") // // A list of extra flags to pass to the 'bundle' commands. // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle // extraPackagerArgs = [] /* Hermes Commands */ // The hermes compiler command to run. By default it is 'hermesc' // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" // // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // hermesFlags = ["-O", "-output-source-map"] /* Autolinking */ autolinkLibrariesWithApp() } /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false /** * The preferred build flavor of JavaScriptCore (JSC) * * For example, to use the international variant, you can use: * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+` * * The international variant includes ICU i18n library and necessary data * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * give correct results when using with locales other than en-US. Note that * this variant is about 6MiB larger per architecture than default. */ def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' android { ndkVersion rootProject.ext.ndkVersion buildToolsVersion rootProject.ext.buildToolsVersion compileSdk rootProject.ext.compileSdkVersion namespace "com.testsexample" defaultConfig { applicationId "com.testsexample" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } } buildTypes { debug { signingConfig signingConfigs.debug } release { // Caution! In production, you need to generate your own keystore file. // see https://reactnative.dev/docs/signed-apk-android. signingConfig signingConfigs.debug minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } } dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } } ================================================ FILE: apps/tests-example/android/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: ================================================ FILE: apps/tests-example/android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: apps/tests-example/android/app/src/main/java/com/testsexample/MainActivity.kt ================================================ package com.testsexample import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate class MainActivity : ReactActivity() { /** * Returns the name of the main component registered from JavaScript. This is used to schedule * rendering of the component. */ override fun getMainComponentName(): String = "TestsExample" /** * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] */ override fun createReactActivityDelegate(): ReactActivityDelegate = DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) } ================================================ FILE: apps/tests-example/android/app/src/main/java/com/testsexample/MainApplication.kt ================================================ package com.testsexample import android.app.Application import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactHost import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost class MainApplication : Application(), ReactApplication { override val reactHost: ReactHost by lazy { getDefaultReactHost( context = applicationContext, packageList = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) }, ) } override fun onCreate() { super.onCreate() loadReactNative(this) } } ================================================ FILE: apps/tests-example/android/app/src/main/res/drawable/rn_edit_text_material.xml ================================================ ================================================ FILE: apps/tests-example/android/app/src/main/res/values/strings.xml ================================================ TestsExample ================================================ FILE: apps/tests-example/android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: apps/tests-example/android/build.gradle ================================================ buildscript { ext { buildToolsVersion = "36.0.0" minSdkVersion = 24 compileSdkVersion = 36 targetSdkVersion = 36 ndkVersion = "27.1.12297006" kotlinVersion = "2.1.20" } repositories { google() mavenCentral() } dependencies { classpath("com.android.tools.build:gradle") classpath("com.facebook.react:react-native-gradle-plugin") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") } } apply plugin: "com.facebook.react.rootproject" ================================================ FILE: apps/tests-example/android/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: apps/tests-example/android/gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true # AndroidX package structure to make it clearer which packages are bundled with the # Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Use this property to specify which architecture you want to build. # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # Use this property to enable support to the new architecture. # This will allow you to use TurboModules and the Fabric render in # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. hermesEnabled=true # Use this property to enable edge-to-edge display support. # This allows your app to draw behind system bars for an immersive UI. # Note: Only works with ReactActivity and should not be used with custom Activity. edgeToEdgeEnabled=false ================================================ FILE: apps/tests-example/android/gradlew ================================================ #!/bin/sh # # Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # SPDX-License-Identifier: Apache-2.0 # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: apps/tests-example/android/gradlew.bat ================================================ @REM Copyright (c) Meta Platforms, Inc. and affiliates. @REM @REM This source code is licensed under the MIT license found in the @REM LICENSE file in the root directory of this source tree. @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @rem SPDX-License-Identifier: Apache-2.0 @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line set CLASSPATH= @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: apps/tests-example/android/settings.gradle ================================================ pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } plugins { id("com.facebook.react.settings") } extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } rootProject.name = 'TestsExample' include ':app' includeBuild('../node_modules/@react-native/gradle-plugin') ================================================ FILE: apps/tests-example/app.json ================================================ { "name": "TestsExample", "displayName": "TestsExample" } ================================================ FILE: apps/tests-example/babel.config.js ================================================ module.exports = { presets: ['module:@react-native/babel-preset'], }; ================================================ FILE: apps/tests-example/index.js ================================================ /** * @format */ import { AppRegistry } from 'react-native'; import App from '../common/test'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => App); ================================================ FILE: apps/tests-example/ios/.xcode.env ================================================ # This `.xcode.env` file is versioned and is used to source the environment # used when running script phases inside Xcode. # To customize your local environment, you can create an `.xcode.env.local` # file that is not versioned. # NODE_BINARY variable contains the PATH to the node executable. # # Customize the NODE_BINARY variable here. # For example, to use nvm with brew, add the following line # . "$(brew --prefix nvm)/nvm.sh" --no-use export NODE_BINARY=$(command -v node) ================================================ FILE: apps/tests-example/ios/Podfile ================================================ # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]}, )', __dir__]).strip platform :ios, min_ios_version_supported prepare_react_native_project! linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => linkage.to_sym end target 'TestsExample' do config = use_native_modules! use_react_native!( :path => config[:reactNativePath], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) post_install do |installer| react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false, # :ccache_enabled => true ) end end ================================================ FILE: apps/tests-example/ios/TestsExample/AppDelegate.swift ================================================ import UIKit import React import React_RCTAppDelegate import ReactAppDependencyProvider @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var reactNativeDelegate: ReactNativeDelegate? var reactNativeFactory: RCTReactNativeFactory? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { let delegate = ReactNativeDelegate() let factory = RCTReactNativeFactory(delegate: delegate) delegate.dependencyProvider = RCTAppDependencyProvider() reactNativeDelegate = delegate reactNativeFactory = factory window = UIWindow(frame: UIScreen.main.bounds) factory.startReactNative( withModuleName: "TestsExample", in: window, launchOptions: launchOptions ) return true } } class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { override func sourceURL(for bridge: RCTBridge) -> URL? { self.bundleURL() } override func bundleURL() -> URL? { #if DEBUG RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") #else Bundle.main.url(forResource: "main", withExtension: "jsbundle") #endif } } ================================================ FILE: apps/tests-example/ios/TestsExample/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: apps/tests-example/ios/TestsExample/Images.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: apps/tests-example/ios/TestsExample/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName TestsExample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads NSAllowsLocalNetworking NSLocationWhenInUseUsageDescription UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities arm64 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance ================================================ FILE: apps/tests-example/ios/TestsExample/LaunchScreen.storyboard ================================================ ================================================ FILE: apps/tests-example/ios/TestsExample/PrivacyInfo.xcprivacy ================================================ NSPrivacyAccessedAPITypes NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons C617.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons CA92.1 NSPrivacyAccessedAPIType NSPrivacyAccessedAPICategorySystemBootTime NSPrivacyAccessedAPITypeReasons 35F9.1 NSPrivacyCollectedDataTypes NSPrivacyTracking ================================================ FILE: apps/tests-example/ios/TestsExample.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 4DBD2015D535E20EC6C39D82 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8F64AB81A41BFF4FD17652F1 /* PrivacyInfo.xcprivacy */; }; 732CDC568E704E6F44B35643 /* libPods-TestsExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 69E2D7F497CEEEAC852E572B /* libPods-TestsExample.a */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 13B07F961A680F5B00A75B9A /* TestsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestsExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TestsExample/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TestsExample/Info.plist; sourceTree = ""; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = TestsExample/PrivacyInfo.xcprivacy; sourceTree = ""; }; 31147FF821344591ECF91105 /* Pods-TestsExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TestsExample.debug.xcconfig"; path = "Target Support Files/Pods-TestsExample/Pods-TestsExample.debug.xcconfig"; sourceTree = ""; }; 69E2D7F497CEEEAC852E572B /* libPods-TestsExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TestsExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = TestsExample/AppDelegate.swift; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = TestsExample/LaunchScreen.storyboard; sourceTree = ""; }; 8F64AB81A41BFF4FD17652F1 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = TestsExample/PrivacyInfo.xcprivacy; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; F9CE96A87F08D217E4116708 /* Pods-TestsExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TestsExample.release.xcconfig"; path = "Target Support Files/Pods-TestsExample/Pods-TestsExample.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 732CDC568E704E6F44B35643 /* libPods-TestsExample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 13B07FAE1A68108700A75B9A /* TestsExample */ = { isa = PBXGroup; children = ( 13B07FB51A68108700A75B9A /* Images.xcassets */, 761780EC2CA45674006654EE /* AppDelegate.swift */, 13B07FB61A68108700A75B9A /* Info.plist */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */, 8F64AB81A41BFF4FD17652F1 /* PrivacyInfo.xcprivacy */, ); name = TestsExample; sourceTree = ""; }; 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 69E2D7F497CEEEAC852E572B /* libPods-TestsExample.a */, ); name = Frameworks; sourceTree = ""; }; 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( ); name = Libraries; sourceTree = ""; }; 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( 13B07FAE1A68108700A75B9A /* TestsExample */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 83CBBA001A601CBA00E9B192 /* Products */, 2D16E6871FA4F8E400B85C8A /* Frameworks */, BBD78D7AC51CEA395F1C20DB /* Pods */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( 13B07F961A680F5B00A75B9A /* TestsExample.app */, ); name = Products; sourceTree = ""; }; BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( 31147FF821344591ECF91105 /* Pods-TestsExample.debug.xcconfig */, F9CE96A87F08D217E4116708 /* Pods-TestsExample.release.xcconfig */, ); path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 13B07F861A680F5B00A75B9A /* TestsExample */ = { isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TestsExample" */; buildPhases = ( D1E7467EB76FA64141FCDC5F /* [CP] Check Pods Manifest.lock */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 3AF9618FCC9D3F3651B00F2C /* [CP] Embed Pods Frameworks */, D47DF3B3DDC54BFA697BDD7E /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = TestsExample; productName = TestsExample; productReference = 13B07F961A680F5B00A75B9A /* TestsExample.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1210; TargetAttributes = { 13B07F861A680F5B00A75B9A = { LastSwiftMigration = 1120; }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TestsExample" */; compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 83CBB9F61A601CBA00E9B192; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 13B07F861A680F5B00A75B9A /* TestsExample */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 13B07F8E1A680F5B00A75B9A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 4DBD2015D535E20EC6C39D82 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(SRCROOT)/.xcode.env.local", "$(SRCROOT)/.xcode.env", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"\\\"$WITH_ENVIRONMENT\\\" \\\"$REACT_NATIVE_XCODE\\\"\"\n"; }; 3AF9618FCC9D3F3651B00F2C /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; D1E7467EB76FA64141FCDC5F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-TestsExample-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; D47DF3B3DDC54BFA697BDD7E /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-resources-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TestsExample/Pods-TestsExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 13B07F871A680F5B00A75B9A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 31147FF821344591ECF91105 /* Pods-TestsExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; INFOPLIST_FILE = TestsExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = TestsExample; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = F9CE96A87F08D217E4116708 /* Pods-TestsExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; INFOPLIST_FILE = TestsExample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = TestsExample; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", ); LIBRARY_SEARCH_PATHS = ( "\"$(SDKROOT)/usr/lib/swift\"", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = true; }; name = Debug; }; 83CBBA211A601CBA00E9B192 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", ); LIBRARY_SEARCH_PATHS = ( "\"$(SDKROOT)/usr/lib/swift\"", "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = "$(inherited)"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TestsExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, 13B07F951A680F5B00A75B9A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TestsExample" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, 83CBBA211A601CBA00E9B192 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; } ================================================ FILE: apps/tests-example/ios/TestsExample.xcodeproj/xcshareddata/xcschemes/TestsExample.xcscheme ================================================ ================================================ FILE: apps/tests-example/ios/TestsExample.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: apps/tests-example/ios/TestsExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: apps/tests-example/jest.config.js ================================================ module.exports = { preset: 'react-native', }; ================================================ FILE: apps/tests-example/metro.config.js ================================================ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); /** * Metro configuration * https://reactnative.dev/docs/metro * * @type {import('@react-native/metro-config').MetroConfig} */ const path = require('path'); const exclusionList = require('metro-config/private/defaults/exclusionList').default; const escape = require('escape-string-regexp'); const pack = require('../../package.json'); const root = path.resolve(__dirname, '../..'); const projectNodeModules = path.join(__dirname, 'node_modules'); const modules = [...Object.keys(pack.peerDependencies)]; const config = { projectRoot: __dirname, watchFolders: [root], // We need to make sure that only one version is loaded for peerDependencies // So we exclude them at the root, and alias them to the versions in example's node_modules resolver: { blacklistRE: exclusionList( modules.map( (m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) ) ), nodeModulesPaths: [projectNodeModules, path.join(__dirname, '../../')], extraNodeModules: modules.reduce((acc, name) => { acc[name] = path.join(__dirname, 'node_modules', name); return acc; }, {}), }, transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }), }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); ================================================ FILE: apps/tests-example/package.json ================================================ { "name": "TestsExample", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest" }, "dependencies": { "react": "19.2.0", "react-native": "0.83.0-rc.0", "react-native-safe-area-context": "^5.5.2", "react-native-svg": "link:../../" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", "@react-native-community/cli": "20.0.0-alpha.2", "@react-native-community/cli-platform-android": "20.0.0-alpha.2", "@react-native-community/cli-platform-ios": "20.0.0-alpha.2", "@react-native/babel-preset": "0.83.0-rc.0", "@react-native/eslint-config": "0.83.0-rc.0", "@react-native/metro-config": "0.83.0-rc.0", "@react-native/typescript-config": "0.83.0-rc.0", "@types/jest": "^29.5.13", "@types/react": "^19.2.0", "@types/react-test-renderer": "^19.1.0", "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", "react-test-renderer": "19.2.0", "typescript": "^5.8.3" }, "engines": { "node": ">=20" } } ================================================ FILE: apps/web-example/.gitignore ================================================ node_modules/ .expo/ dist/ npm-debug.* *.jks *.p8 *.p12 *.key *.mobileprovision *.orig.* web-build/ # macOS .DS_Store ================================================ FILE: apps/web-example/app.json ================================================ { "expo": { "name": "web-example", "slug": "web-example", "version": "1.0.0", "web": { "favicon": "./assets/favicon.png" }, "plugins": [ "expo-asset" ] } } ================================================ FILE: apps/web-example/babel.config.js ================================================ module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], plugins: ['react-native-worklets/plugin'], }; }; ================================================ FILE: apps/web-example/index.js ================================================ import '@expo/metro-runtime'; import { registerRootComponent } from 'expo'; import App from '../common'; // registerRootComponent calls AppRegistry.registerComponent('main', () => App); // It also ensures that whether you load the app in Expo Go or in a native build, // the environment is set up appropriately registerRootComponent(App); ================================================ FILE: apps/web-example/metro.config.js ================================================ // Learn more https://docs.expo.io/guides/customizing-metro const { getDefaultConfig } = require('expo/metro-config'); const path = require('path'); const config = getDefaultConfig(__dirname); // npm v7+ will install ../node_modules/react-native because of peerDependencies. // To prevent the incompatible react-native bewtween ./node_modules/react-native and ../node_modules/react-native, // excludes the one from the parent folder when bundling. config.resolver.blockList = [ ...Array.from(config.resolver.blockList ?? []), new RegExp(path.resolve('../..', 'node_modules', 'react-native')), new RegExp(path.resolve('../..', 'node_modules', 'react')), ]; config.resolver.nodeModulesPaths = [ path.resolve(__dirname, './node_modules'), path.resolve(__dirname, '../../node_modules'), ]; config.watchFolders = [path.resolve(__dirname, '../..')]; config.transformer.getTransformOptions = async () => ({ transform: { experimentalImportSupport: false, inlineRequires: true, }, }); module.exports = config; ================================================ FILE: apps/web-example/package.json ================================================ { "name": "web-example", "main": "index.js", "version": "0.0.1", "scripts": { "start": "expo start --web", "reset-project": "node ./scripts/reset-project.js", "test": "jest --watchAll", "lint": "expo lint", "postinstall": "patch-package" }, "jest": { "preset": "jest-expo" }, "dependencies": { "@expo/vector-icons": "^15.0.2", "@react-native-async-storage/async-storage": "^2.0.0", "@react-navigation/native": "^6.0.2", "@react-navigation/native-stack": "^6.11.0", "@react-navigation/stack": "^6.4.1", "expo": "54.0.12", "expo-asset": "~12.0.9", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.4", "react-native-gesture-handler": "^2.20.0", "react-native-reanimated": "~4.1.1", "react-native-safe-area-context": "~5.6.0", "react-native-svg": "link:../../", "react-native-svg-transformer": "^1.4.0", "react-native-view-shot": "4.0.3", "react-native-web": "^0.21.0", "react-native-worklets": "^0.6.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@expo/metro-runtime": "~6.1.2", "@react-native/metro-config": "^0.74.85", "@types/jest": "^29.5.12", "@types/react": "~19.1.10", "@types/react-test-renderer": "^18.0.7", "jest": "^29.2.1", "jest-expo": "~54.0.12", "patch-package": "^8.0.0", "react-test-renderer": "18.2.0", "typescript": "~5.9.2" }, "private": true } ================================================ FILE: apps/web-example/patches/react-native-worklets+0.6.0.patch ================================================ diff --git a/node_modules/react-native-worklets/lib/module/publicGlobals.js b/node_modules/react-native-worklets/lib/module/publicGlobals.js index b7b1143..9eaba53 100644 --- a/node_modules/react-native-worklets/lib/module/publicGlobals.js +++ b/node_modules/react-native-worklets/lib/module/publicGlobals.js @@ -1,4 +1,5 @@ 'use strict'; +import './runtimeKind.js'; /* eslint-disable reanimated/use-global-this */ // eslint-disable-next-line @typescript-eslint/no-unused-vars ================================================ FILE: apps/web-example/tsconfig.json ================================================ { "compilerOptions": {}, "extends": "expo/tsconfig.base" } ================================================ FILE: babel.config.js ================================================ module.exports = { presets: ['module:@react-native/babel-preset'], }; ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGComponentDescriptors.h ================================================ #pragma once #include #include #include "RNSVGShadowNodes.h" namespace facebook::react { using RNSVGCircleComponentDescriptor = ConcreteComponentDescriptor; using RNSVGClipPathComponentDescriptor = ConcreteComponentDescriptor; using RNSVGDefsComponentDescriptor = ConcreteComponentDescriptor; using RNSVGEllipseComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeBlendComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeColorMatrixComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeCompositeComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeFloodComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeGaussianBlurComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeMergeComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFeOffsetComponentDescriptor = ConcreteComponentDescriptor; using RNSVGFilterComponentDescriptor = ConcreteComponentDescriptor; using RNSVGForeignObjectComponentDescriptor = ConcreteComponentDescriptor; using RNSVGGroupComponentDescriptor = ConcreteComponentDescriptor; using RNSVGLinearGradientComponentDescriptor = ConcreteComponentDescriptor; using RNSVGLineComponentDescriptor = ConcreteComponentDescriptor; using RNSVGMarkerComponentDescriptor = ConcreteComponentDescriptor; using RNSVGMaskComponentDescriptor = ConcreteComponentDescriptor; using RNSVGPathComponentDescriptor = ConcreteComponentDescriptor; using RNSVGPatternComponentDescriptor = ConcreteComponentDescriptor; using RNSVGRadialGradientComponentDescriptor = ConcreteComponentDescriptor; using RNSVGRectComponentDescriptor = ConcreteComponentDescriptor; using RNSVGSymbolComponentDescriptor = ConcreteComponentDescriptor; using RNSVGTextComponentDescriptor = ConcreteComponentDescriptor; using RNSVGTextPathComponentDescriptor = ConcreteComponentDescriptor; using RNSVGTSpanComponentDescriptor = ConcreteComponentDescriptor; using RNSVGUseComponentDescriptor = ConcreteComponentDescriptor; } // namespace facebook::react ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGConcreteShadowNode.h ================================================ #pragma once #include #include #include #include "RNSVGLayoutableShadowNode.h" namespace facebook::react { template class RNSVGConcreteShadowNode : public ConcreteShadowNode< concreteComponentName, ShadowNode, PropsT, ViewEventEmitter, StateData> { public: using BaseShadowNode = ConcreteShadowNode< concreteComponentName, ShadowNode, PropsT, ViewEventEmitter, StateData>; using ConcreteViewProps = PropsT; using BaseShadowNode::BaseShadowNode; static ShadowNodeTraits BaseTraits() { auto traits = BaseShadowNode::BaseTraits(); traits.set(ShadowNodeTraits::Trait::ViewKind); traits.set(ShadowNodeTraits::Trait::FormsStackingContext); traits.set(ShadowNodeTraits::Trait::FormsView); return traits; } Transform getTransform() const override { auto layoutMetrics = BaseShadowNode::getLayoutMetrics(); return BaseShadowNode::getConcreteProps().resolveTransform(layoutMetrics); } bool canBeTouchTarget() const override { auto pointerEvents = BaseShadowNode::getConcreteProps().ViewProps::pointerEvents; return pointerEvents == PointerEventsMode::Auto || pointerEvents == PointerEventsMode::BoxOnly; } bool canChildrenBeTouchTarget() const override { auto pointerEvents = BaseShadowNode::getConcreteProps().ViewProps::pointerEvents; return pointerEvents == PointerEventsMode::Auto || pointerEvents == PointerEventsMode::BoxNone; } }; } // namespace facebook::react ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGImageComponentDescriptor.h ================================================ /* * 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 #include #include #include "RNSVGImageShadowNode.h" namespace facebook { namespace react { /* * Descriptor for component. */ class RNSVGImageComponentDescriptor final : public ConcreteComponentDescriptor { public: RNSVGImageComponentDescriptor(ComponentDescriptorParameters const ¶meters) : ConcreteComponentDescriptor(parameters), imageManager_(std::make_shared(contextContainer_)){}; void adopt(ShadowNode &shadowNode) const override { ConcreteComponentDescriptor::adopt(shadowNode); auto &imageShadowNode = static_cast(shadowNode); // `RNSVGImageShadowNode` uses `ImageManager` to initiate image loading and // communicate the loading state and results to mounting layer. imageShadowNode.setImageManager(imageManager_); } private: const std::shared_ptr imageManager_; }; } // namespace react } // namespace facebook ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGImageShadowNode.cpp ================================================ /* * 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 #include #include #include "RNSVGImageShadowNode.h" namespace facebook { namespace react { const char RNSVGImageComponentName[] = "RNSVGImage"; void RNSVGImageShadowNode::setImageManager( const std::shared_ptr &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 ¤tState = 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 ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGImageShadowNode.h ================================================ /* * 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 #include #include #include #include #include #include "RNSVGImageState.h" namespace facebook { namespace react { JSI_EXPORT extern const char RNSVGImageComponentName[]; /* * `ShadowNode` for component. */ class JSI_EXPORT RNSVGImageShadowNode final : public ConcreteViewShadowNode< RNSVGImageComponentName, RNSVGImageProps, RNSVGImageEventEmitter, 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 std::shared_ptr &imageManager); static RNSVGImageState initialStateData( Props::Shared const &props, ShadowNodeFamily::Shared const &family, 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; std::shared_ptr imageManager_; void updateStateIfNeeded(); }; } // namespace react } // namespace facebook ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGImageState.cpp ================================================ /* * 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 ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGImageState.h ================================================ /* * 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 #include #include #ifdef ANDROID #include #include #include #endif namespace facebook { namespace react { /* * State for component. */ class JSI_EXPORT RNSVGImageState final { public: RNSVGImageState(ImageSource const &imageSource, ImageRequest imageRequest) : imageSource_(imageSource), imageRequest_( std::make_shared(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_; }; } // namespace react } // namespace facebook ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGLayoutableShadowNode.cpp ================================================ #include "RNSVGLayoutableShadowNode.h" #include namespace facebook::react { RNSVGLayoutableShadowNode::RNSVGLayoutableShadowNode( const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family, ShadowNodeTraits traits) : YogaLayoutableShadowNode(fragment, family, traits) { updatePosition(); } RNSVGLayoutableShadowNode::RNSVGLayoutableShadowNode( const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment) : YogaLayoutableShadowNode(sourceShadowNode, fragment) { updatePosition(); } void RNSVGLayoutableShadowNode::updatePosition() { // SVG handles its layout manually on the native side and does not depend on // the Yoga layout. Setting the dimensions to absolute fill is a hack for measure // to return "correct" layout metrics when onPress is tested. It also eliminates // randomly positioned views in the layout inspector when Yoga attempts to interpret // SVG properties like width when viewBox scale is set. Ideal solution would be to // return correct bounding box from native side in getLayoutMetrics. auto style = yogaNode_.style(); style.setPositionType(yoga::PositionType::Absolute); style.setPosition(yoga::Edge::All, yoga::Style::Length::points(0)); style.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::percent(100)); style.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::percent(100)); yogaNode_.setStyle(style); } void RNSVGLayoutableShadowNode::layout(LayoutContext layoutContext) { auto affectedNodes = layoutContext.affectedNodes; layoutContext.affectedNodes = nullptr; YogaLayoutableShadowNode::layout(layoutContext); layoutContext.affectedNodes = affectedNodes; } } // namespace facebook::react ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGLayoutableShadowNode.h ================================================ #include namespace facebook::react { class RNSVGLayoutableShadowNode : public YogaLayoutableShadowNode { public: RNSVGLayoutableShadowNode( const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family, ShadowNodeTraits traits); RNSVGLayoutableShadowNode( const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment); void layout(LayoutContext layoutContext) override; private: void updatePosition(); }; } // namespace facebook::react ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGShadowNodes.cpp ================================================ #include namespace facebook::react { extern const char RNSVGCircleComponentName[] = "RNSVGCircle"; extern const char RNSVGClipPathComponentName[] = "RNSVGClipPath"; extern const char RNSVGDefsComponentName[] = "RNSVGDefs"; extern const char RNSVGEllipseComponentName[] = "RNSVGEllipse"; extern const char RNSVGFeBlendComponentName[] = "RNSVGFeBlend"; extern const char RNSVGFeColorMatrixComponentName[] = "RNSVGFeColorMatrix"; extern const char RNSVGFeCompositeComponentName[] = "RNSVGFeComposite"; extern const char RNSVGFeFloodComponentName[] = "RNSVGFeFlood"; extern const char RNSVGFeGaussianBlurComponentName[] = "RNSVGFeGaussianBlur"; extern const char RNSVGFeMergeComponentName[] = "RNSVGFeMerge"; extern const char RNSVGFeOffsetComponentName[] = "RNSVGFeOffset"; extern const char RNSVGFilterComponentName[] = "RNSVGFilter"; extern const char RNSVGForeignObjectComponentName[] = "RNSVGForeignObject"; extern const char RNSVGGroupComponentName[] = "RNSVGGroup"; extern const char RNSVGLinearGradientComponentName[] = "RNSVGLinearGradient"; extern const char RNSVGLineComponentName[] = "RNSVGLine"; extern const char RNSVGMarkerComponentName[] = "RNSVGMarker"; extern const char RNSVGMaskComponentName[] = "RNSVGMask"; extern const char RNSVGPathComponentName[] = "RNSVGPath"; extern const char RNSVGPatternComponentName[] = "RNSVGPattern"; extern const char RNSVGRadialGradientComponentName[] = "RNSVGRadialGradient"; extern const char RNSVGRectComponentName[] = "RNSVGRect"; extern const char RNSVGSymbolComponentName[] = "RNSVGSymbol"; extern const char RNSVGTextComponentName[] = "RNSVGText"; extern const char RNSVGTextPathComponentName[] = "RNSVGTextPath"; extern const char RNSVGTSpanComponentName[] = "RNSVGTSpan"; extern const char RNSVGUseComponentName[] = "RNSVGUse"; } // namespace facebook::react ================================================ FILE: common/cpp/react/renderer/components/rnsvg/RNSVGShadowNodes.h ================================================ #pragma once #include #include #include #include #include "RNSVGConcreteShadowNode.h" #include "RNSVGImageState.h" namespace facebook::react { JSI_EXPORT extern const char RNSVGCircleComponentName[]; /* * `ShadowNode` for component. */ using RNSVGCircleShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGClipPathComponentName[]; /* * `ShadowNode` for component. */ using RNSVGClipPathShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGDefsComponentName[]; /* * `ShadowNode` for component. */ using RNSVGDefsShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGEllipseComponentName[]; /* * `ShadowNode` for component. */ using RNSVGEllipseShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGFeBlendComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeBlendShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGFeColorMatrixComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeColorMatrixShadowNode = RNSVGConcreteShadowNode< RNSVGFeColorMatrixComponentName, RNSVGFeColorMatrixProps>; JSI_EXPORT extern const char RNSVGFeCompositeComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeCompositeShadowNode = RNSVGConcreteShadowNode< RNSVGFeCompositeComponentName, RNSVGFeCompositeProps>; JSI_EXPORT extern const char RNSVGFeFloodComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeFloodShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGFeGaussianBlurComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeGaussianBlurShadowNode = RNSVGConcreteShadowNode< RNSVGFeGaussianBlurComponentName, RNSVGFeGaussianBlurProps>; JSI_EXPORT extern const char RNSVGFeMergeComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeMergeShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGFeOffsetComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFeOffsetShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGFilterComponentName[]; /* * `ShadowNode` for component. */ using RNSVGFilterShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGForeignObjectComponentName[]; /* * `ShadowNode` for component. */ using RNSVGForeignObjectShadowNode = RNSVGConcreteShadowNode< RNSVGForeignObjectComponentName, RNSVGForeignObjectProps, YogaLayoutableShadowNode>; JSI_EXPORT extern const char RNSVGGroupComponentName[]; /* * `ShadowNode` for component. */ using RNSVGGroupShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGLinearGradientComponentName[]; /* * `ShadowNode` for component. */ using RNSVGLinearGradientShadowNode = RNSVGConcreteShadowNode< RNSVGLinearGradientComponentName, RNSVGLinearGradientProps>; JSI_EXPORT extern const char RNSVGLineComponentName[]; /* * `ShadowNode` for component. */ using RNSVGLineShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGMarkerComponentName[]; /* * `ShadowNode` for component. */ using RNSVGMarkerShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGMaskComponentName[]; /* * `ShadowNode` for component. */ using RNSVGMaskShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGPathComponentName[]; /* * `ShadowNode` for component. */ using RNSVGPathShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGPatternComponentName[]; /* * `ShadowNode` for component. */ using RNSVGPatternShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGRadialGradientComponentName[]; /* * `ShadowNode` for component. */ using RNSVGRadialGradientShadowNode = RNSVGConcreteShadowNode< RNSVGRadialGradientComponentName, RNSVGRadialGradientProps>; JSI_EXPORT extern const char RNSVGRectComponentName[]; /* * `ShadowNode` for component. */ using RNSVGRectShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGSymbolComponentName[]; /* * `ShadowNode` for component. */ using RNSVGSymbolShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGTextComponentName[]; /* * `ShadowNode` for component. */ using RNSVGTextShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGTextPathComponentName[]; /* * `ShadowNode` for component. */ using RNSVGTextPathShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGTSpanComponentName[]; /* * `ShadowNode` for component. */ using RNSVGTSpanShadowNode = RNSVGConcreteShadowNode; JSI_EXPORT extern const char RNSVGUseComponentName[]; /* * `ShadowNode` for component. */ using RNSVGUseShadowNode = RNSVGConcreteShadowNode; } // namespace facebook::react ================================================ FILE: css/package.json ================================================ { "main": "../lib/commonjs/css/index", "module": "../lib/module/css/index", "react-native": "../src/css/index", "types": "../lib/typescript/css/index" } ================================================ FILE: e2e/env.ts ================================================ export const width = 200; export const height = 200; export const maxPixelDiff = width * height * 0.005; export const targetPixelRatio = global.os === 'android' ? 2.625 : 3.0; ================================================ FILE: e2e/failedCases.json ================================================ { "ios": { "paper": [], "fabric": [] }, "android": { "paper": ["2"], "fabric": ["2"] } } ================================================ FILE: e2e/generateReferences.ts ================================================ const path = require('path'); const puppeteer = require('puppeteer'); const fs = require('fs'); const generateReferences = async ( platform: 'android' | 'ios', scaleFactor: number ) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setViewport({ width: 200, height: 200, // This is value which makes it possible to use only devices with particular pixel ratio. You can change it // and regenerate reference images if you want to use device with different pixel ratio // see: https://reactnative.dev/docs/pixelratio deviceScaleFactor: scaleFactor, }); const casesPath = path.resolve('e2e', 'cases'); const referencesPath = path.resolve('e2e', 'references', platform); const cases = fs.readdirSync(casesPath); for (const testCase of cases) { const svgPath = path.resolve(casesPath, testCase); await page.goto(`file://${svgPath}`); await page.$eval('svg', (ev: Element) => { ev.setAttribute('width', '200'); ev.setAttribute('height', '200'); }); const svg = await page.waitForSelector('svg'); await svg.screenshot({ path: path.resolve(referencesPath, testCase.replace('.svg', '.png')), }); } await browser.close(); }; const main = async () => { await generateReferences('ios', 3.0); // We use 2.625 for Android which corresponds to Pixel 7 device becuase the emulator with 3.0 is not available currently on CI await generateReferences('android', 2.625); }; main(); ================================================ FILE: e2e/globals.d.ts ================================================ /* eslint-disable no-var */ import { WebSocket as WsWebSocket, WebSocketServer } from 'ws'; declare global { namespace globalThis { // Leave it as var, changing to let will cause it not to work var server: WebSocketServer; var client: WsWebSocket; var os: string; var arch: string; } } ================================================ FILE: e2e/helpers.ts ================================================ import { E2EMessage } from './types'; import { PNG } from 'pngjs'; import fs from 'node:fs'; import pixelmatch from 'pixelmatch'; const replacer = (key: string, value: any) => { if (key === 'type' && typeof value !== 'string') return value.displayName; return value; }; export const sendToDeviceAndReceive = (message: E2EMessage) => new Promise((resolve) => { global.client.once('message', (message) => { const parsedMessage: E2EMessage = JSON.parse(message.toString('utf-8')); resolve(parsedMessage as R); }); global.client.send(JSON.stringify(message, replacer)); }); export const compareImages = ( image1: Buffer, image2: Buffer, opts: { width: number; height: number; pixelRatio: number; diffFilePath?: string; renderedFilePath?: string; } ) => { const referencePng = PNG.sync.read(image1); const responsePng = PNG.sync.read(image2); const diffPng = new PNG({ height: referencePng.height, width: referencePng.width, }); const pixelDiff = pixelmatch( referencePng.data, responsePng.data, diffPng.data, opts.width * opts.pixelRatio, opts.height * opts.pixelRatio, { // That #5f00a0 is the color of the diff pixels diffColor: [95, 0, 160], } ); if (opts.renderedFilePath) { fs.writeFileSync(opts.renderedFilePath, PNG.sync.write(responsePng)); } if (opts.diffFilePath) { fs.writeFileSync(opts.diffFilePath, PNG.sync.write(diffPng)); } return pixelDiff; }; ================================================ FILE: e2e/matchTestCases.ts ================================================ import { maxPixelDiff, targetPixelRatio } from './env'; // import { storeFailedResult } from './readFailedCases'; import { FailedResults, HandshakeMessageData } from './types'; const extractSvgNumber = (testCase: string) => { const match = testCase.match(/(\d+)\.svg$/)!; return parseInt(match[1], 10).toString(); }; export function verifyComparisons( amountOfDifferentPixels: number, failedCases: FailedResults, global: HandshakeMessageData, testCase: string ) { // if (amountOfDifferentPixels > maxPixelDiff * targetPixelRatio) { // storeFailedResult(global.os, global.arch, matchTestCase(testCase)); // } if ( failedCases[global.os][global.arch].includes(extractSvgNumber(testCase)) ) { expect(amountOfDifferentPixels).toBeGreaterThan( maxPixelDiff * targetPixelRatio ); } else { expect(amountOfDifferentPixels).toBeLessThan( maxPixelDiff * targetPixelRatio ); } } ================================================ FILE: e2e/readFailedCases.ts ================================================ import { Arch, OS } from './types'; import path from 'path'; import fs from 'fs'; const filePath = path.join(__dirname, 'failedCases.json'); function readFileOrCreateIfNotExists(filePath: string): object { try { if (fs.existsSync(filePath)) { const data = fs.readFileSync(filePath, 'utf8'); return JSON.parse(data); } else { const emptyObject = {}; fs.writeFileSync(filePath, JSON.stringify(emptyObject, null, 2), 'utf8'); return emptyObject; } } catch (error) { console.error('Error occurred:', error); return {}; } } interface UpdateFailedResults { ios?: { paper?: string[]; fabric?: string[]; }; android?: { paper?: string[]; fabric?: string[] }; } export function storeFailedResult( platform: OS, architecture: Arch, value: string ): void { try { const data = readFileOrCreateIfNotExists(filePath) as UpdateFailedResults; if (!data[platform]) { data[platform] = {}; } if (!data[platform]?.[architecture]) { data[platform]![architecture] = []; } if (!data[platform]?.[architecture]?.includes(value)) { data[platform]?.[architecture]?.push(value); } fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8'); console.log('Data updated successfully:', data); } catch (error) { console.error('Error occurred while updating the file:', error); } } ================================================ FILE: e2e/setupJest.ts ================================================ import { WebSocketServer } from 'ws'; // This is little hack, we don't use syntax sugar with `async` here as we need to manually resolve promise // whenever a client connects using resolve callback. In result the Jest will wait until some device connects, // so it can be used to render test cases. const setupJest = () => new Promise((resolve) => { const wsServer = new WebSocketServer({ port: 7123 }); wsServer.on('connection', (client) => { global.client = client; // Add handler for one-time handshake message that confirms the client has connected properly client.once('message', (message) => { const parsedMessage = JSON.parse(message.toString('utf-8')); console.log( `[react-native-svg] Received handshake from a test client: ${JSON.stringify( parsedMessage )}` ); global.os = parsedMessage.os; global.arch = parsedMessage.arch; console.log(`[react-native-svg] Running E2E test suites...\n`); resolve(); }); }); console.log( '\n\n[react-native-svg] E2E WebSocket server is running, waiting for client connection. Run example app and select E2E from examples list.\n' ); global.server = wsServer; }); export default setupJest; ================================================ FILE: e2e/teardownJest.ts ================================================ export default () => { global.server.clients.forEach((client) => client.close(1000)) global.server.close() }; ================================================ FILE: e2e/types.ts ================================================ export type E2EMessage = HandshakeMessage | RenderRequest | RenderResponse; export interface HandshakeMessage { type: 'handshake'; data: { os: string; arch: 'paper' | 'fabric'; platformVersion: string; }; } export type OS = 'ios' | 'android'; export type Arch = 'paper' | 'fabric'; export interface HandshakeMessageData { os: OS; arch: Arch; platformVersion: string; } export interface RenderRequest { type: 'renderRequest'; data: any; width: number; height: number; } export interface RenderResponse { type: 'renderResponse'; data: string; // as base64 } export interface FailedResults { ios: { paper: string[]; fabric: string[]; }; android: { paper: string[]; fabric: string[] }; } ================================================ FILE: filter-image/package.json ================================================ { "main": "../lib/commonjs/filter-image/index", "module": "../lib/module/filter-image/index", "react-native": "../src/filter-image/index", "types": "../lib/typescript/filter-image/index" } ================================================ FILE: jest.config.ts ================================================ import { Config } from '@jest/types'; const config: Config.InitialOptions = { testPathIgnorePatterns: ['/node_modules/', '/apps/'], preset: 'react-native', verbose: true, globalSetup: '/e2e/setupJest.ts', globalTeardown: '/e2e/teardownJest.ts', modulePathIgnorePatterns: [ 'lib/typescript', 'helpers.ts|globals.d.ts|setupJest.ts|teardownJest.ts', ], reporters: [ 'default', [ 'jest-html-reporters', { filename: 'report.html', }, ], ], }; export default config; ================================================ FILE: package.json ================================================ { "version": "15.15.4", "name": "react-native-svg", "description": "SVG library for react-native", "homepage": "https://github.com/react-native-community/react-native-svg", "repository": { "type": "git", "url": "https://github.com/react-native-community/react-native-svg" }, "license": "MIT", "main": "lib/commonjs/index.js", "module": "lib/module/index.js", "types": "lib/typescript/index.d.ts", "react-native": "src/index.ts", "files": [ "android", "apple", "common", "lib", "src", "css", "filter-image", "RNSVG.podspec", "!android/build", "windows", "react-native.config.js", "scripts/rnsvg_utils.rb" ], "react-native-builder-bob": { "source": "src", "output": "lib", "targets": [ "commonjs", "module", "typescript" ] }, "keywords": [ "react-component", "react-native", "ios", "android", "windows", "SVG", "ART", "VML", "gradient" ], "scripts": { "bob": "bob build", "format": "yarn format-js && yarn format-ios && yarn format-java", "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} ./apps/**/*.{ts,tsx}", "jest": "jest", "lint": "eslint --ext .ts,.tsx src", "peg": "pegjs -o src/lib/extract/transform.js ./src/lib/extract/transform.peg && peggy -o src/filter-image/extract/extractFiltersString.js src/filter-image/extract/extractFiltersString.pegjs && peggy -o src/lib/extract/transformToRn.js src/lib/extract/transformToRn.pegjs", "prepare": "npm run bob && husky install", "release": "npm login && release-it", "test": "npm run lint && npm run tsc", "tsc": "tsc --noEmit", "e2e": "jest e2e", "generateE2eReferences": "ts-node e2e/generateReferences.ts", "check-archs-consistency": "node ./scripts/codegen-check-consistency.js", "sync-archs": "node ./scripts/codegen-sync-archs.js", "metal-to-ci": "node ./scripts/metal.js" }, "peerDependencies": { "react": "*", "react-native": "*" }, "dependencies": { "css-select": "^5.1.0", "css-tree": "^1.1.3", "warn-once": "0.1.1" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@react-native/babel-preset": "^0.77.0", "@react-native/eslint-config": "^0.77.0", "@types/css-tree": "^1.0.3", "@types/jest": "^27.5.2", "@types/node": "*", "@types/pixelmatch": "^5.2.0", "@types/pngjs": "^6.0.5", "@types/react": "^18.3.12", "@types/ws": "^8.5.13", "@typescript-eslint/eslint-plugin": "^5.11.0", "@typescript-eslint/parser": "^5.11.0", "babel-plugin-module-resolver": "^5.0.0", "clang-format": "^1.8.0", "eslint": "^8.44.0", "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^17.0.0", "eslint-import-resolver-babel-module": "^5.3.2", "eslint-plugin-import": "^2.25.4", "eslint-plugin-n": "^16.0.0", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-standard": "^5.0.0", "husky": "^8.0.1", "jest": "^28.1.0", "jest-html-reporters": "^3.1.7", "lint-staged": "^13.0.3", "peggy": "4.0.3", "pegjs": "^0.10.0", "pixelmatch": "5.3.0", "pngjs": "^7.0.0", "prettier": "3.0.1", "puppeteer": "^22.12.1", "react": "^18.3.1", "react-native": "^0.77.0", "react-native-builder-bob": "^0.20.4", "react-native-windows": "^0.77.0", "react-test-renderer": "^18.2.0", "release-it": "^14.12.5", "ts-node": "^10.9.2", "typescript": "^5.1.6", "ws": "^8.18.0" }, "lint-staged": { "{src,apps/common}/**/*.{js,ts,tsx}": "yarn format-js", "src/**/*.{js,ts,tsx}": "yarn lint", "apple/**/*.{h,m,mm,cpp}": "yarn format-ios", "android/src/**/*.java": "yarn format-java", "src/fabric/*.ts": "yarn sync-archs" }, "nativePackage": true, "codegenConfig": { "name": "rnsvg", "type": "all", "jsSrcsDir": "./src/fabric", "android": { "javaPackageName": "com.horcrux.svg" }, "ios": { "componentProvider": { "RNSVGCircle": "RNSVGCircle", "RNSVGClipPath": "RNSVGClipPath", "RNSVGDefs": "RNSVGDefs", "RNSVGEllipse": "RNSVGEllipse", "RNSVGFeBlend": "RNSVGFeBlend", "RNSVGFeColorMatrix": "RNSVGFeColorMatrix", "RNSVGFeComposite": "RNSVGFeComposite", "RNSVGFeFlood": "RNSVGFeFlood", "RNSVGFeGaussianBlur": "RNSVGFeGaussianBlur", "RNSVGFeMerge": "RNSVGFeMerge", "RNSVGFeOffset": "RNSVGFeOffset", "RNSVGFilter": "RNSVGFilter", "RNSVGForeignObject": "RNSVGForeignObject", "RNSVGGroup": "RNSVGGroup", "RNSVGImage": "RNSVGImage", "RNSVGLine": "RNSVGLine", "RNSVGLinearGradient": "RNSVGLinearGradient", "RNSVGMarker": "RNSVGMarker", "RNSVGMask": "RNSVGMask", "RNSVGPath": "RNSVGPath", "RNSVGPattern": "RNSVGPattern", "RNSVGRadialGradient": "RNSVGRadialGradient", "RNSVGRect": "RNSVGRect", "RNSVGSvgView": "RNSVGSvgView", "RNSVGSymbol": "RNSVGSymbol", "RNSVGTSpan": "RNSVGTSpan", "RNSVGText": "RNSVGText", "RNSVGTextPath": "RNSVGTextPath", "RNSVGUse": "RNSVGUse" } } }, "packageManager": "yarn@1.22.22" } ================================================ FILE: react-native.config.js ================================================ module.exports = { dependency: { platforms: { android: { componentDescriptors: [ 'RNSVGCircleComponentDescriptor', 'RNSVGClipPathComponentDescriptor', 'RNSVGDefsComponentDescriptor', 'RNSVGFeBlendComponentDescriptor', 'RNSVGFeColorMatrixComponentDescriptor', 'RNSVGFeCompositeComponentDescriptor', 'RNSVGFeFloodComponentDescriptor', 'RNSVGFeGaussianBlurComponentDescriptor', 'RNSVGFeMergeComponentDescriptor', 'RNSVGFeOffsetComponentDescriptor', 'RNSVGFilterComponentDescriptor', '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', }, }, }, }; ================================================ FILE: scripts/codegen-check-consistency.js ================================================ const { checkCodegenIntegrity } = require('./codegen-utils'); checkCodegenIntegrity(); ================================================ FILE: scripts/codegen-sync-archs.js ================================================ const { generateCodegenJavaOldArch } = require('./codegen-utils'); generateCodegenJavaOldArch(); ================================================ FILE: scripts/codegen-utils.js ================================================ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const packageJSON = require('../package.json'); const ERROR_PREFIX = 'RNSVG'; const ROOT_DIR = path.resolve(__dirname, '..'); const ANDROID_DIR = path.resolve(ROOT_DIR, 'android'); const GENERATED_DIR = path.resolve(ANDROID_DIR, 'build/generated'); const OLD_ARCH_DIR = path.resolve(ANDROID_DIR, 'src/paper'); const SPECS_DIR = path.resolve(ROOT_DIR, packageJSON.codegenConfig.jsSrcsDir); const PACKAGE_NAME = packageJSON.codegenConfig.android.javaPackageName; const RN_DIR = path.resolve(ROOT_DIR, 'node_modules/react-native'); const RN_CODEGEN_DIR = path.resolve( ROOT_DIR, 'node_modules/@react-native/codegen' ); const SOURCE_FOLDER = 'java/com/facebook/react/viewmanagers'; const SOURCE_FOLDER_HORCRUX = 'java/com/horcrux/svg'; const SOURCE_FOLDERS = [ {codegenPath: `${GENERATED_DIR}/source/codegen/${SOURCE_FOLDER}`, oldArchPath: `${OLD_ARCH_DIR}/${SOURCE_FOLDER}`}, {codegenPath: `${GENERATED_DIR}/source/codegen/${SOURCE_FOLDER_HORCRUX}`, oldArchPath: `${OLD_ARCH_DIR}/${SOURCE_FOLDER_HORCRUX}`}, ] function exec(command) { console.log(`[${ERROR_PREFIX}]> ` + command); execSync(command); } function fixOldArchJavaForRN72Compat(dir) { // see https://github.com/rnmapbox/maps/issues/3193 const files = fs.readdirSync(dir); files.forEach(file => { const filePath = path.join(dir, file); const fileExtension = path.extname(file); if (fileExtension === '.java') { let fileContent = fs.readFileSync(filePath, 'utf-8'); let newFileContent = fileContent.replace( /extends ReactContextBaseJavaModule implements TurboModule/g, 'extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule' ); if (fileContent !== newFileContent) { // also insert an import line with `import com.facebook.react.bridge.ReactModuleWithSpec;` newFileContent = newFileContent.replace( /import com.facebook.react.bridge.ReactMethod;/, 'import com.facebook.react.bridge.ReactMethod;\nimport com.facebook.react.bridge.ReactModuleWithSpec;' ); console.log(' => fixOldArchJava applied to:', filePath); fs.writeFileSync(filePath, newFileContent, 'utf-8'); } } else if (fs.lstatSync(filePath).isDirectory()) { fixOldArchJavaForRN72Compat(filePath); } }); } async function generateCodegen() { exec(`rm -rf ${GENERATED_DIR}`); exec(`mkdir -p ${GENERATED_DIR}/source/codegen/`); exec( `node ${RN_CODEGEN_DIR}/lib/cli/combine/combine-js-to-schema-cli.js --platform android ${GENERATED_DIR}/source/codegen/schema.json ${SPECS_DIR}` ); exec( `node ${RN_DIR}/scripts/generate-specs-cli.js --platform android --schemaPath ${GENERATED_DIR}/source/codegen/schema.json --outputDir ${GENERATED_DIR}/source/codegen --javaPackageName ${PACKAGE_NAME}` ); fixOldArchJavaForRN72Compat(`${GENERATED_DIR}/source/codegen/java/`); } async function generateCodegenJavaOldArch() { await generateCodegen(); SOURCE_FOLDERS.forEach(({codegenPath, oldArchPath}) => { const generatedFiles = fs.readdirSync(codegenPath); const oldArchFiles = fs.readdirSync(oldArchPath); const existingFilesSet = new Set(oldArchFiles.map(fileName => fileName)); generatedFiles.forEach(generatedFile => { if (!existingFilesSet.has(generatedFile)) { console.warn( `[${ERROR_PREFIX}] ${generatedFile} not found in paper dir, if it's used on Android you need to copy it manually and implement yourself before using auto-copy feature.` ); } }); if (oldArchFiles.length === 0) { console.warn( `[${ERROR_PREFIX}] Paper destination with codegen interfaces is empty. This might be okay if you don't have any interfaces/delegates used on Android, otherwise please check if OLD_ARCH_DIR and SOURCE_FOLDERS are set properly.` ); } oldArchFiles.forEach(file => { if (!fs.existsSync(`${codegenPath}/${file}`)) { console.warn( `[${ERROR_PREFIX}] ${file} file does not exist in codegen artifacts source destination. Please check if you still need this interface/delagete.` ); } else { exec(`cp -rf ${codegenPath}/${file} ${oldArchPath}/${file}`); } }); }); } function compareFileAtTwoPaths(filename, firstPath, secondPath) { const fileA = fs.readFileSync(`${firstPath}/${filename}`, 'utf-8'); const fileB = fs.readFileSync(`${secondPath}/${filename}`, 'utf-8'); if (fileA !== fileB) { throw new Error( `[${ERROR_PREFIX}] File ${filename} is different at ${firstPath} and ${secondPath}. Make sure you commited codegen autogenerated files.` ); } } async function checkCodegenIntegrity() { await generateCodegen(); SOURCE_FOLDERS.forEach(({codegenPath, oldArchPath}) => { const oldArchFiles = fs.readdirSync(oldArchPath); oldArchFiles.forEach(file => { compareFileAtTwoPaths(file, codegenPath, oldArchPath); }); }); } module.exports = { generateCodegenJavaOldArch, checkCodegenIntegrity }; ================================================ FILE: scripts/format-java.js ================================================ /* eslint-disable @typescript-eslint/no-var-requires */ /* * This script is a wrapper for gradle & spotlessApply to make * it work properly with lint-staged. */ const { exit } = require('process'); const { execSync } = require('child_process'); const writeToConsoleOnError = (error, stdout) => { if (error) { console.log(error); console.log(stdout); return exit(1); } }; // spotless formatting task in android/build.gradle const spotlessApply = './android/gradlew -p android spotlessApply'; // takes file as parameter passed by lint-staged (optional) const fileName = process.argv[2]; // https://github.com/diffplug/spotless/blob/main/plugin-gradle/IDE_HOOK.md // creates file argument without space between arguments const fileArgument = `-PspotlessIdeHook=${fileName}`; const command = fileName !== undefined ? `${spotlessApply} ${fileArgument}` : spotlessApply; // reformat code execSync(command, writeToConsoleOnError); // file passed by lint-staged is now reformatted if (fileName !== undefined) { // so stage this file again after formatting execSync(`git add ${fileName}`, writeToConsoleOnError); } ================================================ FILE: scripts/metal.js ================================================ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const ROOT_DIR = path.resolve(__dirname, '..'); const FILTERS_DIR = path.resolve(ROOT_DIR, 'apple/Filters/MetalCI'); function exec(command) { execSync(command); } function clearGeneratedFiles() { const files = fs.readdirSync(FILTERS_DIR); console.log('Removing generated files...'); files.forEach((file) => { const filePath = path.join(FILTERS_DIR, file); const fileExtension = path.extname(file); if (fileExtension === '.air' || fileExtension === '.metallib') { exec(`rm -rf ${filePath}`); } }); console.log('Generated files removed.'); } function compileMetalFile(file, sdk) { const filePath = path.join(FILTERS_DIR, file); const fileName = path.basename(filePath).replace('.metal', ''); const filePathWithoutExt = path.join(FILTERS_DIR, file).replace('.metal', ''); console.log('* for ' + sdk); exec( `xcrun -sdk ${sdk} metal -fcikernel -c ${filePathWithoutExt}.metal -o ${filePathWithoutExt}.${sdk}.air` ); console.log(` ├─ ${fileName}.${sdk}.air`); exec( `xcrun -sdk ${sdk} metallib -cikernel ${filePathWithoutExt}.${sdk}.air -o ${filePathWithoutExt}.${sdk}.metallib` ); console.log(` └─ ${fileName}.${sdk}.metallib`); } function generateMetallib() { const files = fs.readdirSync(FILTERS_DIR); files.forEach((file) => { const fileExtension = path.extname(file); if (fileExtension === '.metal') { const fileName = path.basename(file).replace('.metal', ''); console.log('Compiling:', fileName + '.metal'); compileMetalFile(file, 'macosx'); compileMetalFile(file, 'iphoneos'); compileMetalFile(file, 'appletvos'); compileMetalFile(file, 'xros'); } }); } clearGeneratedFiles(); generateMetallib(); ================================================ FILE: scripts/rnsvg_utils.rb ================================================ # Copied from Reanimated https://github.com/software-mansion/react-native-reanimated/blob/c6d68151644056476518241b0087b1ed900b39b6/packages/react-native-reanimated/scripts/reanimated_utils.rb def rnsvg_try_to_parse_react_native_package_json(node_modules_dir) react_native_package_json_path = File.join(node_modules_dir, 'react-native/package.json') if !File.exist?(react_native_package_json_path) return nil end return JSON.parse(File.read(react_native_package_json_path)) end def rnsvg_find_config() result = { :react_native_version => nil, :react_native_minor_version => nil, :react_native_node_modules_dir => nil, } react_native_node_modules_dir = File.join(File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')"`), '..') react_native_json = rnsvg_try_to_parse_react_native_package_json(react_native_node_modules_dir) if react_native_json == nil # user configuration, just in case node_modules_dir = ENV["REACT_NATIVE_NODE_MODULES_DIR"] react_native_json = rnsvg_try_to_parse_react_native_package_json(node_modules_dir) end if react_native_json == nil raise '[RNSVG] Unable to recognize your `react-native` version. Please set environmental variable with `react-native` location: `export REACT_NATIVE_NODE_MODULES_DIR="" && pod install`.' end result[:react_native_version] = react_native_json['version'] result[:react_native_minor_version] = react_native_json['version'].split('.')[1].to_i if result[:react_native_minor_version] == 0 # nightly result[:react_native_minor_version] = 1000 end result[:react_native_node_modules_dir] = File.expand_path(react_native_node_modules_dir) return result end ================================================ FILE: src/ReactNativeSVG.ts ================================================ import Shape from './elements/Shape'; import { AstProps, camelCase, JsxAST, Middleware, parse, Styles, SvgAst, SvgFromUri, SvgFromXml, SvgUri, SvgXml, UriProps, UriState, XmlAST, XmlProps, XmlState, } from './xml'; import { fetchText } from './utils/fetchData'; import { RNSVGCircle, RNSVGClipPath, RNSVGDefs, RNSVGEllipse, RNSVGFeColorMatrix, RNSVGFeComposite, RNSVGFeGaussianBlur, RNSVGFeMerge, RNSVGFeOffset, RNSVGFilter, RNSVGForeignObject, RNSVGGroup, RNSVGImage, RNSVGLine, RNSVGLinearGradient, RNSVGMarker, RNSVGMask, RNSVGPath, RNSVGPattern, RNSVGRadialGradient, RNSVGRect, RNSVGSvgAndroid, RNSVGSvgIOS, RNSVGSymbol, RNSVGText, RNSVGTextPath, RNSVGTSpan, RNSVGUse, } from './fabric'; export { inlineStyles, loadLocalRawResource, LocalSvg, SvgCss, SvgCssUri, SvgWithCss, SvgWithCssUri, WithLocalSvg, } from './deprecated'; export type { CircleProps } from './elements/Circle'; export type { ClipPathProps } from './elements/ClipPath'; export type { EllipseProps } from './elements/Ellipse'; export type { FeBlendProps } from './elements/filters/FeBlend'; export type { FeColorMatrixProps } from './elements/filters/FeColorMatrix'; export type { FeComponentTransferProps } from './elements/filters/FeComponentTransfer'; export type { FeFuncAProps, FeFuncBProps, FeFuncGProps, FeFuncRProps, } from './elements/filters/FeComponentTransferFunction'; export type { FeCompositeProps } from './elements/filters/FeComposite'; export type { FeConvolveMatrixProps } from './elements/filters/FeConvolveMatrix'; export type { FeDiffuseLightingProps } from './elements/filters/FeDiffuseLighting'; export type { FeDisplacementMapProps } from './elements/filters/FeDisplacementMap'; export type { FeDistantLightProps } from './elements/filters/FeDistantLight'; export type { FeDropShadowProps } from './elements/filters/FeDropShadow'; export type { FeFloodProps } from './elements/filters/FeFlood'; export type { FeGaussianBlurProps } from './elements/filters/FeGaussianBlur'; export type { FeImageProps } from './elements/filters/FeImage'; export type { FeMergeProps } from './elements/filters/FeMerge'; export type { FeMergeNodeProps } from './elements/filters/FeMergeNode'; export type { FeMorphologyProps } from './elements/filters/FeMorphology'; export type { FeOffsetProps } from './elements/filters/FeOffset'; export type { FePointLightProps } from './elements/filters/FePointLight'; export type { FeSpecularLightingProps } from './elements/filters/FeSpecularLighting'; export type { FeSpotLightProps } from './elements/filters/FeSpotLight'; export type { FeTileProps } from './elements/filters/FeTile'; export type { FeTurbulenceProps } from './elements/filters/FeTurbulence'; export type { FilterProps } from './elements/filters/Filter'; export type { FilterPrimitiveCommonProps } from './elements/filters/FilterPrimitive'; export type { ForeignObjectProps } from './elements/ForeignObject'; export type { GProps } from './elements/G'; export type { ImageProps } from './elements/Image'; export type { LineProps } from './elements/Line'; export type { LinearGradientProps } from './elements/LinearGradient'; export type { MarkerProps } from './elements/Marker'; export type { MaskProps } from './elements/Mask'; export type { PathProps } from './elements/Path'; export type { PatternProps } from './elements/Pattern'; export type { PolygonProps } from './elements/Polygon'; export type { PolylineProps } from './elements/Polyline'; export type { RadialGradientProps } from './elements/RadialGradient'; export type { RectProps } from './elements/Rect'; export type { StopProps } from './elements/Stop'; export type { SvgProps } from './elements/Svg'; export type { SymbolProps } from './elements/Symbol'; export type { TextProps } from './elements/Text'; export type { TextPathProps } from './elements/TextPath'; export type { TSpanProps } from './elements/TSpan'; export type { UseProps } from './elements/Use'; export * from './lib/extract/types'; export { camelCase, fetchText, parse, RNSVGCircle, RNSVGClipPath, RNSVGDefs, RNSVGEllipse, RNSVGFeColorMatrix, RNSVGFeComposite, RNSVGFeGaussianBlur, RNSVGFeMerge, RNSVGFeOffset, RNSVGFilter, RNSVGForeignObject, RNSVGGroup, RNSVGImage, RNSVGLine, RNSVGLinearGradient, RNSVGMarker, RNSVGMask, RNSVGPath, RNSVGPattern, RNSVGRadialGradient, RNSVGRect, RNSVGSvgAndroid, RNSVGSvgIOS, RNSVGSymbol, RNSVGText, RNSVGTextPath, RNSVGTSpan, RNSVGUse, Shape, SvgAst, SvgFromUri, SvgFromXml, SvgUri, SvgXml, }; export type { AstProps, JsxAST, Middleware, Styles, UriProps, UriState, XmlAST, XmlProps, XmlState, }; export * from './elements'; export { default } from './elements'; ================================================ FILE: src/ReactNativeSVG.web.ts ================================================ import { AstProps, camelCase, JsxAST, Middleware, parse, Styles, SvgAst, SvgFromUri, SvgFromXml, SvgUri, SvgXml, UriProps, UriState, XmlAST, XmlProps, XmlState, } from './xml'; import { fetchText } from './utils/fetchData'; export { inlineStyles, loadLocalRawResource, LocalSvg, SvgCss, SvgCssUri, SvgWithCss, SvgWithCssUri, WithLocalSvg, } from './deprecated'; export { camelCase, fetchText, parse, SvgAst, SvgFromUri, SvgFromXml, SvgUri, SvgXml, }; export * from './lib/extract/types'; export * from './elements'; export { default } from './elements'; export type { AstProps, JsxAST, Middleware, Styles, UriProps, UriState, XmlAST, XmlProps, XmlState, }; ================================================ FILE: src/css/LocalSvg.tsx ================================================ import * as React from 'react'; import { useState, useEffect, Component } from 'react'; import { Image, Platform, type ImageSourcePropType } from 'react-native'; import { fetchText, type SvgProps } from 'react-native-svg'; import { resolveAssetUri } from '../lib/resolveAssetUri'; import { SvgCss, SvgWithCss } from './css'; export function getUriFromSource(source: ImageSourcePropType) { const resolvedAssetSource = Platform.OS === 'web' ? resolveAssetUri(source) : Image.resolveAssetSource(source); return resolvedAssetSource?.uri; } export function loadLocalRawResourceDefault(source: ImageSourcePropType) { const uri = getUriFromSource(source); return fetchText(uri); } export function isUriAnAndroidResourceIdentifier(uri?: string) { return typeof uri === 'string' && uri.indexOf('/') <= -1; } export async function loadAndroidRawResource(uri: string) { try { // eslint-disable-next-line @typescript-eslint/no-explicit-any const RNSVGRenderableModule: any = // neeeded for new arch // eslint-disable-next-line @typescript-eslint/no-var-requires 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: ', e ); return null; } } export function loadLocalRawResourceAndroid(source: ImageSourcePropType) { const uri = getUriFromSource(source); if (uri && isUriAnAndroidResourceIdentifier(uri)) { return loadAndroidRawResource(uri); } else { return fetchText(uri); } } export const loadLocalRawResource = Platform.OS !== 'android' ? loadLocalRawResourceDefault : loadLocalRawResourceAndroid; export type LocalProps = SvgProps & { asset: ImageSourcePropType; override?: object; }; export type LocalState = { xml: string | null }; export function LocalSvg(props: LocalProps) { const { asset, ...rest } = props; const [xml, setXml] = useState(null); useEffect(() => { loadLocalRawResource(asset).then(setXml); }, [asset]); return ; } export class WithLocalSvg extends Component { state = { xml: null }; componentDidMount() { this.load(this.props.asset); } componentDidUpdate(prevProps: { asset: ImageSourcePropType }) { const { asset } = this.props; if (asset !== prevProps.asset) { this.load(asset); } } async load(asset: ImageSourcePropType) { try { this.setState({ xml: asset ? await loadLocalRawResource(asset) : null }); } catch (e) { console.error(e); } } render() { const { props, state: { xml }, } = this; return ; } } export default LocalSvg; ================================================ FILE: src/css/css.tsx ================================================ import * as React from 'react'; import { Component, useEffect, useMemo, useState } from 'react'; import type { JsxAST, Middleware, Styles, UriProps, UriState, XmlAST, XmlProps, XmlState, } from 'react-native-svg'; import { camelCase, fetchText, parse, SvgAst } from 'react-native-svg'; import type { Atrule, AtrulePrelude, CssNode, Declaration, DeclarationList, ListItem, PseudoClassSelector, Rule, Selector, SelectorList, } from 'css-tree'; import csstree, { List } from 'css-tree'; import type { Options } from 'css-select'; import cssSelect from 'css-select'; const err = console.error.bind(console); /* * Style element inlining experiment based on SVGO * https://github.com/svg/svgo/blob/11f9c797411a8de966aacc4cb83dbb3e471757bc/plugins/inlineStyles.js * */ /** * DOMUtils API for rnsvg AST (used by css-select) */ // is the node a tag? // isTag: ( node:Node ) => isTag:Boolean function isTag(node: XmlAST | string): node is XmlAST { return typeof node === 'object'; } // get the parent of the node // getParent: ( node:Node ) => parentNode:Node // returns null when no parent exists function getParent(node: XmlAST | string): XmlAST { return ((typeof node === 'object' && node.parent) || null) as XmlAST; } // get the node's children // getChildren: ( node:Node ) => children:[Node] function getChildren(node: XmlAST | string): Array { return (typeof node === 'object' && node.children) || []; } // get the name of the tag' // getName: ( elem:ElementNode ) => tagName:String function getName(elem: XmlAST): string { return elem.tag; } // get the text content of the node, and its children if it has any // getText: ( node:Node ) => text:String // returns empty string when there is no text function getText(_node: XmlAST | string): string { return ''; } // get the attribute value // getAttributeValue: ( elem:ElementNode, name:String ) => value:String // returns null when attribute doesn't exist function getAttributeValue(elem: XmlAST, name: string): string { return (elem.props[name] || null) as string; } // takes an array of nodes, and removes any duplicates, as well as any nodes // whose ancestors are also in the array function removeSubsets(nodes: Array): Array { let idx = nodes.length; let node; let ancestor; let replace; // Check if each node (or one of its ancestors) is already contained in the // array. while (--idx > -1) { node = ancestor = nodes[idx]; // Temporarily remove the node under consideration delete nodes[idx]; replace = true; while (ancestor) { if (nodes.includes(ancestor)) { replace = false; nodes.splice(idx, 1); break; } ancestor = (typeof ancestor === 'object' && ancestor.parent) || null; } // If the node has been found to be unique, re-insert it. if (replace) { nodes[idx] = node; } } return nodes; } // does at least one of passed element nodes pass the test predicate? function existsOne( predicate: (v: XmlAST) => boolean, elems: Array ): boolean { return elems.some( (elem) => typeof elem === 'object' && (predicate(elem) || existsOne(predicate, elem.children)) ); } /* get the siblings of the node. Note that unlike jQuery's `siblings` method, this is expected to include the current node as well */ function getSiblings(node: XmlAST | string): Array { const parent = typeof node === 'object' && node.parent; return (parent && parent.children) || []; } // does the element have the named attribute? function hasAttrib(elem: XmlAST, name: string): boolean { return Object.prototype.hasOwnProperty.call(elem.props, name); } // finds the first node in the array that matches the test predicate, or one // of its children function findOne( predicate: (v: XmlAST) => boolean, elems: Array ): XmlAST | null { let elem: XmlAST | null = null; for (let i = 0, l = elems.length; i < l && !elem; i++) { const node = elems[i]; if (typeof node === 'string') { /* empty */ } else if (predicate(node)) { elem = node; } else { const { children } = node; if (children.length !== 0) { elem = findOne(predicate, children); } } } return elem; } // finds all of the element nodes in the array that match the test predicate, // as well as any of their children that match it function findAll( predicate: (v: XmlAST) => boolean, nodes: Array, result: Array = [] ): Array { for (let i = 0, j = nodes.length; i < j; i++) { const node = nodes[i]; if (typeof node !== 'object') { continue; } if (predicate(node)) { result.push(node); } const { children } = node; if (children.length !== 0) { findAll(predicate, children, result); } } return result; } const cssSelectOpts: Options = { xmlMode: true, adapter: { removeSubsets, existsOne, getSiblings, hasAttrib, findOne, findAll, isTag, getParent, getChildren, getName, getText, getAttributeValue, }, }; type FlatPseudoSelector = { item: ListItem; list: List; }; type FlatPseudoSelectorList = FlatPseudoSelector[]; type FlatSelector = { item: ListItem; atrule: Atrule | null; rule: CssNode; pseudos: FlatPseudoSelectorList; }; type FlatSelectorList = FlatSelector[]; /** * Flatten a CSS AST to a selectors list. * * @param {Object} cssAst css-tree AST to flatten * @param {Array} selectors */ function flattenToSelectors(cssAst: CssNode, selectors: FlatSelectorList) { csstree.walk(cssAst, { visit: 'Rule', enter(rule: CssNode) { const { type, prelude } = rule as Rule; if (type !== 'Rule') { return; } const atrule = this.atrule; (prelude as SelectorList).children.each((node, item) => { const { children } = node as Selector; const pseudos: FlatPseudoSelectorList = []; selectors.push({ item, atrule, rule, pseudos, }); children.each(({ type: childType }, pseudoItem, list) => { if ( childType === 'PseudoClassSelector' || childType === 'PseudoElementSelector' ) { pseudos.push({ item: pseudoItem, list, }); } }); }); }, }); } /** * Filter selectors by Media Query. * * @param {Array} selectors to filter * @return {Array} Filtered selectors that match the passed media queries */ function filterByMqs(selectors: FlatSelectorList) { return selectors.filter(({ atrule }) => { if (atrule === null) { return true; } const { name, prelude } = atrule; const atPrelude = prelude as AtrulePrelude; const first = atPrelude && atPrelude.children.first(); const mq = first && first.type === 'MediaQueryList'; const query = mq ? csstree.generate(atPrelude) : name; return useMqs.includes(query); }); } // useMqs Array with strings of media queries that should pass ( ) const useMqs = ['', 'screen']; /** * Filter selectors by the pseudo-elements and/or -classes they contain. * * @param {Array} selectors to filter * @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes */ function filterByPseudos(selectors: FlatSelectorList) { return selectors.filter(({ pseudos }) => usePseudos.includes( csstree.generate({ type: 'Selector', children: new List().fromArray( pseudos.map((pseudo) => pseudo.item.data) ), }) ) ); } // usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass const usePseudos = ['']; /** * Remove pseudo-elements and/or -classes from the selectors for proper matching. * * @param {Array} selectors to clean * @return {Array} Selectors without pseudo-elements and/or -classes */ function cleanPseudos(selectors: FlatSelectorList) { selectors.forEach(({ pseudos }) => pseudos.forEach((pseudo) => pseudo.list.remove(pseudo.item)) ); } type Specificity = [number, number, number]; function specificity(selector: Selector): Specificity { let A = 0; let B = 0; let C = 0; selector.children.each(function walk(node: CssNode) { switch (node.type) { case 'SelectorList': case 'Selector': node.children.each(walk); break; case 'IdSelector': A++; break; case 'ClassSelector': case 'AttributeSelector': B++; break; case 'PseudoClassSelector': switch (node.name.toLowerCase()) { case 'not': { const children = (node as PseudoClassSelector).children; children && children.each(walk); break; } case 'before': case 'after': case 'first-line': case 'first-letter': C++; break; // TODO: support for :nth-*(.. of ), :matches(), :has() default: B++; } break; case 'PseudoElementSelector': C++; break; case 'TypeSelector': { // ignore universal selector const { name } = node; if (name.charAt(name.length - 1) !== '*') { C++; } break; } } }); return [A, B, C]; } /** * Compares two selector specificities. * extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211 * * @param {Array} aSpecificity Specificity of selector A * @param {Array} bSpecificity Specificity of selector B * @return {Number} Score of selector specificity A compared to selector specificity B */ function compareSpecificity( aSpecificity: Specificity, bSpecificity: Specificity ): number { for (let i = 0; i < 4; i += 1) { if (aSpecificity[i] < bSpecificity[i]) { return -1; } else if (aSpecificity[i] > bSpecificity[i]) { return 1; } } return 0; } type Spec = { selector: FlatSelector; specificity: Specificity; }; function selectorWithSpecificity(selector: FlatSelector): Spec { return { selector, specificity: specificity(selector.item.data as Selector), }; } /** * Compare two simple selectors. * * @param {Object} a Simple selector A * @param {Object} b Simple selector B * @return {Number} Score of selector A compared to selector B */ function bySelectorSpecificity(a: Spec, b: Spec): number { return compareSpecificity(a.specificity, b.specificity); } // Run a single pass with the given chunk size. function pass(arr: Spec[], len: number, chk: number, result: Spec[]) { // Step size / double chunk size. const dbl = chk * 2; // Bounds of the left and right chunks. let l, r, e; // Iterators over the left and right chunk. let li, ri; // Iterate over pairs of chunks. let i = 0; for (l = 0; l < len; l += dbl) { r = l + chk; e = r + chk; if (r > len) { r = len; } if (e > len) { e = len; } // Iterate both chunks in parallel. li = l; ri = r; while (true) { // Compare the chunks. if (li < r && ri < e) { // This works for a regular `sort()` compatible comparator, // but also for a simple comparator like: `a > b` if (bySelectorSpecificity(arr[li], arr[ri]) <= 0) { result[i++] = arr[li++]; } else { result[i++] = arr[ri++]; } } // Nothing to compare, just flush what's left. else if (li < r) { result[i++] = arr[li++]; } else if (ri < e) { result[i++] = arr[ri++]; } // Both iterators are at the chunk ends. else { break; } } } } // Execute the sort using the input array and a second buffer as work space. // Returns one of those two, containing the final result. function exec(arr: Spec[], len: number): Spec[] { // Rather than dividing input, simply iterate chunks of 1, 2, 4, 8, etc. // Chunks are the size of the left or right hand in merge sort. // Stop when the left-hand covers all of the array. let buffer = new Array(len); for (let chk = 1; chk < len; chk *= 2) { pass(arr, len, chk, buffer); const tmp = arr; arr = buffer; buffer = tmp; } return arr; } /** * Sort selectors stably by their specificity. * * @param {Array} selectors to be sorted * @return {Array} Stable sorted selectors */ function sortSelectors(selectors: FlatSelectorList) { // Short-circuit when there's nothing to sort. const len = selectors.length; if (len <= 1) { return selectors; } const specs = selectors.map(selectorWithSpecificity); return exec(specs, len).map((s) => s.selector); } const declarationParseProps = { context: 'declarationList', parseValue: false, }; function CSSStyleDeclaration(ast: XmlAST) { const { props, styles } = ast; if (!props.style) { props.style = {}; } const style = props.style as Styles; const priority = new Map(); ast.style = style; ast.priority = priority; if (!styles || styles.length === 0) { return; } try { const declarations = csstree.parse( styles, declarationParseProps ) as DeclarationList; declarations.children.each((node) => { try { const { property, value, important } = node as Declaration; const name = property.trim(); priority.set(name, important); style[camelCase(name)] = csstree.generate(value).trim(); } catch (styleError) { if ( styleError instanceof Error && styleError.message !== 'Unknown node type: undefined' ) { console.warn( "Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " + styleError ); } } }); } catch (parseError) { console.warn( "Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " + parseError ); } } interface StyledAST extends XmlAST { style: Styles; priority: Map; } function initStyle(selectedEl: XmlAST): StyledAST { if (!selectedEl.style) { CSSStyleDeclaration(selectedEl); } return selectedEl as StyledAST; } /** * Find the closest ancestor of the current element. * @param node * @param elemName * @return {?Object} */ function closestElem(node: XmlAST, elemName: string) { let elem: XmlAST | null = node; while ((elem = elem.parent) && elem.tag !== elemName) { /* empty */ } return elem; } const parseProps = { parseValue: false, parseCustomProperty: false, }; /** * Moves + merges styles from style elements to element styles * * Options * useMqs (default: ['', 'screen']) * what media queries to be used * empty string element for styles outside media queries * * usePseudos (default: ['']) * what pseudo-classes/-elements to be used * empty string element for all non-pseudo-classes and/or -elements * * @param {Object} document document element * * @author strarsis * @author modified by: msand */ function extractVariables(stylesheet: CssNode): Map { const variables = new Map(); csstree.walk(stylesheet, { visit: 'Declaration', enter(node) { const { property, value } = node as Declaration; if (property.startsWith('--')) { const variableName = property.trim(); const variableValue = csstree.generate(value).trim(); variables.set(variableName, variableValue); } }, }); return variables; } function resolveVariables( value: string | CssNode | undefined, variables: Map ): string { if (value === undefined) { return ''; } const valueStr = typeof value === 'string' ? value : csstree.generate(value); return valueStr.replace( /var\((--[^,)]+)(?:,\s*([^)]+))?\)/g, (_, variableName, fallback) => { const resolvedValue = variables.get(variableName); if (resolvedValue !== undefined) { return resolveVariables(resolvedValue, variables); } return fallback ? resolveVariables(fallback, variables) : ''; } ); } const propsToResolve = [ 'color', 'fill', 'floodColor', 'lightingColor', 'stopColor', 'stroke', ]; const resolveElementVariables = ( element: XmlAST, variables: Map ) => propsToResolve.forEach((prop) => { const value = element.props[prop] as string; if (value && value.startsWith('var(')) { element.props[prop] = resolveVariables(value, variables); } }); export const inlineStyles: Middleware = function inlineStyles( document: XmlAST ) { // collect