Add Windows support (#1632)

Adds Windows support.

Co-authored-by: Adam Gleitman <adam.gleitman@gmail.com>
Co-authored-by: REDMOND\agnel <agnel@microsoft.com>
This commit is contained in:
Marlene Cota
2022-07-15 02:02:21 -07:00
committed by Wojciech Lewicki
parent 4d3c521a22
commit 28d51bdf06
92 changed files with 5679 additions and 4 deletions

View File

@@ -3,7 +3,7 @@
[![Version](https://img.shields.io/npm/v/react-native-svg.svg)](https://www.npmjs.com/package/react-native-svg) [![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) [![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 and Android, and a compatibility layer for the web. `react-native-svg` provides SVG support to React Native on iOS, Android, macOS, Windows, and a compatibility layer for the web.
[Check out the demo](https://snack.expo.io/@msand/react-native-svg-example) [Check out the demo](https://snack.expo.io/@msand/react-native-svg-example)

View File

@@ -20,7 +20,8 @@
"lib", "lib",
"src", "src",
"RNSVG.podspec", "RNSVG.podspec",
"!android/build" "!android/build",
"windows"
], ],
"@react-native-community/bob": { "@react-native-community/bob": {
"source": "src", "source": "src",
@@ -36,6 +37,7 @@
"react-native", "react-native",
"ios", "ios",
"android", "android",
"windows",
"SVG", "SVG",
"ART", "ART",
"VML", "VML",
@@ -87,8 +89,9 @@
"jest": "^28.1.0", "jest": "^28.1.0",
"pegjs": "^0.10.0", "pegjs": "^0.10.0",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"react": "^16.13.0", "react": "^17.0.1",
"react-native": "^0.62.3", "react-native": "^0.64.0",
"react-native-windows": "^0.64.0",
"react-test-renderer": "^16.13.0", "react-test-renderer": "^16.13.0",
"release-it": "^14.12.5", "release-it": "^14.12.5",
"ts-node": "^10.8.0", "ts-node": "^10.8.0",

91
windows/.clang-format Normal file
View File

@@ -0,0 +1,91 @@
---
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: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, TEST_CLASS, TEST_CLASS_EX ]
IncludeBlocks: Preserve
IncludeCategories:
- Regex: 'pch.h'
Priority: -1
- Regex: '.*\.g\..*'
Priority: 1
- Regex: '^<.*\.h(pp)?>'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4
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

92
windows/.gitignore vendored Normal file
View File

@@ -0,0 +1,92 @@
*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/**

187
windows/RNSVG.sln Normal file
View File

@@ -0,0 +1,187 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29215.179
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNSVG", "RNSVG\RNSVG.vcxproj", "{7ACF84EC-EFBA-4043-8E14-40B159508902}"
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}") = "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}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}"
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
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
..\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\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
..\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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM.ActiveCfg = Debug|ARM
{7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM.Build.0 = Debug|ARM
{7ACF84EC-EFBA-4043-8E14-40B159508902}.Debug|ARM.Deploy.0 = Debug|ARM
{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|ARM64.Deploy.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|x64.Deploy.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|ARM.ActiveCfg = Release|ARM
{7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM.Build.0 = Release|ARM
{7ACF84EC-EFBA-4043-8E14-40B159508902}.Release|ARM.Deploy.0 = Release|ARM
{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|ARM64.Deploy.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|x64.Deploy.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
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM
{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|ARM.ActiveCfg = Release|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM
{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
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM
{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|ARM.ActiveCfg = Release|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM
{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|ARM.ActiveCfg = Debug|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM
{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|ARM.ActiveCfg = Release|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM
{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
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM
{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|ARM.ActiveCfg = Release|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {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}
{0CC28589-39E4-4288-B162-97B959F8B843} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {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
EndGlobal

View File

@@ -0,0 +1,24 @@
#include "pch.h"
#include "BrushView.h"
#include "BrushView.g.cpp"
namespace winrt::RNSVG::implementation {
void BrushView::SaveDefinition() {
if (auto const &root{SvgRoot()}) {
CreateBrush();
root.Brushes().Insert(Id(), *this);
}
}
void BrushView::SetBounds(Windows::Foundation::Rect const &rect) {
m_bounds = rect;
UpdateBounds();
}
void BrushView::Unload() {
m_brush.Close();
m_brush = nullptr;
__super::Unload();
}
} // namespace winrt::RNSVG::implementation

28
windows/RNSVG/BrushView.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include "BrushView.g.h"
#include "GroupView.h"
namespace winrt::RNSVG::implementation {
struct BrushView : BrushViewT<BrushView, RNSVG::implementation::GroupView> {
public:
BrushView() = default;
void SaveDefinition();
Microsoft::Graphics::Canvas::Brushes::ICanvasBrush Brush() { return m_brush; }
virtual void CreateBrush() {}
virtual void Unload();
void SetBounds(Windows::Foundation::Rect const &rect);
protected:
Microsoft::Graphics::Canvas::Brushes::ICanvasBrush m_brush{nullptr};
Windows::Foundation::Rect m_bounds{};
virtual void UpdateBounds() {}
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct BrushView : BrushViewT<BrushView, implementation::BrushView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,41 @@
#include "pch.h"
#include "CircleView.h"
#include "CircleView.g.cpp"
#include "JSValueXaml.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void CircleView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "r") {
m_r = SVGLength::From(propertyValue);
} else if (propertyName == "cx") {
m_cx = SVGLength::From(propertyValue);
} else if (propertyName == "cy") {
m_cy = SVGLength::From(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void CircleView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
float cx{Utils::GetAbsoluteLength(m_cx, canvas.Size().Width)};
float cy{Utils::GetAbsoluteLength(m_cy, canvas.Size().Height)};
float r{Utils::GetAbsoluteLength(m_r, Utils::GetCanvasDiagonal(canvas.Size()))};
Geometry(Geometry::CanvasGeometry::CreateCircle(resourceCreator, cx, cy, r));
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,20 @@
#pragma once
#include "CircleView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct CircleView : CircleViewT<CircleView, RNSVG::implementation::RenderableView> {
public:
CircleView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
private:
RNSVG::SVGLength m_r{};
RNSVG::SVGLength m_cx{};
RNSVG::SVGLength m_cy{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct CircleView : CircleViewT<CircleView, implementation::CircleView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,28 @@
#include "pch.h"
#include "CircleViewManager.h"
#include "CircleViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
CircleViewManager::CircleViewManager() {
m_class = RNSVG::SVGClass::RNSVGCircle;
m_name = L"RNSVGCircle";
}
IMapView<hstring, ViewManagerPropertyType> CircleViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"cx", ViewManagerPropertyType::String);
nativeProps.Insert(L"cy", ViewManagerPropertyType::String);
nativeProps.Insert(L"r", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,15 @@
#pragma once
#include "CircleViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct CircleViewManager : CircleViewManagerT<CircleViewManager, RNSVG::implementation::RenderableViewManager> {
CircleViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct CircleViewManager : CircleViewManagerT<CircleViewManager, implementation::CircleViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,10 @@
#include "pch.h"
#include "DefsView.h"
#include "DefsView.g.cpp"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
namespace winrt::RNSVG::implementation {
void DefsView::Render(UI::Xaml::CanvasControl const &/*canvas*/, CanvasDrawingSession const &/*session*/) {}
} // namespace winrt::RNSVG::implementation

17
windows/RNSVG/DefsView.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include "DefsView.g.h"
#include "GroupView.h"
namespace winrt::RNSVG::implementation {
struct DefsView : DefsViewT<DefsView, RNSVG::implementation::GroupView> {
DefsView() = default;
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct DefsView : DefsViewT<DefsView, implementation::DefsView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,10 @@
#include "pch.h"
#include "DefsViewManager.h"
#include "DefsViewManager.g.cpp"
namespace winrt::RNSVG::implementation {
DefsViewManager::DefsViewManager() {
m_class = RNSVG::SVGClass::RNSVGDefs;
m_name = L"RNSVGDefs";
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,12 @@
#pragma once
#include "DefsViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct DefsViewManager : DefsViewManagerT<DefsViewManager, RNSVG::implementation::GroupViewManager> {
DefsViewManager();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct DefsViewManager : DefsViewManagerT<DefsViewManager, implementation::DefsViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,44 @@
#include "pch.h"
#include "EllipseView.h"
#include "EllipseView.g.cpp"
#include "JSValueXaml.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void EllipseView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "cx") {
m_cx = SVGLength::From(propertyValue);
} else if (propertyName == "cy") {
m_cy = SVGLength::From(propertyValue);
} else if (propertyName == "rx") {
m_rx = SVGLength::From(propertyValue);
} else if (propertyName == "ry") {
m_ry = SVGLength::From(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void EllipseView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
float cx{Utils::GetAbsoluteLength(m_cx, canvas.Size().Width)};
float cy{Utils::GetAbsoluteLength(m_cy, canvas.Size().Height)};
float rx{Utils::GetAbsoluteLength(m_rx, canvas.Size().Width)};
float ry{Utils::GetAbsoluteLength(m_ry, canvas.Size().Height)};
Geometry(Geometry::CanvasGeometry::CreateEllipse(resourceCreator, cx, cy, rx, ry));
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,21 @@
#pragma once
#include "EllipseView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct EllipseView : EllipseViewT<EllipseView, RNSVG::implementation::RenderableView> {
public:
EllipseView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
private:
RNSVG::SVGLength m_cx{};
RNSVG::SVGLength m_cy{};
RNSVG::SVGLength m_rx{};
RNSVG::SVGLength m_ry{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct EllipseView : EllipseViewT<EllipseView, implementation::EllipseView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,29 @@
#include "pch.h"
#include "EllipseViewManager.h"
#include "EllipseViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
EllipseViewManager::EllipseViewManager() {
m_class = RNSVG::SVGClass::RNSVGEllipse;
m_name = L"RNSVGEllipse";
}
IMapView<hstring, ViewManagerPropertyType> EllipseViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"cx", ViewManagerPropertyType::String);
nativeProps.Insert(L"cy", ViewManagerPropertyType::String);
nativeProps.Insert(L"rx", ViewManagerPropertyType::String);
nativeProps.Insert(L"ry", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,15 @@
#pragma once
#include "EllipseViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct EllipseViewManager : EllipseViewManagerT<EllipseViewManager, RNSVG::implementation::RenderableViewManager> {
EllipseViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct EllipseViewManager : EllipseViewManagerT<EllipseViewManager, implementation::EllipseViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

172
windows/RNSVG/GroupView.cpp Normal file
View File

@@ -0,0 +1,172 @@
#include "pch.h"
#include "JSValueXaml.h"
#include "GroupView.h"
#if __has_include("GroupView.g.cpp")
#include "GroupView.g.cpp"
#endif
#include "SVGLength.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void GroupView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
auto const &parent{SvgParent().try_as<RNSVG::GroupView>()};
auto fontProp{RNSVG::FontProp::Unknown};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "font") {
auto const &font{propertyValue.AsObject()};
// When any of the font props update, you don't get individual updates.
// Instead, you get a new JSValueObject with all font props set on the element.
// If a prop was removed, you will not get a null type - it just won't
// be part of the new prop object, so we will reset all font values.
if (forceUpdate) {
m_fontPropMap[RNSVG::FontProp::FontSize] = false;
m_fontPropMap[RNSVG::FontProp::FontFamily] = false;
m_fontPropMap[RNSVG::FontProp::FontWeight] = false;
}
for (auto const &item : m_fontPropMap) {
if (!item.second) {
switch (item.first) {
case RNSVG::FontProp::FontSize:
m_fontSize = parent ? parent.FontSize() : 12.0f;
break;
case RNSVG::FontProp::FontFamily:
m_fontFamily = parent ? parent.FontFamily() : L"Segoe UI";
break;
case RNSVG::FontProp::FontWeight:
m_fontWeight = L"auto";
break;
default:
throw hresult_error();
}
}
}
for (auto const &prop : font) {
auto const &key{prop.first};
auto const &value{prop.second};
if (key == "fontSize") {
fontProp = RNSVG::FontProp::FontSize;
if (forceUpdate || !m_fontPropMap[fontProp]) {
m_fontSize = value.AsSingle();
}
} else if (key == "fontFamily") {
fontProp = RNSVG::FontProp::FontFamily;
if (forceUpdate || !m_fontPropMap[fontProp]) {
m_fontFamily = to_hstring(value.AsString());
}
} else if (key == "fontWeight") {
fontProp = RNSVG::FontProp::FontWeight;
auto fontWeight{to_hstring(value.AsString())};
if (forceUpdate) {
m_fontWeight = fontWeight;
} else if (!m_fontPropMap[fontProp]) {
m_fontWeight = L"auto";
}
}
// forceUpdate = true means the property is being set on an element
// instead of being inherited from the parent.
if (forceUpdate && (fontProp != RNSVG::FontProp::Unknown)) {
// If the propertyValue is null, that means we reset the property
m_fontPropMap[fontProp] = true;
}
}
}
}
__super::UpdateProperties(reader, forceUpdate, false);
for (auto const &child : Children()) {
child.UpdateProperties(reader, false, false);
}
if (invalidate && SvgParent()) {
SvgRoot().InvalidateCanvas();
}
}
void GroupView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
std::vector<Geometry::CanvasGeometry> geometries;
for (auto const &child : Children()) {
geometries.push_back(child.Geometry());
}
Geometry(Geometry::CanvasGeometry::CreateGroup(resourceCreator, geometries, FillRule()));
}
void GroupView::SaveDefinition() {
__super::SaveDefinition();
for (auto const &child : Children()) {
child.SaveDefinition();
}
}
void GroupView::MergeProperties(RNSVG::RenderableView const &other) {
__super::MergeProperties(other);
for (auto const &child : Children()) {
child.MergeProperties(*this);
}
}
void GroupView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
auto const &transform{session.Transform()};
if (m_propSetMap[RNSVG::BaseProp::Matrix]) {
session.Transform(transform * SvgTransform());
}
if (auto const &opacityLayer{session.CreateLayer(m_opacity)}) {
if (Children().Size() == 0) {
__super::Render(canvas, session);
} else {
RenderGroup(canvas, session);
}
opacityLayer.Close();
}
session.Transform(transform);
}
void GroupView::RenderGroup(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
for (auto const &child : Children()) {
child.Render(canvas, session);
}
}
void GroupView::CreateResources(ICanvasResourceCreator const &resourceCreator, UI::CanvasCreateResourcesEventArgs const &args) {
for (auto const &child : Children()) {
child.CreateResources(resourceCreator, args);
}
}
void GroupView::Unload() {
for (auto const &child : Children()) {
child.Unload();
}
m_reactContext = nullptr;
m_fontPropMap.clear();
m_children.Clear();
__super::Unload();
}
} // namespace winrt::RNSVG::implementation

62
windows/RNSVG/GroupView.h Normal file
View File

@@ -0,0 +1,62 @@
#pragma once
#include "GroupView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct GroupView : GroupViewT<GroupView, RNSVG::implementation::RenderableView> {
public:
GroupView() = default;
GroupView(Microsoft::ReactNative::IReactContext const &context) : m_reactContext(context) {}
Windows::Foundation::Collections::IVector<RNSVG::IRenderable> Children() { return m_children; }
hstring FontFamily() { return m_fontFamily; }
void FontFamily(hstring const &value) { m_fontFamily = value; }
float FontSize() { return m_fontSize; }
void FontSize(float value) { m_fontSize = value; }
hstring FontWeight(){ return m_fontWeight; }
void FontWeight(hstring const &value) { m_fontWeight = value; }
virtual void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
virtual void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
virtual void SaveDefinition();
virtual void MergeProperties(RNSVG::RenderableView const &other);
virtual void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
virtual void RenderGroup(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
virtual void CreateResources(
Microsoft::Graphics::Canvas::ICanvasResourceCreator const &resourceCreator,
Microsoft::Graphics::Canvas::UI::CanvasCreateResourcesEventArgs const &args);
virtual void Unload();
private:
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Windows::Foundation::Collections::IVector<RNSVG::IRenderable> m_children{
winrt::single_threaded_vector<RNSVG::IRenderable>()};
float m_fontSize{12.0f};
hstring m_fontFamily{L"Segoe UI"};
hstring m_fontWeight{L"auto"};
std::map<RNSVG::FontProp, bool> m_fontPropMap{
{RNSVG::FontProp::FontSize, false},
{RNSVG::FontProp::FontWeight, false},
{RNSVG::FontProp::FontFamily, false},
};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct GroupView : GroupViewT<GroupView, implementation::GroupView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,107 @@
#include "pch.h"
#include "GroupViewManager.h"
#if __has_include("GroupViewManager.g.cpp")
#include "GroupViewManager.g.cpp"
#endif
#include "GroupView.h"
#include <winrt/Windows.UI.Xaml.Shapes.h>
using namespace winrt;
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
namespace winrt::RNSVG::implementation {
GroupViewManager::GroupViewManager() {
m_class = RNSVG::SVGClass::RNSVGGroup;
m_name = L"RNSVGGroup";
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> GroupViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"font", ViewManagerPropertyType::Map);
return nativeProps.GetView();
}
// IViewManagerWithChildren
void GroupViewManager::AddView(FrameworkElement const &parent, UIElement const &child, int64_t /*index*/) {
if (auto const &groupView{parent.try_as<RNSVG::GroupView>()}) {
if (auto const &childView{child.try_as<IRenderable>()}) {
childView.SvgParent(parent);
groupView.Children().Append(childView);
childView.MergeProperties(groupView);
if (auto const &root{groupView.SvgRoot()}) {
root.InvalidateCanvas();
}
}
}
}
void GroupViewManager::RemoveAllChildren(FrameworkElement const &parent) {
if (auto const &groupView{parent.try_as<RNSVG::GroupView>()}) {
for (auto const &child : groupView.Children()) {
child.Unload();
child.SvgParent(nullptr);
}
groupView.Children().Clear();
if (auto const &root{groupView.SvgRoot()}) {
root.InvalidateCanvas();
}
}
}
void GroupViewManager::RemoveChildAt(FrameworkElement const &parent, int64_t index) {
if (auto const &groupView{parent.try_as<RNSVG::GroupView>()}) {
auto const &child{groupView.Children().GetAt(static_cast<uint32_t>(index))};
child.Unload();
child.SvgParent(nullptr);
groupView.Children().RemoveAt(static_cast<uint32_t>(index));
if (auto const &root{groupView.SvgRoot()}) {
root.InvalidateCanvas();
}
}
}
void GroupViewManager::ReplaceChild(
FrameworkElement const &parent,
UIElement const &oldChild,
UIElement const &newChild) {
auto const &groupView{parent.try_as<RNSVG::GroupView>()};
auto const &oldChildView{oldChild.try_as<IRenderable>()};
auto const &newChildView{newChild.try_as<IRenderable>()};
if (groupView && oldChildView && newChildView) {
uint32_t index;
if (groupView.Children().IndexOf(oldChildView, index)) {
groupView.Children().RemoveAt(index);
oldChildView.Unload();
oldChildView.SvgParent(nullptr);
newChildView.SvgParent(parent);
groupView.Children().Append(newChildView);
newChildView.MergeProperties(groupView);
if (auto const &root{groupView.SvgRoot()}) {
root.InvalidateCanvas();
}
}
}
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,28 @@
#pragma once
#include "GroupViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct GroupViewManager : GroupViewManagerT<GroupViewManager, RNSVG::implementation::RenderableViewManager> {
public:
GroupViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
// IViewManagerWithChildren
void
AddView(Windows::UI::Xaml::FrameworkElement const &parent, Windows::UI::Xaml::UIElement const &child, int64_t index);
void RemoveAllChildren(Windows::UI::Xaml::FrameworkElement const &parent);
void RemoveChildAt(Windows::UI::Xaml::FrameworkElement const &parent, int64_t index);
void ReplaceChild(
Windows::UI::Xaml::FrameworkElement const &parent,
Windows::UI::Xaml::UIElement const &oldChild,
Windows::UI::Xaml::UIElement const &newChild);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct GroupViewManager : GroupViewManagerT<GroupViewManager, implementation::GroupViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

267
windows/RNSVG/ImageView.cpp Normal file
View File

@@ -0,0 +1,267 @@
#include "pch.h"
#include "ImageView.h"
#include "ImageView.g.cpp"
#include <winrt/Microsoft.Graphics.Canvas.Effects.h>
#include <winrt/Windows.Security.Cryptography.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Windows.Web.Http.h>
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
using namespace Windows::Security::Cryptography;
using namespace Windows::Storage::Streams;
using namespace Windows::Web::Http;
namespace winrt::RNSVG::implementation {
void ImageView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "src") {
auto const &src{propertyValue.AsObject()};
for (auto const &item : src) {
auto const &key{item.first};
auto const &value{item.second};
if (key == "uri") {
m_source.uri = to_hstring(Utils::JSValueAsString(value));
m_source.type = ImageSourceType::Uri;
m_source.format = ImageSourceFormat::Bitmap;
m_source.width = 0;
m_source.height = 0;
if (SvgParent()) {
LoadImageSourceAsync(SvgRoot().Canvas(), true);
}
} else if (key == "width") {
m_source.width = Utils::JSValueAsFloat(value);
} else if (key == "height") {
m_source.height = Utils::JSValueAsFloat(value);
} else if (key == "scale") {
m_source.scale = Utils::JSValueAsFloat(value);
} else if (key == "method") {
m_source.method = to_hstring(Utils::JSValueAsString(value));
} else if (key == "headers") {
m_source.headers.clear();
for (auto const &header : value.AsObject()) {
m_source.headers.push_back(std::make_pair(to_hstring(header.first), to_hstring(Utils::JSValueAsString(header.second))));
}
} else if (key == "__packager_asset") {
m_source.packagerAsset = value.AsBoolean();
}
}
} else if (propertyName == "x") {
m_x = SVGLength::From(propertyValue);
} else if (propertyName == "y") {
m_y = SVGLength::From(propertyValue);
} else if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void ImageView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
if (m_source.width == 0 || m_source.height == 0) {
m_source.width = canvas.Size().Width;
m_source.height = canvas.Size().Height;
}
float x{Utils::GetAbsoluteLength(m_x, canvas.Size().Width)};
float y{Utils::GetAbsoluteLength(m_y, canvas.Size().Height)};
float width{Utils::GetAbsoluteLength(m_width, canvas.Size().Width)};
float height{Utils::GetAbsoluteLength(m_height, canvas.Size().Height)};
if (width == 0) {
width = m_source.width * m_source.scale;
}
if (height == 0) {
height = m_source.height * m_source.scale;
}
Effects::Transform2DEffect transformEffect{nullptr};
if (m_align != "") {
Rect elRect{x, y, width, height};
Rect vbRect{0, 0, m_source.width, m_source.height};
transformEffect = Effects::Transform2DEffect{};
transformEffect.TransformMatrix(Utils::GetViewBoxTransform(vbRect, elRect, m_align, m_meetOrSlice));
}
if (auto const &opacityLayer{session.CreateLayer(m_opacity)}) {
if (m_source.format == ImageSourceFormat::Bitmap && m_bitmap) {
auto const &transform{session.Transform()};
if (m_propSetMap[RNSVG::BaseProp::Matrix]) {
session.Transform(SvgTransform());
}
if (m_align != "" && transformEffect) {
transformEffect.Source(m_bitmap);
Effects::CropEffect cropEffect{};
cropEffect.SourceRectangle({x, y, width, height});
cropEffect.Source(transformEffect);
session.DrawImage(cropEffect);
} else {
session.DrawImage(m_bitmap, {x, y, width, height});
}
session.Transform(transform);
}
opacityLayer.Close();
}
}
void ImageView::CreateResources(ICanvasResourceCreator const &resourceCreator, UI::CanvasCreateResourcesEventArgs const &args) {
args.TrackAsyncAction(LoadImageSourceAsync(resourceCreator, false));
}
void ImageView::Unload() {
if (m_bitmap) {
m_bitmap.Close();
m_bitmap = nullptr;
}
}
IAsyncAction ImageView::LoadImageSourceAsync(ICanvasResourceCreator resourceCreator, bool invalidate) {
Uri uri{m_source.uri};
hstring scheme{uri ? uri.SchemeName() : L""};
hstring ext{uri ? uri.Extension() : L""};
if (ext == L".svg" || ext == L".svgz") {
m_source.format = ImageSourceFormat::Svg;
co_return;
}
if (scheme == L"http" || scheme == L"https") {
m_source.type = ImageSourceType::Download;
} else if (scheme == L"data") {
m_source.type = ImageSourceType::InlineData;
if (to_string(m_source.uri).find("image/svg+xml") != std::string::npos) {
m_source.format = ImageSourceFormat::Svg;
co_return;
}
}
const bool fromStream{m_source.type == ImageSourceType::Download || m_source.type == ImageSourceType::InlineData};
InMemoryRandomAccessStream stream{nullptr};
// get weak reference before any co_await calls
auto weak_this{get_weak()};
try {
stream = co_await GetImageMemoryStreamAsync(m_source);
if (fromStream && !stream) {
co_return;
}
} catch (winrt::hresult_error const &) {
co_return;
}
if (stream) {
m_bitmap = co_await CanvasBitmap::LoadAsync(resourceCreator, stream);
} else {
m_bitmap = co_await CanvasBitmap::LoadAsync(resourceCreator, uri);
}
m_source.width = m_bitmap.Size().Width;
m_source.height = m_bitmap.Size().Height;
if (invalidate) {
if (auto strong_this{weak_this.get()}) {
strong_this->SvgRoot().InvalidateCanvas();
}
}
}
IAsyncOperation<InMemoryRandomAccessStream> ImageView::GetImageMemoryStreamAsync(ImageSource source) {
switch (source.type) {
case ImageSourceType::Download:
co_return co_await GetImageStreamAsync(source);
case ImageSourceType::InlineData:
co_return co_await GetImageInlineDataAsync(source);
default: // ImageSourceType::Uri
co_return nullptr;
}
}
IAsyncOperation<InMemoryRandomAccessStream> ImageView::GetImageStreamAsync(ImageSource source) {
try {
co_await resume_background();
auto httpMethod{source.method.empty() ? HttpMethod::Get() : HttpMethod{source.method}};
Uri uri{source.uri};
HttpRequestMessage request{httpMethod, uri};
if (!source.headers.empty()) {
for (auto const &header : source.headers) {
if (_stricmp(to_string(header.first).c_str(), "authorization") == 0) {
request.Headers().TryAppendWithoutValidation(header.first, header.second);
} else {
request.Headers().Append(header.first, header.second);
}
}
}
HttpClient httpClient;
HttpResponseMessage response{co_await httpClient.SendRequestAsync(request)};
if (response && response.StatusCode() == HttpStatusCode::Ok) {
IInputStream inputStream{co_await response.Content().ReadAsInputStreamAsync()};
InMemoryRandomAccessStream memoryStream;
co_await RandomAccessStream::CopyAsync(inputStream, memoryStream);
memoryStream.Seek(0);
co_return memoryStream;
}
} catch (hresult_error const &) {
}
co_return nullptr;
}
IAsyncOperation<InMemoryRandomAccessStream> ImageView::GetImageInlineDataAsync(ImageSource source) {
std::string uri{to_string(source.uri)};
size_t start = uri.find(',');
if (start == std::string::npos || start + 1 > uri.length()) {
co_return nullptr;
}
try {
co_await winrt::resume_background();
std::string_view base64String{uri.c_str() + start + 1, uri.length() - start - 1};
auto const &buffer{CryptographicBuffer::DecodeFromBase64String(to_hstring(base64String))};
InMemoryRandomAccessStream memoryStream;
co_await memoryStream.WriteAsync(buffer);
memoryStream.Seek(0);
co_return memoryStream;
} catch (winrt::hresult_error const &) {
// Base64 decode failed
}
co_return nullptr;
}
} // namespace winrt::RNSVG::implementation

58
windows/RNSVG/ImageView.h Normal file
View File

@@ -0,0 +1,58 @@
#pragma once
#include "ImageView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
enum class ImageSourceType { Uri = 0, Download = 1, InlineData = 2 };
enum class ImageSourceFormat { Bitmap = 0, Svg = 1 };
struct ImageSource {
hstring uri{L""};
hstring method{L""};
std::vector<std::pair<hstring, hstring>> headers{};
float width{0.0f};
float height{0.0f};
float scale{1.0f};
bool packagerAsset{false};
ImageSourceType type{ImageSourceType::Uri};
ImageSourceFormat format{ImageSourceFormat::Bitmap};
};
struct ImageView : ImageViewT<ImageView, RNSVG::implementation::RenderableView> {
public:
ImageView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
void CreateResources(
Microsoft::Graphics::Canvas::ICanvasResourceCreator const &resourceCreator,
Microsoft::Graphics::Canvas::UI::CanvasCreateResourcesEventArgs const &args);
void Unload();
private:
RNSVG::SVGLength m_x{};
RNSVG::SVGLength m_y{};
RNSVG::SVGLength m_width{};
RNSVG::SVGLength m_height{};
// preserveAspectRatio
std::string m_align{""};
RNSVG::MeetOrSlice m_meetOrSlice{RNSVG::MeetOrSlice::Meet};
ImageSource m_source{};
Microsoft::Graphics::Canvas::CanvasBitmap m_bitmap{nullptr};
Windows::Foundation::IAsyncAction LoadImageSourceAsync(Microsoft::Graphics::Canvas::ICanvasResourceCreator resourceCreator, bool invalidate);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::InMemoryRandomAccessStream>
GetImageMemoryStreamAsync(ImageSource source);
Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::InMemoryRandomAccessStream>
GetImageStreamAsync(ImageSource source);
Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::InMemoryRandomAccessStream>
GetImageInlineDataAsync(ImageSource source);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct ImageView : ImageViewT<ImageView, implementation::ImageView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,34 @@
#include "pch.h"
#include "ImageViewManager.h"
#include "ImageViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
ImageViewManager::ImageViewManager() {
m_class = RNSVG::SVGClass::RNSVGImage;
m_name = L"RNSVGImage";
}
IMapView<hstring, ViewManagerPropertyType> ImageViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"x", ViewManagerPropertyType::String);
nativeProps.Insert(L"y", ViewManagerPropertyType::String);
nativeProps.Insert(L"height", ViewManagerPropertyType::String);
nativeProps.Insert(L"width", ViewManagerPropertyType::String);
nativeProps.Insert(L"src", ViewManagerPropertyType::String);
// preserveAspectRatio
nativeProps.Insert(L"align", ViewManagerPropertyType::String);
nativeProps.Insert(L"meetOrSlice", ViewManagerPropertyType::Number);
return nativeProps.GetView();
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "ImageViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct ImageViewManager : ImageViewManagerT<ImageViewManager, RNSVG::implementation::RenderableViewManager> {
ImageViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct ImageViewManager : ImageViewManagerT<ImageViewManager, implementation::ImageViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,47 @@
#include "pch.h"
#include "LineView.h"
#include "LineView.g.cpp"
#include "JSValueXaml.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void LineView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "x1") {
m_x1 = SVGLength::From(propertyValue);
} else if (propertyName == "y1") {
m_y1 = SVGLength::From(propertyValue);
} else if (propertyName == "x2") {
m_x2 = SVGLength::From(propertyValue);
} else if (propertyName == "y2") {
m_y2 = SVGLength::From(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void LineView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
float x1{Utils::GetAbsoluteLength(m_x1, canvas.Size().Width)};
float y1{Utils::GetAbsoluteLength(m_y1, canvas.Size().Height)};
float x2{Utils::GetAbsoluteLength(m_x2, canvas.Size().Width)};
float y2{Utils::GetAbsoluteLength(m_y2, canvas.Size().Height)};
auto const &pathBuilder{Geometry::CanvasPathBuilder(resourceCreator)};
pathBuilder.BeginFigure(x1, y1);
pathBuilder.AddLine (x2, y2);
pathBuilder.EndFigure(Geometry::CanvasFigureLoop::Open);
Geometry(Geometry::CanvasGeometry::CreatePath(pathBuilder));
}
} // namespace winrt::RNSVG::implementation

21
windows/RNSVG/LineView.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include "LineView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct LineView : LineViewT<LineView, RNSVG::implementation::RenderableView> {
public:
LineView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
private:
RNSVG::SVGLength m_x1{};
RNSVG::SVGLength m_y1{};
RNSVG::SVGLength m_x2{};
RNSVG::SVGLength m_y2{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct LineView : LineViewT<LineView, implementation::LineView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,29 @@
#include "pch.h"
#include "LineViewManager.h"
#include "LineViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
LineViewManager::LineViewManager() {
m_class = RNSVG::SVGClass::RNSVGLine;
m_name = L"RNSVGLine";
}
IMapView<hstring, ViewManagerPropertyType> LineViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"x1", ViewManagerPropertyType::String);
nativeProps.Insert(L"y1", ViewManagerPropertyType::String);
nativeProps.Insert(L"x2", ViewManagerPropertyType::String);
nativeProps.Insert(L"y2", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,15 @@
#pragma once
#include "LineViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct LineViewManager : LineViewManagerT<LineViewManager, RNSVG::implementation::RenderableViewManager> {
LineViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct LineViewManager : LineViewManagerT<LineViewManager, implementation::LineViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,81 @@
#include "pch.h"
#include "LinearGradientView.h"
#include "LinearGradientView.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void LinearGradientView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "x1") {
m_x1 = SVGLength::From(propertyValue);
} else if (propertyName == "y1") {
m_y1 = SVGLength::From(propertyValue);
} else if (propertyName == "x2") {
m_x2 = SVGLength::From(propertyValue);
} else if (propertyName == "y2") {
m_y2 = SVGLength::From(propertyValue);
} else if (propertyName == "gradient") {
m_stops = Utils::JSValueAsStops(propertyValue);
} else if (propertyName == "gradientUnits") {
m_gradientUnits = Utils::JSValueAsBrushUnits(propertyValue);
} else if (propertyName == "gradientTransform") {
m_transformSet = true;
m_transform = Utils::JSValueAsTransform(propertyValue);
if (propertyValue.IsNull()) {
m_transformSet = false;
}
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
SaveDefinition();
}
void LinearGradientView::Unload() {
m_stops.clear();
__super::Unload();
}
void LinearGradientView::CreateBrush() {
auto const &canvas{SvgRoot().Canvas()};
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
Brushes::CanvasLinearGradientBrush brush{resourceCreator, m_stops};
SetPoints(brush, {0, 0, canvas.Size().Width, canvas.Size().Height});
if (m_transformSet) {
brush.Transform(m_transform);
}
m_brush = brush;
}
void LinearGradientView::UpdateBounds() {
if (m_gradientUnits == "objectBoundingBox") {
SetPoints(m_brush.as<Brushes::CanvasLinearGradientBrush>(), m_bounds);
}
}
void LinearGradientView::SetPoints(Brushes::CanvasLinearGradientBrush brush, Windows::Foundation::Rect const &bounds) {
float x1{Utils::GetAbsoluteLength(m_x1, bounds.Width) + bounds.X};
float y1{Utils::GetAbsoluteLength(m_y1, bounds.Height) + bounds.Y};
float x2{Utils::GetAbsoluteLength(m_x2, bounds.Width) + bounds.X};
float y2{Utils::GetAbsoluteLength(m_y2, bounds.Height) + bounds.Y};
brush.StartPoint({x1, y1});
brush.EndPoint({x2, y2});
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,32 @@
#pragma once
#include "LinearGradientView.g.h"
#include "BrushView.h"
namespace winrt::RNSVG::implementation {
struct LinearGradientView : LinearGradientViewT<LinearGradientView, RNSVG::implementation::BrushView> {
public:
LinearGradientView() = default;
// RenderableView
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void Unload();
private:
RNSVG::SVGLength m_x1{};
RNSVG::SVGLength m_y1{};
RNSVG::SVGLength m_x2{};
RNSVG::SVGLength m_y2{};
std::vector<Microsoft::Graphics::Canvas::Brushes::CanvasGradientStop> m_stops{};
std::string m_gradientUnits{"objectBoundingBox"};
bool m_transformSet{false};
Numerics::float3x2 m_transform{Numerics::make_float3x2_scale(1)};
void CreateBrush();
void UpdateBounds();
void SetPoints(Microsoft::Graphics::Canvas::Brushes::CanvasLinearGradientBrush brush, Windows::Foundation::Rect const &bounds);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct LinearGradientView : LinearGradientViewT<LinearGradientView, implementation::LinearGradientView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,32 @@
#include "pch.h"
#include "LinearGradientViewManager.h"
#include "LinearGradientViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
LinearGradientViewManager::LinearGradientViewManager() {
m_class = RNSVG::SVGClass::RNSVGLinearGradient;
m_name = L"RNSVGLinearGradient";
}
IMapView<hstring, ViewManagerPropertyType> LinearGradientViewManager::NativeProps() {
auto const& parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"x1", ViewManagerPropertyType::String);
nativeProps.Insert(L"y1", ViewManagerPropertyType::String);
nativeProps.Insert(L"x2", ViewManagerPropertyType::String);
nativeProps.Insert(L"y2", ViewManagerPropertyType::String);
nativeProps.Insert(L"gradient", ViewManagerPropertyType::Array);
nativeProps.Insert(L"gradientUnits", ViewManagerPropertyType::Number);
nativeProps.Insert(L"gradientTransform", ViewManagerPropertyType::Array);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,18 @@
#pragma once
#include "LinearGradientViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct LinearGradientViewManager
: LinearGradientViewManagerT<LinearGradientViewManager, RNSVG::implementation::GroupViewManager> {
LinearGradientViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct LinearGradientViewManager
: LinearGradientViewManagerT<LinearGradientViewManager, implementation::LinearGradientViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

295
windows/RNSVG/PathView.cpp Normal file
View File

@@ -0,0 +1,295 @@
#include "pch.h"
#include "PathView.h"
#if __has_include("PathView.g.cpp")
#include "PathView.g.cpp"
#endif
#include <winrt/Microsoft.Graphics.Canvas.Svg.h>
#include "JSValueXaml.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void PathView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "d") {
m_commands.clear();
m_segmentData.clear();
if (propertyValue.IsNull()) {
m_d.clear();
} else {
m_d = propertyValue.AsString();
ParsePath();
}
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void PathView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
Svg::CanvasSvgDocument doc{resourceCreator};
auto const &path{doc.CreatePathAttribute(m_segmentData, m_commands)};
Geometry(path.CreatePathGeometry());
}
void PathView::ParsePath() {
char prev_cmd = ' ';
size_t i{0};
auto length{m_d.length()};
while (i < length) {
SkipSpaces(i);
if (i > length) {
break;
}
bool has_prev_cmd{prev_cmd != ' '};
char first_char = m_d.at(i);
if (!has_prev_cmd && first_char != 'M' && first_char != 'm') {
throw hresult_invalid_argument(L"First segment must be a MoveTo.");
}
bool is_implicit_move_to{false};
char cmd = ' ';
if (IsCommand(first_char)) {
cmd = first_char;
m_commands.push_back(m_cmds[cmd]);
++i;
} else if (has_prev_cmd && IsNumberStart(first_char)) {
if (prev_cmd == 'Z' || prev_cmd == 'z') {
throw hresult_invalid_argument(L"ClosePath cannot be followed by a number.");
}
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.
is_implicit_move_to = true;
if (IsUpper(prev_cmd)) {
cmd = 'L';
m_commands.push_back(m_cmds[cmd]);
} else {
cmd = 'l';
m_commands.push_back(m_cmds[cmd]);
}
} else {
cmd = prev_cmd;
m_commands.push_back(m_cmds[cmd]);
}
} else {
throw hresult_invalid_argument(L"Unexpected character: " + first_char);
}
bool absolute{IsUpper(cmd)};
switch (cmd) {
case 'm':
case 'M':
case 'l':
case 'L':
case 't':
case 'T':
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
break;
case 'h':
case 'H':
case 'v':
case 'V':
m_segmentData.push_back(ParseListNumber(i));
break;
case 's':
case 'S':
case 'q':
case 'Q':
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
break;
case 'c':
case 'C':
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
break;
case 'a':
case 'A':
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseFlag(i));
m_segmentData.push_back(ParseFlag(i));
m_segmentData.push_back(ParseListNumber(i));
m_segmentData.push_back(ParseListNumber(i));
break;
case 'z':
case 'Z':
break;
default:
throw hresult_invalid_argument(L"Unexpected command.");
}
if (is_implicit_move_to) {
if (absolute) {
prev_cmd = 'M';
} else {
prev_cmd = 'm';
}
} else {
prev_cmd = cmd;
}
}
}
void PathView::SkipSpaces(size_t &index) {
while (index < m_d.length() && IsSpace(m_d.at(index))) {
++index;
}
}
void PathView::SkipDigits(size_t& index) {
while (index < m_d.length() && IsDigit(m_d.at(index))) {
++index;
}
}
void PathView::SkipListSeparator(size_t& index) {
if (index < m_d.length() && m_d.at(index) == ',') {
++index;
}
}
bool PathView::IsCommand(char const &cmd) {
return m_cmds.find(cmd) != m_cmds.end();
}
bool PathView::IsNumberStart(char const& c) {
return IsDigit(c) || c == '.' || c == '-' || c == '+';
}
bool PathView::IsDigit(char const &c) {
return std::isdigit(static_cast<unsigned char>(c));
}
bool PathView::IsUpper(char const &c) {
return std::isupper(static_cast<unsigned char>(c));
}
bool PathView::IsSpace(char const& c) {
return std::isspace(static_cast<unsigned char>(c));
}
float PathView::ParseListNumber(size_t &index) {
if (index == m_d.length()) {
throw hresult_invalid_argument(L"Unexpected end.");
}
float result{ParseNumber(index)};
SkipSpaces(index);
SkipListSeparator(index);
return result;
}
float PathView::ParseNumber(size_t &index) {
SkipSpaces(index);
if (index == m_d.length()) {
throw hresult_invalid_argument(L"Unexpected end.");
}
size_t start = index;
char c = m_d.at(start);
// Consume sign.
if (c == '-' || c == '+') {
++index;
c = m_d.at(index);
}
// Consume integer.
if (IsDigit(c)) {
SkipDigits(index);
if (index < m_d.length()) {
c = m_d.at(index);
}
} else if (c != '.') {
throw hresult_invalid_argument(L"Invalid number formating character.");
}
// Consume fraction.
if (c == '.') {
++index;
SkipDigits(index);
if (index < m_d.length()) {
c = m_d.at(index);
}
}
if ((c == 'e' || c == 'E') && ((index + 1) < m_d.length())) {
char c2 = m_d.at(index + 1);
// Check for 'em'/'ex'
if (c2 != 'm' && c2 != 'x') {
++index;
c = m_d.at(index);
if (c == '+' || c == '-') {
++index;
SkipDigits(index);
} else if (IsDigit(c)) {
SkipDigits(index);
} else {
throw hresult_invalid_argument(L"Invalid number formating character.");
}
}
}
auto num{m_d.substr(start, index)};
auto result{std::stof(num, nullptr)};
if (std::isinf(result) || std::isnan(result)) {
throw hresult_invalid_argument(L"Invalid number.");
}
return result;
}
float PathView::ParseFlag(size_t& index) {
SkipSpaces(index);
char c = m_d.at(index);
switch (c) {
case '0':
case '1': {
++index;
if (index < m_d.length() && m_d.at(index) == ',') {
++index;
}
SkipSpaces(index);
break;
}
default:
throw hresult_invalid_argument(L"Unexpected flag.");
}
return static_cast<float>(c - '0');
}
} // namespace winrt::RNSVG::implementation

61
windows/RNSVG/PathView.h Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include "PathView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct PathView : PathViewT<PathView, RNSVG::implementation::RenderableView> {
public:
PathView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
private:
std::string m_d;
std::vector<float> m_segmentData;
std::vector<Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand> m_commands;
std::map<char, Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand> m_cmds{
{'M', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::MoveAbsolute},
{'m', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::MoveRelative},
{'Z', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::ClosePath},
{'z', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::ClosePath},
{'L', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::LineAbsolute},
{'l', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::LineRelative},
{'H', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::HorizontalAbsolute},
{'h', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::HorizontalRelative},
{'V', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::VerticalAbsolute},
{'v', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::VerticalRelative},
{'C', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::CubicAbsolute},
{'c', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::CubicRelative},
{'S', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::CubicSmoothAbsolute},
{'s', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::CubicSmoothRelative},
{'Q', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::QuadraticAbsolute},
{'q', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::QuadraticRelative},
{'T', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::QuadraticSmoothAbsolute},
{'t', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::QuadraticSmoothRelative},
{'A', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::ArcAbsolute},
{'a', Microsoft::Graphics::Canvas::Svg::CanvasSvgPathCommand::ArcRelative},
};
void ParsePath();
// Parser helpers
void SkipSpaces(size_t &index);
void SkipDigits(size_t &index);
void SkipListSeparator(size_t &index);
bool IsCommand(char const &cmd);
bool IsNumberStart(char const &c);
bool IsDigit(char const &c);
bool IsUpper(char const &c);
bool IsSpace(char const &c);
float ParseListNumber(size_t &index);
float ParseNumber(size_t &index);
float ParseFlag(size_t &index);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct PathView : PathViewT<PathView, implementation::PathView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,31 @@
#include "pch.h"
#include "PathViewManager.h"
#if __has_include("PathViewManager.g.cpp")
#include "PathViewManager.g.cpp"
#endif
#include "PathViewManager.h"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
PathViewManager::PathViewManager() {
m_class = RNSVG::SVGClass::RNSVGPath;
m_name = L"RNSVGPath";
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> PathViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"d", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,17 @@
#pragma once
#include "PathViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct PathViewManager : PathViewManagerT<PathViewManager, RNSVG::implementation::RenderableViewManager> {
PathViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct PathViewManager : PathViewManagerT<PathViewManager, implementation::PathViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,134 @@
#include "pch.h"
#include "PatternView.h"
#include "PatternView.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void PatternView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "x") {
m_x = SVGLength::From(propertyValue);
} else if (propertyName == "y") {
m_y = SVGLength::From(propertyValue);
} else if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "patternUnits") {
m_patternUnits = Utils::JSValueAsBrushUnits(propertyValue);
} else if (propertyName == "patternContentUnits") {
m_patternContentUnits = Utils::JSValueAsBrushUnits(propertyValue, "userSpaceOnUse");
} else if (propertyName == "patternTransform") {
m_transformSet = true;
m_transform = Utils::JSValueAsTransform(propertyValue);
if (propertyValue.IsNull()) {
m_transformSet = false;
}
} else if (propertyName == "vbWidth") {
m_vbWidth = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "vbHeight") {
m_vbHeight = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minX") {
m_minX = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minY") {
m_minY = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
SaveDefinition();
if (auto const &root{SvgRoot()}) {
root.InvalidateCanvas();
}
}
void PatternView::UpdateBounds() {
if (m_patternUnits == "objectBoundingBox") {
Rect rect{GetAdjustedRect(m_bounds)};
CreateBrush(rect);
}
}
void PatternView::CreateBrush() {
auto const &canvas{SvgRoot().Canvas()};
Rect elRect{GetAdjustedRect({0, 0, canvas.Size().Width, canvas.Size().Height})};
CreateBrush(elRect);
}
void PatternView::CreateBrush(Windows::Foundation::Rect const &rect) {
auto const &canvas{SvgRoot().Canvas()};
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
if (auto const &cmdList{GetCommandList(rect)}) {
Brushes::CanvasImageBrush brush{resourceCreator, cmdList};
brush.SourceRectangle(rect);
brush.ExtendX(Microsoft::Graphics::Canvas::CanvasEdgeBehavior::Wrap);
brush.ExtendY(Microsoft::Graphics::Canvas::CanvasEdgeBehavior::Wrap);
cmdList.Close();
m_brush = brush;
}
}
Windows::Foundation::Rect PatternView::GetAdjustedRect(Windows::Foundation::Rect const &bounds) {
float x{Utils::GetAbsoluteLength(m_x, bounds.Width) + bounds.X};
float y{Utils::GetAbsoluteLength(m_y, bounds.Height) + bounds.Y};
float width{Utils::GetAbsoluteLength(m_width, bounds.Width)};
float height{Utils::GetAbsoluteLength(m_height, bounds.Height)};
return {x, y, width, height};
}
Microsoft::Graphics::Canvas::CanvasCommandList PatternView::GetCommandList(Windows::Foundation::Rect const &rect) {
auto const &root{SvgRoot()};
auto const &canvas{root.Canvas()};
auto const &cmdList{CanvasCommandList(canvas)};
auto const &session{cmdList.CreateDrawingSession()};
if (m_align != "") {
Rect vbRect{
m_minX * root.SvgScale(),
m_minY * root.SvgScale(),
(m_vbWidth + m_minX) * root.SvgScale(),
(m_vbHeight + m_minY) * root.SvgScale()};
auto transform{Utils::GetViewBoxTransform(vbRect, rect, m_align, m_meetOrSlice)};
if (m_transformSet) {
transform = transform * m_transform;
}
session.Transform(transform);
}
for (auto const &child : Children()) {
child.Render(canvas, session);
}
session.Close();
return cmdList;
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,44 @@
#pragma once
#include "PatternView.g.h"
#include "BrushView.h"
namespace winrt::RNSVG::implementation {
struct PatternView : PatternViewT<PatternView, RNSVG::implementation::BrushView> {
public:
PatternView() = default;
// RenderableView
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
private:
RNSVG::SVGLength m_x{};
RNSVG::SVGLength m_y{};
RNSVG::SVGLength m_width{};
RNSVG::SVGLength m_height{};
std::string m_patternUnits{"objectBoundingBox"};
std::string m_patternContentUnits{"userSpaceOnUse"};
bool m_transformSet{false};
Numerics::float3x2 m_transform{Numerics::make_float3x2_scale(1)};
// ViewBox
float m_minX{0.0f};
float m_minY{0.0f};
float m_vbWidth{0.0f};
float m_vbHeight{0.0f};
std::string m_align{""};
RNSVG::MeetOrSlice m_meetOrSlice{RNSVG::MeetOrSlice::Meet};
// BrushView
void CreateBrush();
void UpdateBounds();
// Helpers
void CreateBrush(Windows::Foundation::Rect const &rect);
Windows::Foundation::Rect GetAdjustedRect(Windows::Foundation::Rect const &bounds);
Microsoft::Graphics::Canvas::CanvasCommandList GetCommandList(Windows::Foundation::Rect const &elRect);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct PatternView : PatternViewT<PatternView, implementation::PatternView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,38 @@
#include "pch.h"
#include "PatternViewManager.h"
#include "PatternViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
PatternViewManager::PatternViewManager() {
m_class = RNSVG::SVGClass::RNSVGPattern;
m_name = L"RNSVGPattern";
}
IMapView<hstring, ViewManagerPropertyType> PatternViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"x", ViewManagerPropertyType::String);
nativeProps.Insert(L"y", ViewManagerPropertyType::String);
nativeProps.Insert(L"width", ViewManagerPropertyType::String);
nativeProps.Insert(L"height", ViewManagerPropertyType::String);
nativeProps.Insert(L"patternUnits", ViewManagerPropertyType::Number);
nativeProps.Insert(L"patternContentUnits", ViewManagerPropertyType::Number);
nativeProps.Insert(L"patternTransform", ViewManagerPropertyType::Array);
nativeProps.Insert(L"minX", ViewManagerPropertyType::Number);
nativeProps.Insert(L"minY", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbHeight", ViewManagerPropertyType::Number);
nativeProps.Insert(L"align", ViewManagerPropertyType::String);
nativeProps.Insert(L"meetOrSlice", ViewManagerPropertyType::Number);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,16 @@
#pragma once
#include "PatternViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct PatternViewManager : PatternViewManagerT<PatternViewManager, RNSVG::implementation::GroupViewManager> {
PatternViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct PatternViewManager : PatternViewManagerT<PatternViewManager, implementation::PatternViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

3
windows/RNSVG/RNSVG.def Normal file
View File

@@ -0,0 +1,3 @@
EXPORTS
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE

240
windows/RNSVG/RNSVG.vcxproj Normal file
View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="16.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
<MinimalCoreWin>true</MinimalCoreWin>
<ProjectGuid>{7acf84ec-efba-4043-8e14-40b159508902}</ProjectGuid>
<ProjectName>RNSVG</ProjectName>
<RootNamespace>RNSVG</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="ReactNativeWindowsProps">
<ReactNativeWindowsDir Condition="'$(ReactNativeWindowsDir)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(SolutionDir), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\</ReactNativeWindowsDir>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<ImportGroup Label="ReactNativeWindowsPropertySheets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\external\Microsoft.ReactNative.Uwp.CppLib.props" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props')" />
<Import Project="$(SolutionDir)\packages\$(WinUIPackageProps)" Condition="'$(WinUIPackageProps)'!='' And Exists('$(SolutionDir)\packages\$(WinUIPackageProps)')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateWindowsMetadata>true</GenerateWindowsMetadata>
<ModuleDefinitionFile>RNSVG.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="BrushView.h" />
<ClInclude Include="CircleView.h" />
<ClInclude Include="CircleViewManager.h" />
<ClInclude Include="DefsView.h" />
<ClInclude Include="DefsViewManager.h" />
<ClInclude Include="EllipseView.h" />
<ClInclude Include="EllipseViewManager.h" />
<ClInclude Include="GroupView.h" />
<ClInclude Include="GroupViewManager.h" />
<ClInclude Include="ImageView.h" />
<ClInclude Include="ImageViewManager.h" />
<ClInclude Include="LinearGradientView.h" />
<ClInclude Include="LinearGradientViewManager.h" />
<ClInclude Include="LineView.h" />
<ClInclude Include="LineViewManager.h" />
<ClInclude Include="PathView.h" />
<ClInclude Include="PathViewManager.h" />
<ClInclude Include="PatternView.h" />
<ClInclude Include="PatternViewManager.h" />
<ClInclude Include="RadialGradientView.h" />
<ClInclude Include="RadialGradientViewManager.h" />
<ClInclude Include="RectView.h" />
<ClInclude Include="RectViewManager.h" />
<ClInclude Include="RenderableView.h" />
<ClInclude Include="RenderableViewManager.h" />
<ClInclude Include="SVGLength.h" />
<ClInclude Include="SvgView.h" />
<ClInclude Include="SvgViewManager.h" />
<ClInclude Include="SymbolView.h" />
<ClInclude Include="SymbolViewManager.h" />
<ClInclude Include="TextView.h" />
<ClInclude Include="TextViewManager.h" />
<ClInclude Include="TSpanView.h" />
<ClInclude Include="TSpanViewManager.h" />
<ClInclude Include="UseView.h" />
<ClInclude Include="UseViewManager.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="ReactPackageProvider.h">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClInclude>
<ClInclude Include="RNSVGModule.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BrushView.cpp" />
<ClCompile Include="CircleView.cpp" />
<ClCompile Include="CircleViewManager.cpp" />
<ClCompile Include="DefsView.cpp" />
<ClCompile Include="DefsViewManager.cpp" />
<ClCompile Include="EllipseView.cpp" />
<ClCompile Include="EllipseViewManager.cpp" />
<ClCompile Include="GroupView.cpp" />
<ClCompile Include="GroupViewManager.cpp" />
<ClCompile Include="ImageView.cpp" />
<ClCompile Include="ImageViewManager.cpp" />
<ClCompile Include="LinearGradientView.cpp" />
<ClCompile Include="LinearGradientViewManager.cpp" />
<ClCompile Include="LineView.cpp" />
<ClCompile Include="LineViewManager.cpp" />
<ClCompile Include="PathView.cpp" />
<ClCompile Include="PatternView.cpp" />
<ClCompile Include="PatternViewManager.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PathViewManager.cpp" />
<ClCompile Include="RadialGradientView.cpp" />
<ClCompile Include="RadialGradientViewManager.cpp" />
<ClCompile Include="ReactPackageProvider.cpp">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="RectView.cpp" />
<ClCompile Include="RectViewManager.cpp" />
<ClCompile Include="RenderableView.cpp" />
<ClCompile Include="RenderableViewManager.cpp" />
<ClCompile Include="SVGLength.cpp" />
<ClCompile Include="SvgView.cpp" />
<ClCompile Include="SvgViewManager.cpp" />
<ClCompile Include="SymbolView.cpp" />
<ClCompile Include="SymbolViewManager.cpp" />
<ClCompile Include="TextView.cpp" />
<ClCompile Include="TextViewManager.cpp" />
<ClCompile Include="TSpanView.cpp" />
<ClCompile Include="TSpanViewManager.cpp" />
<ClCompile Include="UseView.cpp" />
<ClCompile Include="UseViewManager.cpp" />
</ItemGroup>
<ItemGroup>
<Midl Include="ReactPackageProvider.idl" />
<Midl Include="Types.idl" />
<Midl Include="Views.idl">
<SubType>Designer</SubType>
</Midl>
<Midl Include="ViewManagers.idl">
<SubType>Designer</SubType>
</Midl>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="PropertySheet.props" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ReactNativeWindowsTargets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets')" />
</ImportGroup>
<Target Name="EnsureReactNativeWindowsTargets" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props'))" />
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets'))" />
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="$(SolutionDir)\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets" Condition="Exists('$(SolutionDir)\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets')" />
<Import Project="$(SolutionDir)\packages\Win2D.uwp.1.25.0\build\native\Win2D.uwp.targets" Condition="Exists('$(SolutionDir)\packages\Win2D.uwp.1.25.0\build\native\Win2D.uwp.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\Win2D.uwp.1.25.0\build\native\Win2D.uwp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Win2D.uwp.1.25.0\build\native\Win2D.uwp.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,268 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Midl Include="ReactPackageProvider.idl" />
<Midl Include="Views.idl">
<Filter>IDLs</Filter>
</Midl>
<Midl Include="ViewManagers.idl">
<Filter>IDLs</Filter>
</Midl>
<Midl Include="Types.idl">
<Filter>IDLs</Filter>
</Midl>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="ReactPackageProvider.cpp" />
<ClCompile Include="RectView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="SVGLength.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="RectViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="PathViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="PathView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="GroupView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="TextView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="TSpanView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="CircleView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="CircleViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="EllipseViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="EllipseView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="LineViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="LineView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="RenderableView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="SvgView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="SymbolView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="SvgViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="RenderableViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="GroupViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="TextViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="TSpanViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="UseView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="SymbolViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="UseViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="DefsViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="LinearGradientViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="DefsView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="LinearGradientView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="BrushView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="PatternViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
<ClCompile Include="PatternView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="ImageView.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="ImageViewManager.cpp">
<Filter>ViewManagers</Filter>
</ClCompile>
<ClCompile Include="RadialGradientView.cpp">
<Filter>Views\GroupViews</Filter>
</ClCompile>
<ClCompile Include="RadialGradientViewManager.cpp">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ReactPackageProvider.h" />
<ClInclude Include="RNSVGModule.h" />
<ClInclude Include="RectView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="SVGLength.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="RectViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="PathViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="PathView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="GroupView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="TextView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="TSpanView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="CircleView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="CircleViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="EllipseViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="EllipseView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="LineViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="LineView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="RenderableView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="SvgView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="SymbolView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="SvgViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="RenderableViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="GroupViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="TextViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="TSpanViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="UseView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="SymbolViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="UseViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="DefsViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="LinearGradientViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="DefsView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="LinearGradientView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="BrushView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="PatternViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
<ClInclude Include="PatternView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="ImageView.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="ImageViewManager.h">
<Filter>ViewManagers</Filter>
</ClInclude>
<ClInclude Include="RadialGradientView.h">
<Filter>Views\GroupViews</Filter>
</ClInclude>
<ClInclude Include="RadialGradientViewManager.h">
<Filter>ViewManagers\GroupViewManagers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Filter Include="Views">
<UniqueIdentifier>{e902587e-fe1d-4643-875b-d58996b40d98}</UniqueIdentifier>
</Filter>
<Filter Include="ViewManagers">
<UniqueIdentifier>{cb3ce7b2-9fdf-4578-8e0d-4d6853b727bc}</UniqueIdentifier>
</Filter>
<Filter Include="Utils">
<UniqueIdentifier>{8a4e0664-0d52-46ca-b476-a1ad90239a09}</UniqueIdentifier>
</Filter>
<Filter Include="Views\GroupViews">
<UniqueIdentifier>{96f26034-8559-4794-a806-4ecac541e02b}</UniqueIdentifier>
</Filter>
<Filter Include="ViewManagers\GroupViewManagers">
<UniqueIdentifier>{5942afc3-8b5d-4d8c-bb09-e82581f606b7}</UniqueIdentifier>
</Filter>
<Filter Include="IDLs">
<UniqueIdentifier>{50f81ae3-d543-477a-a60c-a0f310289f29}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,33 @@
#pragma once
#include "JSValue.h"
#include "NativeModules.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::RNSVG
{
REACT_MODULE(RNSVGModule, L"RNSVG")
struct RNSVGModule
{
// See https://microsoft.github.io/react-native-windows/docs/native-modules for details on writing native modules
REACT_INIT(Initialize)
void Initialize(ReactContext const &reactContext) noexcept
{
m_reactContext = reactContext;
}
REACT_METHOD(sampleMethod)
void
sampleMethod(std::string stringArgument, int numberArgument, std::function<void(std::string)> &&callback) noexcept
{
// TODO: Implement some actually useful functionality
callback("Received numberArgument: " + std::to_string(numberArgument) + " stringArgument: " + stringArgument);
}
private:
ReactContext m_reactContext{nullptr};
};
} // namespace winrt::RNSVG

View File

@@ -0,0 +1,92 @@
#include "pch.h"
#include "RadialGradientView.h"
#include "RadialGradientView.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void RadialGradientView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "fx") {
m_fx = SVGLength::From(propertyValue);
} else if (propertyName == "fy") {
m_fy = SVGLength::From(propertyValue);
} else if (propertyName == "rx") {
m_rx = SVGLength::From(propertyValue);
} else if (propertyName == "ry") {
m_ry = SVGLength::From(propertyValue);
} else if (propertyName == "cx") {
m_cx = SVGLength::From(propertyValue);
} else if (propertyName == "cy") {
m_cy = SVGLength::From(propertyValue);
} else if (propertyName == "gradient") {
m_stops = Utils::JSValueAsStops(propertyValue);
} else if (propertyName == "gradientUnits") {
m_gradientUnits = Utils::JSValueAsBrushUnits(propertyValue);
} else if (propertyName == "gradientTransform") {
m_transformSet = true;
m_transform = Utils::JSValueAsTransform(propertyValue);
if (propertyValue.IsNull()) {
m_transformSet = false;
}
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
SaveDefinition();
}
void RadialGradientView::Unload() {
m_stops.clear();
__super::Unload();
}
void RadialGradientView::CreateBrush() {
auto const &canvas{SvgRoot().Canvas()};
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
Brushes::CanvasRadialGradientBrush brush{resourceCreator, m_stops};
SetPoints(brush, {0, 0, canvas.Size().Width, canvas.Size().Height});
if (m_transformSet) {
brush.Transform(m_transform);
}
m_brush = brush;
}
void RadialGradientView::UpdateBounds() {
if (m_gradientUnits == "objectBoundingBox") {
SetPoints(m_brush.as<Brushes::CanvasRadialGradientBrush>(), m_bounds);
}
}
void RadialGradientView::SetPoints(Brushes::CanvasRadialGradientBrush brush, Windows::Foundation::Rect const &bounds) {
float rx{Utils::GetAbsoluteLength(m_rx, bounds.Width)};
float ry{Utils::GetAbsoluteLength(m_ry, bounds.Height)};
float fx{Utils::GetAbsoluteLength(m_fx, bounds.Width) + bounds.X};
float fy{Utils::GetAbsoluteLength(m_fy, bounds.Height) + bounds.Y};
float cx{Utils::GetAbsoluteLength(m_cx, bounds.Width) + bounds.X};
float cy{Utils::GetAbsoluteLength(m_cy, bounds.Height) + bounds.Y};
brush.RadiusX(rx);
brush.RadiusY(ry);
brush.Center({cx, cy});
brush.OriginOffset({(fx - cx), (fy - cy)});
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,34 @@
#pragma once
#include "RadialGradientView.g.h"
#include "BrushView.h"
namespace winrt::RNSVG::implementation {
struct RadialGradientView : RadialGradientViewT<RadialGradientView, RNSVG::implementation::BrushView> {
public:
RadialGradientView() = default;
// RenderableView
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void Unload();
private:
RNSVG::SVGLength m_fx{};
RNSVG::SVGLength m_fy{};
RNSVG::SVGLength m_rx{};
RNSVG::SVGLength m_ry{};
RNSVG::SVGLength m_cx{};
RNSVG::SVGLength m_cy{};
std::vector<Microsoft::Graphics::Canvas::Brushes::CanvasGradientStop> m_stops{};
std::string m_gradientUnits{"objectBoundingBox"};
bool m_transformSet{false};
Numerics::float3x2 m_transform{Numerics::make_float3x2_scale(1)};
void CreateBrush();
void UpdateBounds();
void SetPoints(Microsoft::Graphics::Canvas::Brushes::CanvasRadialGradientBrush brush, Windows::Foundation::Rect const &bounds);
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RadialGradientView : RadialGradientViewT<RadialGradientView, implementation::RadialGradientView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,34 @@
#include "pch.h"
#include "RadialGradientViewManager.h"
#include "RadialGradientViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
RadialGradientViewManager::RadialGradientViewManager() {
m_class = RNSVG::SVGClass::RNSVGRadialGradient;
m_name = L"RNSVGRadialGradient";
}
IMapView<hstring, ViewManagerPropertyType> RadialGradientViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"fx", ViewManagerPropertyType::String);
nativeProps.Insert(L"fy", ViewManagerPropertyType::String);
nativeProps.Insert(L"rx", ViewManagerPropertyType::String);
nativeProps.Insert(L"ry", ViewManagerPropertyType::String);
nativeProps.Insert(L"cx", ViewManagerPropertyType::String);
nativeProps.Insert(L"cy", ViewManagerPropertyType::String);
nativeProps.Insert(L"gradient", ViewManagerPropertyType::Array);
nativeProps.Insert(L"gradientUnits", ViewManagerPropertyType::Number);
nativeProps.Insert(L"gradientTransform", ViewManagerPropertyType::Array);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,18 @@
#pragma once
#include "RadialGradientViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct RadialGradientViewManager
: RadialGradientViewManagerT<RadialGradientViewManager, RNSVG::implementation::GroupViewManager> {
RadialGradientViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RadialGradientViewManager
: RadialGradientViewManagerT<RadialGradientViewManager, implementation::RadialGradientViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,50 @@
#include "pch.h"
#include "ReactPackageProvider.h"
#if __has_include("ReactPackageProvider.g.cpp")
#include "ReactPackageProvider.g.cpp"
#endif
#include "RNSVGModule.h"
#include "SvgViewManager.h"
#include "GroupViewManager.h"
#include "PathViewManager.h"
#include "RectViewManager.h"
#include "CircleViewManager.h"
#include "EllipseViewManager.h"
#include "LineViewManager.h"
#include "UseViewManager.h"
#include "ImageViewManager.h"
#include "TextViewManager.h"
#include "TSpanViewManager.h"
#include "SymbolViewManager.h"
#include "DefsViewManager.h"
#include "LinearGradientViewManager.h"
#include "RadialGradientViewManager.h"
#include "PatternViewManager.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::RNSVG::implementation
{
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
{
AddAttributedModules(packageBuilder);
packageBuilder.AddViewManager(L"SvgViewManager", []() { return winrt::make<SvgViewManager>(); });
packageBuilder.AddViewManager(L"GroupViewManager", []() { return winrt::make<GroupViewManager>(); });
packageBuilder.AddViewManager(L"PathViewManager", []() { return winrt::make<PathViewManager>(); });
packageBuilder.AddViewManager(L"RectViewManager", []() { return winrt::make<RectViewManager>(); });
packageBuilder.AddViewManager(L"CircleViewManager", []() { return winrt::make<CircleViewManager>(); });
packageBuilder.AddViewManager(L"EllipseViewManager", []() { return winrt::make<EllipseViewManager>(); });
packageBuilder.AddViewManager(L"LineViewManager", []() { return winrt::make<LineViewManager>(); });
packageBuilder.AddViewManager(L"UseViewManager", []() { return winrt::make<UseViewManager>(); });
packageBuilder.AddViewManager(L"ImageViewManager", []() { return winrt::make<ImageViewManager>(); });
packageBuilder.AddViewManager(L"TextViewManager", []() { return winrt::make<TextViewManager>(); });
packageBuilder.AddViewManager(L"TSpanViewManager", []() { return winrt::make<TSpanViewManager>(); });
packageBuilder.AddViewManager(L"SymbolViewManager", []() { return winrt::make<SymbolViewManager>(); });
packageBuilder.AddViewManager(L"DefsViewManager", []() { return winrt::make<DefsViewManager>(); });
packageBuilder.AddViewManager(L"LinearGradientViewManager", []() { return winrt::make<LinearGradientViewManager>(); });
packageBuilder.AddViewManager(L"RadialGradientViewManager", []() { return winrt::make<RadialGradientViewManager>(); });
packageBuilder.AddViewManager(L"PatternViewManager", []() { return winrt::make<PatternViewManager>(); });
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,21 @@
#pragma once
#include "ReactPackageProvider.g.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::RNSVG::implementation
{
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider>
{
ReactPackageProvider() = default;
void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation
{
struct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider, implementation::ReactPackageProvider> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,9 @@
namespace RNSVG
{
[webhosthidden]
[default_interface]
runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
{
ReactPackageProvider();
};
}

View File

@@ -0,0 +1,55 @@
#include "pch.h"
#include "RectView.h"
#if __has_include("RectView.g.cpp")
#include "RectView.g.cpp"
#endif
#include "JSValueXaml.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void RectView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "x") {
m_x = SVGLength::From(propertyValue);
} else if (propertyName == "y") {
m_y = SVGLength::From(propertyValue);
} else if (propertyName == "rx") {
m_rx = SVGLength::From(propertyValue);
} else if (propertyName == "ry") {
m_ry = SVGLength::From(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void RectView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
float x{Utils::GetAbsoluteLength(m_x, canvas.Size().Width)};
float y{Utils::GetAbsoluteLength(m_y, canvas.Size().Height)};
float width{Utils::GetAbsoluteLength(m_width, canvas.Size().Width)};
float height{Utils::GetAbsoluteLength(m_height, canvas.Size().Height)};
auto const &rxLength{m_rx.Unit() == RNSVG::LengthType::Unknown ? m_ry : m_rx};
auto const &ryLength{m_ry.Unit() == RNSVG::LengthType::Unknown ? m_rx : m_ry};
float rx{Utils::GetAbsoluteLength(rxLength, canvas.Size().Width)};
float ry{Utils::GetAbsoluteLength(ryLength, canvas.Size().Height)};
Geometry(Geometry::CanvasGeometry::CreateRoundedRectangle(resourceCreator, x, y, width, height, rx, ry));
}
} // namespace winrt::RNSVG::implementation

26
windows/RNSVG/RectView.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include "RectView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct RectView : RectViewT<RectView, RNSVG::implementation::RenderableView> {
public:
RectView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
private:
RNSVG::SVGLength m_width{};
RNSVG::SVGLength m_height{};
RNSVG::SVGLength m_x{};
RNSVG::SVGLength m_y{};
RNSVG::SVGLength m_rx{};
RNSVG::SVGLength m_ry{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RectView : RectViewT<RectView, implementation::RectView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,36 @@
#include "pch.h"
#include "RectViewManager.h"
#if __has_include("RectViewManager.g.cpp")
#include "RectViewManager.g.cpp"
#endif
#include "RectView.h"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
RectViewManager::RectViewManager() {
m_class = RNSVG::SVGClass::RNSVGRect;
m_name = L"RNSVGRect";
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> RectViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"height", ViewManagerPropertyType::String);
nativeProps.Insert(L"width", ViewManagerPropertyType::String);
nativeProps.Insert(L"x", ViewManagerPropertyType::String);
nativeProps.Insert(L"y", ViewManagerPropertyType::String);
nativeProps.Insert(L"rx", ViewManagerPropertyType::String);
nativeProps.Insert(L"ry", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,17 @@
#pragma once
#include "RectViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct RectViewManager : RectViewManagerT<RectViewManager, RNSVG::implementation::RenderableViewManager> {
RectViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RectViewManager : RectViewManagerT<RectViewManager, implementation::RectViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,341 @@
#include "pch.h"
#include "RenderableView.h"
#if __has_include("RenderableView.g.cpp")
#include "RenderableView.g.cpp"
#endif
#include "JSValueXaml.h"
#include "SvgView.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void RenderableView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
auto const &parent{SvgParent().try_as<RNSVG::RenderableView>()};
auto const &propList{propertyMap.find("propList")};
if (propList != propertyMap.end()) {
m_propList.clear();
auto const &propValue{(*propList).second};
for (auto const &item : propValue.AsArray()) {
m_propList.push_back(Utils::JSValueAsString(item));
}
}
bool fillSet{std::find(m_propList.begin(), m_propList.end(), "fill") != m_propList.end()};
bool strokeSet{std::find(m_propList.begin(), m_propList.end(), "stroke") != m_propList.end()};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
auto prop{RNSVG::BaseProp::Unknown};
// name is not a prop we want to propagate to child elements
// so we only set it when forceUpdate = true
if (propertyName == "name" && forceUpdate) {
if (parent) {
SvgRoot().Templates().Remove(m_id);
}
m_id = to_hstring(Utils::JSValueAsString(propertyValue));
if (parent) {
SaveDefinition();
}
} else if (propertyName == "strokeWidth") {
prop = RNSVG::BaseProp::StrokeWidth;
if (forceUpdate || !m_propSetMap[prop]) {
auto const &fallbackValue{parent ? parent.StrokeWidth() : RNSVG::SVGLength(1.0f, RNSVG::LengthType::Pixel)};
m_strokeWidth = Utils::JSValueAsSVGLength(propertyValue, fallbackValue);
}
} else if (propertyName == "strokeOpacity") {
prop = RNSVG::BaseProp::StrokeOpacity;
if (forceUpdate || !m_propSetMap[prop]) {
float fallbackValue{parent ? parent.StrokeOpacity() : 1.0f};
m_strokeOpacity = Utils::JSValueAsFloat(propertyValue, fallbackValue);
}
} else if (propertyName == "fillOpacity") {
prop = RNSVG::BaseProp::FillOpacity;
if (forceUpdate || !m_propSetMap[prop]) {
float fallbackValue{parent ? parent.FillOpacity() : 1.0f};
m_fillOpacity = Utils::JSValueAsFloat(propertyValue, fallbackValue);
}
} else if (propertyName == "stroke") {
prop = RNSVG::BaseProp::Stroke;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.Type() == JSValueType::Array) {
auto const &brush{propertyValue.AsArray()};
m_strokeBrushId = to_hstring(Utils::JSValueAsString(brush.at(1)));
} else {
Windows::UI::Color fallbackColor{(parent && !strokeSet) ? parent.Stroke() : Windows::UI::Colors::Transparent()};
m_stroke = Utils::JSValueAsColor(propertyValue, fallbackColor);
}
}
} else if (propertyName == "fill") {
prop = RNSVG::BaseProp::Fill;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.Type() == JSValueType::Array) {
auto const &brush{propertyValue.AsArray()};
m_fillBrushId = to_hstring(Utils::JSValueAsString(brush.at(1)));
} else {
Windows::UI::Color fallbackColor{Windows::UI::Colors::Black()};
if (propertyValue.IsNull() && fillSet) {
fallbackColor = Windows::UI::Colors::Transparent();
} else if (parent) {
fallbackColor = parent.Fill();
}
m_fill = Utils::JSValueAsColor(propertyValue, fallbackColor);
}
}
} else if (propertyName == "strokeLinecap") {
prop = RNSVG::BaseProp::StrokeLineCap;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.IsNull()) {
m_strokeLineCap = parent.StrokeLineCap();
} else {
auto const &strokeLineCap{propertyValue.AsInt32()};
switch (strokeLineCap) {
case 2:
m_strokeLineCap = Geometry::CanvasCapStyle::Square;
break;
case 1:
m_strokeLineCap = Geometry::CanvasCapStyle::Round;
break;
case 0:
default:
m_strokeLineCap = Geometry::CanvasCapStyle::Flat;
break;
}
}
}
} else if (propertyName == "strokeLinejoin") {
prop = RNSVG::BaseProp::StrokeLineJoin;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.IsNull()) {
m_strokeLineCap = parent.StrokeLineCap();
} else {
auto const &strokeLineJoin{propertyValue.AsInt32()};
switch (strokeLineJoin) {
case 2:
m_strokeLineJoin = Geometry::CanvasLineJoin::Bevel;
break;
case 1:
m_strokeLineJoin = Geometry::CanvasLineJoin::Round;
break;
case 0:
default:
m_strokeLineJoin = Geometry::CanvasLineJoin::Miter;
break;
}
}
}
} else if (propertyName == "fillRule") {
prop = RNSVG::BaseProp::FillRule;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.IsNull()) {
m_fillRule = parent.FillRule();
} else {
auto const &fillRule{propertyValue.AsInt32()};
switch (fillRule) {
case 0:
m_fillRule = Geometry::CanvasFilledRegionDetermination::Alternate;
break;
case 1:
default:
m_fillRule = Geometry::CanvasFilledRegionDetermination::Winding;
break;
}
}
}
} else if (propertyName == "strokeDashoffset") {
prop = RNSVG::BaseProp::StrokeDashOffset;
if (forceUpdate || !m_propSetMap[prop]) {
float fallbackValue{parent ? parent.StrokeDashOffset() : 0.0f};
m_strokeDashOffset = Utils::JSValueAsFloat(propertyValue, fallbackValue);
}
} else if (propertyName == "strokeMiterlimit") {
prop = RNSVG::BaseProp::StrokeMiterLimit;
if (forceUpdate || !m_propSetMap[prop]) {
float fallbackValue{parent ? parent.StrokeMiterLimit() : 0.0f};
m_strokeMiterLimit = Utils::JSValueAsFloat(propertyValue, fallbackValue);
}
} else if (propertyName == "strokeDasharray") {
prop = RNSVG::BaseProp::StrokeDashArray;
if (forceUpdate || !m_propSetMap[prop]) {
if (propertyValue.IsNull()) {
m_strokeDashArray = parent.StrokeDashArray();
} else {
auto const &asArray = propertyValue.AsArray();
if (!asArray.empty() && (asArray.size() % 2 == 0)) {
m_strokeDashArray.Clear();
for (auto const &item : asArray) {
m_strokeDashArray.Append(SVGLength::From(item));
}
}
}
}
} else if (propertyName == "matrix") {
prop = RNSVG::BaseProp::Matrix;
if (forceUpdate) {
Numerics::float3x2 fallbackValue{parent ? parent.SvgTransform() : Numerics::make_float3x2_rotation(0)};
m_transformMatrix = Utils::JSValueAsTransform(propertyValue, fallbackValue);
}
} else if (propertyName == "opacity" && forceUpdate) {
m_opacity = Utils::JSValueAsFloat(propertyValue, 1.0f);
}
// forceUpdate = true means the property is being set on an element
// instead of being inherited from the parent.
if (forceUpdate && (prop != RNSVG::BaseProp::Unknown)) {
// If the propertyValue is null, that generally means the prop was deleted
bool propSet{!propertyValue.IsNull()};
// The exception being Fill and Stroke due to 'none' coming through as null
if (prop == RNSVG::BaseProp::Fill) {
propSet = fillSet;
} else if (prop == RNSVG::BaseProp::Stroke) {
propSet = strokeSet;
}
m_propSetMap[prop] = propSet;
}
}
m_recreateResources = true;
if (invalidate && SvgParent()) {
SvgRoot().InvalidateCanvas();
}
}
void RenderableView::SaveDefinition() {
if (m_id != L"") {
SvgRoot().Templates().Insert(m_id, *this);
}
}
void RenderableView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
if (m_recreateResources) {
CreateGeometry(canvas);
}
auto geometry{Geometry()};
if (m_propSetMap[RNSVG::BaseProp::Matrix]) {
geometry = geometry.Transform(SvgTransform());
}
geometry = Geometry::CanvasGeometry::CreateGroup(resourceCreator, {geometry}, FillRule());
if (auto const &opacityLayer{session.CreateLayer(m_opacity)}) {
if (auto const &fillLayer{session.CreateLayer(FillOpacity())}) {
auto const &fill{Utils::GetCanvasBrush(FillBrushId(), Fill(), SvgRoot(), geometry, resourceCreator)};
session.FillGeometry(geometry, fill);
fillLayer.Close();
}
if (auto const &strokeLayer{session.CreateLayer(StrokeOpacity())}) {
Geometry::CanvasStrokeStyle strokeStyle{};
strokeStyle.StartCap(StrokeLineCap());
strokeStyle.EndCap(StrokeLineCap());
strokeStyle.LineJoin(StrokeLineJoin());
strokeStyle.DashOffset(StrokeDashOffset());
strokeStyle.MiterLimit(StrokeMiterLimit());
float canvasDiagonal{Utils::GetCanvasDiagonal(canvas.Size())};
float strokeWidth{Utils::GetAbsoluteLength(StrokeWidth(), canvasDiagonal)};
strokeStyle.CustomDashStyle(Utils::GetAdjustedStrokeArray(StrokeDashArray(), strokeWidth, canvasDiagonal));
auto const &stroke{Utils::GetCanvasBrush(StrokeBrushId(), Stroke(), SvgRoot(), geometry, resourceCreator)};
session.DrawGeometry(geometry, stroke, strokeWidth, strokeStyle);
strokeLayer.Close();
}
opacityLayer.Close();
}
}
void RenderableView::MergeProperties(RNSVG::RenderableView const &other) {
for (auto const &prop : m_propSetMap) {
if (!prop.second) {
switch (prop.first) {
case RNSVG::BaseProp::Fill:
m_fill = other.Fill();
m_fillBrushId = other.FillBrushId();
break;
case RNSVG::BaseProp::FillOpacity:
m_fillOpacity = other.FillOpacity();
break;
case RNSVG::BaseProp::FillRule:
m_fillRule = other.FillRule();
break;
case RNSVG::BaseProp::Stroke:
m_stroke = other.Stroke();
m_strokeBrushId = other.StrokeBrushId();
break;
case RNSVG::BaseProp::StrokeOpacity:
m_strokeOpacity = other.StrokeOpacity();
break;
case RNSVG::BaseProp::StrokeWidth:
m_strokeWidth = other.StrokeWidth();
break;
case RNSVG::BaseProp::StrokeMiterLimit:
m_strokeMiterLimit = other.StrokeMiterLimit();
break;
case RNSVG::BaseProp::StrokeDashOffset:
m_strokeDashOffset = other.StrokeDashOffset();
break;
case RNSVG::BaseProp::StrokeDashArray:
m_strokeDashArray = other.StrokeDashArray();
break;
case RNSVG::BaseProp::StrokeLineCap:
m_strokeLineCap = other.StrokeLineCap();
break;
case RNSVG::BaseProp::StrokeLineJoin:
m_strokeLineJoin = other.StrokeLineJoin();
break;
case RNSVG::BaseProp::Unknown:
default:
break;
}
}
}
}
RNSVG::SvgView RenderableView::SvgRoot() {
if (SvgParent()) {
if (auto const &svgView{SvgParent().try_as<RNSVG::SvgView>()}) {
if (svgView.SvgParent()) {
if (auto const &parent{svgView.SvgParent().try_as<RNSVG::RenderableView>()}) {
return parent.SvgRoot();
}
} else {
return svgView;
}
} else if (auto const &renderable{SvgParent().try_as<RNSVG::RenderableView>()}) {
return renderable.SvgRoot();
}
}
return nullptr;
}
void RenderableView::Unload() {
if (m_geometry) {
m_geometry.Close();
m_geometry = nullptr;
}
m_parent = nullptr;
m_reactContext = nullptr;
m_propList.clear();
m_propSetMap.clear();
m_strokeDashArray.Clear();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,97 @@
#pragma once
#include "RenderableView.g.h"
#include "SVGLength.h"
namespace winrt::RNSVG::implementation {
struct RenderableView : RenderableViewT<RenderableView> {
public:
RenderableView() = default;
RenderableView(Microsoft::ReactNative::IReactContext const &context) : m_reactContext(context) {}
RNSVG::SvgView SvgRoot();
Windows::UI::Xaml::FrameworkElement SvgParent() { return m_parent; }
void SvgParent(Windows::UI::Xaml::FrameworkElement const &value) { m_parent = value; }
Microsoft::Graphics::Canvas::Geometry::CanvasGeometry Geometry() { return m_geometry; }
void Geometry(Microsoft::Graphics::Canvas::Geometry::CanvasGeometry value) { m_geometry = value; }
hstring Id() { return m_id; }
Numerics::float3x2 SvgTransform() { return m_transformMatrix; }
hstring FillBrushId() { return m_fillBrushId; }
Windows::UI::Color Fill() { return m_fill; }
float FillOpacity() { return m_fillOpacity; }
hstring StrokeBrushId() { return m_strokeBrushId; }
Windows::UI::Color Stroke() { return m_stroke; }
float StrokeOpacity() { return m_strokeOpacity; }
float StrokeMiterLimit() { return m_strokeMiterLimit; }
float StrokeDashOffset() { return m_strokeDashOffset; }
RNSVG::SVGLength StrokeWidth() { return m_strokeWidth; }
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> StrokeDashArray() { return m_strokeDashArray; }
Microsoft::Graphics::Canvas::Geometry::CanvasCapStyle StrokeLineCap() { return m_strokeLineCap; }
Microsoft::Graphics::Canvas::Geometry::CanvasLineJoin StrokeLineJoin() { return m_strokeLineJoin; }
Microsoft::Graphics::Canvas::Geometry::CanvasFilledRegionDetermination FillRule() { return m_fillRule; }
virtual void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate = true, bool invalidate = true);
virtual void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const & /*canvas*/) {}
virtual void MergeProperties(RNSVG::RenderableView const &other);
virtual void SaveDefinition();
virtual void Unload();
virtual void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
virtual void CreateResources(
Microsoft::Graphics::Canvas::ICanvasResourceCreator const & /*resourceCreator*/,
Microsoft::Graphics::Canvas::UI::CanvasCreateResourcesEventArgs const & /*args*/) { }
protected:
float m_opacity{1.0f};
std::vector<std::string> m_propList{};
std::map<RNSVG::BaseProp, bool> m_propSetMap{
{RNSVG::BaseProp::Matrix, false},
{RNSVG::BaseProp::Fill, false},
{RNSVG::BaseProp::FillOpacity, false},
{RNSVG::BaseProp::FillRule, false},
{RNSVG::BaseProp::Stroke, false},
{RNSVG::BaseProp::StrokeOpacity, false},
{RNSVG::BaseProp::StrokeWidth, false},
{RNSVG::BaseProp::StrokeMiterLimit, false},
{RNSVG::BaseProp::StrokeDashOffset, false},
{RNSVG::BaseProp::StrokeDashArray, false},
{RNSVG::BaseProp::StrokeLineCap, false},
{RNSVG::BaseProp::StrokeLineJoin, false},
};
private:
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Windows::UI::Xaml::FrameworkElement m_parent{nullptr};
Microsoft::Graphics::Canvas::Geometry::CanvasGeometry m_geometry{nullptr};
bool m_recreateResources{true};
hstring m_id{L""};
Numerics::float3x2 m_transformMatrix{Numerics::make_float3x2_rotation(0)};
Windows::UI::Color m_fill{Windows::UI::Colors::Black()};
Windows::UI::Color m_stroke{Windows::UI::Colors::Transparent()};
hstring m_fillBrushId{L""};
hstring m_strokeBrushId{L""};
float m_fillOpacity{1.0f};
float m_strokeOpacity{1.0f};
float m_strokeMiterLimit{0.0f};
float m_strokeDashOffset{0.0f};
RNSVG::SVGLength m_strokeWidth{1.0f, RNSVG::LengthType::Pixel};
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_strokeDashArray{
winrt::single_threaded_vector<RNSVG::SVGLength>()};
Microsoft::Graphics::Canvas::Geometry::CanvasCapStyle m_strokeLineCap{
Microsoft::Graphics::Canvas::Geometry::CanvasCapStyle::Flat};
Microsoft::Graphics::Canvas::Geometry::CanvasLineJoin m_strokeLineJoin{
Microsoft::Graphics::Canvas::Geometry::CanvasLineJoin::Miter};
Microsoft::Graphics::Canvas::Geometry::CanvasFilledRegionDetermination m_fillRule{
Microsoft::Graphics::Canvas::Geometry::CanvasFilledRegionDetermination::Winding};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RenderableView : RenderableViewT<RenderableView, implementation::RenderableView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,78 @@
#include "pch.h"
#include "RenderableViewManager.h"
#if __has_include("RenderableViewManager.g.cpp")
#include "RenderableViewManager.g.cpp"
#endif
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
Windows::UI::Xaml::FrameworkElement RenderableViewManager::CreateView() {
switch (m_class) {
case RNSVG::SVGClass::RNSVGGroup:
return winrt::RNSVG::GroupView(m_reactContext);
case RNSVG::SVGClass::RNSVGPath:
return winrt::RNSVG::PathView();
case RNSVG::SVGClass::RNSVGRect:
return winrt::RNSVG::RectView();
case RNSVG::SVGClass::RNSVGCircle:
return winrt::RNSVG::CircleView();
case RNSVG::SVGClass::RNSVGEllipse:
return winrt::RNSVG::EllipseView();
case RNSVG::SVGClass::RNSVGLine:
return winrt::RNSVG::LineView();
case RNSVG::SVGClass::RNSVGUse:
return winrt::RNSVG::UseView();
case RNSVG::SVGClass::RNSVGImage:
return winrt::RNSVG::ImageView();
case RNSVG::SVGClass::RNSVGText:
return winrt::RNSVG::TextView();
case RNSVG::SVGClass::RNSVGTSpan:
return winrt::RNSVG::TSpanView();
case RNSVG::SVGClass::RNSVGSymbol:
return winrt::RNSVG::SymbolView();
case RNSVG::SVGClass::RNSVGDefs:
return winrt::RNSVG::DefsView();
case RNSVG::SVGClass::RNSVGLinearGradient:
return winrt::RNSVG::LinearGradientView();
case RNSVG::SVGClass::RNSVGRadialGradient:
return winrt::RNSVG::RadialGradientView();
case RNSVG::SVGClass::RNSVGPattern:
return winrt::RNSVG::PatternView();
}
throw hresult_not_implemented();
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> RenderableViewManager::NativeProps() {
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
nativeProps.Insert(L"name", ViewManagerPropertyType::String);
nativeProps.Insert(L"fill", ViewManagerPropertyType::Number);
nativeProps.Insert(L"fillRule", ViewManagerPropertyType::Number);
nativeProps.Insert(L"fillOpacity", ViewManagerPropertyType::Number);
nativeProps.Insert(L"stroke", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeOpacity", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeWidth", ViewManagerPropertyType::String);
nativeProps.Insert(L"strokeLinecap", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeLinejoin", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeMiterlimit", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeDashoffset", ViewManagerPropertyType::Number);
nativeProps.Insert(L"strokeDasharray", ViewManagerPropertyType::Array);
nativeProps.Insert(L"matrix", ViewManagerPropertyType::Array);
nativeProps.Insert(L"opacity", ViewManagerPropertyType::Number);
nativeProps.Insert(L"propList", ViewManagerPropertyType::Array);
return nativeProps.GetView();
}
void RenderableViewManager::UpdateProperties(
Windows::UI::Xaml::FrameworkElement const &view,
Microsoft::ReactNative::IJSValueReader const &propertyMapReader) {
if (auto const &renderable{view.try_as<RenderableView>()}) {
renderable->UpdateProperties(propertyMapReader);
}
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,35 @@
#pragma once
#include "RenderableViewManager.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct RenderableViewManager : RenderableViewManagerT<RenderableViewManager> {
public:
RenderableViewManager() = default;
// IViewManager
hstring Name() { return m_name; }
Windows::UI::Xaml::FrameworkElement CreateView();
// IViewManagerWithReactContext
Microsoft::ReactNative::IReactContext ReactContext() { return m_reactContext; }
void ReactContext(Microsoft::ReactNative::IReactContext const &value) { m_reactContext = value; }
// IViewManagerWithNativeProperties
void UpdateProperties(
Windows::UI::Xaml::FrameworkElement const &view,
Microsoft::ReactNative::IJSValueReader const &propertyMapReader);
virtual
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
protected:
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
RNSVG::SVGClass m_class{RNSVG::SVGClass::Unknown};
hstring m_name{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct RenderableViewManager : RenderableViewManagerT<RenderableViewManager, implementation::RenderableViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,59 @@
#include "pch.h"
#include "SVGLength.h"
#if __has_include("SVGLength.g.cpp")
#include "SVGLength.g.cpp"
#endif
namespace winrt::RNSVG::implementation {
SVGLength::SVGLength(float value) : m_value(value), m_unit(RNSVG::LengthType::Number) {}
SVGLength::SVGLength(float value, RNSVG::LengthType type) : m_value(value), m_unit(type) {}
RNSVG::SVGLength SVGLength::From(std::string value) {
auto strLength{value.size()};
if (strLength == 0 || value == "normal") {
return {0.0, RNSVG::LengthType::Unknown};
} else if (value.back() == '%') {
return {std::stof(value.substr(0, strLength - 1), nullptr), RNSVG::LengthType::Percentage};
} else if (strLength > 2) {
auto end{strLength - 2};
auto lastTwo{value.substr(end)};
auto unit{RNSVG::LengthType::Unknown};
if (lastTwo == "px") {
unit = RNSVG::LengthType::Number;
} else if (lastTwo == "em") {
unit = RNSVG::LengthType::EMS;
} else if (lastTwo == "ex") {
unit = RNSVG::LengthType::EXS;
} else if (lastTwo == "cm") {
unit = RNSVG::LengthType::Centimeter;
} else if (lastTwo == "mm") {
unit = RNSVG::LengthType::Millimeter;
} else if (lastTwo == "in") {
unit = RNSVG::LengthType::Inch;
} else if (lastTwo == "pt") {
unit = RNSVG::LengthType::Point;
} else if (lastTwo == "pc") {
unit = RNSVG::LengthType::Pica;
} else {
unit = RNSVG::LengthType::Number;
end = strLength;
}
return {std::stof(value.substr(0, end), nullptr), unit};
}
return {std::stof(value, nullptr), RNSVG::LengthType::Number};
}
RNSVG::SVGLength SVGLength::From(Microsoft::ReactNative::JSValue const &propertyValue) {
if (propertyValue.IsNull()) {
return {0.0f, RNSVG::LengthType::Unknown};
} else if (propertyValue.Type() == Microsoft::ReactNative::JSValueType::String) {
return SVGLength::From(propertyValue.AsString());
} else {
return RNSVG::SVGLength(propertyValue.AsSingle());
}
}
} // namespace winrt::RNSVG::implementation

28
windows/RNSVG/SVGLength.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include "SVGLength.g.h"
#include "JSValueXaml.h"
namespace winrt::RNSVG::implementation {
struct SVGLength : SVGLengthT<SVGLength> {
public:
SVGLength() = default;
SVGLength(float value);
SVGLength(float value, RNSVG::LengthType type);
float Value() { return m_value; }
RNSVG::LengthType Unit() { return m_unit; }
static RNSVG::SVGLength From(std::string value);
static RNSVG::SVGLength From(Microsoft::ReactNative::JSValue const &value);
private:
float m_value{0.0f};
RNSVG::LengthType m_unit{RNSVG::LengthType::Unknown};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct SVGLength : SVGLengthT<SVGLength, implementation::SVGLength> {};
} // namespace winrt::RNSVG::factory_implementation

194
windows/RNSVG/SvgView.cpp Normal file
View File

@@ -0,0 +1,194 @@
#include "pch.h"
#include "SvgView.h"
#if __has_include("SvgView.g.cpp")
#include "SvgView.g.cpp"
#endif
#include <winrt/Windows.Graphics.Display.h>
#include "GroupView.h"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
using namespace Windows::Graphics::Display;
namespace winrt::RNSVG::implementation {
SvgView::SvgView(IReactContext const &context) : m_reactContext(context) {
m_scale = static_cast<float>(DisplayInformation::GetForCurrentView().ResolutionScale()) / 100;
m_canvasDrawRevoker = m_canvas.Draw(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_Draw});
m_canvasCreateResourcesRevoker = m_canvas.CreateResources(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_CreateResources});
m_canvasSizeChangedRevoker = m_canvas.SizeChanged(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_SizeChanged});
m_panelUnloadedRevoker = Unloaded(winrt::auto_revoke, {get_weak(), &SvgView::Panel_Unloaded});
Children().Append(m_canvas);
}
void SvgView::SvgParent(Windows::UI::Xaml::FrameworkElement const &value) {
if (value) {
m_canvasDrawRevoker.revoke();
m_canvasCreateResourcesRevoker.revoke();
m_canvasSizeChangedRevoker.revoke();
m_panelUnloadedRevoker.revoke();
m_canvas.RemoveFromVisualTree();
m_canvas = nullptr;
m_parent = value;
}
}
void SvgView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
// If forceUpdate is false, that means this is a nested Svg
// and we're inheriting props. Pass those along to the group.
if (!forceUpdate && m_group) {
m_group.UpdateProperties(reader, forceUpdate, invalidate);
} else {
auto const &propertyMap{JSValueObject::ReadFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "name") {
if (m_parent && m_group) {
m_group.SvgRoot().Templates().Remove(m_id);
}
m_id = to_hstring(Utils::JSValueAsString(propertyValue));
if (m_parent) {
SaveDefinition();
}
} else if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "bbWidth") {
m_bbWidth = SVGLength::From(propertyValue);
Width(m_bbWidth.Value());
} else if (propertyName == "bbHeight") {
m_bbHeight = SVGLength::From(propertyValue);
Height(m_bbHeight.Value());
} else if (propertyName == "vbWidth") {
m_vbWidth = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "vbHeight") {
m_vbHeight = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minX") {
m_minX = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minY") {
m_minY = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
}
}
InvalidateCanvas();
}
}
void SvgView::SaveDefinition() {
if (m_id != L"" && m_group) {
m_group.SvgRoot().Templates().Insert(m_id, *this);
m_group.SaveDefinition();
}
}
void SvgView::MergeProperties(RNSVG::RenderableView const &other) {
if (m_group) {
m_group.MergeProperties(other);
}
}
Size SvgView::MeasureOverride(Size availableSize) {
for (auto const &child : Children()) {
child.Measure(availableSize);
}
return availableSize;
}
Size SvgView::ArrangeOverride(Size finalSize) {
for (auto const &child : Children()) {
child.Arrange({0, 0, finalSize.Width, finalSize.Height});
}
return finalSize;
}
void SvgView::Render(UI::Xaml::CanvasControl const & canvas, CanvasDrawingSession const & session) {
if (m_align != "") {
Rect vbRect{m_minX * m_scale, m_minY * m_scale, m_vbWidth * m_scale, m_vbHeight * m_scale};
float width{static_cast<float>(canvas.ActualWidth())};
float height{static_cast<float>(canvas.ActualHeight())};
bool nested{m_parent};
if (nested) {
width = Utils::GetAbsoluteLength(m_bbWidth, width);
height = Utils::GetAbsoluteLength(m_bbHeight, height);
}
Rect elRect{0, 0, width, height};
session.Transform(Utils::GetViewBoxTransform(vbRect, elRect, m_align, m_meetOrSlice));
}
if (m_group) {
m_group.SaveDefinition();
m_group.Render(canvas, session);
}
}
void SvgView::Canvas_Draw(UI::Xaml::CanvasControl const &sender, UI::Xaml::CanvasDrawEventArgs const &args) {
if (!m_hasRendered) {
m_hasRendered = true;
}
m_brushes.Clear();
m_templates.Clear();
Render(sender, args.DrawingSession());
}
void SvgView::CreateResources(ICanvasResourceCreator const &resourceCreator, UI::CanvasCreateResourcesEventArgs const &args) {
if (m_group) {
m_group.CreateResources(resourceCreator, args);
}
}
void SvgView::Canvas_CreateResources(UI::Xaml::CanvasControl const &sender, UI::CanvasCreateResourcesEventArgs const &args) {
CreateResources(sender, args);
}
void SvgView::Canvas_SizeChanged(
IInspectable const & /*sender*/,
Windows::UI::Xaml::SizeChangedEventArgs const & /*args*/) {
// sender.Invalidate();
}
void SvgView::Panel_Unloaded(IInspectable const &sender, Windows::UI::Xaml::RoutedEventArgs const & /*args*/) {
if (auto const &svgView{sender.try_as<RNSVG::SvgView>()}) {
svgView.Unload();
}
}
void SvgView::Unload() {
m_reactContext = nullptr;
m_templates.Clear();
m_brushes.Clear();
if (m_group) {
m_group.Unload();
}
if (m_canvas) {
m_canvas.RemoveFromVisualTree();
m_canvas = nullptr;
}
}
void SvgView::InvalidateCanvas() {
if (m_hasRendered) {
m_canvas.Invalidate();
}
}
} // namespace winrt::RNSVG::implementation

95
windows/RNSVG/SvgView.h Normal file
View File

@@ -0,0 +1,95 @@
#pragma once
#include "SvgView.g.h"
namespace winrt::RNSVG::implementation {
struct SvgView : SvgViewT<SvgView> {
public:
SvgView() = default;
SvgView(Microsoft::ReactNative::IReactContext const &context);
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl Canvas() { return m_canvas; }
Windows::UI::Xaml::FrameworkElement SvgParent() { return m_parent; }
void SvgParent(Windows::UI::Xaml::FrameworkElement const &value);
RNSVG::GroupView Group() { return m_group; }
void Group(RNSVG::GroupView const &value) { m_group = value; }
Microsoft::Graphics::Canvas::Geometry::CanvasGeometry Geometry() { return m_group ? m_group.Geometry() : nullptr; }
void Geometry(Microsoft::Graphics::Canvas::Geometry::CanvasGeometry /*value*/) { }
float SvgScale() { return m_scale; }
Windows::Foundation::Collections::IMap<hstring, RNSVG::IRenderable> Templates() {
return m_templates;
}
Windows::Foundation::Collections::IMap<hstring, RNSVG::BrushView> Brushes() {
return m_brushes;
}
// IRenderable
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate = true, bool invalidate = true);
void MergeProperties(RNSVG::RenderableView const &other);
void SaveDefinition();
void Unload();
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
void CreateResources(
Microsoft::Graphics::Canvas::ICanvasResourceCreator const &resourceCreator,
Microsoft::Graphics::Canvas::UI::CanvasCreateResourcesEventArgs const &args);
// Overrides
Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size availableSize);
Windows::Foundation::Size ArrangeOverride(Windows::Foundation::Size finalSize);
// CanvasControl
void Canvas_Draw(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &sender,
Microsoft::Graphics::Canvas::UI::Xaml::CanvasDrawEventArgs const &args);
void Canvas_CreateResources(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &sender,
Microsoft::Graphics::Canvas::UI::CanvasCreateResourcesEventArgs const &args);
void Canvas_SizeChanged(
Windows::Foundation::IInspectable const &sender,
Windows::UI::Xaml::SizeChangedEventArgs const &args);
void Panel_Unloaded(Windows::Foundation::IInspectable const &sender, Windows::UI::Xaml::RoutedEventArgs const &args);
void InvalidateCanvas();
private:
bool m_hasRendered{false};
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl m_canvas{};
Windows::UI::Xaml::FrameworkElement m_parent{nullptr};
RNSVG::GroupView m_group{nullptr};
hstring m_id{L""};
float m_scale{0.0f};
float m_minX{0.0f};
float m_minY{0.0f};
float m_vbWidth{0.0f};
float m_vbHeight{0.0f};
RNSVG::SVGLength m_bbWidth{};
RNSVG::SVGLength m_bbHeight{};
RNSVG::SVGLength m_width{};
RNSVG::SVGLength m_height{};
std::string m_align{""};
RNSVG::MeetOrSlice m_meetOrSlice{RNSVG::MeetOrSlice::Meet};
Windows::Foundation::Collections::IMap<hstring, RNSVG::IRenderable> m_templates{
winrt::single_threaded_map<hstring, RNSVG::IRenderable>()};
Windows::Foundation::Collections::IMap<hstring, RNSVG::BrushView> m_brushes{
winrt::single_threaded_map<hstring, RNSVG::BrushView>()};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::Draw_revoker m_canvasDrawRevoker{};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::CreateResources_revoker m_canvasCreateResourcesRevoker{};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::SizeChanged_revoker m_canvasSizeChangedRevoker{};
Windows::UI::Xaml::FrameworkElement::Unloaded_revoker m_panelUnloadedRevoker{};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct SvgView : SvgViewT<SvgView, implementation::SvgView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,108 @@
#include "pch.h"
#include "SvgViewManager.h"
#if __has_include("SvgViewManager.g.cpp")
#include "SvgViewManager.g.cpp"
#endif
#include <winrt/Windows.UI.Xaml.Media.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>
#include "RenderableView.h"
#include "SvgView.h"
namespace winrt {
using namespace Windows::Foundation::Collections;
using namespace Microsoft::Graphics::Canvas::UI::Xaml;
using namespace Microsoft::ReactNative;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
} // namespace winrt
namespace winrt::RNSVG::implementation {
// IViewManager
hstring SvgViewManager::Name() {
return L"RNSVGSvgView";
}
FrameworkElement SvgViewManager::CreateView() {
return winrt::RNSVG::SvgView(m_reactContext);
}
// IViewManagerWithContext
IReactContext SvgViewManager::ReactContext() {
return m_reactContext;
}
void SvgViewManager::ReactContext(IReactContext const &reactContext) {
m_reactContext = reactContext;
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> SvgViewManager::NativeProps() {
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
nativeProps.Insert(L"height", ViewManagerPropertyType::Number);
nativeProps.Insert(L"width", ViewManagerPropertyType::Number);
// viewBox
nativeProps.Insert(L"minX", ViewManagerPropertyType::Number);
nativeProps.Insert(L"minY", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbHeight", ViewManagerPropertyType::Number);
nativeProps.Insert(L"bbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"bbHeight", ViewManagerPropertyType::Number);
// preserveAspectRatio
nativeProps.Insert(L"align", ViewManagerPropertyType::String);
nativeProps.Insert(L"meetOrSlice", ViewManagerPropertyType::Number);
return nativeProps.GetView();
}
void SvgViewManager::UpdateProperties(FrameworkElement const &view, IJSValueReader const &propertyMapReader) {
if (auto const &svgView{view.try_as<SvgView>()}) {
svgView->UpdateProperties(propertyMapReader);
}
}
// IViewManagerWithChildren
void SvgViewManager::AddView(FrameworkElement const &parent, UIElement const &child, int64_t /*index*/) {
auto const &svgView{parent.try_as<RNSVG::SvgView>()};
auto const &group{child.try_as<RNSVG::GroupView>()};
if (svgView && group) {
// Every SvgView has exactly one child - a Group that gets
// all of Svg's children piped through.
group.SvgParent(parent);
svgView.Group(group);
}
}
void SvgViewManager::RemoveAllChildren(FrameworkElement const &parent) {
auto const &svgView{parent.try_as<RNSVG::SvgView>()};
if (svgView && svgView.Group()) {
svgView.Group().Unload();
}
svgView.Group(nullptr);
}
void SvgViewManager::RemoveChildAt(FrameworkElement const &parent, int64_t /*index*/) {
RemoveAllChildren(parent);
}
void SvgViewManager::ReplaceChild(
FrameworkElement const &parent,
UIElement const &oldChild,
UIElement const &newChild) {
auto const &svgView{parent.try_as<RNSVG::SvgView>()};
auto const &oldGroup{oldChild.try_as<RNSVG::GroupView>()};
auto const &newGroup{newChild.try_as<RNSVG::GroupView>()};
if (svgView && oldGroup && newGroup) {
newGroup.MergeProperties(oldGroup);
oldGroup.Unload();
newGroup.SvgParent(parent);
svgView.Group(newGroup);
}
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,40 @@
#pragma once
#include "SvgViewManager.g.h"
namespace winrt::RNSVG::implementation {
struct SvgViewManager : SvgViewManagerT<SvgViewManager> {
SvgViewManager() = default;
// IViewManager
hstring Name();
Windows::UI::Xaml::FrameworkElement CreateView();
// IViewManagerWithReactContext
Microsoft::ReactNative::IReactContext ReactContext();
void ReactContext(Microsoft::ReactNative::IReactContext const &value);
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
void UpdateProperties(
Windows::UI::Xaml::FrameworkElement const &view,
Microsoft::ReactNative::IJSValueReader const &propertyMapReader);
// IViewManagerWithChildren
void
AddView(Windows::UI::Xaml::FrameworkElement const &parent, Windows::UI::Xaml::UIElement const &child, int64_t index);
void RemoveAllChildren(Windows::UI::Xaml::FrameworkElement const &parent);
void RemoveChildAt(Windows::UI::Xaml::FrameworkElement const &parent, int64_t index);
void ReplaceChild(
Windows::UI::Xaml::FrameworkElement const &parent,
Windows::UI::Xaml::UIElement const &oldChild,
Windows::UI::Xaml::UIElement const &newChild);
private:
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct SvgViewManager : SvgViewManagerT<SvgViewManager, implementation::SvgViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,37 @@
#include "pch.h"
#include "SymbolView.h"
#include "SymbolView.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void SymbolView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "vbWidth") {
m_vbWidth = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "vbHeight") {
m_vbHeight = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minX") {
m_minX = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minY") {
m_minY = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,35 @@
#pragma once
#include "SymbolView.g.h"
#include "GroupView.h"
namespace winrt::RNSVG::implementation {
struct SymbolView : SymbolViewT<SymbolView, RNSVG::implementation::GroupView> {
public:
SymbolView() = default;
float MinX() { return m_minX; }
float MinY() { return m_minY; }
float VbWidth() { return m_vbWidth; }
float VbHeight() { return m_vbHeight; }
hstring Align() { return to_hstring(m_align); }
RNSVG::MeetOrSlice MeetOrSlice() { return m_meetOrSlice; }
// RenderableView
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &/*canvas*/,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &/*session*/){};
private:
float m_minX{0.0f};
float m_minY{0.0f};
float m_vbWidth{0.0f};
float m_vbHeight{0.0f};
std::string m_align{""};
RNSVG::MeetOrSlice m_meetOrSlice{RNSVG::MeetOrSlice::Meet};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct SymbolView : SymbolViewT<SymbolView, implementation::SymbolView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,32 @@
#include "pch.h"
#include "SymbolViewManager.h"
#include "SymbolViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation
{
SymbolViewManager::SymbolViewManager() {
m_class = RNSVG::SVGClass::RNSVGSymbol;
m_name = L"RNSVGSymbol";
}
IMapView<hstring, ViewManagerPropertyType> SymbolViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"minX", ViewManagerPropertyType::Number);
nativeProps.Insert(L"minY", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbHeight", ViewManagerPropertyType::Number);
nativeProps.Insert(L"align", ViewManagerPropertyType::String);
nativeProps.Insert(L"meetOrSlice", ViewManagerPropertyType::Number);
return nativeProps.GetView();
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "SymbolViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct SymbolViewManager : SymbolViewManagerT<SymbolViewManager, RNSVG::implementation::GroupViewManager> {
SymbolViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct SymbolViewManager : SymbolViewManagerT<SymbolViewManager, implementation::SymbolViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,52 @@
#include "pch.h"
#include "TSpanView.h"
#include "TSpanView.g.cpp"
#include "Utils.h"
#include <winrt/Microsoft.Graphics.Canvas.Text.h>
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void TSpanView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "content") {
m_content = propertyValue.AsString();
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void TSpanView::CreateGeometry(UI::Xaml::CanvasControl const &canvas) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
Microsoft::Graphics::Canvas::Text::CanvasTextFormat const& textFormat{};
textFormat.FontSize(FontSize());
textFormat.FontFamily(FontFamily());
textFormat.FontWeight(Utils::FontWeightFrom(FontWeight(), SvgParent()));
Geometry(Geometry::CanvasGeometry::CreateText({resourceCreator, to_hstring(m_content), textFormat, canvas.Size().Width, canvas.Size().Height}));
}
void TSpanView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
auto const &transform{session.Transform()};
bool translateXY{X().Size() > 0 || Y().Size() > 0};
if (translateXY) {
float x{X().Size() > 0 ? X().GetAt(0).Value() : 0};
float y{Y().Size() > 0 ? Y().GetAt(0).Value() : 0};
session.Transform(transform * Numerics::make_float3x2_translation(x, y));
}
__super::Render(canvas, session);
if (translateXY) {
session.Transform(transform);
}
}
} // namespace winrt::RNSVG::implementation

23
windows/RNSVG/TSpanView.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
#include "TSpanView.g.h"
#include "TextView.h"
namespace winrt::RNSVG::implementation {
struct TSpanView : TSpanViewT<TSpanView, RNSVG::implementation::TextView> {
public:
TSpanView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void CreateGeometry(Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas);
virtual void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
private:
std::string m_content;
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct TSpanView : TSpanViewT<TSpanView, implementation::TSpanView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,26 @@
#include "pch.h"
#include "TSpanViewManager.h"
#include "TSpanViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
TSpanViewManager::TSpanViewManager() {
m_class = RNSVG::SVGClass::RNSVGTSpan;
m_name = L"RNSVGTSpan";
}
Windows::Foundation::Collections::IMapView<hstring, ViewManagerPropertyType> TSpanViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"content", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "TSpanViewManager.g.h"
#include "TextViewManager.h"
namespace winrt::RNSVG::implementation {
struct TSpanViewManager : TSpanViewManagerT<TSpanViewManager, RNSVG::implementation::TextViewManager> {
TSpanViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct TSpanViewManager : TSpanViewManagerT<TSpanViewManager, implementation::TSpanViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,61 @@
#include "pch.h"
#include "TextView.h"
#include "TextView.g.cpp"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void TextView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "x") {
m_x.Clear();
for (auto const &item : propertyValue.AsArray()) {
m_x.Append(SVGLength::From(item));
}
} else if (propertyName == "y") {
m_y.Clear();
for (auto const &item : propertyValue.AsArray()) {
m_y.Append(SVGLength::From(item));
}
} else if (propertyName == "dx") {
m_dx.Clear();
for (auto const &item : propertyValue.AsArray()) {
m_dx.Append(SVGLength::From(item));
}
} else if (propertyName == "dy") {
m_dy.Clear();
for (auto const &item : propertyValue.AsArray()) {
m_dy.Append(SVGLength::From(item));
}
} else if (propertyName == "rotate") {
m_rotate.Clear();
for (auto const &item : propertyValue.AsArray()) {
m_rotate.Append(SVGLength::From(item));
}
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void TextView::RenderGroup(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
auto const &transform{session.Transform()};
bool translateXY{X().Size() > 0 || Y().Size() > 0};
if (translateXY) {
float x{X().Size() > 0 ? X().GetAt(0).Value() : 0};
float y{Y().Size() > 0 ? Y().GetAt(0).Value() : 0};
session.Transform(transform * Numerics::make_float3x2_translation(x, y));
}
__super::RenderGroup(canvas, session);
if (translateXY) {
session.Transform(transform);
}
}
} // namespace winrt::RNSVG::implementation

31
windows/RNSVG/TextView.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include "TextView.g.h"
#include "GroupView.h"
namespace winrt::RNSVG::implementation {
struct TextView : TextViewT<TextView, RNSVG::implementation::GroupView> {
public:
TextView() = default;
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> X() { return m_x; }
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> Y() { return m_y; }
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> DX() { return m_dx; }
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> DY() { return m_dy; }
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> Rotate() { return m_rotate; }
virtual void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
virtual void RenderGroup(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
private:
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_x{winrt::single_threaded_vector<RNSVG::SVGLength>()};
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_y{winrt::single_threaded_vector<RNSVG::SVGLength>()};
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_dx{winrt::single_threaded_vector<RNSVG::SVGLength>()};
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_dy{winrt::single_threaded_vector<RNSVG::SVGLength>()};
Windows::Foundation::Collections::IVector<RNSVG::SVGLength> m_rotate{winrt::single_threaded_vector<RNSVG::SVGLength>()};
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct TextView : TextViewT<TextView, implementation::TextView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,30 @@
#include "pch.h"
#include "TextViewManager.h"
#include "TextViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
TextViewManager::TextViewManager() {
m_class = RNSVG::SVGClass::RNSVGText;
m_name = L"RNSVGText";
}
Windows::Foundation::Collections::IMapView<hstring, ViewManagerPropertyType> TextViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"x", ViewManagerPropertyType::Array);
nativeProps.Insert(L"y", ViewManagerPropertyType::Array);
nativeProps.Insert(L"dx", ViewManagerPropertyType::Array);
nativeProps.Insert(L"dy", ViewManagerPropertyType::Array);
nativeProps.Insert(L"rotate", ViewManagerPropertyType::Array);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,15 @@
#pragma once
#include "TextViewManager.g.h"
#include "GroupViewManager.h"
namespace winrt::RNSVG::implementation {
struct TextViewManager : TextViewManagerT<TextViewManager, RNSVG::implementation::GroupViewManager> {
TextViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct TextViewManager : TextViewManagerT<TextViewManager, implementation::TextViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

79
windows/RNSVG/Types.idl Normal file
View File

@@ -0,0 +1,79 @@
namespace RNSVG {
enum SVGClass {
RNSVGGroup,
RNSVGPath,
RNSVGText,
RNSVGTSpan,
RNSVGTextPath,
RNSVGImage,
RNSVGCircle,
RNSVGEllipse,
RNSVGLine,
RNSVGRect,
RNSVGClipPath,
RNSVGDefs,
RNSVGUse,
RNSVGSymbol,
RNSVGLinearGradient,
RNSVGRadialGradient,
RNSVGPattern,
RNSVGMask,
RNSVGMarker,
RNSVGForeignObject,
Unknown,
};
enum MeetOrSlice {
Meet,
Slice,
None,
};
enum BaseProp {
Matrix,
Fill,
FillOpacity,
FillRule,
Stroke,
StrokeOpacity,
StrokeWidth,
StrokeMiterLimit,
StrokeDashOffset,
StrokeDashArray,
StrokeLineCap,
StrokeLineJoin,
Unknown,
};
enum FontProp {
FontSize,
FontWeight,
FontFamily,
Unknown,
};
enum LengthType
{
Unknown,
Number,
Percentage,
EMS,
EXS,
Pixel,
Centimeter,
Millimeter,
Inch,
Point,
Pica,
};
[default_interface]
runtimeclass SVGLength {
SVGLength();
SVGLength(Single param);
SVGLength(Single param, LengthType type);
Single Value{ get; };
LengthType Unit{ get; };
};
}

105
windows/RNSVG/UseView.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "pch.h"
#include "UseView.h"
#include "UseView.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
void UseView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
const JSValueObject &propertyMap{JSValue::ReadObjectFrom(reader)};
for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};
if (propertyName == "href") {
m_href = to_hstring(Utils::JSValueAsString(propertyValue));
} else if (propertyName == "x") {
m_x = SVGLength::From(propertyValue);
} else if (propertyName == "y") {
m_y = SVGLength::From(propertyValue);
} else if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
}
}
__super::UpdateProperties(reader, forceUpdate, invalidate);
}
void UseView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
if (auto const &view{GetRenderableTemplate()}) {
auto const &originalTransform{session.Transform()};
auto transform{Numerics::make_float3x2_scale(1)};
// Figure out any necessary transforms
if (auto const &symbol{view.try_as<RNSVG::SymbolView>()}) {
if (symbol.Align() != L"") {
if (auto const &root{SvgRoot()}) {
Rect vbRect{
symbol.MinX() * root.SvgScale(),
symbol.MinY() * root.SvgScale(),
(symbol.MinX() + symbol.VbWidth()) * root.SvgScale(),
(symbol.MinY() + symbol.VbHeight()) * root.SvgScale()};
float elX{Utils::GetAbsoluteLength(m_x, canvas.Size().Width)};
float elY{Utils::GetAbsoluteLength(m_y, canvas.Size().Height)};
float elWidth{Utils::GetAbsoluteLength(m_width, canvas.Size().Width)};
float elHeight{Utils::GetAbsoluteLength(m_height, canvas.Size().Height)};
Rect elRect{elX, elY, elWidth, elHeight};
transform = Utils::GetViewBoxTransform(vbRect, elRect, to_string(symbol.Align()), symbol.MeetOrSlice());
}
}
} else {
float x{Utils::GetAbsoluteLength(m_x, canvas.Size().Width)};
float y{Utils::GetAbsoluteLength(m_y, canvas.Size().Height)};
transform = Numerics::make_float3x2_translation({x, y});
}
// Combine new transform with existing one if it's set
if (m_propSetMap[RNSVG::BaseProp::Matrix]) {
transform = transform * SvgTransform();
}
session.Transform(transform);
// Propagate props to template
view.MergeProperties(*this);
// Set opacity and render
if (auto const &opacityLayer{session.CreateLayer(m_opacity)}) {
if (auto const &symbol{view.try_as<RNSVG::SymbolView>()}) {
symbol.RenderGroup(canvas, session);
} else {
view.Render(canvas, session);
}
opacityLayer.Close();
}
// Restore original template props
if (auto const &parent{view.SvgParent().try_as<RNSVG::RenderableView>()}) {
view.MergeProperties(parent);
}
// Restore session transform
session.Transform(originalTransform);
} else {
throw hresult_not_implemented(L"'Use' element expected a pre-defined svg template as 'href' prop. Template named: " + m_href + L" is not defined");
}
}
RNSVG::IRenderable UseView::GetRenderableTemplate() {
if (auto const &root{SvgRoot()}) {
return root.Templates().TryLookup(m_href);
}
return nullptr;
}
} // namespace winrt::RNSVG::implementation

28
windows/RNSVG/UseView.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include "UseView.g.h"
#include "RenderableView.h"
namespace winrt::RNSVG::implementation {
struct UseView : UseViewT<UseView, RNSVG::implementation::RenderableView> {
public:
UseView() = default;
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate, bool invalidate);
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
private:
hstring m_href{L""};
RNSVG::SVGLength m_x{};
RNSVG::SVGLength m_y{};
RNSVG::SVGLength m_width{};
RNSVG::SVGLength m_height{};
RNSVG::IRenderable GetRenderableTemplate();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct UseView : UseViewT<UseView, implementation::UseView> {};
} // namespace winrt::RNSVG::factory_implementation

View File

@@ -0,0 +1,30 @@
#include "pch.h"
#include "UseViewManager.h"
#include "UseViewManager.g.cpp"
using namespace winrt;
using namespace Microsoft::ReactNative;
namespace winrt::RNSVG::implementation {
UseViewManager::UseViewManager() {
m_class = RNSVG::SVGClass::RNSVGUse;
m_name = L"RNSVGUse";
}
IMapView<hstring, ViewManagerPropertyType> UseViewManager::NativeProps() {
auto const &parentProps{__super::NativeProps()};
auto const &nativeProps{winrt::single_threaded_map<hstring, ViewManagerPropertyType>()};
for (auto const &prop : parentProps) {
nativeProps.Insert(prop.Key(), prop.Value());
}
nativeProps.Insert(L"href", ViewManagerPropertyType::String);
nativeProps.Insert(L"x", ViewManagerPropertyType::String);
nativeProps.Insert(L"y", ViewManagerPropertyType::String);
nativeProps.Insert(L"width", ViewManagerPropertyType::String);
nativeProps.Insert(L"height", ViewManagerPropertyType::String);
return nativeProps.GetView();
}
} // namespace winrt::RNSVG::implementation

View File

@@ -0,0 +1,16 @@
#pragma once
#include "UseViewManager.g.h"
#include "RenderableViewManager.h"
namespace winrt::RNSVG::implementation {
struct UseViewManager : UseViewManagerT<UseViewManager, RNSVG::implementation::RenderableViewManager> {
UseViewManager();
// IViewManagerWithNativeProperties
Windows::Foundation::Collections::IMapView<hstring, Microsoft::ReactNative::ViewManagerPropertyType> NativeProps();
};
} // namespace winrt::RNSVG::implementation
namespace winrt::RNSVG::factory_implementation {
struct UseViewManager : UseViewManagerT<UseViewManager, implementation::UseViewManager> {};
} // namespace winrt::RNSVG::factory_implementation

341
windows/RNSVG/Utils.h Normal file
View File

@@ -0,0 +1,341 @@
#pragma once
#include "pch.h"
#include <winrt/Microsoft.Graphics.Canvas.Brushes.h>
#include <winrt/Windows.Foundation.Numerics.h>
#include <winrt/Windows.UI.Text.h>
#include "JSValueReader.h"
#define _USE_MATH_DEFINES
#include <math.h>
using namespace winrt;
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::ReactNative;
using namespace Windows::UI;
using namespace Windows::UI::Text;
namespace winrt::RNSVG {
struct Utils {
public:
static std::vector<float> GetAdjustedStrokeArray(IVector<SVGLength> const &value, float strokeWidth, float canvasDiagonal) {
std::vector<float> result;
for (auto const &item : value) {
float absValue{GetAbsoluteLength(item, canvasDiagonal)};
// Win2D sets the length of each dash as the product of the element value in array and stroke width,
// we divide each value in the dashArray by StrokeWidth to account for this.
// http://microsoft.github.io/Win2D/WinUI2/html/P_Microsoft_Graphics_Canvas_Geometry_CanvasStrokeStyle_CustomDashStyle.htm
result.push_back(absValue / (strokeWidth == 0.0f ? 1.0f : strokeWidth));
}
return std::move(result);
}
static float GetCanvasDiagonal(Windows::Foundation::Size const &size) {
float powX{std::powf(size.Width, 2)};
float powY{std::powf(size.Height, 2)};
return std::sqrtf(powX + powY) * static_cast<float>(M_SQRT1_2);
}
static float GetAbsoluteLength(SVGLength const &length, float relativeTo) {
auto value{length.Value()};
// 1in = 2.54cm = 96px
auto inch{96.0f};
auto cm{inch / 2.54f};
switch (length.Unit()) {
case RNSVG::LengthType::Percentage:
return value / 100.0f * relativeTo;
case RNSVG::LengthType::Centimeter:
// 1cm = 96px/2.54
return value * cm;
case RNSVG::LengthType::Millimeter:
// 1mm = 1/10th of 1cm
return value * cm / 10.0f;
case RNSVG::LengthType::Inch:
// 1in = 2.54cm = 96px
return value * inch;
case RNSVG::LengthType::Point:
// 1pt = 1/72th of 1in
return value * inch / 72.0f;
case RNSVG::LengthType::Pica:
// 1pc = 1/6th of 1in
return value * inch / 6.0f;
case RNSVG::LengthType::Pixel:
default:
return value;
}
}
static Numerics::float3x2 GetRotationMatrix(float degrees) {
// convert to radians
auto radians{degrees * static_cast<float>(M_PI) / 100.0f};
return Numerics::make_float3x2_rotation(radians);
}
static FontWeight FontWeightFrom(hstring const& weight, Xaml::FrameworkElement const& parent) {
if (weight == L"normal") {
return FontWeights::Normal();
} else if (weight == L"bold") {
return FontWeights::Bold();
} else if (weight == L"bolder" || weight == L"lighter" || weight == L"auto") {
auto const &groupView{parent.try_as<RNSVG::GroupView>()};
FontWeight parentWeight{
groupView ? FontWeightFrom(groupView.FontWeight(), groupView.SvgParent()) : FontWeights::Normal()};
if (weight == L"bolder") {
return Bolder(parentWeight.Weight);
} else if (weight == L"lighter") {
return Lighter(parentWeight.Weight);
} else if (weight == L"auto") {
return parentWeight;
}
}
return GetClosestFontWeight(std::stof(weight.c_str(), nullptr));
}
static FontWeight GetClosestFontWeight(float weight) {
if (weight > 325 && weight < 375) {
return FontWeights::SemiLight();
} else if (weight > 925) {
return FontWeights::ExtraBlack();
} else {
switch (static_cast<uint16_t>(std::round(weight / 100.0f))) {
case 1:
return FontWeights::Thin();
case 2:
return FontWeights::ExtraLight();
case 3:
return FontWeights::Light();
case 4:
return FontWeights::Normal();
case 5:
return FontWeights::Medium();
case 6:
return FontWeights::SemiBold();
case 7:
return FontWeights::Bold();
case 8:
return FontWeights::ExtraBold();
case 9:
default:
return FontWeights::ExtraBlack();
}
}
}
static FontWeight Bolder(uint16_t weight) {
if (weight < 350) {
return FontWeights::Normal();
} else if (weight < 550) {
return FontWeights::Bold();
} else if (weight < 900) {
return FontWeights::Black();
} else {
return FontWeights::ExtraBlack();
}
}
static FontWeight Lighter(uint16_t weight) {
if (weight < 550) {
return FontWeights::Thin();
} else if (weight < 750) {
return FontWeights::Normal();
} else {
return FontWeights::Bold();
}
}
static Numerics::float3x2 GetViewBoxTransform(Rect vbRect, Rect elRect, std::string align, RNSVG::MeetOrSlice 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.
float vbX = vbRect.X;
float vbY = vbRect.Y;
float vbWidth = vbRect.Width;
float vbHeight = vbRect.Height;
// Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
float eX = elRect.X;
float eY = elRect.Y;
float eWidth = elRect.Width;
float eHeight = elRect.Height;
// Initialize scale-x to e-width/vb-width.
float scaleX = eWidth / vbWidth;
// Initialize scale-y to e-height/vb-height.
float scaleY = eHeight / vbHeight;
// 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 != "none" && meetOrSlice == RNSVG::MeetOrSlice::Meet) {
scaleX = scaleY = std::min(scaleX, scaleY);
} else if (align != "none" && meetOrSlice == RNSVG::MeetOrSlice::Slice) {
scaleX = scaleY = std::max(scaleX, scaleY);
}
// Initialize translate-x to e-x - (vb-x * scale-x).
float translateX = eX - (vbX * scaleX);
// Initialize translate-y to e-y - (vb-y * scale-y).
float translateY = eY - (vbY * scaleY);
// If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
if (align.find("xMid") != std::string::npos) {
translateX += (eWidth - vbWidth * scaleX) / 2.0f;
}
// If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
if (align.find("xMax") != std::string::npos) {
translateX += (eWidth - vbWidth * scaleX);
}
// If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
if (align.find("YMid") != std::string::npos) {
translateY += (eHeight - vbHeight * scaleY) / 2.0f;
}
// If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
if (align.find("YMax") != std::string::npos) {
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).
auto const &translate{Numerics::make_float3x2_translation(translateX, translateY)};
auto const &scale{Numerics::make_float3x2_scale(scaleX, scaleY)};
return scale * translate;
}
static RNSVG::MeetOrSlice GetMeetOrSlice(JSValue const &value) {
if (value.IsNull()) {
return RNSVG::MeetOrSlice::Meet;
}
switch (value.AsInt8()) {
case 2:
return RNSVG::MeetOrSlice::None;
case 1:
return RNSVG::MeetOrSlice::Slice;
case 0:
default:
return RNSVG::MeetOrSlice::Meet;
}
}
static std::string JSValueAsBrushUnits(JSValue const &value, std::string defaultValue = "objectBoundingBox") {
if (value.IsNull()) {
return defaultValue;
} else {
switch (value.AsInt32()) {
case 1:
return "userSpaceOnUse";
case 0:
default:
return "objectBoundingBox";
}
}
}
static float JSValueAsFloat(JSValue const &value, float defaultValue = 0.0f) {
if (value.IsNull()) {
return defaultValue;
} else {
return value.AsSingle();
}
}
static std::string JSValueAsString(JSValue const &value, std::string defaultValue = "") {
if (value.IsNull()) {
return defaultValue;
} else {
return value.AsString();
}
}
static Color JSValueAsColor(JSValue const &value, Color defaultValue = Colors::Transparent()) {
if (value.IsNull()) {
return defaultValue;
} else if (auto const &brush{value.To<Xaml::Media::Brush>()}) {
if (auto const &scb{brush.try_as<Xaml::Media::SolidColorBrush>()}) {
return scb.Color();
}
}
return defaultValue;
}
static SVGLength JSValueAsSVGLength(JSValue const &value, SVGLength const &defaultValue = {}) {
if (value.IsNull()) {
return defaultValue;
} else {
return RNSVG::implementation::SVGLength::From(value);
}
}
static Numerics::float3x2 JSValueAsTransform(JSValue const& value, Numerics::float3x2 defaultValue = {}) {
if (value.IsNull()) {
return defaultValue;
} else {
auto const &matrix{value.AsArray()};
return Numerics::float3x2(
matrix.at(0).AsSingle(),
matrix.at(1).AsSingle(),
matrix.at(2).AsSingle(),
matrix.at(3).AsSingle(),
matrix.at(4).AsSingle(),
matrix.at(5).AsSingle());
}
}
static std::vector<Brushes::CanvasGradientStop> JSValueAsStops(JSValue const& value) {
if (value.IsNull()) {
return {};
}
auto const &stops{value.AsArray()};
std::vector<Brushes::CanvasGradientStop> canvasStops{};
for (size_t i = 0; i < stops.size(); ++i) {
Brushes::CanvasGradientStop stop{};
stop.Position = Utils::JSValueAsFloat(stops.at(i));
stop.Color = Utils::JSValueAsColor(stops.at(++i));
canvasStops.push_back(stop);
}
return canvasStops;
}
static Brushes::ICanvasBrush GetCanvasBrush(
hstring const &brushId,
Color color,
RNSVG::SvgView const &root,
Geometry::CanvasGeometry const &geometry,
ICanvasResourceCreator const &resourceCreator) {
Brushes::ICanvasBrush brush{nullptr};
if (root && brushId != L"") {
if (auto const &brushView{root.Brushes().TryLookup(brushId)}) {
brushView.SetBounds(geometry.ComputeBounds());
brush = brushView.Brush();
}
}
if (!brush) {
brush = Brushes::CanvasSolidColorBrush(resourceCreator, color);
}
return brush;
}
};
} // namespace winrt::RNSVG

View File

@@ -0,0 +1,115 @@
import "Types.idl";
namespace RNSVG
{
[default_interface]
runtimeclass SvgViewManager
: Microsoft.ReactNative.IViewManager
, Microsoft.ReactNative.IViewManagerWithReactContext
, Microsoft.ReactNative.IViewManagerWithNativeProperties
, Microsoft.ReactNative.IViewManagerWithChildren
{
SvgViewManager();
};
[default_interface]
unsealed runtimeclass RenderableViewManager
: Microsoft.ReactNative.IViewManager
, Microsoft.ReactNative.IViewManagerWithReactContext
, Microsoft.ReactNative.IViewManagerWithNativeProperties
{
RenderableViewManager();
};
[default_interface]
runtimeclass RectViewManager : RenderableViewManager
{
RectViewManager();
};
[default_interface]
runtimeclass CircleViewManager : RenderableViewManager
{
CircleViewManager();
};
[default_interface]
runtimeclass EllipseViewManager : RenderableViewManager
{
EllipseViewManager();
};
[default_interface]
runtimeclass LineViewManager : RenderableViewManager
{
LineViewManager();
};
[default_interface]
runtimeclass PathViewManager : RenderableViewManager
{
PathViewManager();
};
[default_interface]
runtimeclass UseViewManager : RenderableViewManager
{
UseViewManager();
};
[default_interface]
runtimeclass ImageViewManager : RenderableViewManager
{
ImageViewManager();
};
[default_interface]
unsealed runtimeclass GroupViewManager
: RenderableViewManager
, Microsoft.ReactNative.IViewManagerWithChildren
{
GroupViewManager();
};
[default_interface]
runtimeclass DefsViewManager : GroupViewManager
{
DefsViewManager();
};
[default_interface]
runtimeclass LinearGradientViewManager : GroupViewManager
{
LinearGradientViewManager();
};
[default_interface]
runtimeclass RadialGradientViewManager : GroupViewManager
{
RadialGradientViewManager();
};
[default_interface]
runtimeclass PatternViewManager : GroupViewManager
{
PatternViewManager();
};
[default_interface]
runtimeclass SymbolViewManager : GroupViewManager
{
SymbolViewManager();
};
[default_interface]
unsealed runtimeclass TextViewManager : GroupViewManager
{
TextViewManager();
};
[default_interface]
runtimeclass TSpanViewManager : TextViewManager
{
TSpanViewManager();
};
}

181
windows/RNSVG/Views.idl Normal file
View File

@@ -0,0 +1,181 @@
import "Types.idl";
namespace RNSVG
{
interface IRenderable
{
Windows.UI.Xaml.FrameworkElement SvgParent;
Microsoft.Graphics.Canvas.Geometry.CanvasGeometry Geometry;
void CreateResources(
Microsoft.Graphics.Canvas.ICanvasResourceCreator resourceCreator,
Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args);
void Render(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl canvas,
Microsoft.Graphics.Canvas.CanvasDrawingSession session);
void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader, Boolean forceUpdate, Boolean invalidate);
void MergeProperties(RenderableView other);
void SaveDefinition();
void Unload();
};
[default_interface]
runtimeclass SvgView : Windows.UI.Xaml.Controls.Panel, IRenderable
{
SvgView(Microsoft.ReactNative.IReactContext context);
Single SvgScale{ get; };
GroupView Group;
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl Canvas{ get; };
Windows.Foundation.Collections.IMap<String, IRenderable> Templates{ get; };
Windows.Foundation.Collections.IMap<String, BrushView> Brushes{ get; };
void InvalidateCanvas();
};
[default_interface]
unsealed runtimeclass RenderableView : Windows.UI.Xaml.FrameworkElement, IRenderable
{
RenderableView(Microsoft.ReactNative.IReactContext context);
SvgView SvgRoot{ get; };
String Id{ get; };
Windows.Foundation.Numerics.Matrix3x2 SvgTransform{ get; };
Windows.UI.Color Fill{ get; };
Single FillOpacity{ get; };
String FillBrushId{ get; };
Windows.UI.Color Stroke{ get; };
Single StrokeOpacity{ get; };
String StrokeBrushId{ get; };
SVGLength StrokeWidth{ get; };
Single StrokeMiterLimit{ get; };
Single StrokeDashOffset{ get; };
Windows.Foundation.Collections.IVector<SVGLength> StrokeDashArray{ get; };
Microsoft.Graphics.Canvas.Geometry.CanvasCapStyle StrokeLineCap{ get; };
Microsoft.Graphics.Canvas.Geometry.CanvasLineJoin StrokeLineJoin{ get; };
Microsoft.Graphics.Canvas.Geometry.CanvasFilledRegionDetermination FillRule{ get; };
void CreateGeometry(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl canvas);
};
[default_interface]
runtimeclass RectView : RenderableView
{
RectView();
};
[default_interface]
runtimeclass CircleView : RenderableView
{
CircleView();
};
[default_interface]
runtimeclass EllipseView : RenderableView
{
EllipseView();
};
[default_interface]
runtimeclass LineView : RenderableView
{
LineView();
};
[default_interface]
runtimeclass PathView : RenderableView
{
PathView();
};
[default_interface]
runtimeclass UseView : RenderableView
{
UseView();
};
[default_interface]
runtimeclass ImageView : RenderableView
{
ImageView();
};
[default_interface]
unsealed runtimeclass GroupView : RenderableView
{
GroupView(Microsoft.ReactNative.IReactContext context);
Windows.Foundation.Collections.IVector<IRenderable> Children { get; };
Single FontSize;
String FontFamily;
String FontWeight;
void RenderGroup(
Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl canvas,
Microsoft.Graphics.Canvas.CanvasDrawingSession session);
};
[default_interface]
unsealed runtimeclass TextView : GroupView
{
TextView();
Windows.Foundation.Collections.IVector<SVGLength> X{ get; };
Windows.Foundation.Collections.IVector<SVGLength> Y{ get; };
Windows.Foundation.Collections.IVector<SVGLength> DX{ get; };
Windows.Foundation.Collections.IVector<SVGLength> DY{ get; };
};
[default_interface]
runtimeclass TSpanView : TextView
{
TSpanView();
Windows.Foundation.Collections.IVector<SVGLength> Rotate { get; };
};
[default_interface]
runtimeclass DefsView : GroupView
{
DefsView();
};
[default_interface]
runtimeclass SymbolView : GroupView
{
SymbolView();
Single MinX{ get; };
Single MinY{ get; };
Single VbWidth{ get; };
Single VbHeight{ get; };
String Align{ get; };
MeetOrSlice MeetOrSlice{ get; };
};
[default_interface]
unsealed runtimeclass BrushView : GroupView
{
BrushView();
Microsoft.Graphics.Canvas.Brushes.ICanvasBrush Brush{ get; };
void CreateBrush();
void SetBounds(Windows.Foundation.Rect rect);
};
[default_interface]
runtimeclass LinearGradientView : BrushView
{
LinearGradientView();
};
[default_interface]
runtimeclass RadialGradientView : BrushView
{
RadialGradientView();
};
[default_interface]
runtimeclass PatternView : BrushView
{
PatternView();
};
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.UI.Xaml" version="2.3.191129002" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.200615.7" targetFramework="native" />
<package id="Win2D.uwp" version="1.25.0" targetFramework="native" />
</packages>

1
windows/RNSVG/pch.cpp Normal file
View File

@@ -0,0 +1 @@
#include "pch.h"

31
windows/RNSVG/pch.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#define NOMINMAX
#include <hstring.h>
#include <restrictederrorinfo.h>
#include <unknwn.h>
#include <windows.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Data.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Xaml.Media.h>
#include <winrt/Windows.UI.Xaml.Navigation.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Microsoft.Graphics.Canvas.h>
#include <winrt/Microsoft.Graphics.Canvas.Geometry.h>
#include <winrt/Microsoft.Graphics.Canvas.UI.Xaml.h>
#include <winrt/Microsoft.ReactNative.h>
#include <winrt/Microsoft.UI.Xaml.Automation.Peers.h>
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>
#include <winrt/Microsoft.UI.Xaml.Media.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
using namespace winrt::Windows::Foundation;